AVR128, CCP und Optimierung

OP #6673433
Lesenswert?

Hallo Zusammen,
ich programmiere gerade für einen AVR128DA32.

Hier kann man die Clock Settings nur anpassen wenn vorher der CCP 
Register mit einem bestimmten Wert beschrieben wird, und danach 
innerhalb von 4 Clockzyklen kann dann die Clock Einstellung geschrieben 
werden.

Habe nun bemerkt dass dies mit Optimierung -O0 nicht funktioniert.
Das ASM listing zeigt auch warum. Es vergehen mehr als 4 Zyklen bevor 
CLKCTRL_OSCHFCTRLA geschrieben wird.

Meine Frage ist nun warum. Warum wird ohne Optimierung erst ein anderes 
Registerpaar mit der Adresse geladen und danach in Z kopiert.
Und d.h. mit O0 kann man die Clocksettings in C nicht umstellen und 
müsste evt. händisch ASM Befehle einfügen?
1
CCP=0xD8;
2
CLKCTRL_OSCHFCTRLA=0x24;
1
CCP=0xD8;
2
     a7e:  84 e3         ldi  r24, 0x34  ; 52
3
     a80:  90 e0         ldi  r25, 0x00  ; 0
4
     a82:  28 ed         ldi  r18, 0xD8  ; 216
5
     a84:  fc 01         movw  r30, r24
6
     a86:  20 83         st  Z, r18
7
  CLKCTRL_OSCHFCTRLA=0x24;
8
     a88:  88 e6         ldi  r24, 0x68  ; 104
9
     a8a:  90 e0         ldi  r25, 0x00  ; 0
10
     a8c:  24 e2         ldi  r18, 0x24  ; 36
11
     a8e:  fc 01         movw  r30, r24
12
     a90:  20 83         st  Z, r18

PS:
Mit Optimierung (Os) wird aus den 5 Zeilen vorher um eine Konstante zu 
schreiben ein 2 Zeiler:
1
198:  88 ed         ldi  r24, 0xD8  ; 216
2
19a:  84 bf         out  0x34, r24  ; 52
OP #6673629
Lesenswert?

Wilhelm M. schrieb:
> Cyblord -. schrieb:
>> Habe nun bemerkt dass dies mit Optimierung -O0 nicht funktioniert.
>
> Sorry, das habe ich jetzt erst gelesen: -O0 schaltet fast alle
> Optimierungen ab.

Das ist bekannt. Erklärt für mich aber nicht warum hier derart unnötige 
Operationen eingefügt werden.

> Also, was willst Du erwarten. Ab -O oder -O1 ist alles
> so wie es sein soll.

Ich hätte erwartet dass es für die Zuweisung einer Konstanten an eine 
Speicherstelle, auch ohne Optimierung, eine bessere Umsetzung gibt.
Hier ist ja kein Optimierungsbedarf im eigentlichen Sinne. Selbst wenn 
kein OUT verwendet werden würde, könnte man mit 3 Instruktionen (Z 
Pointer laden + STORE) jede Speicherstelle beschreiben.
#6673675
Lesenswert?

Bei mir wird aus
1
#include <cstdint>
2
#include <mcu/avr.h>
3
#include <mcu/internals/ccp.h>
4
#include <mcu/internals/clock.h>
5

6
using ccp = AVR::Cpu::Ccp<>;
7
using clock = AVR::Clock<>;
8

9
int main() {
10
    ccp::unlock([]{
11
        clock::prescale<2>();
12
    });
13
}

dann mit -O1 und gcc 10.3.0 oder 12.0.0
1
__CCP__ = 0x34
2
.text
3
.type   main, @function
4
main:
5
ldi r24,lo8(-40)         ;  tmp44,
6
out __CCP__,r24  ;  MEM[(volatile value_type &)48B + 4], tmp44
7
ldi r24,lo8(1)   ;  tmp46,
8
sts 97,r24       ;  MEM[(struct ControlRegister *)96B + 1B].hwRegister, tmp46
9
ldi r25,0                ;
10
ldi r24,0                ;
11
ret

Und bei -O0 willst Du es gar nicht wissen ;-) (s.a. Anlage)

Ich sehe überhaupt keinen Sinn darin, mit -O0 zu compilieren.
Angehängte Dateien:
#6673725
Lesenswert?

Cyblord -. schrieb:
> Wilhelm M. schrieb:
>> Ich sehe überhaupt keinen Sinn darin, mit -O0 zu compilieren.
>
> Macht ja nichts. Aber manchmal will oder muss man.

Ich will und musste es nie ...

> Ich finde es nur
> interessant das dann die 4 zugebilligten Instruktionen des CCP gerissen
> werden.

Dieses semantische Constraint ist im backend nicht drin. Wie schon 
gesagt: es gammelt vor sich hin und fliegt bald raus.
#6673893
Lesenswert?

