Watchdog

16 Feb 2010

Hi, I'm wonder if it's possible to control watchdog on mbed ?

 

Regards

macc

17 Feb 2010

Yes, but you'll have to do it yourself, there are no ready-made classes in mbed library.

17 Feb 2010 . Edited: 17 Feb 2010

It shouldn't be hard. What would make a good natural interface?

Something like:

Watchdog wd;      // create a watchdog
wd.feed(1.0);     // feed the watchdog with a specific timeout
wd.feed();        // re-feed the watchdog with the same timeout

I've not done a review of may watchdog architectures, but I can't believe they can't support something like that.

Simon

17 Feb 2010

A good source of inspiration could be NXP's driver library. For example, here's what they have for the watchdog:

void WDT_Init (uint32_t ClkSrc, uint32_t WDTMode) Initial for Watchdog function Clock source = RTC , PCLK, IRC 
void WDT_Start (uint32_t TimeOut) Start WDT activity with given timeout value.
void WDT_Feed (void) After set WDTEN, call this function to start Watchdog or reload the Watchdog timer.
FlagStatus WDT_ReadTimeOutFlag (void) Read WDT Time out flag.
void WDT_ClrTimeOutFlag (void) Clear WDT Time out flag.
void WDT_UpdateTimeOut (uint32_t TimeOut) Update WDT timeout value and feed.
uint32_t WDT_GetCurrentCount (void) Get the current value of WDT.

P.S. I thought watchdog is supposed to be kicked, not fed? ;)

17 Feb 2010

Wikipedia says:

  • writing a “service pulse”
  • "kicking the dog"
  • “petting the dog”
  • "feed the watchdog"
  • "waking the watchdog"

I do wonder sometimes in these sorts of wikipedia listings whether it is more someone sitting down coming up with as many ideas of what they could imagine calling something, rather than what anyone actually calls it :)

I think I prefer kick, but why kicking a watchdog keeps him quiet I'm not sure.

17 Feb 2010

I think it's like kicking the dog so that it keeps away and doesn't bite you :)

17 Feb 2010 . Edited: 17 Feb 2010

Here is a quick example that does something:

#include "mbed.h"

DigitalOut led(LED1);

class Watchdog {
public:
    void kick(float s) {
        LPC_WDT->WDCLKSEL = 0x1;                // Set CLK src to PCLK
        uint32_t clk = SystemCoreClock / 16;    // WD has a fixed /4 prescaler, PCLK default is /4 
        LPC_WDT->WDTC = s * (float)clk;         
        LPC_WDT->WDMOD = 0x3;                   // Enabled and Reset        
        kick();
    }
    
    void kick() {
        LPC_WDT->WDFEED = 0xAA;
        LPC_WDT->WDFEED = 0x55;
    }
};

Watchdog w;

