3
\$\begingroup\$

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?

\$\endgroup\$
5
  • \$\begingroup\$ There is too much layered stuff here. Really, you need a compiler on a machine that only has 255 usable instruction locations!? For example, we don't know what SLEEP() actually does. \$\endgroup\$ Commented Sep 8, 2015 at 17:58
  • 1
    \$\begingroup\$ SLEEP is a built-in function and part of MPLAB X. It calls the assembler instruction of the same name. The PIC10F200 does not have a comparator and does not define the register. I'm used to C and there is no reason for me to learn PICs variant of assembler. Thanks for your comment's though. \$\endgroup\$
    – con-f-use
    Commented Sep 8, 2015 at 18:33
  • 1
    \$\begingroup\$ Usually when a watchdog occurs, it restarts the program from the beginning again. So you will never get to the second SLEEP() call. \$\endgroup\$
    – tcrosley
    Commented Sep 8, 2015 at 18:43
  • \$\begingroup\$ From AVRs I'm used to continuing the program, where it left off, but you'd have to set the watchdog to interrupt mode instead of reset mode. I was looking for something similar on the PIC and thought from the data sheet it would be the default behavior: "Some registers are not reset in any way [...] They are not affected by a WDT Reset during Sleep or MCLR Reset during Sleep, since these Resets are viewed as resumption of normal operation." What good is a watchdog timer with sleep mode if there's no way to retain data between sleeps? \$\endgroup\$
    – con-f-use
    Commented Sep 8, 2015 at 18:56
  • \$\begingroup\$ Never assume anything when changing between vendors.. Intel once did a die shrink on the 8051 series of micro's ... The performance changed enough to break some pcb designs. So even the same vendor can mess you up. (The solution was 20k pullups for those who need to know.) \$\endgroup\$
    – Spoon
    Commented Sep 8, 2015 at 22:02

1 Answer 1

3
\$\begingroup\$

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();                
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Additionally I want to express my discontent with one of the comments on my initial question. Questioning why I want to use C and showing a lack of knowledge of basic functions is not really constructive. If you think a question is stupid, it should be easy to answer. If you don't want to waste the time, ignore it. \$\endgroup\$
    – con-f-use
    Commented Sep 14, 2015 at 11:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.