Hallo mikrocontroller Gemeinde,
ich habe mir den Artikel "AVR Bootloader in C - eine einfache Anleitung"
hier durchgelesen und versuche nun den Bootloader zum laufen zu bekommen
um ein HEX File damit zu schreiben..
Leider macht mein µC dabei komische Sachen.
Ich verwende einen AT90CAN128, habe die fuses eingestellt und das -Ttext
Flag beim Linker auf den richtigen Wert gesetzt, funktioniert alles
Prima - bootloader startet und meldet sich über den UART.
Nun sobald ich versuche eine Datei zu schreiben ('p') macht er beim
ersten Zeichen, das ich ihm sende ein Reset.
Ich habe durchgetestet und herausgefunden an welcher Stelle er resetted:
(Anfang der main Schleife)
1
do
2
{
3
c=uart_getc();
4
if(!(c&UART_NO_DATA))
5
{
6
/* Programmzustand: Parser */
7
if(boot_state==BOOT_STATE_PARSER)
8
{
9
// HIER KOMMT ER NOCH HIN
10
switch(parser_state)
11
{
12
/* Warte auf Zeilen-Startzeichen */
13
casePARSER_STATE_START:
14
// HIER NICHT MEHR
15
if((uint8_t)c==START_SIGN)
16
{
.. obwohl parser_state auf PARSER_STATE_START stehen MUSS
Nun kommt der oberwitz: frage ich direkt über dem switch(..) ab, ob
parser_state PARSER_STATE_START ist
1
if(parser_state==PARSER_STATE_START){
2
PORTC^=(1<<PC0);
3
}
dann funktioniert alles :/
Der compiler macht dann auch einen ganz anderen assembler code daraus:
ohne IF Abfrage:
Leider kenne ich mich mit assembler nicht so gut aus, aber ich denke die
unterscheiden sich ganz massiv.. warum der reset stattfindet würde mich
sehr interessieren
jemand eine Idee??
mfg kevin
>Nun sobald ich versuche eine Datei zu schreiben ('p') macht er beim>ersten Zeichen, das ich ihm sende ein Reset.
Folgende Dinge führen häufig zu einem Reset:
Interrupt freigeschaltet und kein Interruptvektor dafür vorhanden.
Stackoverflow.
Arraygrenzen überschritten.
Watchdog aktiv.
Mit deinen Codeschnipseln kann kein Mensch was anfangen,
oder das Problem finden. Das liegt vermutlich ganz woanders.
Hallo Holger
> Interrupt freigeschaltet und kein Interruptvektor dafür vorhanden.
ich habe ISR(BADISR_vect) { } definiert, sollte also nicht passieren
> Stackoverflow.
1. Wie kann ich das herausfinden? 2. Sollte avr-gcc doch so schlau sein
keinen stack overflow zu erzeugen, oder?
> Arraygrenzen überschritten.
An der Stelle wird auf kein Array zugegriffen
> Watchdog aktiv.
Das werde ich mal prüfen, ist aber wohl auch eher unwahrscheinlich da
der reset immer bei der gleichen aktion auftritt.
Den code habe ich 1:1 aus dem artikel übernommen
http://www.mikrocontroller.net/articles/AVR_Bootloader_in_C_-_eine_einfache_Anleitung
Ich habe nun die compilereinstellungen der beiden Versionen abgeglichen,
bei 6.2 immernoch das gleiche Verhalten.
AVR GCC Versionen: 4.6.2 (Atmel Studio 6.0) und 4.8.1 (Atmel Studio 6.2)
Kann doch nur ein Compilerproblem sein, wenn alle Einstellungen +
Programm identisch sind und es beim einen geht, beim anderen nicht, ...
?
kevin schrieb:> if((uint8_t)c == START_SIGN)> 1e28e: 8a e3 ldi r24, 0x3A ; 58> 1e290: e8 12 cpse r14, r24> 1e292: 4b c1 rjmp .+662 ; 0x1e52a <main+0x35a>kevin schrieb:> if((uint8_t)c == START_SIGN)> 1e276: 8a e3 ldi r24, 0x3A ; 58> 1e278: 48 12 cpse r4, r24> 1e27a: 62 c1 rjmp .+708 ; 0x1e540 <main+0x37e>
Einmal wird r14 auf empfangenes Zeichen geprüft (ohne Abfrage),
im anderen Fall wird r4 geprüft (mit Abfrage).
Du machst da zwar cast auf uint8, aber das sieht man nicht, also
muss es weiter oben gemacht worden sein (wenn uberhaupt).
Und warum Compiler das machen sollte - auch mit Optimisierung -
ist fur mich unverständlich.
Wie ist 'UART_NO_DATA' definiert ?
kevin schrieb:> #define UART_NO_DATA 0x0100 /* no receive datakevin schrieb:> if( !(c & UART_NO_DATA) )
Also, ich verstehe diese komische Abfrage überhaupt nicht...
Ob du ein Zeichen empfangen hast oder nicht - das Ergebnis ist für
mich immer dasselbe.
(c & UART_NO_DATA) = (c & 0x0100) = 0x00
somit ist deine Behauptung:
> .. obwohl parser_state auf PARSER_STATE_START stehen MUSS
schon mal nicht zutreffend.
Dein Programm ist ohne ein Zeichen zu empfangen zum SWITCH angelangt.
Jedenfalls sehe ich das so.
Marc Vesely schrieb:> Also, ich verstehe diese komische Abfrage überhaupt nicht...> Ob du ein Zeichen empfangen hast oder nicht - das Ergebnis ist für> mich immer dasselbe.> (c & UART_NO_DATA) = (c & 0x0100) = 0x00
Nein, denn c ist größer als 8 Bit (sollte es jedenfalls sein). Die
Fleury-Lib gibt nun mal in den unteren 8 Bit das empfangene Zeichen und
in den oberen 8 Bit zusätzliche Statusinformationen zurück. Deshalb auch
der Cast auf 8-Bit bei dem späteren Vergleich.
Stefan Ernst schrieb:> Nein, denn c ist größer als 8 Bit (sollte es jedenfalls sein). Die> Fleury-Lib gibt nun mal in den unteren 8 Bit das empfangene Zeichen und> in den oberen 8 Bit zusätzliche Statusinformationen zurück. Deshalb auch> der Cast auf 8-Bit bei dem späteren Vergleich.
Ja, cast hab ich gesehen, aber nicht in den gesendetem assembler-code,
also muss es schon vorher gemacht worden sein. Und wo soll der Compiler
das gemacht haben, ausser bei der Abfrage ?
Marc Vesely schrieb:> Ja, cast hab ich gesehen, aber nicht in den gesendetem assembler-code,> also muss es schon vorher gemacht worden sein. Und wo soll der Compiler> das gemacht haben, ausser bei der Abfrage ?
Was soll er denn da weiter "machen"? Der Cast im Vergleich sagt doch nur
"beschneide c für diesen Vergleich auf die unteren 8 Bit". Und genau das
macht der Assembler-Code, denn er vergleicht nur das untere Byte.
Stefan Ernst schrieb:> Was soll er denn da weiter "machen"? Der Cast im Vergleich sagt doch nur> "beschneide c für diesen Vergleich auf die unteren 8 Bit". Und genau das> macht der Assembler-Code, denn er vergleicht nur das untere Byte.
Einmal r14/r15 und das andere mal r4/r5 nehmen, obwohl der code bis zur
Abfrage Zeile für Zeile gleich ist ?
Das sind verschiedene Abfragen, erst wird mit (!(c & UART_NODATA))
geprüft, ob ein Zeichen empfangen wurde, (c ist uint16), dann wird
geprüft, ob das empfangene Zeichen gleich START_SIGN, also ':' ist.
Ich habe mir das auch nicht selbst ausgedacht sondern - wie gesagt - es
ist das Programm aus dem mikrocontroller.net Artikel.
Und es funktioniert mit Atmel Studio 6 einwandfrei, mit 6.2 habe ich
dieses komische Verhalten, leider verstehe ich den Assembler code nicht
und habe deshalb keine Idee wo genau nun das Problem liegen könnte,
interessieren würde es mich aber schon.
anbei der sourcecode - das programm ist in test.c, die uart lib habe ich
der Vollständigkeit halber mal angehängt.
Und die beiden .lss einmal mit 6.0 und einmal mit Atmel Studio 6.2
kompiliert..
Marc Vesely schrieb:> Einmal r14/r15 und das andere mal r4/r5 nehmen
c steckt halt in den beiden Fällen in unterschiedlichen Registern.
Marc Vesely schrieb:> obwohl der code bis zur> Abfrage Zeile für Zeile gleich ist ?
In dem gezeigten Assembler-Code vor dem Vergleich kommt c gar nicht vor,
also was soll das "obwohl" hier bedeuten?
Stefan Ernst schrieb:> In dem gezeigten Assembler-Code vor dem Vergleich kommt c gar nicht vor,> also was soll das "obwohl" hier bedeuten?kevin schrieb:> c = uart_getc();> if( !(c & UART_NO_DATA) )
Und da du ja so ein Genie bist, kann Kevin die Lösung seines Problems
in den nächsten 5 min. erwarten.
Bei der nicht funktionierenden Variante wird das switch über eine
Sprungtabelle realisiert. Diese liegt hinter den Interrupt-Vectoren.
Beim Auslesen des Tabelleneintrags wird nur ein lpm verwendet (kein
elpm/RAMPZ). Bei einem Bootloader geht das auf Grund seiner besonderen
Adresslage in die Hose und es kracht.
Ich würde es mit -fno-jump-tables versuchen.
Stefan Ernst schrieb:> Beim Auslesen des Tabelleneintrags wird nur ein lpm verwendet (kein> elpm/RAMPZ). Bei einem Bootloader geht das auf Grund seiner besonderen> Adresslage in die Hose und es kracht.
Bravo.
Hab kein Problem zuzugeben, wenn jemand Recht hat und du hast Recht.
Obwohl es mehr als 5 min. gedauert hat ;)
Vielen Dank Stefan, das flag werde ich mal probieren.
Heißt also, dass solche Probleme auch mit einer älteren avr-gcc Version
auftreten könnten und ich nur das Glück hatte, dass hier keine
Sprungtabelle verwendet wurde, oder liege ich da falsch?