Forum: Mikrocontroller und Digitale Elektronik Kam Reset durch Watchdog


von Watchdog Reset (Gast)


Lesenswert?

Heyho.

Ich hab zwar hier schon viel gesucht, aber leider nichts passendes 
gefunden. Ich hab einen watchdog in auf meinem Tiny85 am laufen. Wenn es 
aber von dem einen reset gab, will ich das herausfinden:
1
void wdt_init(void)
2
{
3
  
4
  uint8_t buffer;
5
  buffer = MCUSR & (1 << WDRF);
6
  
7
  if (buffer == 1) {
8
    IsWatchdogReset = true;
9
  } else {
10
    IsWatchdogReset = false;
11
  };
12
  
13
  MCUSR = 0;
14
  wdt_disable();
15
16
  return;
17
}

Nur ist bei mir IsWatchdogReset immer false. Was mache ich falsch?

Danke für die Hilfe :-)

von Cyblord -. (cyblord)


Lesenswert?

> if (buffer == 1)

ersetze durch

if (buffer)

Deine Programmierung ist echt umständlich.
1
IsWatchdogReset = (MCUSR & (1 << WDRF));

und fertig.

von Route_66 (Gast)


Lesenswert?

Hallo!
WDRF ist Bit 3 in MCUSR.
Nach dem binären AND hast Du in buffer 0 oder 8 und nie 1.

von Panorama (Gast)


Lesenswert?

Eventuell ein simpler Fehler: WDRF ist Bit 3 im Register.
Wenn das Bit gesetzt war steht daher dezimal 8 im Buffer, du prüfst 
allerdings auf 1. Ein simples "if(buffer)" wäre hier richtig, das prüft 
ob ein beliebiges Bit gesetzt ist.

Probier mal so:
1
uint8_t buffer = MCUCSR;
2
3
if(buffer & (1 << WDRF))
4
  IsWatchdogReset = 1;

von Panorama (Gast)


Lesenswert?

Ooh schon wieder zu langsam :(

Eine kleine Anmerkung habe ich noch. Leg in so einen allgemeinen Puffer 
immer das vollständige Register. Wenn du irgendwann mal auf Power-On 
Reset prüfen willst wunderst du dich sonst wieso das Bit nicht kommt, 
hattest doch sogar gepuffert. Bei einer größeren Funktion geht dann die 
Sucherei und Umbau los.

von Cyblord -. (cyblord)


Lesenswert?

Panorama schrieb:
> Ooh schon wieder zu langsam :(
>
> Eine kleine Anmerkung habe ich noch. Leg in so einen allgemeinen Puffer
> immer das vollständige Register. Wenn du irgendwann mal auf Power-On
> Reset prüfen willst wunderst du dich sonst wieso das Bit nicht kommt,
> hattest doch sogar gepuffert. Bei einer größeren Funktion geht dann die
> Sucherei und Umbau los.

Der bessere Tipp wäre auf solch "allgemeine Puffer" komplett zu 
verzichten. Variabeln und Funktionen sprechend benennen. Namen wie 
"buffer","x","a" usw. einfach weg lassen.

von Watchdog Reset (Gast)


Lesenswert?

Ach mist, da hatte ich einen denkfehler. Ich hatte das shift genau 
falsch herum gelesen - dann käme da eine 1 raus.

wenn ich jetzt aber nach einen watchdog reset prüfe:
1
int main () {
2
  // Gab es einen Watchdog-Reset?                            
3
  if (IsWatchdogReset) {
4
    
5
    // Blinken
6
    for (int i = 0; i < 10; i++) {
7
      
8
      PB1_on();
9
      _delay_ms(100);
10
      PB1_off();
11
      _delay_ms(500);
12
    };      
13
  };
14
};

Dann blinkt die led nie, auch wenn der watchdog einen reset gemacht 
hat??!!

Weis einer wieso? Vielen Dank :-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Watchdog Reset schrieb:
>
1
> int main () {
2
>   // Gab es einen Watchdog-Reset?
3
>   if (IsWatchdogReset) {
4
>

Wo setzt Du denn IsWatchdogReset? Ich sehe in main() lediglich die 
Abfrage der Variable. Deine Funktion wdt_init() wird auch nirgendwo 
aufgerufen.

Zeig Deinen kompletten Code. So ist das sinnfrei.

: Bearbeitet durch Moderator
von Watchdog Reset (Gast)


Lesenswert?

Frank M. schrieb:
> Deine Funktion wdt_init() wird auch nirgendwo
> aufgerufen.
1
void wdt_init(void) __attribute__((naked)) __attribute__((section(".init1")));
2
3
void wdt_init(void)
4
{
5
  
6
  IsWatchdogReset = (MCUSR & (1 << WDRF));
7
  
8
  MCUSR = 0;
9
  wdt_disable();
10
11
  return;
12
}
13
14
int main () {
15
  // Gab es einen Watchdog-Reset?                            
16
  if (IsWatchdogReset) {
17
    
18
    // Blinken
19
    for (int i = 0; i < 10; i++) {
20
      
21
      PB1_on();
22
      _delay_ms(100);
23
      PB1_off();
24
      _delay_ms(500);
25
    };      
26
  };
27
28
  // Watchdog einschalten
29
  wdt_enable(WDTO_8S);
30
  
31
  while(1)
32
  {
33
     // nix
34
  };
35
};

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Watchdog Reset schrieb:
> void wdt_init(void) __attribute__((naked))
> __attribute__((section(".init1")));

Aha. Wo ist die Definition von IsWatchdogReset? Wann werden globale 
Variablen mit 0 initialisiert? Vor oder nach der init1-Section?

: Bearbeitet durch Moderator
von Michael S. (stroggi)


Lesenswert?

Und an welcher Stelle wird wdt_init überhaupt aufgerufen?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Michael Strosche schrieb:
> Und an welcher Stelle wird wdt_init überhaupt aufgerufen?

Das passiert durch die Platzerung der Funktion in die Section namens 
"init1". Aber ich nehme mal nicht an, dass der Compiler dadurch 
automatisch weiß, dass wdt_init() vor main() aufgerufen werden könnte 
und zudem auch noch eine globale Variable setzt - Stichwort: volatile.

Aber gerade die Definition der globalen Variablen hat der TO 
unterschlagen.... damit die Kristallkugeln weiterhin brav poliert 
werden...

von Cyblord -. (cyblord)


Lesenswert?

Diese merkwürdige Verlagerung der Init Funktion in die init1 Sektion ist 
mir nicht so ganz klar. Nötig ist sie für das was wir hier sehen 
jedenfalls nicht. Das ganze Spiel geht auch direkt aus der main heraus.

Sollte man solche Handstände machen, wenn man grade noch mit einem 
"bitwise and" gekämpft hat? Ich glaube nicht Tim.

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Cyblord ---- schrieb:
> Diese merkwürdige Verlagerung der Init Funktion in die init1 Sektion ist
> mir nicht so ganz klar.

Es gab hier in der Vergangenheit schon diverse Threads, wo wdt_disable() 
als erster Aufruf in main() zu spät kam und man dadurch den µC in eine 
Art Dauer-Watchdog-Reset versetzt hat.

Die Lösung, die dann immer angeboten wurde, war, den Aufruf von 
wdt_reset() in die init1-Section zu verlagern.

Ich habe aber gerade mal die Funktionen des TOs kompiliert und gesehen, 
dass standardmäßig erstmal wdt_init() komplett wegoptimiert wird. Es 
landet schon gar nicht mehr im lss-File.

von Jay (Gast)


Lesenswert?

Hallo,

ich glaube das Verlagern der Funktion hat etwas damit zu tun, dass der 
Watchdog bei einigen AVRs nach einem Reset weiterhin aktiv ist. Dadurch 
kann es passieren, dass der Watchdog in der main() evt. nicht 
rechtzeitig deaktiviert werden kann. Aber ich bin mir bei init1 auch 
nicht sicher.

CU,
Jay

von Jay (Gast)


Lesenswert?

... kurz mal Google befragt: 
http://www.nongnu.org/avr-libc/user-manual/group__avr__watchdog.html

Dort gibt es auch Beispielcode. In der main() dann stattdessen 
mcusr_mirror benutzen:
IsWatchdogReset = (mcusr_mirror & (1 << WDRF));
So sollte es funktionieren...

von Watchdog Reset (Gast)


Lesenswert?

Frank M. schrieb:
> Watchdog Reset schrieb:
>> void wdt_init(void) __attribute__((naked))
>> __attribute__((section(".init1")));
>
> Aha. Wo ist die Definition von IsWatchdogReset? Wann werden globale
> Variablen mit 0 initialisiert? Vor oder nach der init1-Section?

Ach entschuldigung, das vergaß ich tatsächlich:
1
#define F_CPU 8000000L
2
3
#include <avr/io.h>
4
#include <util/delay.h>
5
#include <avr/interrupt.h>
6
#include <avr/wdt.h>
7
#define F_CPU 8000000L
8
9
void wdt_init(void) __attribute__((naked)) __attribute__((section(".init1")));
10
11
void wdt_init(void)
12
{
13
  
14
  IsWatchdogReset = (MCUSR & (1 << WDRF));
15
  
16
  MCUSR = 0;
17
  wdt_disable();
18
19
  return;
20
}
21
22
int main () {
23
  // Gab es einen Watchdog-Reset?                            
24
  if (IsWatchdogReset) {
25
    
26
    // Blinken
27
    for (int i = 0; i < 10; i++) {
28
      
29
      PB1_on();
30
      _delay_ms(100);
31
      PB1_off();
32
      _delay_ms(500);
33
    };      
34
  };
35
36
  // Watchdog einschalten
37
  wdt_enable(WDTO_8S);
38
  
39
  while(1)
40
  {
41
     // nix
42
  };
43
};

Jay schrieb:
> ich glaube das Verlagern der Funktion hat etwas damit zu tun, dass der
> Watchdog bei einigen AVRs nach einem Reset weiterhin aktiv ist

Vollkommen richtig. Beim Tiny85 resettet sich sogar der vorteiler sodass 
er in den kürzesten interrupt von 16ms fällt. Dann kommt er nichteinmal 
bis zum wdt_disable(); selbst wenn es an derster stelle steht.

von Watchdog Reset (Gast)


Lesenswert?

Ach mist jetzt hat er was beim kopieren verloren:
1
volatile bool IsWatchdogReset;
2
3
void wdt_init(void) __attribute__((naked)) __attribute__((section(".init1")));
4
...
5
...

von Michael (Gast)


Lesenswert?

Watchdog Reset schrieb:
> Ach mist jetzt hat er was beim kopieren verloren:

Ohne das auszuprobieren: Funktioniert der Code so wie beschrieben, wenn 
du es schaffst, beim Einfachen Copy & Paste eines gesamten 
Codeschnippsels eine einzelne Zeile dazwischen zu verlieren? Jede 
Zwischenablage, die ich kenne, kann das nicht...

von Watchdog Reset (Gast)


Lesenswert?

Michael schrieb:
> Jede Zwischenablage, die ich kenne, kann das nicht...

Ich verstehe irgendwie nicht wie das bei der lösungs des problems hilft.

von Michael (Gast)


Lesenswert?

Das hilft insofern, dass ich so nicht ganz glauben kann, dass der Code 
ein vollständiges Beispiel darstellt bzw. scheinbar ja nicht so 
ausprobiert wurde (sonst wäre die Variablendeklaration ja im ersten 
Copy&Paste-Vorgang mitgekommen). Deshalb auch die Frage, ob der Code so 
wirklich funktioniert? (oder halt nicht, aber mit beschriebenem Symptom)

von Fritz G. (fritzg)


Lesenswert?

Das funktioniert bei mir (printBootReason in der main aufrufen):
1
uint8_t mcusr_mirror __attribute__ ((section (".noinit")));    // Für Reset-Grund
2
3
void get_mcusr(void) __attribute__((naked)) __attribute__((section(".init3")));
4
void get_mcusr(void)
5
{
6
    mcusr_mirror = MCUSR;
7
    MCUSR = 0;
8
    wdt_disable();
9
}
10
void wdt_init(void) __attribute__((naked)) __attribute__((section(".init3")));
11
void wdt_init(void)
12
{
13
    MCUSR = 0;
14
    wdt_disable();
15
    return;
16
}
17
18
19
/**
20
 *  @brief Gibt den Grund des Resets aus
21
 *
22
 *  @return  none
23
 */
24
25
void printBootReason(void) {
26
    printf_P(PSTR("Reset: "));
27
    
28
    if (mcusr_mirror&(1<<WDRF)) {
29
        printf_P(PSTR("Watchdog "));
30
    }
31
    if (mcusr_mirror&(1<<BORF)) {
32
        printf_P(PSTR("Brownout "));
33
    }
34
    if (mcusr_mirror&(1<<EXTRF)) {
35
        printf_P(PSTR("External "));
36
    }
37
    if (mcusr_mirror&(1<<PORF)) {
38
        printf_P(PSTR("Power-on "));
39
    }
40
    if (mcusr_mirror==0)
41
        printf_P(PSTR("unknown "));
42
    printf_P(PSTR("\n"));
43
}

von Watchdog Reset (Gast)


Lesenswert?

Vielen Dank Fritz, Dein Ansatz funktioniert.

Dem verständnis nach muss man also die globale Variable dann in den 
Noinit-Block schieben, damit sie nicht beim Startvorgang des µC 
überschrieben wird, oder?

Und woher weiß der Controller, dass get_mcusr() vor wdt_init() 
aufgerufen werden muss? Eine Hirarchie kann ich nicht erkennen. Oder 
liegt das nur daran, da das mcusr vor dem init steht und das ganze 
sequenziell abgearbeitet wird?

von Fritz G. (fritzg)


Lesenswert?

Watchdog Reset schrieb:
> Eine Hirarchie kann ich nicht erkennen. Oder
> liegt das nur daran, da das mcusr vor dem init steht und das ganze
> sequenziell abgearbeitet wird?

Nehme ich mal an. Ich glaube den Code habe ich hier im Forum gefunden.

von Watchdog Reset (Gast)


Lesenswert?

Ok. Jedenfalls tut es genau das, was es soll.

Vielen Dank :)

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.