Hallo zusammen, ich steh irgendwie aufm Schlauch und komm nicht weiter, vielleicht hat einer von euch ne Idee. Ich hab nen Bootloader auf nem ATMEGA328P ab 0x7000 (byte adresse), dieser wird nach einem Power-On Reset auch korrekt angesprungen, meldet sich und funktioniert soweit. Ins Hauptprogramm springe ich dann via void (*start)( void ) = 0x0000; Auch das Hauptprogramm startet und arbeitet einwandfrei. Aaaber ich komme leider nicht wieder zurück in den Bootloader per Software, noch nicht einmal via Hardware-Reset-Taster. Beide Varianten haben denselben Effekt. Hardware: Reset Pin low ziehen Software: cli(); wdt_enable(WDTO_15MS); while (1); Der Bootloader startet erneut aber scheint sich dann periodisch alle paar ms zu resetten so als ob der Watchdog zuschlägt. Ich habe aber sowohl im Bootloader als auch im Anwendungsprogramm den Befehl wdt_disable(); direkt am Anfang. Im Anwendungsprogramm funktioniert das auch, d.h. wenn ich ohne Bootloader zu flashen den watchdog reset ausführe startet das Anwendungsprogramm neu und läuft einwandfrei. Direkt die Bootloaderadresse anspringen klappt leider auch nicht: void (*bootloader)( void ) = (void*)0x7000; bootloader(); Da geht dan gar nix. Ohne Bootloader läuft der PC offenbar wie erwartet hoch bis zum Überlauf und das Hauptprogramm startet korrekt. Jemand ne Idee? Vielen Dank für eure Hilfe :)
p.s. word adresse void (*bootloader)( void ) = (void*)0x3800; hab ich auch versucht, leider ebenfalls ohne Erfolg. Was wäre eigentlich theoretisch richtig?
Wie sehen die Fuse-Bits aus? Stimmen denn die Einstellungen für den Bootloader? Außerdem wäre etwas Code ganz nützlich, um Softwarefehler auszuschließen. Grüße Oliver
:
Bearbeitet durch User
Fuses im Anhang, aber das sollte eigentlich passen, glaub ich zumindest. (Test)Bootloader nach der Vorlage von Mikrocontroller.net: int main() { unsigned int c=0; unsigned char temp,flag=1, p_mode=0; void (*start)( void ) = 0x0000; wdt_disable(); char sregtemp = SREG; cli(); temp = MCUCR; MCUCR = temp | (1<<IVCE); MCUCR = temp | (1<<IVSEL); SREG = sregtemp; uart_init( UART_BAUD_SELECT(BOOT_UART_BAUD_RATE,F_CPU) ); sei(); uart_puts("Hallo hier ist der Bootloader\n\r"); _delay_ms(1000); do { c = uart_getc(); if( !(c & UART_NO_DATA) ) { switch((unsigned char)c) { case 'q': flag=0; uart_puts("Verlasse den Bootloader!\n\r"); break; default: uart_puts("Du hast folgendes Zeichen gesendet: "); uart_putc((unsigned char)c); uart_puts("\n\r"); break; } } } while(flag); uart_puts("Springe zur Adresse 0x0000!\n\r"); _delay_ms(1000); cli(); temp = MCUCR; MCUCR = temp | (1<<IVCE); MCUCR = temp & ~(1<<IVSEL); start(); return 0; } Das Anwendungsprogramm ist zu groß zum posten, aber es passt auf jeden Fall vor den Bootloader. Programmstart: int main(void) { uint8 u8CpuStatus = MCUSR; MCUSR = 0; wdt_disable(); ... Reset Optionen: else if(SERIAL_bCmdStrCmp(sCmd, 0, "reset")) { cli(); wdt_enable(WDTO_1S); while(1); } else if(SERIAL_bCmdStrCmp(sCmd, 0, "boot")) { void (*bootloader)( void ) = (void*)0x3800; //void (*bootloader)( void ) = (void*)0x7000; bootloader(); }
So, habe nun doch noch mal ein extra Testprogramm ebenfalls nach Vorlage geschrieben. Folgendes Verhalten: - Sprung nach 0x3800 funktioniert hier, ich gehe davon aus das bei meiner eigenen ASW irgendwelche Interrupts bzw. Peripherie die noch läuft das Problem darstellen bzw. in der Folge die umgebogene Interruptvectortabelle. Muss ich aber noch untersuchen. - Der WDT-Reset funktioniert aber nach wie vor NICHT. Selbes Verhalten wie bei meiner ASW: Auf dem Terminal läuft ununterbrochen ... Hallo hier ist deHallo hier ist deHallo hier ist deHallo hier ist deHallo hier ist deHallo hier ist deHallo hier ist deHallo hier ist deHallo hier ist deHallo hier ist deHallo hier ist deHallo hier ist deHallo hier ist deHallo hier ist deH allo hier ist deHallo hier ist deHallo hier ist deHallo hier ist deHallo hier is t deHallo hier ist deHallo hier ist deHallo hier ist deHallo hier ist ... Testprogramm: #include <avr/io.h> #include <avr/wdt.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include <util/delay.h> #include "uart.h" #define UART_BAUD_RATE 9600 int main() { unsigned int c; void (*bootloader)( void ) = (void*)0x3800; // Achtung Falle: Hier Word-Adresse uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); sei(); uart_puts_P("\n\rHier ist das Anwendungsprogramm..."); for(;;) { c = uart_getc(); if(!(c & UART_NO_DATA)) { switch( (unsigned char)c) { case 'b': uart_puts("\n\rSpringe zum Bootloader..."); _delay_ms(1000); bootloader(); break; case 'r': uart_puts("\n\rReset..."); _delay_ms(1000); cli(); // Interrupts global abschalten wdt_enable(WDTO_15MS); // Watchdog aufziehen auf 15ms while (1); // warten, bis er zubeisst... break; default: uart_puts("\n\rDu hast folgendes Zeichen gesendet: "); uart_putc((unsigned char)c); break; } } } return 0; } Für Hinweise was das Problem beim Watchdog Reset sein könnte wäre ich dankbar, da ich eigentlich dachte hierbei wird der Controller komplett reinitialisiert, aber irgendas muss gegenüber Power-On ja offenbar anders sein... Schönes WE euch allen :)
falls jemand über dieselbe Falle stolpert: Lösung für das Watchdog Problem: MCUSR = 0; // Sonst funktioniert das Abschalten des Watchdogs nicht wdt_disable(); Es würde auch reichen nur das Watchdog-Bit in MCUSR zu löschen aber ich brauch den Rest nicht. Schade das wdt_disable(); sich nicht darum kümmert, das habe ich fälschlicherweise vorausgesetzt. (siehe auch Beitrag "AVR spinnt nach Watchdog reset!")
Janus schrieb: > falls jemand über dieselbe Falle stolpert: > > Lösung für das Watchdog Problem: > MCUSR = 0; // Sonst funktioniert das Abschalten des Watchdogs nicht > wdt_disable(); Das Problem hatte ich auch schon. Eigentlich macht es aber gar keinen Sinn, dass MCUSR gelöscht werden muss?
Das ist bestimmt Absicht, damit der Watchdog nicht aus versehen bei einem Absturz deaktiviert wird. Bei vielen AVR kann man ihn gar nicht abschalten, nur einschalten. Der Reset initialisiert fast alles, den Watchdog ausnahmsweise nicht. Wenn er an ist, bleibt er an.
Stefan us schrieb: > Das ist bestimmt Absicht, damit der Watchdog nicht aus versehen bei > einem Absturz deaktiviert wird. Das ist Absicht. Wenn man schon etwas sicherheitsrelevantes per Software abschalten kann, dann aber auch nicht "mal eben". Da ich in C und nicht in Assembler programmiere weiß ich es jetzt nicht ganz genau, aber zum Beschreiben des EEPROM muss wohl auch eine spezielle Sequenz eingehalten werden.
Stefan us schrieb: > Das ist bestimmt Absicht, damit der Watchdog nicht aus versehen bei > einem Absturz deaktiviert wird. Bei vielen AVR kann man ihn gar nicht Martin Kreiner schrieb: > Das ist Absicht. Wenn man schon etwas sicherheitsrelevantes per > Software abschalten kann, dann aber auch nicht "mal eben". Das Handbuch ist da nicht ganz eindeutig. Um Attiny85 Handbuch wird auf Seite 42 nicht erwähnt, dass zum Abschalten MCUSR beschrieben werden muss. wdt_disable() scheint nur die Zugriffe auf WDCE und WDE abzubilden. Im Beispielcode ist der Zugriff auf MCUSR aber ohne weitere Erklärung enthalten.
Tim schrieb: > Das Handbuch ist da nicht ganz eindeutig. Um Attiny85 Handbuch wird auf > Seite 42 nicht erwähnt, dass zum Abschalten MCUSR beschrieben werden > muss. In der Beschreibung des WDE Bits steht es explizit drin.
:
Bearbeitet durch User
Stefan Ernst schrieb: > Tim schrieb: >> Das Handbuch ist da nicht ganz eindeutig. Um Attiny85 Handbuch wird auf >> Seite 42 nicht erwähnt, dass zum Abschalten MCUSR beschrieben werden >> muss. > > In der Beschreibung des WDE Bits steht es explizit drin. Stimmt, dann hat Atmel es in der Beschreibung auf Seite 42 vergessen. Sollte man mal dem Support melden...
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.