int main() {
    printf("Hello World!\n");
    w.kick(2.5);

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

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

WatchdogExample

I'm sure it needs lots of refinement, but might be an interesting starting point.

Simon

17 Feb 2010

Hi Igor,

In the stuff from the driver library, what are the units for timeout, PCLK cycles?

17 Feb 2010

Thanks for reply.

Where are the NXP driver library ? When I'm traying to include :

#include "lpc17xx_wdt.h"

or  #include ""LPC1768/LPC17xx_wdt.h"

compiler complain "Cannot open source file ....".

The deeper question is how to use NXP driver library or other resources not beeing included into compiler

 

 

Regards

macc

 

17 Feb 2010

Timeout is milliseconds. The library routine sets up the clock and converts the timeout value as necessary. Here's the code:

/********************************************************************//**
 * @brief         Set WDT time out value and WDT mode
 * @param[in]    clk_source select Clock source for WDT device
 * @param[in]    timeout value of time-out for WDT (us)
 * @return        None
 *********************************************************************/
uint8_t WDT_SetTimeOut (uint8_t clk_source, uint32_t timeout)
{

    uint32_t pclk_wdt = 0;
    uint32_t tempval = 0;

    switch ((WDT_CLK_OPT) clk_source)
    {
    case WDT_CLKSRC_IRC:
        pclk_wdt = 4000000;
        // Calculate TC in WDT
        tempval  = (((pclk_wdt) / WDT_US_INDEX) * (timeout / 4));
        // Check if it valid
        if ((tempval >= WDT_TIMEOUT_MIN) && (tempval <= WDT_TIMEOUT_MAX))
        {
            LPC_WDT->WDTC = tempval;
            return    SUCCESS;
        }

        break;

    case WDT_CLKSRC_PCLK:

        // Get WDT clock with CCLK divider = 4
        pclk_wdt = SystemCoreClock / 4;
        // Calculate TC in WDT
        tempval  = (((pclk_wdt) / WDT_US_INDEX) * (timeout / 4));

        if ((tempval >= WDT_TIMEOUT_MIN) && (tempval <= WDT_TIMEOUT_MAX))
        {
            CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_WDT, CLKPWR_PCLKSEL_CCLK_DIV_4);
            LPC_WDT->WDTC = (uint32_t) tempval;
            return SUCCESS;
        }

        // Get WDT clock with CCLK divider = 2
        pclk_wdt = SystemCoreClock / 2;
        // Calculate TC in WDT
        tempval  = (((pclk_wdt) / WDT_US_INDEX) * (timeout / 4));

        if ((tempval >= WDT_TIMEOUT_MIN) && (tempval <= WDT_TIMEOUT_MAX))
        {
            CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_WDT, CLKPWR_PCLKSEL_CCLK_DIV_2);
            LPC_WDT->WDTC = (uint32_t) tempval;
            return    SUCCESS;
        }

        // Get WDT clock with CCLK divider = 1
        pclk_wdt = SystemCoreClock;
        // Calculate TC in WDT
        tempval  = (((pclk_wdt) / WDT_US_INDEX) * (timeout / 4));

        if ((tempval >= WDT_TIMEOUT_MIN) && (tempval <= WDT_TIMEOUT_MAX))
        {
            CLKPWR_SetPCLKDiv (CLKPWR_PCLKSEL_WDT, CLKPWR_PCLKSEL_CCLK_DIV_1);
            LPC_WDT->WDTC = (uint32_t) tempval;
            return    SUCCESS;
        }
        break ;


    case WDT_CLKSRC_RTC:
        pclk_wdt = 32768;
        // Calculate TC in WDT
        tempval  = (((pclk_wdt) / WDT_US_INDEX) * (timeout / 4));
        // Check if it valid
        if ((tempval >= WDT_TIMEOUT_MIN) && (tempval <= WDT_TIMEOUT_MAX))
        {
            LPC_WDT->WDTC = (uint32_t) tempval;
            return    SUCCESS;
        }

        break;

// Error parameter
        default:
            break;
}

    return ERROR;
}
17 Feb 2010

I made it to compile in the online compiler. Should be importable as library. Get links here: DriverLibrary For documentation see index.chm in the original package.

The code is quite sloppy, I had to fix tons of warnings and found a couple of bugs in the process, but don't assume there are none left.

17 Feb 2010

Wow , I'm ipressed ! Good work.

Thanks for clear and detailed explanation.

 

macc

29 Mar 2010

I wrote a watchdog class inspired by Simon's post that includes Reset and Interrupt operations.

But I can't seem to read the status of the reset to main to determine what happened: Power-on or Watchdog Timeout. Reading LPC_WDT->WDMOD yields 0. Seems that I am reading the wrong register.

Is this the correct register to read?

 

