Forum: Mikrocontroller und Digitale Elektronik Mit Watchdogreset zum Bootloader springen


von Sam .. (sam1994)


Lesenswert?

Hi

Ich versuche zurzeit eine andere Möglichkeit zum Bootloader zu springen 
als jedesmal die Stromversorgung zu kappen. Ich nutze den Avrootloader 
Beitrag "AVR-Bootloader mit Verschlüsselung" und resette über den Watchdog 
bei einem empfangenen Zeichen über rs232.

Ich beschreibe mal die Problematik:

- Avr mit Strom versorgen
->Bootloader wartet 0.25s und startet Programm
->Programm läuft wie gewohnt
- Über die PC-Software den Bootloader verbinden
->Avr resettet sich und springt in Bootloader
- Disconnect des Bootloaders
->Blinken der LED-Anzeige ->Avr resettet sich die ganze Zeit

main.c
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/pgmspace.h>
4
#include <avr/wdt.h>
5
6
#include "keys.h"
7
#include "display.h"
8
#include "animation.h"
9
#include "uart.h"
10
11
#define F_CPU 6144000
12
13
char buffer[5];
14
15
int main(void)
16
{
17
    //Watchdog deaktivieren
18
    cli();
19
    wdt_disable();
20
    wdt_reset();
21
    uart_init(UART_BAUD_SELECT(38400,F_CPU));
22
    uart_puts_P("Init Display\r\n");
23
    display_init();
24
    uart_puts_P("Init Keys\r\n");
25
    keys_init();
26
    sei();
27
    animation_init();
28
    for(;;)
29
    {
30
        if(animation_update_required)
31
            animation_update();
32
        if(keys_changed)
33
        {
34
            animation_next();
35
            keys_changed = 0;   
36
        }
37
        if((unsigned char)uart_getc())
38
        {
39
            cli();
40
            wdt_enable(0);
41
            for(;;) asm volatile("nop");
42
        }
43
    }   
44
}

Kann es sein das sich der Watchdog mit den obrigen Zeilen nicht 
ausschalten lässt? Eine fehlende ISR kann es ja nicht sein, da es, wenn 
der Watchdog noch nicht gestartet worden ist, noch funktioniert.

Hier noch die Konfiguration des Bootloaders:
1
.equ  UseWDR      = 1        ; set to 0/1 to de/activate WatchDog
2
.equ  UseAutobaud    = 1        ; set to 0/1 to de/activate Baudrate Detection
3
.equ  UseVerify    = 1        ; set to 0/1 to de/activate Verify FLASH Command, FLASH write/erase includes implicit verify, can be deactivated
4
.equ  UseE2Write    = 1        ; set to 0/1 to de/activate EEPROM Write Command
5
.equ  UseE2Read    = 1        ; set to 0/1 to de/activate EEPROM Read Command
6
.equ  UseSRAM      = 0        ; set to 0/1 to de/activate SRAM Commands
7
.equ  UseCrypt    = 0        ; set to 0/1 to de/activate cryptography
8
.equ  UseCryptFLASH   = 0        ; set to 0/1 to de/activate only use cryptography for writing to FLASH
9
.equ  UseCryptE2    = 0        ; set to 0/1 to de/activate only use cryptography for writing to EEPROM
10
.equ  UartInvert    = 1        ; set to 1 to invert UART levels, for RS232 drivers such as MAX232
11
12
.equ  RX_PORT      = PORTD      ; Receive Port and Pin
13
.equ  RX        = PD0
14
.equ  TX_PORT      = PORTD      ; Transmit Port and Pin
15
.equ  TX        = PD1
16
17
.set  XTAL      = 6144000    ; only important for BootDelay if Autobaud is used
18
.set  BootDelay    = XTAL/4    ; 250ms
19
.set  BootBaudrate  = 38400    ; only used if no Baudrate Detection activated, XTAL is important
20
.set  BootVersion    = 2        ; Version 2
21
.set  BootCodeSize  = 502      ; compile and set to value in [.cseg] Used, compile again

Was macht eigentlich genau die UseWDR Option?

von Michael H. (michael_h45)


Lesenswert?

Ist der Bootloader vielleicht zu langsam, um den Watchdog innerhalb von 
15ms zurückzusetzen?
Nimm doch anstatt
1
wdt_enable(0);
 einfach mal
1
wdt_enable(WDTO_500MS)

von Sam .. (sam1994)


Lesenswert?

Michael H. schrieb:
> Ist der Bootloader vielleicht zu langsam, um den Watchdog innerhalb von
> 15ms zurückzusetzen?
> Nimm doch anstattwdt_enable(0); einfach malwdt_enable(WDTO_500MS)

Der müsste eigentlich damit arbeiten. Denn er braucht 250ms und kommt 
durch. Nachdem reset müsste die Zeit zurückgesetzt sein (auf 15ms), 
deswegen sollte es nicht helfen. Aber probieren werde ich es mal.

Ganz vergessen, ich nutze den Atmega48.

EDIT: Gleiches Phänomen.

von Sam .. (sam1994)


Lesenswert?

Die Frage ist ja warum wird der Watchdog nicht zurückgesetzt? Reicht es 
nicht einfach wdt_disable(); aufzurufen?

von Sam .. (sam1994)


Lesenswert?

Könnte man den Controller auch anderst resetten?   Irgendwie muss man 
doch in den Bootloader springen können. Aber ein rjmp wäre wohl nicht 
die elegante Lösung.

von Thomas E. (thomase)


Lesenswert?

Samuel K. schrieb:
> Könnte man den Controller auch anderst resetten?

Wenn du noch einen Port frei hast, kanns du den Reset auch damit einfach 
auf GND ziehen. Der Rest geht dann von selbst.

Samuel K. schrieb:
> Aber ein rjmp wäre wohl nicht
>
> die elegante Lösung.

Warum denn nicht?

Setz' einfach einen Funktionspointer auf den Anfang der Bootsection.


mfg.

von Michael H. (michael_h45)


Lesenswert?

Thomas Eckmann schrieb:
> Warum denn nicht?
das klappt nicht: pointer stimmen nicht, register werden nicht 
zurückgesetzt, usw...

ein watchdog-reset muss funktionieren.

Samuel K. schrieb:
> ->Avr resettet sich und springt in Bootloader
soweit alles klar

> - Disconnect des Bootloaders
was heißt "disconnect"? hat er die applikation geladen?

> ->Blinken der LED-Anzeige ->Avr resettet sich die ganze Zeit
welche led-anzeige? wo ist der code dazu?

von Thomas E. (thomase)


Lesenswert?

Michael H. schrieb:
> Thomas Eckmann schrieb:
>
>> Warum denn nicht?
>
> das klappt nicht: pointer stimmen nicht, register werden nicht
>
> zurückgesetzt, usw...

Aber sicher klappt das.

mfg.

von Michael H. (michael_h45)


Lesenswert?

dann widerleg doch bitte die 2 gründe, die ich auf die schnelle 
angeführt habe, warum es eben nicht funktioniert.

von Sam .. (sam1994)


Lesenswert?

Michael H. schrieb:
>> - Disconnect des Bootloaders
> was heißt "disconnect"? hat er die applikation geladen?

Mit disconnect trenne ich den Bootloader von der PC-Software. Der 
bootloader startet dann deas eigentliche Programm. Ein neues Programm 
muss man gar nicht laden, man kann einfach verbinden und die Verbindung 
wieder trennen (das mache ich zum Test).

>> ->Blinken der LED-Anzeige ->Avr resettet sich die ganze Zeit
> welche led-anzeige? wo ist der code dazu?

2*7Segmente. Das ist alles Interrupt gesteuert. Genauso wie die 
Tastenabfrage. Aber wenn es beim ersten mal klappt müsste es doch dann 
auch funktionieren.

Ich kann den Code vom Display mal posten aber versprech dir nicht so 
viel davon, ich hatte keinen Port mit 7 freien Pins und deswegen ist es 
eine blöde Bitschieberei. Der Asm-Code ist exterm uneffektiv. Aber bei 
50Fps macht das nichts aus.

display.c
1
#include "display.h"
2
3
const uint8_t font[] PROGMEM = {
4
    0b00111111, // 0
5
    0b00000110, // 1
6
    0b01011011, // 2
7
    0b01001111, // 3
8
    0b01100110, // 4
9
    0b01101101, // 5
10
    0b01111101, // 6
11
    0b00000111, // 7
12
    0b01111111, // 8
13
    0b01101111};// 9
