Forum: Mikrocontroller und Digitale Elektronik Periodischer Reset trotz wdt_disable();


von Janus (Gast)


Lesenswert?

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 :)

von Janus (Gast)


Lesenswert?

p.s. word adresse void (*bootloader)( void ) = (void*)0x3800; hab ich 
auch versucht, leider ebenfalls ohne Erfolg. Was wäre eigentlich 
theoretisch richtig?

von Oliver J. (skriptkiddy)


Lesenswert?

Wie sehen die Fuse-Bits aus? Stimmen denn die Einstellungen für den 
Bootloader?

Außerdem wäre etwas Code ganz nützlich, um Softwarefehler 
auszuschließen.

Grüße Oliver

: Bearbeitet durch User
von Janus (Gast)


Angehängte Dateien:

Lesenswert?

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();
  }

von Janus (Gast)


Lesenswert?

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 :)

von Janus (Gast)


Lesenswert?

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!")

von Tim  . (cpldcpu)


Lesenswert?

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?

von Stefan F. (Gast)


Lesenswert?

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.

von Martin K. (maart)


Lesenswert?

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.

von Tim  . (cpldcpu)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

: Bearbeitet durch User
von Tim  . (cpldcpu)


Lesenswert?

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...

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.