Wie schon in der Überschrift drinsteht will ich ein "goto" in mein Programm einbauen. Hier mal die Beschreibung: RESTART: . . . goto RESTART aber irgendetwas mach ich falsch, da der Compiler mein Projekt so nicht mag. Eine andere Frage würde sich darauf beziehen, wie ich an Adresse 0 springen kann, denn nichts anderes will ich hier bewirken (also einen Software Reset)
Wenn Du an den Anfang von main(...) springst, dann ist das kein Neustart. Vor main wird nämlich noch der Startup-Code ausgeführt. Die saubere Lösung für einen Reset wäre, den Watchdog einzuschalten und in einer Endlosschleife zu verharren, bis der Watchdog auslöst.
OK, das ist die Alternative, die ich aber momentan aus diversen gründen nicht gehen will. Gibt es dann noch ne andere Möglichkeit, und warum geht mein goto nicht?
Wenn Du umbedingt zur Adresse 0 springen willst, ginge ein
1 | void (*gotozero)(void) = NULL; |
2 | gotozero(); |
Zu Deinem goto. Solange Du nicht mehr Code und/oder die Fehlermeldung postest, kann ich Dir nicht helfen.
Also mehr code ist kein Problem, wobei obrige Lösung mir schon sehr gefällt, mal noch testen... ... SIGNAL(SIG_COMPARATOR) // signal handler for analog comperator { goto RESTART; // Zeile : 127 } ... int main(void) { RESTART: // Zeile 140 ... ----------------------------------------------------- Fehlermeldung: prog.c: In function `__vector_18': prog.c:127: error: parse error before numeric constant prog.c: In function `main': prog.c:140: warning: label `RESTART' defined but not used make: *** [prog.o] Error 1
So weit ich weiß, kann man in C mit goto ("das ist böse, BÖSE!") nicht zwischen zwei Funktionen hin- und herspringen. Das wird so also nix. An die Adresse für den Resetvektor (normalerweise 0) kämst Du außerdem je nach AVR auch mit
1 | asm volatile ("jmp __vectors"::); |
oder (bei kleineren Modelle)
1 | asm volatile ("rjmp __vectors"::); |
Noch eine Anmerkung zum Unterschied Sprung an die Adresse 0 und Verwendung des Watchdogs: Beim Sprung bleiben alle Register in ihrem bisherigen Zustand. D.h. man beachte insb. Interrupts und Timer etc. Bei einem Watchdog-Reset werden alle Register und HW-Komponenten auf ihren Default-Wert gesetzt. Volkmar
Kleine AVRs haben keinen jmp-Befehl nur rjmp. Und "rjmp 0" funktioniert - im Gegensatz zu "jmp 0" - nicht im gewünschten Sinne (d.h. es springt zur ersten Codezeile in der aktuellen Datei, bei mir oft ein Interrupt-Handler). Daher der Sprung zum Symbol __vectors.
Salve, Sprung zur Adresse 0 ist - wie hier ja schon öfters angemerkt wurde - noch lange kein Software-Reset. Ziel eines Resets ist ja die Rückkehr in einen definierten Zustand - meist dann, wenn ein Ausnahmezustand eingetreten ist, der nicht behandelt werden kann. Ein Sprung an Adresse 0 hilft Dir dann überhaupt nicht, wenn sämtliche Interrupts weiterlaufen und I/Os geschaltet bleiben. Also: Mach es sauber über den Watchdog. Du sparst Dir ne Menge Zeit und Ärger. Sind ja auch nur zwei Zeilen. @Volkmar: Bist Du sicher, daß die Register initialisiert werden? Imho bleiben die bestehen (solange die Spannung nicht getrennt wird), nur I/O-Ports werden auf 0x00 gelöscht. Mark
@Mark, in Bezug auf die Register hast Du (meine ich) Recht, der Speicher wird nicht angefaßt. Ich hatte jedoch beim Wort Register hauptsächlich die Hardware-Register die zB für die Interrupts, Timer, USART, etc. im Kopf. Volkmar
Ich kann's nur immer wiederholen. Atmels Appnote AVR109 macht es völlig portabel vor:
1 | void (*funcptr)( void ) = 0x0000; // Set up function pointer to |
2 | RESET vector |
3 | ...
|
4 | funcptr(); // Jump to Reset vector 0x0000 in |
5 | Application Section |
Mit Optimierung generiert das Ganze exakt einen CALL (oder RCALL, je nach Prozessor) nach 0, ohne weiteren Speicherverbrauch o.ä.
Also das mit den void (*funcptr)( void ) = 0x0; tut nicht; bei mir wird das so übersetzt: LDS r30,0x0060 LDS r31,0x0061 ICALL Also springt der Atmel auf den Inhalt dieser beiden SRAM Zellen :-( _asm_ __volatile ( "ldi r30,0" "\n\t" "ldi r31,0" "\n\t" "icall" "\n\t" ); macht "jump 0x0000"
> Also springt der Atmel auf den Inhalt > dieser beiden SRAM Zellen :-( Und, was steht in denen denn drin? Ich verwette meine nicht vorhandene Perücke, dass da eine 0 drin steht. Du hast bloß keine Optimierung eingeschaltet, sonder würde er das gleich in einem JMP 0 übersetzen.
> _asm_ __volatile > ( > "ldi r30,0" "\n\t" > "ldi r31,0" "\n\t" > "icall" "\n\t" > ); > > macht "jump 0x0000" Sofern in r00 gerade eine 0 steht.
Hallo Joerg, die Perücke bist du los ... da sind laut .map zwei Variablen abgelegt. Übrigens, übersetzt wurde mit avr-gcc 3.4.5 und -os. Gruß Wolfgang
Anbei der DCC Decoder; einfacher Accessory Decoder, selbstlernend, entweder 4 Pulsausgänge oder Signale bzw. Ampelsteuerung.
Liebst du das auch so, Jörg. Eigentlich möchte man sich als Helfer nur auf ein kleines Detail konzentrieren und dieses lösen. Und dann wird auf die Nachfrage nach Code ein Monsterprogramm gesendet. :-)
Ich hoffe, du meinst -Os. Mit -os würde das Ergebnis einfach in eine Datei namens s geschrieben.
Hmm, also mein avr-g++ macht aus dem Aufruf:
1 | lds r30,funcptr |
2 | lds r31,(funcptr)+1 |
3 | icall |
Das ist genau das, was ich erwartet hätte. Daß er den Zugriff auf funcptr nicht wegoptimieren kann, ist logisch, da es weder eine lokale Variable, noch konstant ist. Damit kann der Compiler nicht darauf vertrauen, daß der Wert immer 0 ist und muß den Lesezugriff auf die Variable tatsächlich durchführen.
Ich bekomme dafür (allerdings mit GCC 3.4.6, ebenfalls -Os) diesen Code generiert: /* #APP */ cli /* #NOAPP */ rcall 0 rjmp .L536 Allerdings löst der Assembler den rcall 0 irgendwie ,,schräg'' auf, offenbar versucht er die 0 relativ auf irgendwas zu beziehen. Es entsteht daraus ein Call auf die Adresse 0x7a (init_main). Das halte ich für einen Bug im Assembler. Für einen Prozessor > 8 KB macht er dann einen call 0 draus, was korrekt ist. GCC 4.1.0 macht daraus: /* #APP */ cli /* #NOAPP */ ldi r30,lo8(0) ldi r31,hi8(0) icall rjmp .L189 Das sollte unstrittig richtig sein.
p.s.: Während ich probiert habe, hab' ich natürlich nicht die laufende Diskussion verfolgt. Mein Ergebnis bezieht sich daher auf den originale Dekoder, jedoch den auskommentierten funcptr eingeblendet statt des inline asm Codes.
> Allerdings löst der Assembler den rcall 0 irgendwie ,,schräg'' > auf, offenbar versucht er die 0 relativ auf irgendwas zu beziehen. Das r im rcall steht doch für "relative". Sollte der übergebene Wert nicht relativ zur aktuellen Adresse sein?
> Sollte der übergebene Wert > nicht relativ zur aktuellen Adresse sein? Zumindest trägt er dann keine 0 ein in den Opcode. ;-) Normalerweise steht da ja eine externe Referenz, die der Linker dann auflöst. Wenn man einen Label auf Adresse 0 setzen würde, könnte der Compiler stattdessen den RCALL auf diesen Label beziehen. Im Prinzip gibt's den Label sogar, der heißt __vectors. Der Compiler könnte also ein "rcall __vectors" ausgeben, dann wäre alles in Butter...
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.