Forum: Compiler & IDEs Watchdog ATMega 2560 nach Reset


von Richard W. (richardw)


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.
1
; void _setTimeout(unsigned char r24);
2
_setTimeout:
3
  wdr
4
  push r16
5
  push r17
6
  lds r16, 0x60    ; read WDT register
7
  andi r16, 0xD8    ; clear WDP bits
8
  or r16, r24      ; set timeout from parameter, leave old bits
9
  ldi r17, 0x10 | 0x08 ; load WDE and WDCE
10
  sts 0x60, r17    ; start WDT manipulation
11
  sts 0x60, r16    ; write new WDT content
12
  pop r17
13
  pop r16
14
  ret
15
16
_enableWatchdog:
17
  push r16
18
  lds r16, 0x60  ; load content of WDTCSR
19
  ori r16, 0x08  ; enable WDE and WDCE
20
  sts 0x60, r16  ; write back to WDTCSR
21
  pop r16
22
  ret
23
24
_disableWatchdog:
25
  wdr        ; reset WDT
26
  push r16
27
  push r17
28
  lds r16, 0x60      ; load WDTCSR content
29
  mov r17, r16       ; one copy is also needed
30
  ori r16, 0x10 | 0x18  ; set WDCE and WDE, but leave WDP bits
31
  andi r17, ~(0x10 | 0x08); clear WDCE and WDE bit, but leave WDP bits
32
  sts 0x60, r16      ; write to WDTCSR to begin watch dog manipulation
33
  sts 0x60, r17      ; disable watchdog
34
  pop r17
35
  pop r16
36
  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:
1
__attribute__((naked)) __attribute__((section(".init1"))) void initWatchdog()
2
{
3
  _disableWatchdog();
4
}

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

von Peter D. (peda)


Lesenswert?

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

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


Peter

von Richard W. (richardw)


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:
1
class Watchdog
2
{
3
4
public:
5
  enum WatchdogBits
6
  {
7
    WDP0 = 0x01, WDP1 = 0x02, WDP2 = 0x04, WDE = 0x08, WDCE = 0x10, WDP3 = 0x20, WDIE = 0x40, WDIF = 0x80
8
  };
9
  /**
10
   * Timeout timings in milliseconds
11
   */
12
  enum Timeout
13
  {
14
    NONE = 0x10,
15
    MS_16 = 0,
16
    MS_32 = WDP0,
17
    MS_64 = WDP1,
18
    MS_125 = WDP0 + WDP1,
19
    MS_250 = WDP2,
20
    MS_500 = WDP2 + WDP0,
21
    MS_1000 = WDP2 + WDP1,
22
    MS_2000 = WDP2 + WDP1 + WDP0,
23
    MS_4000 = WDP3,
24
    MS_8000 = WDP3 + WDP0
25
  };
26
27
  static void setTimeout(Timeout timeout);
28
  static void enable();
29
  static void disable();
30
  static void reset();
31
32
private:
33
  static void inline _wdr();
34
};
35
36
/**
37
 * Helper to access registers 
38
 */
39
struct WatchdogRegisters
40
{
41
  volatile unsigned char WDTCSR;
42
43
  WatchdogRegisters* operator ->()
44
  {
45
    return reinterpret_cast<WatchdogRegisters*> (WD_BASE);
46
  }
47
};
48
49
/**
50
 * Function that will disable the watchdog immediately after boot.
51
 */
