Understanding the usage of the PICmicro watchdog timer

Thread Starter

ke5nnt

Joined Mar 1, 2009
384
I've never been able to understand using the built-in watchdog timer on PIC micros. I know what they do, but I'm confused on how to properly program them.
I use MPLAB X IDE with microchip's XC8 compiler to program in C language.
I understand that the watchdog timer overflows at a nominal rate of 18ms without using a postscaler, so my questions are...

How do I ensure that during program execution, the WDT gets reset in time every time? Do I need to count clock cycles and put a clear WDT instruction in multiple locations throughout the program?
Also, if I had a routine that called a long delay, such as many seconds long, would the WDT not force a reset during this delay?

Thanks for the input, and let me know if I need to clarify something.
 

Markd77

Joined Sep 7, 2009
2,806
In most programs the WDT is simply disabled so you don't need to worry about it. It's an option in the configuration word.
It's useful sometimes because it can wake the chip from low power sleep mode, so you can check the ADC or something, then go back to sleep. Also it can be used to create fairly random numbers, because it's speed is fairly unpredictable compared to the main clock frequency.
I'd disable it for now and only use it if you find a need for it.
 

Papabravo

Joined Feb 24, 2006
21,226
The way to do a watchdog timer is to put the watchdog reset in a piece of code that executes periodically. This should not be in an interrupt routine. You can however use a timer interrupt to set a reminder flag that you can check in the non-interrupt code in case a part of your process takes longer than you expect. The reason for this is that if you get stuck in an interrupt state and cannot execute your non-interrupt code the WD will expire and reset you.
 

Thread Starter

ke5nnt

Joined Mar 1, 2009
384
Markd77 said:
I'd disable it for now and only use it if you find a need for it.
Mark, I very much appreciate you taking the time to respond and your input. I have, up to this point, turned off the WDT in all of my programs because I've never felt the need to implement it. Now, for the sake of expanding my knowledge, I'm trying to learn how to use it.

Papabravo said:
The way to do a watchdog timer is to put the watchdog reset in a piece of code that executes periodically.
I wonder if you, or anyone else, would be kind enough to provide an example of this. I had seen an example somewhere else of a while(1) loop which started with the clear wdt instruction so that the wdt would be cleared each go around. However, the example didn't explain anything about how to ensure it actually gets cleared often enough that it doesn't just continuously reset the program.
This example also showed the usage of a preprocessor directive, which was
Rich (BB code):
#use delay(clock=1000000, RESTART_WDT)
The example stated that this was so the compiler would include a clear wdt instruction into longer delay instructions automatically. As far as I can tell, the XC8 compiler doesn't have anything like this, at least not that I can find in the compiler manual.
 

JohnInTX

Joined Jun 26, 2012
4,787
To see what your loop time is toggle an unused output line at the top of the loop and watch it on a scope. And, yes, dumb delays are problematic when you use the WDT. One fix as you know is to have clrwdt in the delay loop but as you have seen in C you are at the mercy of the library. Per PapaBravo, a good way to use it is to put it at the top of your main super-loop such that if a routine stalls, the dog times out. Of course, this is problematic when you have lots of long delay loops...

Perhaps a better question to ask is 'How to I write code so that it doesn't need long delay loops?' As you know, when you delay just by counting you lose a lot of the ability to do anything else during the delay. Personally, I create a System Tick, an interrupt-driven timer with a suitable period, 1msec for example. The service routine for this timer runs a list of registers (derived timers) and decrements each non-zero one, stopping at 0. To use them, a routine stuffs a byte into its timer and returns. The main loop calls the routine each time through.. since timing now consists of inspecting the selected register for 0, nobody waits around for anything and the main loop rips around calling all of the various routines that make up the program. Since there is now only execution time (not burning time counting out delays) the top of the loop gets hit often enough to clear the dog. Nice. And its more robust. Since the dog gets cleared only once, the main loop can inspect the system, making sure that nothing has clobbered the system configuration (it happens!). If its happy, it clears the dog. If not, it hangs itself and the PIC resets.

For ease of use, limit the derived timers to one byte. If 255*SysTik isn't enough time, add a prescaler in front of a second set of derived timers. Maybe you wind up with 1ms, 100ms, 1sec periods or whatever you need. Keeping it to one byte means you don't have to worry about getting interrupted while reading/setting multiple bytes. If you have a specific need, you can always custom code something.

The C code to service the timers is simplicity:
Rich (BB code):
void serviceSysTIK(){    

    if(timerA) --timerA;    // A:run to 0 and stop
    if(timerB) --timerB;    // B:run to 0 and stop
    // add as many as you need
}
To set a timer:
Rich (BB code):
 timerA = 10; // single byte, no IRQ worries
Checking the timers is easy too:
Rich (BB code):
    if(timerA==0)        
        timerAis0();    // call the function to do something when the timer runs to 0
There are lots of variations on the theme but hopefully you get the idea. As I said, it means a different coding paradigm than simple turn on-delay-turn off stuff but its the secret to getting lots done without bogging down in delays.

As whether to use the WDT, I always do from the get-go. PIC has no real memory/register protection so an errant write to space can cause real damage. Its easier to design with it active than to add it later, for me at least. Since you are looking for a lead-pipe solution to a lost PIC, you can set the prescaler to something convenient, I run mine a little on the long side. I also inspect the power-up flags that tell why a reset happened. A WDT gets special handling.

As PB indicated, don't clear the WDT in an IRQ routine, the main code can hang and the IRQs will never know it. In general, never clear the WDT while you are waiting on any IRQ, I/O, peripherial etc. Things in the outside world (non main-program flow) can fail and wait forever. If you, for example, clrwdt while looping and waiting for an I/O pin to change, you've defeated the purpose of the WDT.

Have fun.
 
Last edited:

Thread Starter

ke5nnt

Joined Mar 1, 2009
384
My apologies on the delay in responding. I appreciate the longer explanation John, thank you for taking the time. I will give those ideas a try.
 
I use clrwdt in my timing routines instead of a NOP.
See below:

Rich (BB code):
;******************************************
;63 max input
WAITWSECONDS MOVWF TEMP2
 CLRC
 RLF TEMP2,F ;*2
 RLF TEMP2,W ;*4
 GOTO SECS
WAIT1SECOND
 
 MOVLW 4
SECS MOVWF TEMP2
L3
 MOVLW 250   ;250MS LOOP
 MOVWF TEMP1
L2
 MOVLW 250 ;1 MS LOOP
 MOVWF TEMP
L1 CLRWDT
 DECFSZ TEMP,F
 GOTO L1
 DECFSZ TEMP1,F
 GOTO L2
 DECFSZ TEMP2,F
 GOTO L3
 RETLW 0
;************************************
WAIT1MS MOVLW 250
 MOVWF TEMP
W1M CLRWDT
 DECFSZ TEMP,F
 GOTO W1M
 RETLW 0
;***********************************
WAIT250MS MOVLW 250
 MOVWF TEMP2
W2M CALL WAIT1MS
 DECFSZ TEMP2,F
 GOTO W2M
 RETLW 0
;*************************************
 
Top