Forum: Mikrocontroller und Digitale Elektronik Bootloader und Watchdog Reset


von Chrud (ruder)


Angehängte Dateien:

Lesenswert?

Guten Tag

Ich habe ein komisches Verhalten nach einem Watchdog Reset im 
Boodloader. Nach dem Reset bleibt der Controller vermutlich in einer 
Reset-Schlaufe. Die LEDs blinken mit etwa 12Hz. Das KO-Bild im Anhang 
zeigt auf Kanal 1 PB1 und auf Kanal 2 PB2. Ein Reset über den Reset-Pin 
bringt keine Abhilfe. Nur nach dem trennen der Stromversorgung verhält 
sich der Controller wieder normal.

Das Schema vom Aufbau des Controllers (ATmega88) ist angehängt. Der Code 
wurde im Atmel Studio 7.0.1417 geschrieben und kompiliert. Die Fuses 
sind auf Extended 0xF9, High 0xDE, Low 0xE2 gesetzt.

Als erstes programmiere ich den Controller mit der Bootloader.hex über 
den ISP. Das Programm für den Bootloader stammt ursprünglich vom Artikel 
AVR Bootloader in C - eine einfache Anleitung und wurde von mir 
angepasst.

Anschliessend lade ich mit PuTTY die Programm.hex Datei auf den 
Controller. Geplant ist, dass nach erfolgreichem Upload ein Reset 
erfolgt und der Controller direkt in das Hauptprogramm springt (aus 
diesem Grund wurde die Extended.Bootrst Fuse nicht gesetzt). Der 
Controller zeigt aber das oben beschriebene Verhalten.

Nach dem Neuanklemmen der Versorgungsspannung wird, wie gewünscht, das 
Programm ausgeführt d.h. die grüne LED blinkt mit 1Hz, die rote LED 
leuchtet konstant. Durch eine Eingabe in PuTTY von einem 'p', springt 
der Controller wie gewünscht in den Bootloader.

Hat jemand eine Idee was ich falsch mache?

Vielen Dank

von Einer K. (Gast)


Lesenswert?

Bei einem Reset wird bei AVRs (alle?) NICHT der Watchdog abgeschaltet.
Das ist dann eine Aufgabe für den Bootloader.

Der Prescaler des Watchdog wird bein Reset auf den kleinsten Wert 
gesetzt.

von Chrud (ruder)


Lesenswert?

Ich aktiviere den Watchdog am Ende vom Bootloader
1
wdt_enable(1);
Am Anfang vom Hauptprogramm wird er zur Sicherheit deaktiviert
1
wdt_disable();
Für die Funktionen nutze ich
1
#include <avr/wdt.h>

Ich benötige den Watchdog im ganzen Programm nicht. Ich möchte nur einen 
sauberen Reset nachdem der Bootloader seine Arbeit verrichtet hat. 
Deshalb der Einsatz des Watchdog.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Christian R. schrieb:

> Ich benötige den Watchdog im ganzen Programm nicht. Ich möchte nur einen
> sauberen Reset nachdem der Bootloader seine Arbeit verrichtet hat.
> Deshalb der Einsatz des Watchdog.

Ja. Schwachsinn. Schreibe statt dessen den Bootloader so, dass er alle 
benutzte Hardware ordentlich in den Urzustand bringt und du kannst diese 
Watchdog-Scheisse komplett knicken. Du brauchst sie dann einfach nicht.

Der Watchdog gehört der Anwendung. Nur im Kontext einer Anwendung macht 
er (wenigstens ein wenig) Sinn.

Ich selber hab' ihn noch nie benötigt, jedenfalls nicht in der 
eigentlichen Funktion als Watchdog. Als Timer benutze ich ihn hingegen 
gelegentlich schon.

Ich gebe aber zu, dass es Anwendungen (nicht aber Bootloader!) geben 
kann, bei denen der Watchdog als solcher sinnvoll eingesetzt werden 
könnte. Sind aber sehr, sehr rar.

von foobar (Gast)


Lesenswert?

Falls dein Bootloader etwas länger braucht (z.B. auf Daten von UART 
wartet), musst du den Watchdog beim Starten des Bootloaders bereits 
abschalten - im Hauptprogramm ist es zu spät, da kommt er gar nicht mehr 
hin.

von Chrud (ruder)


Lesenswert?

