mikrocontroller.net

Forum: Compiler & IDEs goto im avr gcc


Autor: Anton Wert (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Christian Zietz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Anton Wert (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Christian Zietz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Du umbedingt zur Adresse 0 springen willst, ginge ein
  void (*gotozero)(void) = NULL;
  gotozero();

Zu Deinem goto. Solange Du nicht mehr Code und/oder die Fehlermeldung
postest, kann ich Dir nicht helfen.

Autor: Anton Wert (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Christian Zietz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
  asm volatile ("jmp __vectors"::);

oder (bei kleineren Modelle)
  asm volatile ("rjmp __vectors"::);

Autor: Benedikt (Gast)
Datum:

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

Autor: Volkmar Dierkes (volkmar)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Christian Zietz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Mark Hämmerling (haemi)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Volkmar Dierkes (volkmar)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kann's nur immer wiederholen.  Atmels Appnote AVR109
macht es völlig portabel vor:
    void (*funcptr)( void ) = 0x0000; // Set up function pointer to
RESET vector
...
                funcptr(); // Jump to Reset vector 0x0000 in
Application Section

Mit Optimierung generiert das Ganze exakt einen CALL (oder RCALL,
je nach Prozessor) nach 0, ohne weiteren Speicherverbrauch o.ä.

Autor: Wolfgang Kufer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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"

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Sofern in r00 gerade eine 0 steht.

Wie kommt da jetzt R0 ins Spiel?

Autor: Rolf Magnus (Gast)
Datum:

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

Autor: Wolfgang Kufer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Send sources!

Autor: Wolfgang Kufer (Gast)
Datum:
Angehängte Dateien:

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

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht 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.

:-)

Autor: Wolfgang Kufer (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Entschuldigung,

anbei nochmals des Pudels Kern.

Gruß Wolfgang

Autor: Rolf Magnus (Gast)
Datum:

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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm, also mein avr-g++ macht aus dem Aufruf:
        lds r30,funcptr
        lds r31,(funcptr)+1
        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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.