mikrocontroller.net

Forum: Compiler & IDEs Watchdog ATMega 2560 nach Reset


Autor: Richard W. (richardw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich versuche gerade, den Watchdog auf dem AtMega2560 zu benutzen. Dafür 
habe ich mir ein paar Routinen geschrieben. _enableWatchdog und 
_disableWatchdog verändern die Prescalerbits nicht.
; void _setTimeout(unsigned char r24);
_setTimeout:
  wdr
  push r16
  push r17
  lds r16, 0x60    ; read WDT register
  andi r16, 0xD8    ; clear WDP bits
  or r16, r24      ; set timeout from parameter, leave old bits
  ldi r17, 0x10 | 0x08 ; load WDE and WDCE
  sts 0x60, r17    ; start WDT manipulation
  sts 0x60, r16    ; write new WDT content
  pop r17
  pop r16
  ret

_enableWatchdog:
  push r16
  lds r16, 0x60  ; load content of WDTCSR
  ori r16, 0x08  ; enable WDE and WDCE
  sts 0x60, r16  ; write back to WDTCSR
  pop r16
  ret

_disableWatchdog:
  wdr        ; reset WDT
  push r16
  push r17
  lds r16, 0x60      ; load WDTCSR content
  mov r17, r16       ; one copy is also needed
  ori r16, 0x10 | 0x18  ; set WDCE and WDE, but leave WDP bits
  andi r17, ~(0x10 | 0x08); clear WDCE and WDE bit, but leave WDP bits
  sts 0x60, r16      ; write to WDTCSR to begin watch dog manipulation
  sts 0x60, r17      ; disable watchdog
  pop r17
  pop r16
  ret

Das klappt auch so weit innerhalb des Programms. Ich kann den Prescaler 
setzen und den Watchdog beliebig oft aktivieren und deaktivieren. Wenn 
er allerdings zuschlägt und der Controller neu startet, dann 
funktioniert _disableWatchdog nicht mehr und der Watchdog schlägt sofort 
wieder zu, obwohl das eigentlich hiermit abgestellt werden sollte:
__attribute__((naked)) __attribute__((section(".init1"))) void initWatchdog()
{
  _disableWatchdog();
}

Die Routine wird auch zum richtigen Zeitpunkt angesprungen, denn wenn 
ich in initWatchdog einen Aufruf zu _setTimeout mit einem beliebigen 
Prescalerwert einfüge, dann wird der Watchdog nach einem Watchdog-Reset 
auch abgestellt.

Hat jemand eine Idee, warum ich nach einem Watchdog-Reset unbedingt die 
Prescalerbits setzen muss?

Danke
Richard

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Richard W. schrieb:
> Wenn
> er allerdings zuschlägt und der Controller neu startet, dann
> funktioniert _disableWatchdog nicht mehr
MCUSR = 0;

Und warum nimmst Du nicht einfach die Funktionen aus wdt.h statt Dich 
mit Assembler abzuquälen?


Peter

Autor: Richard W. (richardw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Peter,

das Löschen des MCUSR-Registers hat scheinbar keinen Einfluss. Ich muss 
explizit irgendein Prescalerbit beschreiben.

Warum nicht die wdt.h? Mein Watchdogtreiber soll sich in ein bestehendes 
Framework integrieren, welches keinerlei Abhängigkeit zu den 
AVR-Bibliotheken aufweist. Ich hab's jetzt in Hochsprache gebracht, da 
muss ich nur noch eine einzige Zeile Assembler schreiben. So ungefähr 
siehts aus:
class Watchdog
{

public:
  enum WatchdogBits
  {
    WDP0 = 0x01, WDP1 = 0x02, WDP2 = 0x04, WDE = 0x08, WDCE = 0x10, WDP3 = 0x20, WDIE = 0x40, WDIF = 0x80
  };
  /**
   * Timeout timings in milliseconds
   */
  enum Timeout
  {
    NONE = 0x10,
    MS_16 = 0,
    MS_32 = WDP0,
    MS_64 = WDP1,
    MS_125 = WDP0 + WDP1,
    MS_250 = WDP2,
    MS_500 = WDP2 + WDP0,
    MS_1000 = WDP2 + WDP1,
    MS_2000 = WDP2 + WDP1 + WDP0,
    MS_4000 = WDP3,
    MS_8000 = WDP3 + WDP0
  };

  static void setTimeout(Timeout timeout);
  static void enable();
  static void disable();
  static void reset();

private:
  static void inline _wdr();
};

/**
 * Helper to access registers 
 */
struct WatchdogRegisters
{
  volatile unsigned char WDTCSR;

  WatchdogRegisters* operator ->()
  {
    return reinterpret_cast<WatchdogRegisters*> (WD_BASE);
  }
};

/**
 * Function that will disable the watchdog immediately after boot.
 */
void initWatchdog();

}

void Watchdog::setTimeout(Timeout timeout)
{
  InterruptLock lock;
  uint8 content = WatchdogRegisters()->WDTCSR;
  content &= ~(WDP3 | WDP2 | WDP1 | WDP0);
  content |= timeout;
  WatchdogRegisters()->WDTCSR |= WDCE | WDE;
  WatchdogRegisters()->WDTCSR = content;
}

void Watchdog::enable()
{
  InterruptLock lock;
  WatchdogRegisters()->WDTCSR |= WDCE | WDE;
  WatchdogRegisters()->WDTCSR |= WDE;
}

void Watchdog::disable()
{
  InterruptLock lock;
  _wdr();
  WatchdogRegisters()->WDTCSR |= WDCE | WDE;
  WatchdogRegisters()->WDTCSR &= ~WDE;
}

void Watchdog::reset()
{
  _wdr();
}

void Watchdog::_wdr()
{
  asm volatile ("wdr"::);
}

__attribute__((naked)) __attribute__((section(".init1"))) void initWatchdog()
{
  Watchdog::disable();
  Watchdog::setTimeout(Watchdog::MS_125); // without setting prescaler watchdog can not be disabled
}

Autor: Richard W. (richardw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sapperlot!

Tatsächlich muss ich das MCUSR-Register zurücksetzen, ich habs nur 
anscheinend nicht richtig gemacht.

So ungefähr funktioniert's jetzt ganz prima und ohne dass ich mich mit 
Assembler abquälen muss ;-) Vielen Dank für die Hilfe.
class Watchdog
{

public:
  enum WatchdogBits
  {
    WDP0 = 0x01, WDP1 = 0x02, WDP2 = 0x04, WDE = 0x08, WDCE = 0x10, WDP3 = 0x20, WDIE = 0x40, WDIF = 0x80
  };
  /**
   * Timeout timings in milliseconds
   */
  enum Timeout
  {
    MS_16 = 0,
    MS_32 = WDP0,
    MS_64 = WDP1,
    MS_125 = WDP0 + WDP1,
    MS_250 = WDP2,
    MS_500 = WDP2 + WDP0,
    MS_1000 = WDP2 + WDP1,
    MS_2000 = WDP2 + WDP1 + WDP0,
    MS_4000 = WDP3,
    MS_8000 = WDP3 + WDP0
  };

  static void setTimeout(Timeout timeout);
  static void enable();
  static void disable();
  static void reset();

private:
  static void inline _wdr();
};

/**
 * After a reset caused by the watchdog, we have to disable it immediately.
 */
void initWatchdog();



enum RegisterBits
{
  PORF = 0x01, EXTRF = 0x02, BORF = 0x04, WDRF = 0x08
};

struct Registers
{
  volatile uint8 dummy0[0x54]; // 0x00..0x53
  volatile uint8 MCUSR; // 0x54
  volatile uint8 MCUCR; // 0x55
  volatile uint8 dummy1[10];
  volatile uint8 WDTCSR; // 0x60

  Registers* operator->()
  {
    return reinterpret_cast<Registers*> (0);
  }
};



void Watchdog::setTimeout(Timeout timeout)
{
  InterruptLock lock;
  uint8 content = Registers()->WDTCSR | WDCE ;
  content &= ~(WDP3 | WDP2 | WDP1 | WDP0);
  content |= timeout;
  Registers()->WDTCSR |= WDCE | WDE;
  Registers()->WDTCSR = content;
}

void Watchdog::enable()
{
  InterruptLock lock;
  Registers()->WDTCSR |= WDCE | WDE;
  Registers()->WDTCSR |= WDE;
}

void Watchdog::disable()
{
  InterruptLock lock;
  _wdr();
  uint8 disabled = Registers()->WDTCSR & (~WDE);
  Registers()->WDTCSR |= WDCE | WDE;
  Registers()->WDTCSR = disabled;
}

void Watchdog::reset()
{
  _wdr();
}

void Watchdog::_wdr()
{
  asm volatile ("wdr"::);
}

__attribute__((naked)) __attribute__((section(".init1"))) void initWatchdog()
{
  Registers()->MCUSR &= ~WDRF;
  Watchdog::disable();
}



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.