Periodischer Reset trotz wdt_disable();

Gast #3425238
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 :)
Gast #3425241
p.s. word adresse void (*bootloader)( void ) = (void*)0x3800; hab ich 
auch versucht, leider ebenfalls ohne Erfolg. Was wäre eigentlich 
theoretisch richtig?
Gast #3425480
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();
  }
Angehängte Dateien:
Gast #3425520
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 :)
Gast #3425545
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!")
#3425561
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?
Gast #3425658
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.
#3426035
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.
#3426759
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.
#3426880
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...

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 12 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.