5 years, 1 month ago.

Watch Dog

I am using the WD on the LPC1114 as follows (in conjunction with Simon Ford's WDT code

*****

Watchdog wdt;

Ticker flipper;

wdt.kick(5.0);

flipper.attach(&wdt_reset, 1.0);

*******

What I noticed is that if the processor hangs up, I do not get a reset within the timeout period - it typically 10 to 20 seconds.

I make extensive use of the wait(x) function throughout the program, but the longest time is 3 seconds.

Question 1: is the WDT the highest priority interrupt and if not, how can I make it the highest? Question 2: In the program, while I service some routines, I disable the interrupts with

disable_irq();

and then re-enable them once the activity is completed. Could this be the cause of my problem?

Note, all the interrupt service routines are very short - I just set a flag and then go and service the routine, so there are no long interrupt service routines whatsoever in the program.

Thanks

1 Answer

5 years, 1 month ago.

Hello Andrew,

  • Watchdog is a free-running downcounter.
  • It's clocked by its own dedicated low-speed clock (LSI) and thus stays active even if the main clock fails.
  • You cannot assign a priority to the watchdog. It runs in a totally independent process outside the main application, but has lower timing accuracy constraints (hence it isn't very accurate). That's why your program activities (calling ISR, waiting, disabling interrupts ...) have no effect on the watchdog.
  • Triggers system reset rather than an interrupt when the downcounter value of 0x000 is reached.

Below is a well commented source code you can experiment with. It's configured to use the fastest possible clock speed in order to get the highest accuracy.

  • Debug mode is turned on.
  • You can fine tune it by changing the adjustment coefficient. Reduce it (make it smaller than one) if the timeout is longer than suppose to be.
  • Setting LPC_WDT->TC to 256 will result in the shortest timeout and setting LPC_WDT->TC to 16777216 will produce the longest one.
  • Since I do not have access to such target board please send me the program printout.
  • You can disable the debug mode by commenting out the line #define DEBUG 1.

#include "mbed.h"

#define DEBUG 1

float adjustment = 1.0f;

DigitalOut  led(LED1);

class Watchdog
{
public:
    /**
 * @brief
 * @note
 * @param
 * @retval
 */
    void kick(float s)
    {
        LPC_SYSCON->SYSAHBCLKCTRL = LPC_SYSCON->SYSAHBCLKCTRL | (1 << 15);  // Enable clock for watch dog 

        // When switching clock sources, both clocks must be running before the clock source is updated!
        LPC_SYSCON->WDTCLKSEL = 0x01;           // Change clock source to from IRC to 'main clock'
        LPC_SYSCON->WDTCLKUEN = 0x01;           // Update clock souce
        LPC_SYSCON->WDTCLKUEN = 0x00;           // For the update to take effect toggle WDTCLKUEN
        LPC_SYSCON->WDTCLKUEN = 0x01;           
        
        // WDT clock divider values:
        // 0: Disable WDCLK.
        // 1: Divide by 1.
        // to
        // 255: Divide by 255.
        LPC_SYSCON->WDTCLKDIV = 0x01;           // Set clock divider to 0x01 (to have fastest clocking).
        
        // Then WDCLK = main clock / clock divider. (See Fig 8. LPC111x/LPC11Cxx CGU block diagram in chapter 3.4 "Clock generation")
        uint32_t  WDCLK = SystemCoreClock / LPC_SYSCON->WDTCLKDIV;
        
#if defined(DEBUG)
        printf("WDCKL = %d\r\n, WDCLK");
#endif        
        
        // The Watchdog consists of a divide by 4 fixed pre-scaler and a 24-bit counter. The clock is
        // fed to the timer via a pre-scaler. The timer decrements when clocked. The minimum value
        // from which the counter decrements is 0xFF. Setting a value lower than 0xFF causes 0xFF
        // to be loaded in the counter. Hence the minimum Watchdog interval is (TWDCLK x 256 x 4)
        // and the maximum Watchdog interval is (TWDCLK x 2^24 x 4) in multiples of (TWDCLK x 4).

        uint32_t  TWDCLK = WDCLK / 4;
        
#if defined(DEBUG)
        printf("TWDCLK = %d\r\n, TWDCLK");
#endif        
        
        // The Watchdog should be used in the following manner:
        // 1. Set the Watchdog timer constant reload value in WDTC register.
        LPC_WDT->TC = s * (float)TWDCLK * adjust; // = time_in_seconds x number_of_ticks_per_second (min 256, max  2^24) 
        
#if defined(DEBUG)
        printf("LPC_WDT->TC = %d\r\n, LPC_WDT->TC");
#endif        

        // 2. Setup the Watchdog timer operating mode in WDMOD register.
        LPC_WDT->MOD = 0x03;    // selects Watchdog reset mode. 
        // When this mode is selected, a watchdog counter underflow will reset the microcontroller.
        // Although the Watchdog interrupt is also enabled in this case (WDEN = 1) it will not be recognized
        // since the watchdog reset will clear the WDINT flag.

        // 3. Enable the Watchdog by writing 0xAA followed by 0x55 to the WDFEED register
        //   (reloads the watchdog timer with the value contained in   LPC_WDT->TC).    
        kick();
    }

    void    kick()  {
        LPC_WDT->FEED = 0xAA; 
        LPC_WDT->FEED = 0x55;
    };
};

Watchdog  watchDog;

int main()
{
    printf("Hello World!\n");
    watchDog.kick(1);

    int hang = 0;
    
    while (1) {
        printf("loop...\n");
        wait(0.1);

        if (hang == 10) {
            while (1);
        }

        hang++;
        watchDog.kick();
    }
}

Thanks Zoltan appreciate your answer and clarification.

The other question I need to get some resolution on is why does it take 10 to 20 seconds for the WDT to reset the system when I have set the WDT timeout to 1-3 seconds. Ideally, I want to set it to about 100 milli-seconds because if the controller hangs up in my application and a catastrophic failure occurs, it needs to shutdown quickly.

Thank you

Andrew

posted by Andrew R 06 Mar 2019
  • Try to select the highest oscillator frequency:

LPC111x User Manual wrote:

3.5.6 Watchdog oscillator control register
This register configures the watchdog oscillator. The oscillator consists of an analog and a digital part. The analog part contains the oscillator function and generates an analog clock (Fclkana). With the digital part, the analog output clock (Fclkana) can be divided to the required output clock frequency wdt_osc_clk. The analog output frequency (Fclkana) can be adjusted with the FREQSEL bits between 600 kHz and 4.6 MHz. With the digital part Fclkana will be divided (divider ratios = 2, 4,...,64) to wdt_osc_clk using the DIVSEL bits.
The output clock frequency of the watchdog oscillator can be calculated as wdt_osc_clk = Fclkana/(2 x (1 + DIVSEL)) = 9.4 kHz to 2.3 MHz (nominal values).
Remark: Any setting of the FREQSEL bits will yield a Fclkana value within +/- 40% of the listed frequency value.

  • To achieve higher accuracy the User Manual suggests to use IRC or system oscillator rather than the analog one:

LPC111x User Manual wrote:

If accurate timing is required, use the IRC or system oscillator.

posted by Zoltan Hudak 07 Mar 2019

Hi Zoltan,

still on this issue unfortunately. I don't really need the WDT reset to be accurate. If the clock is +- 50% accurate that's fine. The problem I have is that the WDT reset is taking place 15-18 seconds after the system has hung-up. I set the time-out to 0.5 seconds and it still takes 15-18 seconds to reset. is it possible to that the processor hangs up but still triggers the WD for another 15 to 18 seconds before fully crashing?

I also disabled the WDT kick (i.e. the WDT is then not being periodically reset) and I have the same problem. The WDT like this is effectively useless.

Any ideas?

posted by Andrew R 12 Mar 2019

Could please give me a link to the watchdog library (there seems to be more versions) you actually imported into your project?

posted by Zoltan Hudak 12 Mar 2019

Zoltan, here is the WDT set up code I am using

/* Main code copied from: http://mbed.org/cookbook/WatchDog-Timer Modified for use with LPC1114 with source code found here: https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/targets/cmsis/TARGET_NXP/TARGET_LPC11XX_11CXX/LPC11xx.h With some inspiration from: https://github.com/Mrjohns42/RSL/blob/master/LPC1114/nRF24L01/wdt.c

  • /

LEDs used to indicate code activity and reset source

DigitalOut led1(dp1);

DigitalOut led2(dp4);

Simon's Watchdog code from http://mbed.org/forum/mbed/topic/508/

class Watchdog {

public:

Load timeout value in watchdog timer and enable

void kick(float s) {

LPC_SYSCON->SYSAHBCLKCTRL = LPC_SYSCON->SYSAHBCLKCTRL|(1<<15);

LPC_SYSCON->WDTCLKSEL = 0x1; Set CLK src to Main Clock

LPC_SYSCON->WDTCLKUEN = 0x01; /* Update clock */

LPC_SYSCON->WDTCLKUEN = 0x00; /* Toggle update register once */

LPC_SYSCON->WDTCLKUEN = 0x01;

LPC_SYSCON->WDTCLKDIV = 0x10; uint32_t clk = SystemCoreClock/16; WD has a fixed /4 prescaler, PCLK default is /4

LPC_WDT->TC = s * (float)clk;

LPC_WDT->MOD = 0x3; Enabled and Reset

kick();

}

"kick" or "feed" the dog - reset the watchdog timer by writing this required bit pattern

void kick() {

LPC_WDT->FEED = 0xAA;

LPC_WDT->FEED = 0x55;

}

};

Here is the code I am using in my program before the main operating loop

Watchdog wdt;

Ticker flipper; use MCU timer to generate WD reset public function

wdt.kick(3.0); WD timeout set to 3 seconds - after which reset MCU

flipper.attach(&wdt_reset, 1.0); kick the WD every 1 seconds

posted by Andrew R 12 Mar 2019

In order not to exceed the max comment limit (3000 char) I have appended some new info to my first answer.

posted by Zoltan Hudak 13 Mar 2019

Thanks Zoltan - I will try that and report back.

regards

Andrew

posted by Andrew R 13 Mar 2019