int main() {
 int ResetType = w.status();   // read watchdog to determine why we are here
// bool ResetType = w.status();   // read watchdog to determine why we are here
 

/*===========================================================
        status     Read Watchdog status
       
    This procedure reads the current Watchdog status to
    determine how we were reset.
 ==========================================================*/  

#if 0
    bool Watchdog::status() {            // read Status
         bool foo = (LPC_WDT->WDMOD & (1<<WDTOF)); // to get WDTOF flag
         LPC_WDT->WDMOD &= ~(1<<WDTOF); // reset status for next time
         return(foo);
    }
#endif   
    int Watchdog::status() {            // read Status
         int foo = LPC_WDT->WDMOD; // to get WDTOF flag
         LPC_WDT->WDMOD &= ~(1<<WDTOF); // reset status for next time
         return(foo);
    }

 

 

31 Mar 2010

You appear to be reading the correct register (and I assume WDTOF is set to 2). Carrying on from Simon's example, I have:

#include "mbed.h"

// Simon's Watchdog example

class Watchdog {
public:
    void kick(float s) {
        LPC_WDT->WDCLKSEL = 0x1;                // Set CLK src to PCLK
        uint32_t clk = SystemCoreClock / 16;    // WD has a fixed /4 prescaler, PCLK default is /4 
        LPC_WDT->WDTC = s * (float)clk;         
        LPC_WDT->WDMOD = 0x3;                   // Enabled and Reset        
        kick();
    }
    
    void kick() {
        LPC_WDT->WDFEED = 0xAA;
        LPC_WDT->WDFEED = 0x55;
    }
};

Watchdog wdt;

// Watchdog service routine

void bad_dog(void)
{
    wdt.kick();    
    printf("Dog kicked\n");
}

int main() {
    Ticker          service;
    DigitalOut      heartbeat(LED1);
    unsigned long   wd_flag;
    int             count = 0;
    
    printf("Reset!\n");
    wd_flag = (LPC_WDT->WDMOD >> 2) & 1;
    printf("Watchdog caused reset: %s\n", (wd_flag > 0) ? "True" : "False");    
    wd_flag = (LPC_WDT->WDMOD >> 2) & 1;
    printf("Check watchdog cleared before clear: %s\n", (wd_flag == 0) ? "True" : "False");
    LPC_WDT->WDMOD &= ~(1 << 2);
    wd_flag = (LPC_WDT->WDMOD >> 2) & 1;
    printf("Check watchdog cleared after clear: %s\n", (wd_flag == 0) ? "True" : "False");
    
    wdt.kick(5.0);          // 5 second timeout on watchdog - to make it visible
    
    service.attach(&bad_dog, 2);
    while(1)
    {
        heartbeat = !heartbeat;
        wait(0.5);
        count++;
        if(count > 20)
            service.detach();   // Stop servicing watchdog, to force "bite"
    }
}
On the serial console, after a button push, this give me:

Reset!
Watchdog caused reset: False
Check watchdog cleared before clear: True
Check watchdog cleared after clear: True
Dog kicked
Dog kicked
Dog kicked
Dog kicked
Dog kicked
Reset!
Watchdog caused reset: True
Check watchdog cleared before clear: False
Check watchdog cleared after clear: True
Dog kicked
...

31 Mar 2010

Thanks Jon,

I had created two methods as Reset and Interrupt. The Reset proc was ok, but the Interrupt procedure was not. Need to do a little more study here as I can see the WDTOF flag true at the interrupt entry but this gets cleared when I attempt to pass pass this onward as a Reset method with time as 0.

Thanks for the feedback!

 

20 Dec 2010

I've written a library for the watchdog, adding seconds, milliseconds, and microseconds as the available settings.

I'll update with guide as soon as possible.

To use:

watchdog w(5); 5 seconds, or watchdog_ms w(5000); 5 seconds, as milliseconds same with _us...

in routine (while or something), w.feed(); updates the WDT.

My code is from Simon Ford's example, it's ugly, but it works.

Lerche

07 Mar 2011

What registers are available to pass information to the newly rebooted code.

i.e besides knowing if the 'dog' reset the machine can you pass any other flags.

This would be of help in providing information to the app, it could take into account that a sensor was providing faulty reading for example.

Thank you.

05 Apr 2011

Sorry for the bad formatting of my former answer !

There are 5 registers in the RTC (LPC_RPC->GPREG0 to ...4) intended for this purpose. I tested this with a little change in the example of Simon Ford. I add two functions: getBU returns one RTC backup register setBU write a new value

The main test program increments this BU counter after each restart i = w.getBU(); printf("Hello World! this is nr %i\n",i); w.setBU(i+1); ...and the test was positive !

Robert

#include "mbed.h"
#include "LPC17xx.h"

DigitalOut led1(LED1),led2(LED2);
Serial pc(USBTX, USBRX);


class Watchdog {
// from // http://mbed.org/forum/mbed/topic/508/
public:
    void kick(float s) { //set the watchdog duration = s
        LPC_WDT->WDCLKSEL = 0x1;                // Set CLK src to PCLK
        uint32_t clk = SystemCoreClock / 16;    // WD has a fixed /4 prescaler, PCLK default is /4 
        LPC_WDT->WDTC = s * (float)clk;         
        LPC_WDT->WDMOD = 0x3;                   // Enabled and Reset        
        kick();
    }
    
    void kick() { //reset the watchdog
        LPC_WDT->WDFEED = 0xAA;
        LPC_WDT->WDFEED = 0x55;
    }
    void setBU(char x){
        LPC_RTC->GPREG0 = x;
    }
    char getBU(){
        return LPC_RTC->GPREG0;
    }
};

Watchdog w;

int main() {
    wait(0.2);
    led1=1;
    pc.baud(115200); //i
    int i;
    i = w.getBU();
    printf("Hello World! this is nr %i\n",i);
    w.setBU(i+1);
    w.kick(2.5);

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

        w.kick();
        hang++;
    }
}
06 Apr 2011

