Selbst bei einfachen Programmen kommt bei mir manchmal nicht das erwünschte Ergebnis aus dem Compiler (avr-gcc (GCC) 3.4.3; Atmega8). Selbst einfache For-schleifen bringen ihn manchmal zum Aufhängen (der verwendete Variablentyp stimmt). Wenn man dann die Optimierung ausschaltet, dann gehts manchmal plötzlich! Also programmiert man gemütlich so weiter. Und irgendwann mit einer ganz harmlosen Zeile Code dreht der Controller wieder durch. Wenn man dann Glück hat, gehts mit einer anderen Optimierungsstufe wieder. Irgendwann war ich dann an dem Punkt, an dem keine Optimierungsstufe mehr einwandfrei funkioniert hat. Aber in jeder ging irgendwas anderes nicht. Absolut nicht nachvollziehbar. Ich hab jetzt auch gemerkt, dass die "hex"-Datei nicht mit der "lss"-Datei übereinstimmt (Die Adressen der Funktionen stimmen nicht). Kann das sein? Ist das ganze eventuell eine Einstellungssache? Controller und Frequenz sind in der Makefile eingetragen.
#include <avr/io.h> #include <stdint.h> #include "lcd_atmega8.h" void main(void) { unsigned int i; LCD_Init(); LCD_Clr(); DDRB= (1<<PB0) | (1<<PB5); PORTB=1; for (i=0;i<=30000;i++) ; PORTB|= (1<<5); LCD_Str("irgendwas"); while (1); return 0; } Hin und wieder kann man kurz das Wort auf dem LCD lesen, dann ists wieder weg und irgenwann wieder da. Im gleichen Takt wechselt der PortB-5 seinen Zustand. PortB-0 bleibt auf 5V. Wenn ich die Schleife und die Port-Befehle rausmache, dann filmmert das LCD (als obs ständig aktualisiert würde). (Optimierungsstufe 0)
Trivial, hier ohne Belang und vom Compiler angezeigt: return in einer void-Funktion. Welche Schleife rausgemacht? Sind 2 drin. Ohne die zweite tät's mich nicht wundern. Wenn sich jedoch während der while(1)-Schleife auf dem LCD oder den Ports etwas tut, dann liegt das Problem in der Hardware, nicht der Software. Mal vorausgesetzt, dass die LCD-Routinen keine Interrupts verwenden.
Bei while (1); und bei der for-schleife schreib besser while (1) asm volatile ("nop"); weil sonst optimiert er die Schleife weg.
Der Compiler optimiert nur Dinge weg, die aus seiner keine Wirkung haben. Die while(1)-Schleife aber darf er nicht wegoptimieren, da sonst der Code dahinter ausgeführt würde. Nicht zu verwechseln mit Zählschleifen. Da kann's schon sein, dass aus for (i=1;i!=1000;++i); am Ende ein einfaches i=1000 wird.
Konnte es noch weiter eingrenzen: void main(void) { unsigned int i; DDRB= (1<<PB0) | (1<<PB5); PORTB=1; for (i=0;i<=30000;i++) ; PORTB|= (1<<5); while (1) ;//asm volatile ("nop") return 0; } So bleibt PortB auf 1 stehen (d.h. er macht ab der For-Schleife nicht mehr das, was er soll. Wenn ich jedoch das "asm..." in der while Schleife eintrage, dann gehts wunderbar. Aber wieso passiert das mit der Optimierungsstufe 0? In der "lss"-Datei steht der Befehl (rjmp -2) noch drin. In der Hex stimmt dann gar nix mehr überein! Außerdem war dies auch nur ein kleines Beispiel meiner Probleme. Bei größeren Projekten habe ich keine Chance mehr irgendwas zu kontrollieren. Da optimiert er einfach Sachen weg, obwohl sie nötig sind. Ich habe keine Ahnung mehr was ich da machen kann. Hat von euch niemand solche Probleme?
Die Hex liegt bei. Gibts eine Möglichkeit, dass er alles so wie in der lss-Datei auch in die Hex übernimmt? void main(void) { 5c: cd e5 ldi r28, 0x5D ; 93 5e: d4 e0 ldi r29, 0x04 ; 4 60: de bf out 0x3e, r29 ; 62 62: cd bf out 0x3d, r28 ; 61 unsigned int i; //LCD_Init(); //LCD_Clr(); DDRB= (1<<PB0) | (1<<PB5); 64: 81 e2 ldi r24, 0x21 ; 33 66: 80 93 37 00 sts 0x0037, r24 PORTB=1; 6a: 81 e0 ldi r24, 0x01 ; 1 6c: 80 93 38 00 sts 0x0038, r24 for (i=0;i<=30000;i++) ; 70: 19 82 std Y+1, r1 ; 0x01 72: 1a 82 std Y+2, r1 ; 0x02 74: 89 81 ldd r24, Y+1 ; 0x01 76: 9a 81 ldd r25, Y+2 ; 0x02 78: 25 e7 ldi r18, 0x75 ; 117 7a: 81 33 cpi r24, 0x31 ; 49 7c: 92 07 cpc r25, r18 7e: 30 f4 brcc .+12 ; 0x8c 80: 89 81 ldd r24, Y+1 ; 0x01 82: 9a 81 ldd r25, Y+2 ; 0x02 84: 01 96 adiw r24, 0x01 ; 1 86: 89 83 std Y+1, r24 ; 0x01 88: 9a 83 std Y+2, r25 ; 0x02 8a: f4 cf rjmp .-24 ; 0x74 PORTB|= (1<<5); 8c: 80 91 38 00 lds r24, 0x0038 90: 80 62 ori r24, 0x20 ; 32 92: 80 93 38 00 sts 0x0038, r24 //LCD_Str("irgendwas"); while (1) ;//asm volatile ("nop") 96: ff cf rjmp .-2 ; 0x96
"Da optimiert er einfach Sachen weg, obwohl sie nötig sind." Da wäre ein konkretes Beispiel recht hilfreich - also der betreffende C-Code und das falsche Resultat (.lst oder .lss). Im oben gezeigten Code ist bis hin zum Hex-File alles ok. "Hat von euch niemand solche Probleme?" Ich selbst nicht und der allgemeinen Diskussionskultur hier nach zu schliessen auch sonst niemand. Anbei Disassembly vom Hex.
PORTB=1; for (i=0;i<=30000;i++) ; PORTB|= (1<<5); "So bleibt PortB auf 1 stehen" Ich sehe auch keinen Grund, warum der Mega8 das nicht so halten sollte. Die erste Zeile setzt B5 auf 1, die dritte Zeile ändert B5 von 1 auf 1. Wenn B5 da auf 0 gehen soll, dann mit PORTB &= ~(1<<5);
Nicht ganz richtig. Nach der ersten Zeile ist PORTB 1, nach der dritten 0x21.
@A.K. Genau, der PortB müsste 0x21 sein, ist er aber definitiv nicht. Ich hab mal das Hex mit dem AVR-Studio debugged und siehe da, auch hier ist nur PB0 gesetzt nicht aber PB5! Das deutet doch daraufhin, dass hex und lss doch nicht übereinstimmen, oder bin ich blind? Habt ihr das hex mal ausprobiert? Oder könnte jemand von euch mal die obigen Zeilen kompilieren und das hex hier reinstellen, dann könnte ich sehen obs vielleicht doch an meinen Einstellung liegt.
mit PORTB=1; und PORTB|= (1<<5); ist es glaub ich kein Wunder wenn PB5 nicht gesetzt ist. mit einem |= wird ein bit gelöscht. mit &=~ wird es gesetzt
Schau dir mal Zeit und Datum der .lss und .hex Datei an. Sollte eigentlich identisch sein.
Habe die Ursache gefunden. Es liegt am Übertragungsprogramm: Das wird reingeschickt: 0000: 12 C0 2B C0 2A C0 29 C0 28 C0 27 C0 26 C0 25 C0 0010: 24 C0 23 C0 22 C0 21 C0 20 C0 1F C0 1E C0 1D C0 0020: 1C C0 1B C0 1A C0 11 24 1F BE CF E5 D4 E0 DE BF 0030: CD BF 10 E0 A0 E6 B0 E0 E6 E9 F0 E0 02 C0 05 90 0040: 0D 92 A0 36 B1 07 D9 F7 10 E0 A0 E6 B0 E0 01 C0 0050: 1D 92 A0 36 B1 07 E1 F7 01 C0 D2 CF CD E5 D4 E0 0060: DE BF CD BF 81 E2 80 93 37 00 81 E0 80 93 38 00 0070: 19 82 1A 82 89 81 9A 81 8F 31 91 05 30 F4 89 81 0080: 9A 81 01 96 89 83 9A 83 F5 CF 80 91 38 00 80 62 0090: 80 93 38 00 FF CF Und beim Auslesen kommt das zurück: 0000: 12 C0 2B C0 2A C0 29 C0 28 C0 27 C0 26 C0 25 C0 0010: 24 C0 23 C0 22 C0 21 C0 20 C0 1F C0 1E C0 1D C0 0020: 1C C0 1B C0 1A C0 11 24 1F BE CF E5 D4 E0 DE BF 0030: CD BF 10 E0 A0 E6 B0 E0 E6 E9 F0 E0 02 C0 05 90 0040: 0D 92 A0 36 B1 07 D9 F7 10 E0 A0 E6 B0 E0 01 C0 0050: 1D 92 A0 36 B1 07 E1 F7 01 C0 D2 CF CD E5 D4 E0 0060: DE BF CD BF 81 E2 80 93 37 00 81 E0 80 93 38 00 0070: 19 82 1A 82 89 81 9A 81 8F 31 91 05 30 F4 89 81 0080: 9A 81 01 96 89 83 9A 83 F5 CF 80 91 38 00 80 62 0090: 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Da fehlen eindeutig die letzten 2 Befehle. Werde mal schauen wo da der Fehler liegt. Danke für eure Hilfe!
Übrigens, nur nebenbei: das LSS-Listing ist ein Disassemblerlisting, das von der Ausgabe her rückwärts generiert wird und dann anhand der Debuginformationen mit den Codeschnipseln ,,annotiert'' wird. Das muss ganz zwangsläufig mit der ELF-Date übereinstimmen, und sofern nicht jemand das Extrahieren der HEX-Datei aus dem ELF verpfuscht hat, dann auch mit dieser.
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.