Proton BASIC Compiler - Another way to use the Watchdog

  • Pic® Basic

  • Another way to use the Watchdog

    All PICmicro® devices have a Watchdog timer which gives the code developer a way to reset the device in the event of unexpected code operation probably due to a High ESD received in a pin or power supply. The WDT must reset the device automatically.

    In this article I will not explain how the WDT runs, but I would like to present another way to use the WDT.

    It is only effective if used properly. Too many “clear Watchdog timer” instructions can potentially allow the device to get stuck in a loop that clears the Watchdog. The Watchdog timer can be enabled in the configuration bits for the device. In the PIC18CXXX family, the Watchdog timer can be disabled in the configuration bits but still be enabled by software. This has a big disadvantage, it can be accidentally disabled. Too many “clear Watchdog timer” instructions in the code reduces a efficiently protection of the code.

    After a device has received a Watchdog timer reset it will start executing code from the reset vector.
    A Watchdog timer reset will not change the state of any general purpose RAM locations, but some of the special function registers will be initialized.

    Do not forget that a project without Watchdog is not homologated to CE standards. Or rather, if the CPU crashes and will not start again immediately your project will not be approved.

    First step:
    Not use the “clear Watchdog timer” instructions in the code generated by the compiler commands.
    e.g. Write at the top of the .bas file:
    Declare Watchdog = OFF

    Second step:
    Write "WDTEN = On ' WDT always enabled" in the Config Fuses.
    Take care, some bootloaders do not accept this configuration mode. The developer must use a short value for the duration of the WDT timer. In the example code I choosed.
    WDTPS = 64 ' 1:64 x 4mS = 256 mS.

    Third step:
    The software designer can place the “clear Watchdog timer” instructions in the critical positions in the code to clear the WDT counter and prevent a WDT reset from occurring.

    A big issue:
    What happen with the large delays?

    Thanks for Steve (chuckieboy in the forum), he used a Delay routine inside the interrupt handler, I suppose not to receive any influence of the interrupts on delays. See the thread HERE.
    Using this idea I have written a new "MyDelay(x)" command running by interrupt replacing the DelayMS X of the compiler.

    Code in the interrupt handler.
            If F_Delay = 1 Then             ' The Delay is started.
                If DelayCounter = 0 Then    ' Check if delay counter reaches 0.
                    F_Delay = 0             ' Delay OFF, clear the delay FLAG.
                EndIf                       ' AS WE ARE USING INTERRUPT WE CANNOT USE DELAYMS SO THIS IS USED FOR Delay
                Dec DelayCounter            ' Decrements the DelayCounter every 1 mS or 4 mS.
    The main MyDelayMS(x) code.
    ' Make a Milisegond Delay:
    $define MyDelayMS(pDelay) '
        DelayCounter = pDelay '
        GoSub MYDELAY_Sub
        F_Delay = 1                 ' Starts the delay. (enabled the interrupt counter module).
        While F_Delay = 1 : Wend    ' Waiting the delay flag cleared by the interrupt timer.
    How to use the Watchdog reset:
    Anticipate a Watchdog will not serve too much if you do not know and how many times when it triggered.
    The minimum resource would light a led when the Watchdog was triggered. This LED should stay on until the user decides to shut it down.
    It would also be possible to count the number of resest caused by the watchdog timer. This will see the bad or good quality of our installation or product. May be, You will not want to know it!

    How to init the Watchdog counter:
    Of course the watchdog counter is saved in the eeprom memory.
        ' At power up for first time the value of the Watchdog counter in the eeprom is $FFFF. It must be equal to 0.
        DataWord = ERead ADD_WDT_COUNTER_Check
        If DataWord <> $A5A5 Then
            DataWord = 0
            EWrite ADD_WDT_COUNTER,[DataWord]
            DataWord = $A5A5
            EWrite ADD_WDT_COUNTER_Check,[DataWord]
    Detect the WDT reset and count:
        WDT_Detected = 0                        ' Clear the WDT flag first.
        If F_TO = 0 Then                        ' Try to read a watchdog reset occured.
            WDT_Detected = 1                    ' A wachtdog reset has occured.
            DataWord = ERead ADD_WDT_COUNTER    ' Read the value of the Watchdog counter saved in the eeprom.
            Inc DataWord                        ' Increment the watchdog counter
            EWrite ADD_WDT_COUNTER,[DataWord]   ' Save the new value in the eeprom (5mS delay to write)
    Set the WDT LED:
        ' Set the WDT LED if the Watchdog reset is detected.
        DataWord = ERead ADD_WDT_COUNTER        ' Read the value of the Watchdog counter saved in the eeprom.
        If DataWord > 0 Then
            WDT_LED = 1                         ' Set the Watchdog LED.
            WDT_LED = 0                         ' Clear the Watchdog LED.    
    Give a notice in the terminal:
        If WDT_Detected = 1 Then
            DataWord = ERead ADD_WDT_COUNTER                    ' Read the value of the Watchdog counter saved in the eeprom.
            HRSOut "WATCHDOG COUNTER: ", Dec DataWord, CR, CR
    The demo codes:
    The "" file.
    As I'm using a few buttons, I have used and modified the "Debounce_8Bits_By_Interrupts" library available in the wiki. The MydelayMS(x) runs every 4 mS in this case.

    The "" file.
    I modified the timing to run the MydelayMS(x) every 1mS.

    If the "$define _TestWatchDogReset_" is enabled at the top of the bas file and compiled, the code can generate some Watchdog resets. Disable this line, compile again and see the results. Use a programmer that does not clear the eeprom memory.

    The Watchdog counter is cleared by the SW7 button pulsed.

    I hope I have given you another view of how you can use the Watchdog reset.

    Download the code from HERE.