Forum: Compiler & IDEs Function Pointer führt bei 8515 zu Reset?


von Michael Dahlke (Gast)


Lesenswert?

Ahoi zusammen,

ich habe ein Problem, das vermutlich schon einmal behandelt wurde, habe

aber doch keinen entsprechenden Eintrag im Forum oder auf Google finden

können, also poste ich mal, vielleicht kann mir ja jemand von Euch
helfen.
Es geht um

  Function Pointer in C (ja, ich weiß...)

Leider warte ich schon seit einigen Wochen auf meinen ISDN Anschluß
(danke,
Telekom, dass Ihr den für mich erfinden wollt), und muss von meinem
Arbeitsplatz aus posten, so dass ich die Quellen nicht zur Hand habe
und
aus dem Gedächtnis zitieren muss, ich hoffe, ich vertue mich nicht...

Also folgendes Trivialprogramm


...
static void toggle_led8 ()
{
    PORTB = PINB ^ 0x80;
}

static void toggle_led1 ();
{
    PORTB = PINB ^ 0x01;
}

typedef void (* fptr_t) ();

void main ()
{
    DDRB = 0xFF;


    /* Funktionszeiger definieren */

    fptr_t func;
    func = toggle_led1;


    /* Umschalten von LED 8 zeigt den Programmbeginn an */

    toggle_led8 ();


    /* LED 1 Blinkenlichten */

    for (;;) {
        delay ();
        func ();
    }

}



zeigt folgendes Verhalten:

  * läßt sich anstandslos kompilieren:
    avr-gcc -std=c99 -Wall -ffreestanding -O2 -mmcu=at90s8515 -o
dingens dingens.c
    (ist das cdk4avr-Paket mit dem avr-gcc 3.3.1, meine ich)

  * Der generierte Assemblercode scheint mir in Ordnung zu sein, ich
habe mir
    einmal den Dump angeschaut. An der Stelle, an der der toggle_led1
über den
    Function Pointer aufgerufen wird, zeigen die Register R30 & R31
unmittelbar
    vor dem ICALL auf die korrekte Adresse (Dump habe kann ich aus dem
Kopf
    natürlich nicht zitieren...).

  * Das Programm lässt sich im Simulator sehr besonders prima ausführen
und
    zeigt genau das erwartete Verhalten: LED 8 schaltet einmal um, LED
1 blinkt.

  * Auf einem STK-500 in einen 8515 geflasht blinkt(!) LED 8, es wird
also
    offenbar ständig resettet.

Ich habe schon einiges ausprobiert, tappe aber immer noch im Dunkeln.
Hat jemand
eine Lösung oder einen Vorschlag, in welche Richtung ich da weiter
forschen könnte?
Kann das evtl. ein Bug im '8515 sein? Compilerfehler schließe ich mal
aus, da der
Assemblercode ja okay zu sein scheint.


Besten Dank vorab und schönen Gruß,

  Michael

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


Lesenswert?

> static void toggle_led8 ()
> {
>     PORTB = PINB ^ 0x80;
> }

Nur so: PORTB = PORTB ^ 0x80; oder kurz
PORTB ^= 0x80; ist meines Erachtens
sinnvoller.

Außerdem: wir schreiben das Jahr 2005, nicht 1985.  Seit ANSI-C89
alias ISO-C90 gibt's Funktionsprototypen.  Also

static void toggle_led8(void)...

und:

> typedef void (* fptr_t) ();

typedef void (*fptr_t)(void);

>   * läßt sich anstandslos kompilieren:
>     avr-gcc -std=c99 -Wall -ffreestanding -O2 -mmcu=at90s8515 -o
> dingens dingens.c
>     (ist das cdk4avr-Paket mit dem avr-gcc 3.3.1, meine ich)

-ffreestanding würde ich persönlich nicht benutzen.  Zwar erreichst du
damit, dass "void main(void);" ein gültiger Prototyp für main()
wird,
aber das erkaufst du u. U. recht teuer, da der Compiler sein Wissen um
die Standardbibliothek komplett vergessen muss.  Schreibst du irgendwo
"x = strlen("foo");", so muss er z. B. wirklich strlen() aufrufen,
statt der Variablen x einfach die Konstante 3 zuzuweisen, usw. usf.

Sowie eine C-Standardbibliothek dazukommt, ist eben selbst eine
Microcontroller-Applikation gar nicht mehr so "freestanding", wie
sie
es auf den ersten Blick zu sein scheint.

