Forum: Mikrocontroller und Digitale Elektronik compiler optimierung zuviel :/


von Waldgichtel (Gast)


Angehängte Dateien:

Lesenswert?

Guten Abend zusammen,

da mir zur Anzeige von Informationen nur eine einzelnde RGB-LED zur 
Verfügung steht habe ich mir mittels einem Timer eine kleine Funktion 
geschrieben die unterschiedliche Blink-sequenzen ausgeben kann. Mein 
Problem ist nun dass bei abgeschalteter Compiler-Optimierung alles 
einwandfrei funktioniert, ist allerdings -Os eingeschaltet kommt es zu 
Problemen.

Im Anhang der Beispielcode.

Ohne optimierung:
die erste led Sequenz wird nach dem Start angezeigt. Nach drücken auf 
den Taster wird die zweite Sequenz geladen. ... alles wie es sein soll.

Mit Optimierung (-Os):
Nach dem Start sind alle LED-Ausgänge auf low. Nach Drücken des Tasters 
wird die zweite LED-Sequenz angezeigt. ... das erste init_led_seq 
scheint ignoriert zu werden.

Habe auch schon versucht die globalen Variablen direkt zu setzten, ohne 
eine extra Funktion (init_led_seq()) zu verwenden. Hatte leider den 
gleichen Effekt.

Habe auch schon die Warteschleife bis der Taster gedrückt wird mit ein 
paar Zeilen gefüllt, auf den Verdacht hin, dass da etwas wegoptimiert 
wird ... auch kein Erfolg.

Was mach ich falsch?

Vielen Dank schonmal, und schönen Abend noch.

Toni

von --> (Gast)


Lesenswert?

Poste doch mal das generierte Assemblerfile

von Vlad T. (vlad_tepesch)


Lesenswert?

vielleicht ist der unoptimierte Code so langsam, dass die 
Tasterentprellung von Haus mitgeliefert wird.

von Experte (Gast)


Lesenswert?

Das ist doch sonnenklar:

Du hast Race-Conditions. Und davon eine ganze Menge.

Auch wenn in jedem AVR-Tutorial erzählt wird, dass "volatile" alle 
Probleme löst, ist es eben nicht so. "volatile" zu benutzen ist relativ 
dämlich, da ineffizient. Korrekt macht man so etwas mit 
Memory-Barrieren. Aber das ist ein anderes Thema, darum soll es hier 
nicht gehen.

Dein Problem sind die volatile-16-Bit-Variablen (led_out_seq, 
led_aku_seq). Die können nun mal nicht atomar auf einem 8-Bit Prozessor 
abgebildet werden. Wieder ein Beispiel wie bescheuert die 
"volatile"-Technik ist.

Dazu noch Datenabhängkeiten zwischen Variablen. Auch hier versagt 
volatile grandios.

Nun gut, einfach Lösung:
1
void init_led_seq(PGM_P led_seq, UCHAR delay){
2
  cli();
3
  led_aku_seq = led_seq; 
4
  led_delay = delay; 
5
  led_out_seq = led_seq; 
6
  sei();
7
}

von Waldgichtel (Gast)


Angehängte Dateien:

Lesenswert?

Im Anhang nochmal zur Sicherheit led_test.c die ich compliert habe. 
Einmal optimiert und einmal ohne optimierung.

Wegen der Tastenentprellung:
eigentlich sollte es ja egal sein wie oft die Taste nachprellt, da nach 
dem ersten Kontakt sowieso in die Endlosschleife gesprungen wird. 
Anstatt des Tasterdrucks habe ichs aber auch mit delays versucht.

Bei soetwas:

init_led_seq(led_1_min, 100);
_delay_ms(10000);
init_led_seq(led_5_min, 150);
_delay_ms(10000);
init_led_seq(led_10_sec, 100);

passiert 2*100000ms gar nix (Ausgänge bleiben auf low) und erst 
led_10_sec ganz am Ende wird ausgegeben. Bei ausgeschalteter Optimierung 
funktionierts aber auch hier wie erwartet ... 100000ms led_1min, 100000 
led_5_min, nachfolgend led_10_sec_

Toni

von Waldgichtel (Gast)


Angehängte Dateien:

Lesenswert?

@ Experte

... zu spät deine Antwort gesehen. Habs nun auch so versucht wie du 
geschrieben hast.

Sowohl mit volatile als auch ohne vor den entsprechenden Variablen. 
Beides mal wieder ... ohne optimierungs klappts, mit nicht :/.

Wenns eine andere, schönere Möglichkeit gibt, mein Geblinke umzusetzten 
werf ich das ganze auch weg ;-) Nur fehlts mir da an den Ideen :/.

Toni

von Andreas F. (aferber)


Lesenswert?

Deklarier die beiden Pointer mal als
1
PGM_P volatile led_out_seq = 0 ;
2
PGM_P volatile led_aku_seq = 0 ;

Warum das nötig ist? Deutlicher wird es bei normalen Pointern ohne die 
Makros:
1
volatile char *foo;

Damit wird ein Zeiger auf ein "volatile char" deklariert, d.h. das 
Ziel des Pointers ist volatile, der Zeiger selbst aber nicht. Um den 
Pointer selbst volatile zu machen ist folgendes nötig:
1
char * volatile foo;

Auf das PGM_P-Makro übertragen sieht das dann wie oben aus.

Da der Zeiger selbst in deinem Code nicht volatile ist, optimiert der 
Compiler dann den ersten Schreibzugriff weg, da in main() vor dem 
zweiten Schreibzugriff nicht mehr auf die Variablen zugegriffen wird.

Andreas

von Andreas F. (aferber)


Lesenswert?

Andreas Ferber schrieb:
> Deklarier die beiden Pointer mal als

Nachtrag: das cli()/sei() in init_led_seq() ist natürlich trotzdem noch 
nötig, um die Zugriffe atomar zu machen.

Andreas

von Pothead (Gast)


Lesenswert?

Experte schrieb:
> Die können nun mal nicht atomar auf einem 8-Bit Prozessor
> abgebildet werden. Wieder ein Beispiel wie bescheuert die
> "volatile"-Technik ist.

Toll! Das ist ja auch gar nicht die Aufgabe von volatile. Thema 
verfehlt, sechs, setzen.

http://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html

von Waldgichtel (Gast)


Lesenswert?

Super vielen Dank :) jetzt funktionierts endlich :) Der Tipp von 
Andreas hat jetzt zum Ziel geführt :) freude :). Besten Dank.

Toni

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.