Forum: Compiler & IDEs AVR GCC Codeoptimierung selektiv ausschalten für CLKPR Zugriffe


von D. E. (stb)


Lesenswert?

Hallo,

so richtig bin ich bei der Forensuche nicht fündig geworden, deshalb mal 
hier ein ganz einfaches Problem:

Wenn man bei (neueren) AVRs wie z.B. ATtiny25 den Clock Prescaler ändern 
möchte, dann kann man das theoretisch sehr elegant mit
1
CLKPR = 0x80  // MCU anzeigen, daß Teilerfaktor geändert werden soll
2
CLKPR = 0x03  // Prescale auf "divide by 8"

Wenn man Pech hat optimiert der Compiler die erste Zuweisung weg, damit 
wird nur die 2. ausgeführt, diese wird von der MCU aber nicht umgesetzt, 
weil die erste Anweisung nicht angekommen ist.

Gibt es eine Möglichkeit den GCC anzuweisen selektiv keine Optimierung 
durchzuführen.

Grüße

STB

von (prx) A. K. (prx)


Lesenswert?

Wenn du nachweisen kannst, dass der Compiler das wirklich wegoptimiert, 
dann wäre das einen Bugreport wert. Darf er nämlich nicht, wenn CLKPR 
"volatile" ist.

von D. E. (stb)


Lesenswert?

Hi !

Bei mir geht es z.Zt. ich verwende -s als Optimierung.
In anderen Forenbeiträgen hatten aber viele schon das Problem, daß die 
Einstellung mittels CLKPR "nicht geht", was auf die Wegoptimierung 
hindeuten würde.
Aus dem Zusammenhang kam die Frahe hoch ob es einen "kugelsicheren" Weg 
gibt, jedes Risiko zu vermeiden.

Grüße

STB

von yalu (Gast)


Lesenswert?

Wegoptimieren tut der GCC an dieser Stelle sicher nichts, da alle
Register im Header-File mit volatile deklariert sind. Möglicherweise
fügt er aber zusätzliche Befehle zwischen die beiden Zugriffe ein, so
dass ihr zeitlicher Abstand die geforderten 4 Taktzyklen überschreitet.
Das würde man im Assemblerlisting sehen. Ich kann das bei mir aber weder
mit dem GCC 4.2.4 noch mit dem 4.3.2 reproduzieren. Vielleicht postet du
mal ein kurzes Stück deines Codes.

> Aus dem Zusammenhang kam die Frahe hoch ob es einen "kugelsicheren"
> Weg gibt, jedes Risiko zu vermeiden.

Den 100% sicheren Weg gibt es nicht, da der C-Standard keine Garantien
für die zeitbeschränkte Auaführung von Code vorsieht, was man aber in
diesem Fall bräuchte. Beim GCC gäbe es immerhin noch die Möglichkeit,
die beiden Anweisungen in Inline-Assembler zu implementieren, um zu
verhindern, dass sie auseinadergerissen werden.

von Stefan E. (sternst)


Lesenswert?

> In anderen Forenbeiträgen hatten aber viele schon das Problem, daß die
> Einstellung mittels CLKPR "nicht geht", was auf die Wegoptimierung
> hindeuten würde

Nochmal: die Register sind alle volatile deklariert, damit werden 
Zuweisungen auch nicht wegoptimiert.
Wenn jemand mit den obigen beiden Zeilen Probleme hat, dann deshalb, 
weil er die Optimierungen nicht eingeschaltet hat. Dann wird das 
nötige Timing nämlich nicht eingehalten.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Genau dafür gibt's aber auch die inline-asm-Funktionen in
<avr/power.h>.  Diese sind optimierungsunabhängig.

von D. E. (stb)


Lesenswert?

Danke Jörg!

Mit der Funktion:
1
clock_prescale_set(x)

aus <avr/power.h> wird es kugelsicher, man muss halt nur wissen wo es 
steht :-)

@"die anderen": Mir ging es weniger darum, was der Compiler machen darf 
bzw. je nach Optimierungsstufe tut (bei mir funktioniert es ja). Ich war 
auf der Suche nach der "kugelsicheren" Lösung des Problems.

Danke nochmal an alle!

STB

von Stefan (Gast)


Lesenswert?

kleiner Tipp-Nachtrag:
schalte vor der Ausführung von
1
clock_prescale_set(x)
die Interrupts ab.
Sonst kann es (ganz selten) passieren, dass zwischen beide Befehle ein 
IR funkt, damit ist das 4-Zyklen-Timing nicht eingehalten und der Atmel 
ignoriert den Befehl.

Dasselbe gilt übrigens auch für einige Flash-Schreibbefehle, wer z.B. in 
seinem Bootloader IRs erlaubt, sollte daran denken.

Gruß, Stefan

von Stefan E. (sternst)


Lesenswert?

Stefan wrote:
> kleiner Tipp-Nachtrag:
> schalte vor der Ausführung von
>
1
> clock_prescale_set(x)
2
>
> die Interrupts ab.

Das Deaktivieren der Interrupts ist in der Funktion bereits enthalten.

von DerDan (Gast)


Lesenswert?

Mal im Ernst, der Stefan hat Recht!

Man sollte es auf jeden Fall kontrollieren!
mich hat es bei dem auslesen der Fuse Byte erwischt!

1
diag = boot_lock_fuse_bits_get (GET_EXTENDED_FUSE_BITS);

Geht meistens aber manchmal nicht.
Interrupts sperren und schon geht es immer.

1
cli();
2
diag = boot_lock_fuse_bits_get (GET_EXTENDED_FUSE_BITS);
3
sei();



mfg

DerDan

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dirk E. wrote:

>
1
> CLKPR = 0x80  // MCU anzeigen, daß Teilerfaktor geändert werden soll
2
> CLKPR = 0x03  // Prescale auf "divide by 8"
3
>
>
> Wenn man Pech hat optimiert der Compiler die erste Zuweisung weg, damit
> wird nur die 2. ausgeführt, diese wird von der MCU aber nicht umgesetzt,
> weil die erste Anweisung nicht angekommen ist.

Hast du eine Quelle dafür?

-- Quellcode, so daß es auf einem anderen Rechner nachvollzogen werden 
kann (zB. i-File)

-- Compilerversion / OS

-- avr-gcc Aufruf-Parameter

Falls er die erste Zeile trotz volatile raushaut, ist das ein Bug.

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.