LPC1768 and LPC11U24 watchdog timer

Dependents:   GSwifi_tsutenkaku barometer-m0 BMAGThrRev

WDT.cpp

Committer:
okini3939
Date:
2016-05-25
Revision:
3:b1efde09d8a7
Parent:
2:f6f05e2eafd0

File content as of revision 3:b1efde09d8a7:

#include "mbed.h"
#include "WDT.h"

FunctionPointer Watchdog::_fptr;

// Simon's Watchdog
// see: http://mbed.org/forum/mbed/topic/508/
void Watchdog::init(float s) {
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
    LPC_WDT->WDCLKSEL = 0x01;               // 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 = 0x03;                   // Enabled and Reset
#elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11UXX)
    LPC_WWDT->CLKSEL = 0x01;               // Set CLK src to WDOSC
    uint32_t clk = 500000 / 64 / 4;    // WD has a fixed /4 prescaler, WDOSC default is /4
    LPC_WWDT->TC = s * (float)clk;
    LPC_WWDT->MOD = 0x03;                   // Enabled and Reset
#elif defined(TARGET_LPC81X) || defined(TARGET_LPC82X)
    LPC_SYSCON->WDTOSCCTRL = (0xA << 5);    // wdt_osc_clk = Fclkana/2, Fclkana = 3.5MHz
    LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 17); // Enable Clock WWDT
    LPC_SYSCON->PDRUNCFG &= ~(1 << 6);      // Enable Power WDTOSC_PD
    uint32_t clk = ((3500000 / 2) / 4);         // COUNT = wdt_osc_clk/4
    LPC_WWDT->TC = s * (float)clk;
    LPC_WWDT->MOD = 0x3;                    // Enabled and Reset
#endif
    kick();
}
// "kick" or "feed" the dog - reset the watchdog timer
// by writing this required bit pattern
void Watchdog::kick() {
    __disable_irq();
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
    LPC_WDT->WDFEED = 0xAA;
    LPC_WDT->WDFEED = 0x55;
#elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11UXX)
    LPC_WWDT->FEED = 0xAA;
    LPC_WWDT->FEED = 0x55;
#elif defined(TARGET_LPC81X) || defined(TARGET_LPC82X)
    LPC_WWDT->FEED = 0xAA;
    LPC_WWDT->FEED = 0x55;
#endif
    __enable_irq();
}

int Watchdog::getFlg () {
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
    return LPC_WDT->WDMOD & (1<<2) ? 1 : 0;
#elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11UXX)
    return LPC_WWDT->MOD & (1<<2) ? 1 : 0;
#elif defined(TARGET_LPC81X) || defined(TARGET_LPC82X)
    return LPC_WWDT->MOD & (1<<2) ? 1 : 0;
#endif
}

void Watchdog::attach (void (*fptr)(void), float s) {
    if (fptr) {
        _fptr.attach(fptr);
    }
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
    LPC_WDT->WDCLKSEL = 0x02;               // Set CLK src to RTC
    uint32_t clk = 32768 / 4;    // WD has a fixed /4 prescaler
    LPC_WDT->WDTC = s * (float)clk;
    LPC_WDT->WDMOD = 0x01;                   // Enabled but Reset disable
#elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11UXX)
    LPC_SYSCON->SYSAHBCLKCTRL |= (1<<15);
    LPC_SYSCON->PDRUNCFG &= ~(1<<6); // WDT on
    LPC_SYSCON->WDTOSCCTRL = (1<<5)|(0x1f<<0); // 500kHz / 64

    LPC_WWDT->CLKSEL = (1<<0);               // Set CLK src to WDOSC
    uint32_t clk = 500000 / 64 / 4;    // WD has a fixed /4 prescaler, WDOSC default is /4
    LPC_WWDT->TC = s * (float)clk;
    LPC_WWDT->WARNINT = 0;
    LPC_WWDT->MOD = 0x01;                   // Enabled but Reset disable
    kick();
    LPC_SYSCON->STARTERP1 |= (1<<12);
#elif defined(TARGET_LPC81X) || defined(TARGET_LPC82X)
    LPC_SYSCON->WDTOSCCTRL = (0xA << 5);    // wdt_osc_clk = Fclkana/2, Fclkana = 3.5MHz
    LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 17); // Enable Clock WWDT
    LPC_SYSCON->PDRUNCFG &= ~(1 << 6);      // Enable Power WDTOSC_PD
    uint32_t clk = ((3500000 / 2) / 4);         // COUNT = wdt_osc_clk/4
    LPC_WWDT->TC = s * (float)clk;
    LPC_WWDT->WARNINT = 0;
    LPC_WWDT->MOD = 0x1;                    // Enabled and Reset
    kick();
    LPC_SYSCON->STARTERP1 |= (1<<12);