This code works great! Thank You...

Is there a way to capture on a reboot that the reboot was triggered by the Watchdog? Like, could w.setBU(1) be set if the watchdog engages and triggers a reboot? Then the bit could be read on the next startup...

Example (on Startup):

if(w.getBU() == 1){pc.printf("Rebooted By Watchdog...\n"); w.setBU(0);}

06 Apr 2011

This is what I have done : Let us use one bit of this register: - when the programs starts , set this bit "on" - when the program stops in a normal way, set this bit "off" . I need a menu to stop the program because I use a electronic switch. The power-on occurs with a push-button. Then the microprocessor starts and a digital out sets the same mosfet to ground, maintaining the power-on status. The "off" menu releases this digital out and the power is off.

Now it is easy: if the program starts with the bit "on"...it is a restart from the watchdog. If the program starts with the bit "off"...it is a normal start.

This was done with a atmega128 but it is not the real answer to your precise question. The LPC 1768 is a powerfull beast: in the user manual look at 3.4.1 Reset Source Identification Register.(RSID) It is at the page 21 of UM10360 (your are lucky...there are 840 pages) The bit WDTR is set when ...a watchdog timeout occurs and this is the answer to your question (I hope ...) This should be the LPC_SC->RSID register. Try to return in the getBU - the backup registers, like my example return LPC_RTC->GPREG0; - the reset source LPC_SC->RSID

The compiler accepts this LPC_SC->RSID but I did not test further.

Robert

06 Apr 2011

I recall that there are status register bits for the cause of reset: power-on, watchdog timeout, etc.

04 Jul 2012

can we or can we not turn off the watchdog in LPC1768??

09 Jul 2012

I believe its OFF by default

09 Jul 2012

If you're unsure of the mode it's set in:

printf("Watchdog mode register: %x\r\n", LPC_WDT->WDMOD);


To turn it off:

LPC_WDT->WDMOD = 0x0;



Lerche

22 Oct 2012

How can I get the above to work for the lpc11u24 ?

Cheers

Ceri

23 Oct 2012

ceri clatworthy wrote:

How can I get the above to work for the lpc11u24 ?

Cheers

Ceri


Here: http://mbed.org/users/Lerche/code/WatchDog/

23 Oct 2012

Thanks for the code,

a few problems ...

feed does not work, I cannot add it as:

feed();
WatchDog.feed();

or

Watchdog WD 


WD.feed()

additionaly, just using:

DigitalIn CtlAltDel(P0_1);
WatchDog (4.0);

while (1)
{
    // Flash LED's for 3.5 seconds ..

    if (!CtlAltDel)
    {
       LED's = ON;
       wait (6);
    }

}

the LPC11U24 does reset, but the DFU/ISP pin is ignored :( and just runs normal code.

As my main reason was to jump to boot-loader with a single button.

I would of expected this to happen ? or am I wrong ?

Cheers

Ceri

23 Oct 2012

Hi Ceri.

I guess that the bootloader on the LPC11U24 is really invoked when hardreset. I really don't know this, try going through the user manual for the chip.

BTW: Try naming the WatchDog like:

WatchDog wdt(4.0);

wdt.feed();


Lerche

24 Oct 2012

Thanks The above works,

but still not able to get LPC11U24 to reset into DFU/ISP Bootloader.

Thanks

Ceri

25 Oct 2012

Hi Ceri.

I'm not sure why you can't go to bootloader after watchdog reset.
I will try setting up on of my boards to test if it goes to bootloader after WDT reset.

Lerche