14
15
volatile uint8_t data[DIGITS];
16
volatile uint8_t digit;
17
volatile uint8_t digit2;        //= 2^digit
18
19
20
#define PD2_7 (~(( 1 << PD0 ) | ( 1 << PD1 )))
21
#define PB0_1 ((1 << PB0) | (1 << PB1))
22
23
void display_init(void)
24
{
25
    //Ausgange definieren
26
    DDRD |= PD2_7;          //PORTD als Ausgang schalten bis auf PD0 und PD1
27
    DDRC |= 1 << PC3;       //PC3 als Ausgang schalten (7. Segment)
28
    DDRB |= PB0_1;          //PB0 und PB1 als Ausgang schlaten (Backplane)
29
    
30
    //Timer2 konfigurieren
31
    TCCR2B = ( 1 << CS22 ) | ( 1 << CS20 ); //Prescaler 256
32
    //Multiplex-Frequenz wird durch F_CPU / 256 / Prescaler / DIGITS errechnet
33
    //6144000 / 256 / 256 / 2 = 46,875
34
    TIMSK2 |= ( 1 << TOIE2 ); //Overflow Interrupt aktivieren
35
    //Startwerte setzen
36
    digit = DIGITS - 1;     //digit auf max. Wert setzen
37
    digit2 = (1 << (DIGITS - 1));//digit2 auch auf max. Wert setzen
38
}
39
40
ISR (TIMER2_OVF_vect)
41
{
42
    //nächtes Digit berechnen
43
    digit2 = digit2 >> 1;       //digit2 durch 2 teilen
44
    digit--;                    //digit eins abziehen, damit 2^digit == digit2 stimmt
45
    if(digit2 == 0)             //wenn digit2 0 ist
46
    {
47
        digit = DIGITS - 1;     //digit auf max. Wert setzen
48
        digit2 = (1 << (DIGITS - 1));//digit2 auch auf max. Wert setzen
49
    }
50
    uint8_t value = pgm_read_byte(&font[data[digit]]);
51
    //Alle Segmente auschalten
52
    PORTD |= PD2_7;
53
    PORTC |= 1 << PC3;
54
    //Backplane wechseln
55
    PORTB &= ~PB0_1;
56
    PORTB |= digit2;
57
    //Segmente setzen
58
    PORTD &= (~(value & 0b00111111)) << 2;
59
    PORTC &= (~(value & 0b01000000)) >> 3;
60
}

keys.c
1
volatile uint8_t keys_changed;
2
volatile uint8_t keycounter1, keycounter2;
3
void keys_init(void)
4
{
5
    //Tasten initialisieren
6
    DDRC &= ~(( 1 << PC1 ) | ( 1 << PC2 )); //Eingänge definieren
7
    PORTC |=  ( 1 << PC1 ) | ( 1 << PC2 );  //Interne PullUps zuschalten
8
    
9
    StartTimer(); //Prescaler 1024
10
    //Maximale "Drück"-Frequenz wird mit F_CPU / 256 / Prescaler / SOFT_PRESCALER ausgerechnet
11
    //6144000 / 256 / 1024 / SOFT_PRESCALER = ~24 / SOFT_PRESCALER
12
    TIMSK0 |= ( 1 << TOIE0 ); //Overflow Interrupt aktivieren
13
}
14
15
ISR (TIMER0_OVF_vect)
16
{
17
    if(keycounter1 > 0)
18
        keycounter1--;
19
    else
20
        if((PINC & (1 << PC1)) == 0)
21
        {
22
            keycounter1 = SOFT_PRESCALER;
23
            if(++data[0] > 9)
24
                data[0] = 0;  
25
            keys_changed = 1;
26
        }
27
    if(keycounter2 > 0)
28
        keycounter2--;
29
    else
30
        if((PINC & (1 << PC2)) == 0)
31
        {
32
            keycounter2 = SOFT_PRESCALER;
33
            if(++data[1] > 9)
34
                data[1] = 0;
35
            keys_changed = 1;
36
        }
37
}

Die animation.c ist ein bisschen länger. Um die als Fehlerquelle 
auszuschließen hab ich sie einfach mal auskommentiert, ändert am 
Programm ablauf aber nichts.

von Thomas E. (thomase)


Lesenswert?

Michael H. schrieb:
> dann widerleg doch bitte die 2 gründe, die ich auf die schnelle
>
> angeführt habe, warum es eben nicht funktioniert.

Ein Grund reicht. Der zweite ist ja nun Blödsinn: > pointer stimmen 
nicht

Wenn du meinen Beitrag aufmerksam gelesen hättest, müsstest du diese 
Frage gar nicht stellen.

Denn da steht:
>Setz' einfach einen Funktionspointer auf den Anfang der Bootsection.

Das ist der Resetvektor der Bootsection. Dort steht ein Sprungbefehl auf 
die Initialisierung des Bootloaders. Und nach dem er sich neu 
initialisiert hat, inklusive Stack, geht es in die main des Bootloaders 
und der Controller fühlt sich fast wie neu geboren.

mfg.

von Michael H. (michael_h45)


Lesenswert?

Samuel K. schrieb:
>>> ->Blinken der LED-Anzeige ->Avr resettet sich die ganze Zeit
>> welche led-anzeige? wo ist der code dazu?
>
> 2*7Segmente. Das ist alles Interrupt gesteuert. Genauso wie die
ach, die led-anzeige taucht im code als "display" auf... etzad! das hat 
mich etwas verwundert.


ich wollte mir grad das watchdog-handling im bootloader anschauen - kann 
es sein, dass du eine alte version des bootloaders benutzt?
neu wäre:
Beitrag "Re: AVR-Bootloader mit Verschlüsselung"
oder mindestens:
Beitrag "Re: AVR-Bootloader mit Verschlüsselung"