>   * Auf einem STK-500 in einen 8515 geflasht blinkt(!) LED 8, es
> wird also offenbar ständig resettet.

Ist das der einzige Code, oder hast du da noch mehr drin?  (Das
delay() muss ja auch irgendwo her kommen.)  Insbesondere die Frage:
hast du irgendwo Interrupts gestattet und dich vielleicht im
Interrupt-Handler verschrieben?

> * Der generierte Assemblercode scheint mir in Ordnung zu sein, ich
> habe mir einmal den Dump angeschaut.

avr-gcc -mmcu=at90s8515 -O2 -S dingens.c

hätte dir die Assemblerdatei direkt geliefert.

von Michael Dahlke (Gast)


Lesenswert?

Hallo Jörg,

danke für die schnelle Antwort.

Das delay() ist eine simple Verzögerungsschleife, es existieren keine
Interrupthandler o.ä., d.h. dieses Simpelprogramm ist tatsächlich
beinahe vollständig.

Wenn innerhalb der Schleife die Funktion toggle_led1() direkt
anstelle von func() aufgerufen wird, läuft alles tadellos, daher kann
ich (denke ich?) Fehlerquellen wie Interrupts oder einen "heimlich"
laufenden Watchdog ausschließen.

Den Dump hatte ich angefertigt, weil er m.E. um einiges
übersichtlicher ist, als das nackte Assemblerlisting. Ich werde heute
mal Disketten kaufen gehen (lange nicht mehr gemacht...), und die
richtigen Dateien morgen früh posten.


Viele Grüße,

  Michael

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


Lesenswert?

Pliebe eigentlich nur ein Problem mit dem Stack als verdächtig
übrig.  Der Indirektaufruf erzwingt einen ICALL, während
möglicherweise in der direkten Variante die super-simple
,,Funktion'' einfach inlined wird, sodass Stack-Probleme keine
Auswirkung haben.

von Michael Dahlke (Gast)


Lesenswert?

Hmmm, nein, in der direkten Variante läuft's auf einen RCALL raus,
das hatte ich mal gesehen, ge-inline-d wird das wohl nicht.

Ist vermutlich tatsächlich irgendein Stack-Problem, merkwürdig nur,
dass der Simulator das nicht aufdeckt. Dummerweise ist das genau die
Sorte von Fehlern, die sich richtig schlecht "live" debuggen
lassen.

Mist. ;-)

Ich werde heute Nachmittag mal in der Richtung weiter forschen, danke
für den Tip.


Gruß,

  Michael

von Michael Dahlke (Gast)


Lesenswert?

So, ich hab's!

Es ist ein Hardware-Defekt, die Bits in R31 kippen offenbar
willkürlich, damit geht der ICALL natürlich ins Nirvana.

Ich war wohl zu sehr daran gewöhnt, dass Hardware einfach
funktioniert. Besonders, wenn sie recht frisch eingekauft ist, da
habe ich mit dieser Sorte Fehler nicht gerechnet. Die letzten Tage
waren nicht sehr gut für mein Ego ;-)

Besten Dank an Jörg und alle anderen, die sich vielleicht auch um
eine Lösung bemüht haben.


Gruß und schönes Wochenende

  Michael

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


Lesenswert?

Shit happens.

Aber sag mal, warum kaufst du noch AT90S8515 neu?

von Michael Dahlke (Gast)


Lesenswert?

Tja, gab's halt günstig (ca. 2,20 €).
Jetzt weiß ich auch, warum... ;-)

von Peter Dannegger (Gast)


Lesenswert?

"Es ist ein Hardware-Defekt, die Bits in R31 kippen offenbar
willkürlich"

In AVRfreaks war mal ein Thread, daß die LPM-Instruktion bei einigen
Chargen des Mega128 extrem empfindlich gegen hohen Takt war, lief wohl
erst unter 12MHz einigermaßen, d.h. weit unter den erlaubten 16MHz.
Das könnte ja auch auf andere Z-Operationen zutreffen.

Geh doch einfach mal mit dem Takt auf 1..4MHz runter, obs dann läuft.


Peter

von Michael Dahlke (Gast)


Lesenswert?

Hallo Peter,

Entschuldigung für die späte Antwort. Die Schaltung läuft mit den
3,686400 MHz, die das STK-500 Board zur Verfügung stellt, es muss
sich wohl um einen anderen (genau so massiven) Knall handeln.
Trotzdem vielen Dank für den Hinweis.


Gruß,

  Michael

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.