mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Mit Watchdogreset zum Bootloader springen


Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht 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
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>

#include "keys.h"
#include "display.h"
#include "animation.h"
#include "uart.h"

#define F_CPU 6144000

char buffer[5];

int main(void)
{
    //Watchdog deaktivieren
    cli();
    wdt_disable();
    wdt_reset();
    uart_init(UART_BAUD_SELECT(38400,F_CPU));
    uart_puts_P("Init Display\r\n");
    display_init();
    uart_puts_P("Init Keys\r\n");
    keys_init();
    sei();
    animation_init();
    for(;;)
    {
        if(animation_update_required)
            animation_update();
        if(keys_changed)
        {
            animation_next();
            keys_changed = 0;   
        }
        if((unsigned char)uart_getc())
        {
            cli();
            wdt_enable(0);
            for(;;) asm volatile("nop");
        }
    }   
}

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:
.equ  UseWDR      = 1        ; set to 0/1 to de/activate WatchDog
.equ  UseAutobaud    = 1        ; set to 0/1 to de/activate Baudrate Detection
.equ  UseVerify    = 1        ; set to 0/1 to de/activate Verify FLASH Command, FLASH write/erase includes implicit verify, can be deactivated
.equ  UseE2Write    = 1        ; set to 0/1 to de/activate EEPROM Write Command
.equ  UseE2Read    = 1        ; set to 0/1 to de/activate EEPROM Read Command
.equ  UseSRAM      = 0        ; set to 0/1 to de/activate SRAM Commands
.equ  UseCrypt    = 0        ; set to 0/1 to de/activate cryptography
.equ  UseCryptFLASH   = 0        ; set to 0/1 to de/activate only use cryptography for writing to FLASH
.equ  UseCryptE2    = 0        ; set to 0/1 to de/activate only use cryptography for writing to EEPROM
.equ  UartInvert    = 1        ; set to 1 to invert UART levels, for RS232 drivers such as MAX232

.equ  RX_PORT      = PORTD      ; Receive Port and Pin
.equ  RX        = PD0
.equ  TX_PORT      = PORTD      ; Transmit Port and Pin
.equ  TX        = PD1

.set  XTAL      = 6144000    ; only important for BootDelay if Autobaud is used
.set  BootDelay    = XTAL/4    ; 250ms
.set  BootBaudrate  = 38400    ; only used if no Baudrate Detection activated, XTAL is important
.set  BootVersion    = 2        ; Version 2
.set  BootCodeSize  = 502      ; compile and set to value in [.cseg] Used, compile again

Was macht eigentlich genau die UseWDR Option?

Autor: Michael H. (michael_h45)
Datum:

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

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sam .. (sam1994)
Datum:

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

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michael H. (michael_h45)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michael H. (michael_h45)
Datum:

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

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht 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
#include "display.h"

const uint8_t font[] PROGMEM = {
    0b00111111, // 0
    0b00000110, // 1
    0b01011011, // 2
    0b01001111, // 3
    0b01100110, // 4
    0b01101101, // 5
    0b01111101, // 6
    0b00000111, // 7
    0b01111111, // 8
    0b01101111};// 9

volatile uint8_t data[DIGITS];
volatile uint8_t digit;
volatile uint8_t digit2;        //= 2^digit


#define PD2_7 (~(( 1 << PD0 ) | ( 1 << PD1 )))
#define PB0_1 ((1 << PB0) | (1 << PB1))

void display_init(void)
{
    //Ausgange definieren
    DDRD |= PD2_7;          //PORTD als Ausgang schalten bis auf PD0 und PD1
    DDRC |= 1 << PC3;       //PC3 als Ausgang schalten (7. Segment)
    DDRB |= PB0_1;          //PB0 und PB1 als Ausgang schlaten (Backplane)
    
    //Timer2 konfigurieren
    TCCR2B = ( 1 << CS22 ) | ( 1 << CS20 ); //Prescaler 256
    //Multiplex-Frequenz wird durch F_CPU / 256 / Prescaler / DIGITS errechnet
    //6144000 / 256 / 256 / 2 = 46,875
    TIMSK2 |= ( 1 << TOIE2 ); //Overflow Interrupt aktivieren
    //Startwerte setzen
    digit = DIGITS - 1;     //digit auf max. Wert setzen
    digit2 = (1 << (DIGITS - 1));//digit2 auch auf max. Wert setzen
}

ISR (TIMER2_OVF_vect)
{
    //nächtes Digit berechnen
    digit2 = digit2 >> 1;       //digit2 durch 2 teilen
    digit--;                    //digit eins abziehen, damit 2^digit == digit2 stimmt
    if(digit2 == 0)             //wenn digit2 0 ist
    {
        digit = DIGITS - 1;     //digit auf max. Wert setzen
        digit2 = (1 << (DIGITS - 1));//digit2 auch auf max. Wert setzen
    }
    uint8_t value = pgm_read_byte(&font[data[digit]]);
    //Alle Segmente auschalten
    PORTD |= PD2_7;
    PORTC |= 1 << PC3;
    //Backplane wechseln
    PORTB &= ~PB0_1;
    PORTB |= digit2;
    //Segmente setzen
    PORTD &= (~(value & 0b00111111)) << 2;
    PORTC &= (~(value & 0b01000000)) >> 3;
}

keys.c
volatile uint8_t keys_changed;
volatile uint8_t keycounter1, keycounter2;
void keys_init(void)
{
    //Tasten initialisieren
    DDRC &= ~(( 1 << PC1 ) | ( 1 << PC2 )); //Eingänge definieren
    PORTC |=  ( 1 << PC1 ) | ( 1 << PC2 );  //Interne PullUps zuschalten
    
    StartTimer(); //Prescaler 1024
    //Maximale "Drück"-Frequenz wird mit F_CPU / 256 / Prescaler / SOFT_PRESCALER ausgerechnet
    //6144000 / 256 / 1024 / SOFT_PRESCALER = ~24 / SOFT_PRESCALER
    TIMSK0 |= ( 1 << TOIE0 ); //Overflow Interrupt aktivieren
}

ISR (TIMER0_OVF_vect)
{
    if(keycounter1 > 0)
        keycounter1--;
    else
        if((PINC & (1 << PC1)) == 0)
        {
            keycounter1 = SOFT_PRESCALER;
            if(++data[0] > 9)
                data[0] = 0;  
            keys_changed = 1;
        }
    if(keycounter2 > 0)
        keycounter2--;
    else
        if((PINC & (1 << PC2)) == 0)
        {
            keycounter2 = SOFT_PRESCALER;
            if(++data[1] > 9)
                data[1] = 0;
            keys_changed = 1;
        }
}

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.

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michael H. (michael_h45)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michael H. (michael_h45)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Michael H. (michael_h45)
Datum:

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

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael H. schrieb:
> ich warte...

"Sweetwater wartet auf dich"

"Irgendeiner wartet immer"

(Zitat: C'era una Volta il West)

mfg.

Autor: Andreas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: mfg (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.