Mit Watchdogreset zum Bootloader springen

OP #2110788
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?
OP #2110912
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.
#2111630
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?
OP #2111669
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.
#2111717
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.
#2111723
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?
#2111752
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.
OP #2111758
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).
Gast #2111955
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren