Forum: Mikrocontroller und Digitale Elektronik Watchdog Interrupt


von Martin (Gast)


Lesenswert?

Hi,

ich würde den Watchdog gerne nutzen um meinen µC (Mega88PA) aus dem 
Standby aufzuwecken. Das funktioniert leider nur teilweise. Der Watchdog 
soll nur einen Interrupt auslösen, keinen Reset. Auslösen soll er nach 
einer Sekunde.
Passieren tut jetzt folgendes:
Der Controller geht in den Standby und wacht schon wieder nach 16ms 
(Default-Settings) auf. Laut Datenblatt muss der Zugriff auf das 
Register innerhalb von 4 Taktzyklen erfolgen, nachdem es freigeschaltet 
wurde mit dem WDCE-Bit. Ich hab schon etwas gesucht, aber eine richtige 
Lösung hatte niemand. Ich hab leider nur sehr wenig Ahnung von 
Assembler, ich geh aber davon aus (wenn ich das .lss-File anschaue) das 
der Compiler zu viele "Schritte" draus macht.

Folgenden Code habe ich aktuell:
1
void GlobalSleepMode(void)
2
{
3
  cli();
4
  WDTCSR |= (1<<WDCE);    //WD Interrupt Enable, WD Change Enable
5
  WDTCSR |= 0x70;        //128k, ca. 0,97s
6
  sei();
7
  
8
  _delay_ms(5);            //Auf evtl. UART Übertragungen warten
9
  set_sleep_mode(SLEEP_MODE_STANDBY);
10
  sleep_mode();
11
}
12
13
void GlobalWakeUp(void)
14
{
15
  SleepStatus = 0;
16
  
17
  cli();
18
   WDTCSR |= (1<<WDCE); //0x04;  //WD Change Enable
19
   WDTCSR = 0x00;        //Turn WD off
20
  sei();
21
}
22
23
int main (void)
24
{
25
  DDRB |= (1<<DDB0);
26
27
  uart_init(UART_BAUD_SELECT(38400,F_CPU));
28
  sei();
29
30
  while (1)
31
  {
32
    if (SleepStatus == 1)
33
    {
34
      PORTB |= (1<<PORTB0);
35
      
36
      GlobalSleepMode();
37
      GlobalWakeUp();
38
      
39
      PORTB &= ~(1<<PORTB0);
40
    }
41
    else
42
    {
43
//[...] (ADC Auswertung)
44
      if (rx_status() == STATUS_COMPLETE)
45
      {
46
        //[...] (Übertragung Daten UART)
47
      
48
        SleepStatus = 1;
49
      }
50
    }
51
  }
52
}
53
ISR(WDT_vect)
54
{
55
  
56
}