#endif
    NVIC_SetVector(WDT_IRQn, (uint32_t)&Watchdog::isr_wdt);
    NVIC_ClearPendingIRQ(WDT_IRQn);
    NVIC_EnableIRQ(WDT_IRQn);
}

template<typename T>
void Watchdog::attach (T *object, void (*fptr)(void), float s) {
    if (fptr) {
        _fptr.attach(object, fptr);
    }
    attach(NULL, s);
}

void Watchdog::isr_wdt(void) {
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
    LPC_WDT->WDMOD |= (1<<3);
    LPC_WDT->WDMOD &= ~(1<<2);
#elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11UXX)
    LPC_WWDT->MOD |= (1<<3);
    LPC_WWDT->MOD &= ~(1<<2);
#elif defined(TARGET_LPC81X) || defined(TARGET_LPC82X)
    LPC_WWDT->MOD |= (1<<3);
    LPC_WWDT->MOD &= ~(1<<2);
#endif
    _fptr.call();
}

void Watchdog::sleep () {
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
    LPC_SC->PCON = 0;
#elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11UXX)
    LPC_PMU->PCON = 0;
#elif defined(TARGET_LPC81X) || defined(TARGET_LPC82X)
    LPC_PMU->PCON = 0;
#endif
    SCB->SCR &= ~(1<<2);
    __WFI();
}

void Watchdog::deepSleep () {
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
    LPC_SC->PCON &= ~(7<<0);
    LPC_SC->PCON |= (1<<0);
#elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11UXX)
    LPC_SYSCON->PDSLEEPCFG &= ~(1<<6); // WDT on
    LPC_SYSCON->PDAWAKECFG = LPC_SYSCON->PDRUNCFG;
    LPC_PMU->PCON &= ~(7<<0);
    LPC_PMU->PCON |= (1<<0);
#elif defined(TARGET_LPC81X) || defined(TARGET_LPC82X)
    LPC_SYSCON->PDSLEEPCFG &= ~(1<<6); // WDT on
    LPC_SYSCON->PDAWAKECFG = LPC_SYSCON->PDRUNCFG;
    LPC_PMU->PCON &= ~(7<<0);
    LPC_PMU->PCON |= (1<<0);
#endif
    SCB->SCR |= (1<<2);
    __WFI();
}

void Watchdog::powerDown () {
#if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
    LPC_SC->PCON &= ~(7<<0);
    LPC_SC->PCON |= (2<<0);
#elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11UXX)
    LPC_SYSCON->PDSLEEPCFG &= ~(1<<6); // WDT on
    LPC_SYSCON->PDAWAKECFG = LPC_SYSCON->PDRUNCFG;
    LPC_PMU->PCON &= ~(7<<0);
    LPC_PMU->PCON = (2<<0);
#elif defined(TARGET_LPC81X) || defined(TARGET_LPC82X)
    LPC_SYSCON->PDSLEEPCFG &= ~(1<<6); // WDT on
    LPC_SYSCON->PDAWAKECFG = LPC_SYSCON->PDRUNCFG;
    LPC_PMU->PCON &= ~(7<<0);
    LPC_PMU->PCON = (2<<0);
#endif
    SCB->SCR |= (1<<2);
    __WFI();
}