@c-hater: Ursprünglich bin ich nach dem Bootloader wieder zur Adresse 
0x0000 gesprungen:
1
void (*start)(void) = 0x0000;
Und dann den Aufruf
1
start();
Da hat allerdings das Programm nicht mehr ganz korrekt funktionert. Ich 
kam nicht dahinter, was ich nicht richtig zurückgesetz hatte. Dashalb 
die Idee für einen "sauberen Reset".
Der Bootloader ist noch so, wie ich ihn im Endsystem nutze. Soviel zum 
Zurücksetzen gibt's ja nicht. Es wird ja nur die UART gebraucht und die 
inizialisiere ich ja beim Programmstart wieder. Das und auch der Rest 
wird ja beim Sprung an den Start neu inizialisiert. Oder übersehe ich da 
etwas?

@foobar: Beim Neustart/Reset springe ich nicht in den Bootloader sondern 
direkt in das Hauptprogramm. Der Bootloader kann nur über das 
Hauptprogramm angesprungen werden (oder bei der ersten programmierung, 
da ja sonst noch nichts auf dem Controller ist).

von c-hater (Gast)


Lesenswert?

Christian R. schrieb:

> @c-hater: Ursprünglich bin ich nach dem Bootloader wieder zur Adresse
> 0x0000 gesprungen:
1
void (*start)(void) = 0x0000;
> Und dann den Aufruf
>
1
start();

Schon fast OK. Da fehlt nur noch die Korrektur des Stackpointers.

> Ich
> kam nicht dahinter, was ich nicht richtig zurückgesetz hatte.

Dann musst du halt dein Werk weiter Analysieren. Was denn sonst?

> Soviel zum
> Zurücksetzen gibt's ja nicht. Es wird ja nur die UART gebraucht

Du bist definitiv ein C&P-Idiot, wenn du nichtmal geschnallt hast, dass 
du auch die Interrupvektortabelle umschaltest...

Im Übrigen ist auch das "Zurückschalten" der UART nicht ganz trivial.

Aber für beides gilt: alles, was man dazu wissen muss, steht in den DBs. 
Man muss sie einfach nur lesen und verstehen...

Ja, für C&Pler mag das eine neue Erfahrung sein, aber es ist ein 
nützliche...

von Chrud (ruder)


Lesenswert?

@c-hater: Vielen Dank für deine Beleidigung. Da freut man sich immer 
besonders. Es gibt halt Leute, die können nicht alles so gut wie du und 
es gibt bestimmt auch solche, die Sachen viel besser können.
Habe ich viel kopiert? Ja, gebe ich auch zu (im Anfangspost).
Habe ich alles verstanden? Nein. Das werde ich auch nie von einem Thema 
behaupten.
Sind Foren dafür da, das einem andere Leute Tips geben könne? Ja, ich 
denke schon.
Muss man sich in diesen Foren beleidigen? Nein, das bringt keinen 
weiter.

Die Vektoren wurden mit
1
temp = MCUCR;
2
MCUCR = temp | (1<<IVCE);
3
MCUCR = temp | (1<<IVSEL);
angepasst. Hatte ich vergessen oben zu erwähnen.

von Chrud (ruder)


Lesenswert?

Falls jemand mal das gleiche Problem hat, hier die Lösung die bei mir 
funktioniert hat.

Ich habe das mit dem Watchdog Reset im Bootloader aufgegeben. D.h. ich 
springe wieder wie im Artikel [[AVR Bootloader in C - eine einfache 
Anleitung]] beschrieben an Adresse 0x0000.
Das Problem bei mir war, dass ich im Hauptprogram sehrwohl die USART0 
benutzt hatte, aber nicht zusammem mit Peter Fleury's Bibliothek. Das 
hat dann in meinem Hauptprogramm zu Unstimmigkeiten geführt.
ACHTUNG: Die Änderung wurde für ein ATmega88 in Zusammenhang mit der 
USART0 geschrieben. Für andere Prozessoren können die Register und Bits 
andere Namen haben.
Das Ende vom Code des Artikels wurde von:
1
    uart_puts("Reset AVR!\n\r");
2
    _delay_ms(1000);
3
 
4
    /* Interrupt Vektoren wieder gerade biegen */
5
    temp = MCUCR;
6
    MCUCR = temp | (1<<IVCE);
7
    MCUCR = temp & ~(1<<IVSEL);
8
 
9
    /* Reset */
10
    start();
11
12
    return 0;

geändert zu:
1
    uart_puts("Reset AVR!\n\r");
