Forum: Compiler & IDEs AVR128, CCP und Optimierung


von Cyblord -. (cyblord)


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

:
von Wilhelm M. (wimalopaan)


Lesenswert?

Gute Frage, wobei ich selbst noch nie Probleme damit hatte. Vielleicht 
hat Johann ja recht, dass das AVR-Backend einfach mit der Zeit 
vergammelt.

Welchen gcc  nimmst Du denn?

von Wilhelm M. (wimalopaan)


Lesenswert?

Cyblord -. schrieb:
> 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.

Stimmt nicht ganz: 4 Instruktionen.

von Wilhelm M. (wimalopaan)


Lesenswert?

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. Also, was willst Du erwarten. Ab -O oder -O1 ist alles 
so wie es sein soll.

von Cyblord -. (cyblord)


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.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Angehängte Dateien:

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.

von Cyblord -. (cyblord)


Lesenswert?

Wilhelm M. schrieb:
> Ich sehe überhaupt keinen Sinn darin, mit -O0 zu compilieren.

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

von Wilhelm M. (wimalopaan)


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.

von Cyblord -. (cyblord)


Lesenswert?

Wilhelm M. schrieb:
> 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 ...

Das ist sehr schön für dich.

von Harry L. (mysth)


Lesenswert?

Wickel den Code-Abschnitt doch in Pragmas ein!

z.B. so:
1
#pragma GCC push_options
2
#pragma GCC optimize ("O1")
3
4
// critical code
5
6
#pragma GCC pop_options

von Oliver S. (oliverso)


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

von Cyblord -. (cyblord)


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.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Cyblord -. schrieb:
> 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.

Gibt es bei den xmega-Architekturen

von Oliver S. (oliverso)


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

von Falk B. (falk)


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
}

von Wilhelm M. (wimalopaan)


Lesenswert?

Wie gesagt, das ist im xmaga-support der avrlibc drin: xmega.h

von Rolf M. (rmagnus)


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.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Cyblord -. schrieb:
> Ich hätte erwartet dass es für die Zuweisung einer Konstanten an eine
> Speicherstelle, auch ohne Optimierung, eine bessere Umsetzung gibt.

Ganz einfach: nimm dir die gcc-Quellen, schreib einen Patch, reich den 
ein, sorge dafür, daß der angenommen wird, und alles wird gut.

Oliver

von Cyblord -. (cyblord)


Lesenswert?

Wilhelm M. schrieb:
> Wie gesagt, das ist im xmaga-support der avrlibc drin: xmega.h

Ich nutze aber keinen xmega. Ich werde aber mal schauen ob für die 
avr128 ein solches Makro auch existiert.

Danke für den Tipp Falk.

von Wilhelm M. (wimalopaan)


Lesenswert?

Cyblord -. schrieb:
> Ich nutze aber keinen xmega.

Doch. Der AVR128DAxxx ist eine xmega4 Architektur.

Benutze einfach das Makro was Du in dem header xmega.h findest, wie oben 
schon gesagt.

von Cyblord -. (cyblord)


Angehängte Dateien:

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.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

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

von Cyblord -. (cyblord)


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.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

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.

von Cyblord -. (cyblord)


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ß?

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Na, wie Du meinst.
Die devices-specs stammen übrigens aus dem offiziellen DFP-Pack von 
MicroChip.

: Bearbeitet durch User
von Oliver S. (oliverso)


Lesenswert?

Cyblord -. schrieb:
> Also der Hersteller bezeichnet das alles komplett anders.

Das liest sich so, wie eine Unterteilung der VW-Modelle in luftgekühlte 
Boxer und wassergekühlte Reihenvierzylinder.

Die Welt hat sich seit dem doch etwas weitergedreht, und die 
Modellvielfalt ist in der Realität deutlich komplexer.

Oliver

Beitrag #6675475 wurde von einem Moderator gelöscht.
von foobar (Gast)


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.
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Cyblord -. (cyblord)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.