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?
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
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
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.
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.
:-)
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...