Forum: Compiler & IDEs goto im avr gcc


von Anton Wert (Gast)


Lesenswert?

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)

von Christian Zietz (Gast)


Lesenswert?

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.

von Anton Wert (Gast)


Lesenswert?

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?

von Christian Zietz (Gast)


Lesenswert?

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.

von Anton Wert (Gast)


Lesenswert?

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

von Christian Zietz (Gast)


Lesenswert?

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"::);

von Benedikt (Gast)


Lesenswert?

oder ganz einfach:
asm volatile ("jmp 0");

von Volkmar D. (volkmar)


Lesenswert?

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

von Christian Zietz (Gast)


Lesenswert?

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.

von Mark H. (haemi)


Lesenswert?

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

von Volkmar D. (volkmar)


Lesenswert?

@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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.ä.

von Wolfgang Kufer (Gast)


Lesenswert?

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"

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> 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.

von Rolf Magnus (Gast)


Lesenswert?

> _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.

von Karl heinz B. (kbucheg)


Lesenswert?

> Sofern in r00 gerade eine 0 steht.

Wie kommt da jetzt R0 ins Spiel?

von Rolf Magnus (Gast)


Lesenswert?

Ok, das war natürlich Quatsch. Hab hier irgendwie ldi und lds
verwechselt.

von Wolfgang Kufer (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Send sources!

von Wolfgang Kufer (Gast)


Angehängte Dateien:

Lesenswert?

Anbei der DCC Decoder; einfacher Accessory Decoder, selbstlernend,
entweder 4 Pulsausgänge oder Signale bzw. Ampelsteuerung.

von Karl heinz B. (kbucheg)


Lesenswert?

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.

:-)

von Wolfgang Kufer (Gast)


Angehängte Dateien:

Lesenswert?

Entschuldigung,

anbei nochmals des Pudels Kern.

Gruß Wolfgang

von Rolf Magnus (Gast)


Lesenswert?

Ich hoffe, du meinst -Os. Mit -os würde das Ergebnis einfach in eine
Datei namens s geschrieben.

von Rolf Magnus (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Rolf Magnus (Gast)


Lesenswert?

> 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?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> 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
Noch kein Account? Hier anmelden.