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
vielleicht ist der unoptimierte Code so langsam, dass die Tasterentprellung von Haus mitgeliefert wird.
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 | }
|
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
@ 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
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
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.