52
void initWatchdog();
53
54
}
55
56
void Watchdog::setTimeout(Timeout timeout)
57
{
58
  InterruptLock lock;
59
  uint8 content = WatchdogRegisters()->WDTCSR;
60
  content &= ~(WDP3 | WDP2 | WDP1 | WDP0);
61
  content |= timeout;
62
  WatchdogRegisters()->WDTCSR |= WDCE | WDE;
63
  WatchdogRegisters()->WDTCSR = content;
64
}
65
66
void Watchdog::enable()
67
{
68
  InterruptLock lock;
69
  WatchdogRegisters()->WDTCSR |= WDCE | WDE;
70
  WatchdogRegisters()->WDTCSR |= WDE;
71
}
72
73
void Watchdog::disable()
74
{
75
  InterruptLock lock;
76
  _wdr();
77
  WatchdogRegisters()->WDTCSR |= WDCE | WDE;
78
  WatchdogRegisters()->WDTCSR &= ~WDE;
79
}
80
81
void Watchdog::reset()
82
{
83
  _wdr();
84
}
85
86
void Watchdog::_wdr()
87
{
88
  asm volatile ("wdr"::);
89
}
90
91
__attribute__((naked)) __attribute__((section(".init1"))) void initWatchdog()
92
{
93
  Watchdog::disable();
94
  Watchdog::setTimeout(Watchdog::MS_125); // without setting prescaler watchdog can not be disabled
95
}

von Richard W. (richardw)


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.
1
class Watchdog
2
{
3
4
public:
5
  enum WatchdogBits
6
  {
7
    WDP0 = 0x01, WDP1 = 0x02, WDP2 = 0x04, WDE = 0x08, WDCE = 0x10, WDP3 = 0x20, WDIE = 0x40, WDIF = 0x80
8
  };
9
  /**
10
   * Timeout timings in milliseconds
11
   */
12
  enum Timeout
13
  {
14
    MS_16 = 0,
15
    MS_32 = WDP0,
16
    MS_64 = WDP1,
17
    MS_125 = WDP0 + WDP1,
18
    MS_250 = WDP2,
19
    MS_500 = WDP2 + WDP0,
20
    MS_1000 = WDP2 + WDP1,
21
    MS_2000 = WDP2 + WDP1 + WDP0,
22
    MS_4000 = WDP3,
23
    MS_8000 = WDP3 + WDP0
24
  };
25
26
  static void setTimeout(Timeout timeout);
27
  static void enable();
28
  static void disable();
29
  static void reset();
30
31
private:
32
  static void inline _wdr();
33
};
34
35
/**
36
 * After a reset caused by the watchdog, we have to disable it immediately.
37
 */
38
void initWatchdog();
39
40
41
42
enum RegisterBits
43
{
44
  PORF = 0x01, EXTRF = 0x02, BORF = 0x04, WDRF = 0x08
45
};
46
47
struct Registers
48
{
49
  volatile uint8 dummy0[0x54]; // 0x00..0x53
50
  volatile uint8 MCUSR; // 0x54
51
  volatile uint8 MCUCR; // 0x55
52
  volatile uint8 dummy1[10];
53
  volatile uint8 WDTCSR; // 0x60
54
55
  Registers* operator->()
56
  {
57
    return reinterpret_cast<Registers*> (0);
58
  }
59
};
60
61
62
63
void Watchdog::setTimeout(Timeout timeout)
64
{
65
  InterruptLock lock;
66
  uint8 content = Registers()->WDTCSR | WDCE ;
67
  content &= ~(WDP3 | WDP2 | WDP1 | WDP0);
68
  content |= timeout;
69
  Registers()->WDTCSR |= WDCE | WDE;
70
  Registers()->WDTCSR = content;
71
}
72
73
void Watchdog::enable()
74
{
75
  InterruptLock lock;
76
  Registers()->WDTCSR |= WDCE | WDE;
77
  Registers()->WDTCSR |= WDE;
78
}
79
80
void Watchdog::disable()
81
{
82
  InterruptLock lock;
83
  _wdr();
84
  uint8 disabled = Registers()->WDTCSR & (~WDE);
85
  Registers()->WDTCSR |= WDCE | WDE;
86
  Registers()->WDTCSR = disabled;
87
}
88
89
void Watchdog::reset()
90
{
91
  _wdr();
92
}
93
94
void Watchdog::_wdr()
95
{
96
  asm volatile ("wdr"::);
97
}
98
99
__attribute__((naked)) __attribute__((section(".init1"))) void initWatchdog()
100
{
101
  Registers()->MCUSR &= ~WDRF;
102
  Watchdog::disable();
103
}

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.