Die entsprechenden Zeilen aus dem .lss:
1
void GlobalSleepMode(void)
2
{
3
  cli();
4
 3e8:  f8 94         cli
5
  WDTCSR |= (1<<WDCE);    //WD Interrupt Enable, WD Change Enable
6
 3ea:  e0 e6         ldi  r30, 0x60  ; 96
7
 3ec:  f0 e0         ldi  r31, 0x00  ; 0
8
 3ee:  80 81         ld  r24, Z
9
 3f0:  80 61         ori  r24, 0x10  ; 16
10
 3f2:  80 83         st  Z, r24
11
  WDTCSR |= 0x70;        //128k, ca. 0,97s
12
 3f4:  80 81         ld  r24, Z
13
 3f6:  80 67         ori  r24, 0x70  ; 112
14
 3f8:  80 83         st  Z, r24
15
  sei();
16
 3fa:  78 94         sei
17
[...]
18
void GlobalWakeUp(void)
19
{
20
  SleepStatus = 0;
21
 424:  10 92 21 01   sts  0x0121, r1
22
  rfm12_sleepmode(0);
23
 428:  80 e0         ldi  r24, 0x00  ; 0
24
 42a:  d3 df         rcall  .-90       ; 0x3d2 <rfm12_sleepmode>
25
  
26
  cli();
27
 42c:  f8 94         cli
28
   WDTCSR |= (1<<WDCE); //0x04;  //WD Change Enable
29
 42e:  e0 e6         ldi  r30, 0x60  ; 96
30
 430:  f0 e0         ldi  r31, 0x00  ; 0
31
 432:  80 81         ld  r24, Z
32
 434:  80 61         ori  r24, 0x10  ; 16
33
 436:  80 83         st  Z, r24
34
   WDTCSR = 0x00;        //Turn WD off
35
 438:  10 82         st  Z, r1
36
  sei();
37
 43a:  78 94         sei
38
 43c:  08 95         ret
39
40
0000043e <main>:
41
}


Wie bekomm ich das also jetzt so hin, das das funktioniert?
Ich habe schon versucht die Hex-Werte direkt zu schreiben, dann Wacht 
der µC aber gar nicht mehr auf.
Die wdt.h habe ich schon genutzt, aber keine Möglichkeit gefunden 
einzustellen, das nur die ISR aufgerufen wird. Weiß jemand, wie ich das 
lösen kann?
Vielen dank schon mal!

von Martin (Gast)


Lesenswert?

Hm, hab ich was vergessen oder ist etwas unklar, oder weiß wirklich 
niemand Rat?

von Oliver (Gast)


Lesenswert?

Rat weiß das Datenblatt. Das solltest du nochmal anschauen, incl. des 
dort gezeigten Beispielcodes.

Dazu dann die Optimierung beim kompilieren einschalten.

Oliver

von Martin (Gast)


Lesenswert?

Hi,

Optimierung ist auf -Os (Optimize for size).
Code aus dem DB habe ich probiert, gerade extra nochmal. Nur das WDE 
habe ich zu einem WDIE gemacht, da ich ja einen Interrupt und keinen 
Reset haben will (Siehe DB Seite 54, Table 11-1). Geht auch nicht. Der 
µC geht nur für 16ms schlafen.
1
  cli();
2
  wdt_reset();
3
  WDTCSR |= (1<<WDCE)|(1<<WDIE);        //WD Interrupt Enable, WD Change Enable
4
  WDTCSR = (1<<WDIE)|(1<<WDP2)|(1<<WDP1);    //128k, ca. 0,97s      
5
  sei();

von Uwe (Gast)


Lesenswert?

> WDTCSR |= 0x70;
Probier doch mal
WDTCSR |= 0x24;

von Uwe (Gast)


Lesenswert?

Wenn die prescaler alle auf 0 stehen sinds 16ms

von Martin (Gast)


Lesenswert?

Hi Uwe,

mit 0x24 setz ich WDP2 und WDP3 auf 1 - diese Einstellung gibt es laut 
Datenblatt nicht.

Ja, ich weiß das es 16ms sind wenn alles auf 0 steht. Aber ich will ja 
eine Sekunde erreichen und das funktioniert nicht.

von Uwe (Gast)


Lesenswert?

Stimmt ist dann aber trotzdem nicht :
> WDTCSR |= 0x70;
sondern
WDTCSR |= 0x06;

mit
> WDTCSR |= 0x70;
setzt du nur WDIF auf 1 und die Prtescaler bleiben auf 0 also 16ms bis 
zu Watchdog Interupt.

von Martin (Gast)


Lesenswert?

Ich hab nochmal etwas gegoogelt. In Anlehnung an den Code: 
http://electronics.stackexchange.com/questions/74840/use-avr-watchdog-like-normal-isr

Hab ichs dann so geändert (einfach nur die schreibweise)
1
   WDTCSR |= (1<<WDCE)|(1<<WDE);        //WD Interrupt Enable, WD Change Enable
2
   WDTCSR = (1<<WDIE)|(1<<WDP2)|(1<<WDP1);    //128k, ca. 0,97s

Und so geht es. Man muss also das WDE Bit mit setzen, bevor man 
Änderungen am Register vornehmen kann. Das Datenblatt ist da sehr wage 
zu interpretieren. (Meiner Meinung nach)

Danke an alle helfenden!

von Oliver (Gast)


Lesenswert?

Martin schrieb:
> Das Datenblatt ist da sehr wage
> zu interpretieren. (Meiner Meinung nach)

Na ja, selbst wenn man den Text als vage mißversteht, steht das ganz 
genauso in dem Codebeispiel. Nocht konkreter geht das eigentlich gar 
nicht.

Oliver

von Martin (Gast)


Lesenswert?

Jetzt im nachhinein ja - aber es wird halt als Reset Programmiert im 
Beispiel, und das WDE Bit ist definitiv das Bit um die Reset-Funktion zu 
aktivieren (siehe Tabelle 11-1). Daher ergab das für mich keinen Sinn, 
das mit rein zu schreiben.

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.