Understanding the usage of the PICmicro watchdog timer

Discussion in 'Programmer's Corner' started by ke5nnt, Mar 23, 2013.

  1. ke5nnt

    Thread Starter Active Member

    Mar 1, 2009
    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.
  2. Markd77

    Senior Member

    Sep 7, 2009
    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.
    absf likes this.
  3. Papabravo


    Feb 24, 2006
    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.
    ErnieM and absf like this.
  4. ke5nnt

    Thread Starter Active Member

    Mar 1, 2009
    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.

    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
    Code ( (Unknown Language)):
    1. #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.
  5. JohnInTX


    Jun 26, 2012
    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:
    Code ( (Unknown Language)):
    1. void serviceSysTIK(){    
    3.     if(timerA) --timerA;    // A:run to 0 and stop
    4.     if(timerB) --timerB;    // B:run to 0 and stop
    5.     // add as many as you need
    6. }
    To set a timer:
    Code ( (Unknown Language)):
    1.  timerA = 10; // single byte, no IRQ worries
    Checking the timers is easy too:
    Code ( (Unknown Language)):
    1.     if(timerA==0)        
    2.         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: Mar 23, 2013
  6. ke5nnt

    Thread Starter Active Member

    Mar 1, 2009
    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.
  7. nigelwright7557

    AAC Fanatic!

    May 10, 2008
    I use clrwdt in my timing routines instead of a NOP.
    See below:

    Code ( (Unknown Language)):
    2. ;******************************************
    3. ;63 max input
    5.  CLRC
    6.  RLF TEMP2,F ;*2
    7.  RLF TEMP2,W ;*4
    8.  GOTO SECS
    11.  MOVLW 4
    13. L3
    14.  MOVLW 250   ;250MS LOOP
    15.  MOVWF TEMP1
    16. L2
    17.  MOVLW 250 ;1 MS LOOP
    18.  MOVWF TEMP
    19. L1 CLRWDT
    20.  DECFSZ TEMP,F
    21.  GOTO L1
    22.  DECFSZ TEMP1,F
    23.  GOTO L2
    24.  DECFSZ TEMP2,F
    25.  GOTO L3
    26.  RETLW 0
    27. ;************************************
    28. WAIT1MS MOVLW 250
    29.  MOVWF TEMP
    30. W1M CLRWDT
    31.  DECFSZ TEMP,F
    32.  GOTO W1M
    33.  RETLW 0
    34. ;***********************************
    35. WAIT250MS MOVLW 250
    36.  MOVWF TEMP2
    37. W2M CALL WAIT1MS
    38.  DECFSZ TEMP2,F
    39.  GOTO W2M
    40.  RETLW 0
    41. ;*************************************
    ke5nnt likes this.