Cyblord -. schrieb:
> Macht ja nichts. Aber manchmal will oder muss man. Ich finde es nur
> interessant das dann die 4 zugebilligten Instruktionen des CCP gerissen
> werden.

Das dich das überrascht zeigt, daß du anscheinend das allerstemal mit 
einem AVR und dem gcc dazu zu tun hast.

Diese 4-Zyklen-Absicherung gibts bei allen AVRs für verschiedene 
Einstellungen, und das hat der gcc noch nie ohne Optimierung geschafft. 
Über das wieso, weshalb, warum zu sinnieren ist zweckfrei, wie alle 
solche Fragen darüber, warum ein Compiler etwas so macht, wie er es 
macht. Ist halt so.

Und weil das so ist, gibts in der avrlibc dafür Hilfsfunktionen (in 
Assembler), die einem diese Sorge abnehmen.

Für die nicht berücksichtigten Fälle muß man sich die dann halt selber 
schreiben.

Oliver
OP #6673938
Lesenswert?

Oliver S. schrieb:
> Cyblord -. schrieb:
>> Macht ja nichts. Aber manchmal will oder muss man. Ich finde es nur
>> interessant das dann die 4 zugebilligten Instruktionen des CCP gerissen
>> werden.
>
> Das dich das überrascht zeigt, daß du anscheinend das allerstemal mit
> einem AVR und dem gcc dazu zu tun hast.

Beileibe nicht.

> Diese 4-Zyklen-Absicherung gibts bei allen AVRs für verschiedene
> Einstellungen, und das hat der gcc noch nie ohne Optimierung geschafft.

Nicht übertreiben. Lange nicht bei allen. Ich arbeite bisher vorwiegend 
mit dem ATTiny841. Dort gibts das noch nicht und auch bei keinen der 
Vorgänger. Auch nicht bei Megas der gleichen oder Vorgängergeneration. 
Das ist ein recht neues Feature der aktuelleren AVRs.
> Für die nicht berücksichtigten Fälle muß man sich die dann halt selber
> schreiben.

Was hier auch kein Problem darstellt. Das ist mit 3 Zeilen ASM erledigt.
#6674883
Lesenswert?

Cyblord -. schrieb:
> Auch nicht bei Megas der gleichen oder Vorgängergeneration.
> Das ist ein recht neues Feature der aktuelleren AVRs.

Dieses 4 clock cycle Sicherheitsfeature gegen unbeabsichtigtes Setzen 
gibt es mindestens beim EEPROM schreiben, Watchdog en/-disablen, Flash 
programmieren über SPM, und wer weiß wo sonst noch

Das hat einfach jeder AVR irgendwo, seit dem allerersten Modell.

Oliver
#6675109
Lesenswert?

Dafür gibt es ein Inline-ASM Macro, das funktioniert in ALLEN 
Optimierungsstufen. Das stammt aus einer application note.
1
/*! \brief CCP write helper function written in assembly.
2
 *
3
 *  This function is written in assembly because of the timecritial
4
 *  operation of writing to the registers.
5
 *
6
 *  \param address A pointer to the address to write to.
7
 *  \param value   The value to put in to the register.
8
 */
9
void CCPWrite( volatile uint8_t * address, uint8_t value )
10
{
11
  volatile uint8_t * tmpAddr = address;
12
#ifdef RAMPZ
13
  RAMPZ = 0;
14
#endif
15
  asm volatile(
16
    "movw r30,  %0"        "\n\t"
17
    "ldi  r16,  %2"        "\n\t"
18
    "out   %3, r16"        "\n\t"
19
    "st     Z,  %1"       "\n\t"
20
    :
21
    : "r" (tmpAddr), "r" (value), "M" (CCP_IOREG_gc), "i" (&CCP)
22
    : "r16", "r30", "r31"
23
    );
24
}
#6675177
Lesenswert?

Cyblord -. schrieb:
>> Sorry, das habe ich jetzt erst gelesen: -O0 schaltet fast alle
>> Optimierungen ab.
>
> Das ist bekannt. Erklärt für mich aber nicht warum hier derart unnötige
> Operationen eingefügt werden.

Er fügt sie nicht zusätzlich ein, sondern optimiert sie nur eben nicht 
raus.

>> Also, was willst Du erwarten. Ab -O oder -O1 ist alles
>> so wie es sein soll.
>
> Ich hätte erwartet dass es für die Zuweisung einer Konstanten an eine
> Speicherstelle, auch ohne Optimierung, eine bessere Umsetzung gibt.

Was heißt für dich "auch ohne Optimierung eine bessere Umsetzung"? Wenn 
man es gegenüber einer direkten 1:1-Umsetzung aus dem C-Code verbessert, 
nennt man das "Optimierung".

> Hier ist ja kein Optimierungsbedarf im eigentlichen Sinne. Selbst wenn
> kein OUT verwendet werden würde, könnte man mit 3 Instruktionen (Z
> Pointer laden + STORE) jede Speicherstelle beschreiben.