lasst du ein verify laufen?

von Sam .. (sam1994)


Lesenswert?

Michael H. schrieb:
> ich wollte mir grad das watchdog-handling im bootloader anschauen - kann
> es sein, dass du eine alte version des bootloaders benutzt?

Kann sein, ich habe versucht mir eine neuere rauszusuchen, aber der 
Thread ist wirklich unüberschaubar geworden.

Ich teste mal die neue.

von Michael H. (michael_h45)


Lesenswert?

Thomas Eckmann schrieb:
> Das ist der Resetvektor der Bootsection. Dort steht ein Sprungbefehl auf
es gibt auch noch andere zeiger.

> und der Controller fühlt sich fast wie neu geboren.
interruptflags.
ddr-register.

ein rjmp 0 ist und bleibt blödsinn.
denk einfach mal ein bisschen nach, du findest genügend szenarien, mit 
denen solches gemurkse schief geht.

von Thomas E. (thomase)


Lesenswert?

Michael H. schrieb:
> ein rjmp 0 ist und bleibt blödsinn.

Wer redet denn von rjmp0?

Erst richtig lesen, dann verstehen, dann nachdenken, dann eventuell was 
dazu schreiben. Sonst die Klappe halten.


> denk einfach mal ein bisschen nach, du findest genügend szenarien, mit
>
> denen solches gemurkse schief geht.

Nur weil du keine Ahnung hast, ist das noch lange kein Gemurkse.


mfg.

von Sam .. (sam1994)


Lesenswert?

Ich hatte Version 2, das ist jetzt V6. Ich glaub meiner war schon ein 
bisschen zu alt.
Danke für den Tipp, es funktioniert jetzt.

Da der Mega48 sowieso kein Bootloadersupport bietet, ist es auch egal 
wie groß der Bootloader ist? also wenn meiner jetzt 550B groß wäre würde 
ich nicht 200B verschwenden, oder?

Noch eine Frage: Warum ist der Bootloader so langsam? Mein Programm ist 
gerade knapp 700B groß, trotzdem dauert es fast 1s (bei 38400Baud). Die 
Baudrate müsste doch für eine schnelleres Programmieren reichen (zum 
Vergleich: Mein Usbasp programmiert den ganzen Atmega48 in 1s).

von Michael H. (michael_h45)


Lesenswert?

Michael H. schrieb:
>> und der Controller fühlt sich fast wie neu geboren.
> interruptflags.
> ddr-register.
ich warte...

von Thomas E. (thomase)


Lesenswert?

Michael H. schrieb:
> ich warte...

"Sweetwater wartet auf dich"

"Irgendeiner wartet immer"

(Zitat: C'era una Volta il West)

mfg.

von Andreas (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> (Zitat: C'era una Volta il West)

Ein sehr passendes Zitat, denn auch Du erreichst den Pazifik mit Deinem 
Funktionspointer auf den Anfang der Bootloader-Section nicht - oder 
zumindest nur mit großen Umwegen.
Den Funktionspointer könnte man nur verwenden, wenn der Bootloader den 
Controller "zu Fuß" auf einen definierten Zustand zurücksetzt. Das ist 
ziemlich viel Aufwand, den man sich sparen kann, wenn man einen Reset 
ausführt. Nach einem Reset sind die Register nämlich wirklich 
jungfräulich. Welche Werte sie jeweils haben, steht sogar in der 
Dokumenation.

Für den Reset den Watchdog zu benutzen ist eine gute Idee, weil das in 
jedem Board funktioniert, also ohne dass bestimmte Pins in bestimmter 
Weise verdrahtet sein müssen.

von Thomas E. (thomase)


Lesenswert?

Andreas schrieb:
> Controller "zu Fuß" auf einen definierten Zustand zurücksetzt. Das ist
>
> ziemlich viel Aufwand, den man sich sparen kann, wenn man einen Reset
>
> ausführt. Nach einem Reset sind die Register nämlich wirklich
>
> jungfräulich. Welche Werte sie jeweils haben, steht sogar in der
>
> Dokumenation.

Und was ist dabei das Problem?

mfg.

von mfg (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> Und was ist dabei das Problem?

Na genau die oben schon genannten:
Flags von irgendwelchen Interrupts oder auch die DDR Register.
Dumm wäre auch wenn ein Timer in dieser Zeit überläuft. Was passiert 
dann?

von Thomas E. (thomase)


Lesenswert?

mfg schrieb:
> Dumm wäre auch wenn ein Timer in dieser Zeit überläuft. Was passiert
>
> dann?

Gar nichts. Weil die Interrupts abgeschaltet sind.


mfg.

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.