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
> 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.
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
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.
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
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
Tja, gab's halt günstig (ca. 2,20 ). Jetzt weiß ich auch, warum... ;-)
"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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.