2
    _delay_ms(1000);
3
 
4
    /* Interrupt ausschalten */
5
    cli();
6
7
    /* USART0 ausschalten */
8
    UCSR0B &= ~((1<<RXCIE0) | (1<<TXCIE0) | (1<<UDRIE0) | (1<<RXEN0) | (1<<TXEN0));
9
10
    /* Interrupt Vektoren wieder gerade biegen */
11
    temp = MCUCR;
12
    MCUCR = temp | (1<<IVCE);
13
    MCUCR = temp & ~(1<<IVSEL);
14
 
15
    /* Reset */
16
    start();
17
18
    return 0;

von Einer K. (Gast)


Lesenswert?

Christian R. schrieb:
> Ich habe das mit dem Watchdog Reset im Bootloader aufgegeben.

Eine weise Entscheidung, wie mir scheint!

von Chrud (ruder)


Lesenswert?

Noch ein kleiner Nachtrag. Es reicht einfach die Interrupts von der 
USART zu deaktivieren.
1
UCSR0B &= ~((1<<RXCIE0) | (1<<TXCIE0) | (1<<UDRIE0);
Somit gibts beim wieder Einschalten keine "komischen" Zeichen auf der 
Schnittstelle.

von W.S. (Gast)


Lesenswert?

Christian R. schrieb:
> @c-hater: Vielen Dank für deine Beleidigung.

Christian R. schrieb:
> Noch ein kleiner Nachtrag. Es reicht einfach die Interrupts von der
> USART zu deaktivieren.

Nun, aus deinem Eröffnungspost kann man durchaus ablesen, daß du zu den 
Leuten gehörst, die sich etwas vornehmen, was gemessen an ihrem 
momentanen Wissens- und Könnens-Stand etwas zuviel ist.

Salopp gesagt: Beiße nie mehr ab, als du schlucken kannst, sonst 
bleibt's dir im Halse stecken.

Nun scheint mir ein AVR nicht garzu kompliziert in seiner inneren 
Architektur zu sein, weswegen das Zurücksetzen der HW auf einen Stand, 
wie er exakt nach einem echten Reset vorliegt, wohl durchaus möglich 
ist. Ob das für den USART gilt, ob die zugehörigen Pins tatsächlich 
wieder im Ur-Zustand sind, wenn du mal bloß den Int sperrst, das 
bezweifle ich.

Und nun meinst du, daß du als Allererstes dich an ein Diskussionsforum 
wendest, weil all die anderen ja nur dazu da sind, dir zu helfen. OK, 
das haben sie auch. Aber mit der Zeit wird da der eine oder andere 
derart genervt, daß ihm der Kragen platzt.

Christian R. schrieb:
> Als erstes programmiere ich den Controller mit der Bootloader.hex über
> den ISP.

Ah ja. Und warum programmierst du deine Anwendung nicht gleich damit? 
Dann hättest du all die Probleme mit dem Bootlader überhaupt nicht.

Ich schätze, du solltest über deine Software-Architektur in deinem µC 
nochmal gründlich nachdenken.

W.S.

von Chrud (ruder)


Lesenswert?

Das gepostete Programm und das Schema sind nur ein vereinfachter Teil 
von einem grösseren Projekt. Ich habe versucht alles so zu beschreiben, 
dass das Verhalten reproduzierbar ist. Dadurch scheinen gewisse Aspekte 
vielleicht etwas komisch. Das ein Watchdog Reset nach dem Ende des 
Bootlaoders wohl keine gute Idee ist, wusste ich nicht.
Ich bin mit dem gesammten Endresultat zufrieden und das Thema ist für 
mich somit abgeschlossen.

: Bearbeitet durch User
von Bauform B. (bauformb)


Lesenswert?

Darf ich bitte noch eine Frage fragen?

Christian R. schrieb:
> Anschliessend lade ich mit PuTTY die Programm.hex Datei auf den
> Controller.

Machst du das von der Kommandozeile mit plink o.ä. oder aus dem 
eigentlichen putty heraus? Letzteres kann zwar seriell, aber ich finde 
nichts, wie man eine Datei senden könnte.

von Chrud (ruder)


Lesenswert?

Zuerst stelle ich mit PuTTY eine Verbindung zu meinem Controller her. 
Dann öffne ich die hex-Datei mit einem Editor (z.B. Notepad++), markiere 
und kopiere alles. Anschliessen wähle ich das PuTTY-Fenster wieder an. 
Mit einem klick mit der rechten Maustaste in das Fenster wird alles 
eingefügt/auf den Controller übertragen.

von Bauform B. (bauformb)


Lesenswert?

Christian R. schrieb:
> Mit einem klick mit der rechten Maustaste in das Fenster wird alles
> eingefügt/auf den Controller übertragen.

Ja, okay... also eigentlich geht es nicht, aber die Natur findet immer 
einen Weg ;)
Dankeschön!

Meine hex-Dateien haben so zwischen 2000 und 5000 Zeilen, deswegen hatte 
ich auf etwas direkteres spekuliert. Putty ist so ein nettes Programm 
und kann ziemlich viel, aber so eine Kleinigkeit darf es nicht können?

von Chrud (ruder)


Lesenswert?

Für den Test und meine Datei mit unter 200 Zeilen hat es gereicht. 
Vielleicht hilft das weiter: 
https://electronics.stackexchange.com/questions/233056/can-putty-be-used-to-send-serial-data-from-the-pc-to-the-pic-how

von Bauform B. (bauformb)


Lesenswert?

Danke, das ist nett. Irgendwie anders geht es natürlich, der 
entscheidende Unterschied wäre, wenn es mit dem sowieso installierten 
Putty ginge. Manche Leute dürfen nicht so einfach "irgendwelche 
verseuchten" Programme installieren :(

von M. P. (phpmysqlfreak)


Lesenswert?

Bauform B. schrieb:
> Christian R. schrieb:
>> Mit einem klick mit der rechten Maustaste in das Fenster wird alles
>> eingefügt/auf den Controller übertragen.
>
> Ja, okay... also eigentlich geht es nicht, aber die Natur findet immer
> einen Weg ;)
> Dankeschön!
>
> Meine hex-Dateien haben so zwischen 2000 und 5000 Zeilen, deswegen hatte
> ich auf etwas direkteres spekuliert. Putty ist so ein nettes Programm
> und kann ziemlich viel, aber so eine Kleinigkeit darf es nicht können?

Ja, das habe ich auch schon ab und an vermisst.

Aber auch bie 10k Zeilen hilft noch immer Ctrl-A; Ctrl-C - und der 
Rechtsklick ist auch nicht sooo schwer, aber irgendwie auch ein 
Windows-Ding :D ;)

Wenn ich mal mit nem Bootloader arbeite, ist dieser (oder das HEX-File) 
so "modifiziert", dass ein "cat file.hex > /dev/ttyS0" reicht (oder eine 
beliebige andere Schnittstelle)


Lobenswert ist auf jedenfall zu erwähnen, dass Bootloader UND Programm 
hier als C, sowie auch als HEX im ERSTEN Beitrag angehängt waren! :)


Was den Beitrag von W.S. angeht: Ich stimme ihm in den ersten paar 
Zeilen zu,

W.S. schrieb:
> Aber mit der Zeit wird da der eine oder andere
> derart genervt, daß ihm der Kragen platzt.

Hier hörte es aber bei mir auf. - c-hater ist ja bekannt dafür, in 
dieser Richtung ausfallend zu werden - und das halt auch nicht erst seit 
gestern...
Von einem anderen, der ausfallend wurde oder dem der "Kragen geplatz" 
sei, habe ich in diesem Thread nichts lesen können.

von Chrud (ruder)


Lesenswert?

Falls sich noch jemand für die (mutmassliche) Lösung des ursprünglchen 
Problems interessiert. Ich hätte auch vor dem Watchdog Reset die 
Vektor-Tabelle wieder anpassen müssen. In dem Fall hier ist er nach dem 
Reset nicht nach 0x0000 gesprungen (an den Anfang vom Hauptprogramm), 
sondern nach 0x0C00. Also an den Anfang vom Bootloader. Am Anfang vom 
Bootloader wurde der Watchdog nicht deaktivert, somit hat er immer 
wieder zugeschlagen. Die Timeout-Zeit von 16ms (Die Timeout-Zeit wird 
nach dem Reset zurückgesetzt) entspricht auch schön der Länge des 
Low-Pegels auf Kanal 1 des Oszilloskop-Bildes. Die Zeit des High-Pegels 
entspricht den 65ms Boot-Delay (gem. LOW.SUT_CKSEL Fuse).
Das erklärt auch, warum ein Reset mit Taster keine Abhilfe brachte, aber 
ein ab- und anklemmen der Stromversorgung schon.

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.