CCP ist ein Makro, das einen Integer-Wert in einen Zeiger castet. Genau 
das macht der Compiler hier. Er lädt einen Integer-Wert und kopiert ihn 
in ein Zeiger-Registerpaar.
OP #6675195
Lesenswert?

Wilhelm M. schrieb:
> Cyblord -. schrieb:
>> Ich nutze aber keinen xmega.
>
> Doch. Der AVR128DAxxx ist eine xmega4 Architektur.

Also der Hersteller bezeichnet das alles komplett anders.
Es gibt eine AVRxm Architektur (XMEGA). Die AVR128DA sind aber AVRxt 
welches der Nachfolger ist.
Hier steht sogar dabei die Anleihen an AVRe (attiny) sind größer.
Angehängte Dateien:
OP #6675199
Lesenswert?

Wilhelm M. schrieb:
> Schau in den specs des gcc nach: avrxmega4 (bezieht sich natürlich nur
> auf die CPU)

Danke. Aber ich halte mich an die Specs des Herstellers. Es ist möglich 
dass innerhalb des gcc das alles etwas anders heißt oder anders 
zusammengefasst ist. Was es nicht unbedingt richtig macht.
Zu behaupten AVR128 wäre im Prinzip XMEGA stimmt aber eben nicht und ist 
irreführend.
OP #6675204
Lesenswert?

Wilhelm M. schrieb:
> Cyblord -. schrieb:
>> Danke. Aber ich halte mich an die Specs des Herstellers. Es ist möglich
>> dass innerhalb des gcc das alles etwas anders heißt oder anders
>> zusammengefasst ist. Was es nicht unbedingt richtig macht.
>
> Dann benutzt Du den gcc nicht? Ok, was lamentierst Du dann herum.

Natürlich nutze ich den. Was mich aber nicht zu falschen Aussagen wie

> Der AVR128DAxxx ist eine xmega4 Architektur.

verleiten könnte.

Vielleicht wolltest du ja sagen:

Der gcc nennt die AVR128 Architektur xmega4.

Wer weiß?
Beitrag #6675475 wurde von einem Moderator gelöscht.
Gast #6675487
Lesenswert?

In dem Zusammenhang (korrektes Timing zwischen zwei Befehlen) hab ich 
übrigens auch das umgekehrte Problem schon erlebt: "sei(); sleep();" 
müssen direkt aufeinander folgen um Race-Conditions zu vermeiden. 
Beides ASM-Statements und klappt ohne Optimierung auch.  Dann hatte ich 
aber so eine Konstellation[1]:
1
   if (...) {
2
      ...
3
      sei();
4
      sleep();
5
  } else {
6
      ...
7
      sleep();
8
  }
und der Compiler hat bei -Oirgendwas den "sleep", der in beiden Pfaden 
als letzter Befehl vorkommt, zusammengefasst und hinter das if-statement 
geschoben. Peng - dem sei() folgte ein Jump zum sleep und damit ist die 
Bedingung verletzt und führt irgendwann zu einem Lock-Up.



[1] nicht exakt diese, aber auch CSE basierend mit einem Jump hinter dem 
sei.
Beitrag #6677395 wurde von einem Moderator gelöscht.
Beitrag #6677466 wurde von einem Moderator gelöscht.
Beitrag #6685923 wurde von einem Moderator gelöscht.
Moderator Persönliche Seite #6685940
Lesenswert?

Cyblord -. schrieb:
> Es gibt eine AVRxm Architektur (XMEGA). Die AVR128DA sind aber AVRxt
> welches der Nachfolger ist.

Da steht aber auch, dass sie von der Xmega-Architektur abgelitten sind, 
und die hatte halt schon immer ihr CCP.

Alternative zu den genannten Makros + Inline-Assembler: schreib dir für 
das, wo du CCP anfassen musst, Wrapper-Funktionen, die du in eine eigene 
Quelldatei packst und dann mit mehr als -O0 compilierst auch denn, wenn 
du für den Rest unbedingt -O0 haben willst.
OP #6685960
Lesenswert?

Jörg W. schrieb:
> Da steht aber auch, dass sie von der Xmega-Architektur abgelitten sind,
> und die hatte halt schon immer ihr CCP.

In der Tat habe ich das CCP schon unterbewusst auf einem tiny841 benutzt 
um das Flash zu beschreiben für einen Bootloader. Für den Schutz 
bestimmter Register wird es hier aber noch nicht benutzt.

> Alternative zu den genannten Makros + Inline-Assembler: schreib dir für
> das, wo du CCP anfassen musst, Wrapper-Funktionen, die du in eine eigene
> Quelldatei packst und dann mit mehr als -O0 compilierst auch denn, wenn
> du für den Rest unbedingt -O0 haben willst.

ccp_write_io gibt es ohne Klimmzüge auch für den avr128, somit ich nutze 
ich das. Danke für diesen Tipp.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren