Electronic – How to wake from sleep on PIC10F200 via watchdog

microcontrollerpicprogrammingsleepwatchdog

So far I have worked with many other micro controllers but not the PIC-family. I'm having trouble with waking from sleep via watchdog on a PIC10F200. I'm programming it in C using the MPLAB X IDE v2.35. All function's an macros are part of microchip's baseline libraries for the processor.

Here is a minimal example of what my problem is:

#include <xc.h>
#pragma config CP    = OFF   // Code protection off
#pragma config MCLRE = OFF   // GP3/MCLR pin fuction is digital I/O
#pragma config WDTE  = ON    // Watchdog Timer enabled
#define _XTAL_FREQ 4000000

void main(void) {
    OPTION = 0 | nGPWU | nGPPU & ~T0CS & ~T0SE | PSA | PS2 | PS1 | PS0;    // bits: 7: no wake-up on pin change; 6: no weak pullups; 5: internal clock; 4: incremnt low to high; 3: prescale on wdt (Timer0 if cleared); 2-0: clock division by 128
    TRISGPIO = 0b00000000; // set all to output

    while(1) {
        GP0 = 1;   GP1 = 1;   GP2 = 1;   SLEEP();  // set all high and sleep a bit
        GP0 = 0;   GP1 = 0;   GP2 = 0;   SLEEP();  // set all low  and sleep a bit
    }
}

Basically this is a classic toggle-pin (blink LED) example using the watchdog. Only the pins are high all the time. What did I do wrong?

Best Answer

The answer finally came to me in form of Howardlong. The watchdog indeed causes a reset every time sleep mode is entered. However, one can preserve variables between resets after sleep using the persistent keyword in variable declaration.

The catch is, this way the variable cannot be initialized the normal way. To give it an initial value, the best way is to detect a power-on reset and initialize it solely on that from of reset. Initializing it normally would lead to a chicken-and-egg kind of problem, where you want to preserve the value, but set it on very reset. Note that some registers also get reset by a WDT-reset and therefore need to be set every time!

Here is an example:

#include <xc.h>
#include <stdbool.h>
#pragma config CP    = OFF   // Code protection off
#pragma config MCLRE = OFF   // Master Clear Enable (GP3/MCLR pin fuction is digital I/O, MCLR internally tied to VDD)
#pragma config WDTE  = ON   // Watchdog Timer enabled
#define _XTAL_FREQ 40000000

static persistent bool _bState; // Persistent so the C startup code doesn't initialise

void main(void) {   
    // Check STATUS bits for type of reset
    if ( ! ( GPWUF==0 && nPD==0 && nTO==0 ) ) {
        // NOT a WDT wakeup from sleep, so treat as a power on reset
        _bState=false;
        OSCCALbits.FOSC4=0;
    }
    // These SFRs must be re-written after every reset
    OPTION = 0b11001100; // WDT is div-by-32 prescaled
    TRISGPIO = 0b1011;   // GP2 output

    GP2=_bState;
    _bState=!_bState;
    SLEEP();                
}