Periodischer Reset trotz wdt_disable();

Gast #3425238
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 :)
Gast #3425480
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();
  }
Angehängte Dateien:
Gast #3425520
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 :)
Gast #3425545
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!")
Gast #3425658
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.
#3426035
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.
#3426759
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.

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