From 682d181213dfa42109df5a2d9926292a6e23d561 Mon Sep 17 00:00:00 2001 From: Nathael Pajani Date: Sat, 1 May 2021 21:34:03 +0200 Subject: [PATCH] Watchdog support fixed and tested. To be completed though. --- core/watchdog.c | 88 +++++++++++++++++++++++++++++++---------- include/core/watchdog.h | 41 +++++++++++++------ 2 files changed, 98 insertions(+), 31 deletions(-) diff --git a/core/watchdog.c b/core/watchdog.c index 96445d8..ae3870c 100644 --- a/core/watchdog.c +++ b/core/watchdog.c @@ -40,8 +40,45 @@ void watchdog_feed(void) lpc_enable_irq(); } -static void (*wdt_callback)(void) = NULL; +/* Return 0 if flag is not set, or LPC_WDT_TIMEOUT_FLAG if flag is set. + * This function does not clear the flag + */ +uint32_t watchdog_check_timeout_flag(void) +{ + struct lpc_watchdog* wdt = LPC_WDT; + return (wdt->mode & LPC_WDT_TIMEOUT_FLAG); +} + +/* Clear the timeout flag. + * No checks performed, clear even if flag is not set + */ +void watchdog_clear_timeout_flag(void) +{ + struct lpc_watchdog* wdt = LPC_WDT; + wdt->mode |= LPC_WDT_TIMEOUT_FLAG; +} + +/* Return current watchdog timer value */ +uint32_t watchdog_get_timer_val(void) +{ + struct lpc_watchdog* wdt = LPC_WDT; + return wdt->timer_value; +} + +/* Change the watchdog timer value, if not protected */ +void watchdog_set_timer_val(uint32_t nb_clk) +{ + struct lpc_watchdog* wdt = LPC_WDT; + + if (!(wdt->mode & LPC_WDT_TIMER_VAL_PROTECT)) { + wdt->timer_const = ((nb_clk >> 2) & LPC_WDT_TIMER_MAX); + } +} + + +/***************************************************************************** */ +static void (*wdt_callback)(void) = NULL; /* With no callback, the watchdog interupt may be used to wake up by generating an interrupt */ void WDT_Handler(void) @@ -54,6 +91,7 @@ void WDT_Handler(void) } } +/***************************************************************************** */ /* Lock the watchdog clock source power. * Once locked, writes to the current watchdog clock power bits in powerdown_*_cfg will @@ -79,16 +117,6 @@ void watchdog_lock_timer_val(void) wdt->mode |= LPC_WDT_TIMER_VAL_PROTECT; } -/* Change the watchdog timer value, if not protected */ -void watchdog_set_timer_val(uint32_t nb_clk) -{ - struct lpc_watchdog* wdt = LPC_WDT; - - if (!(wdt->mode & LPC_WDT_TIMER_VAL_PROTECT)) { - wdt->timer_const = ((nb_clk >> 2) & LPC_WDT_TIMER_MAX); - } -} - /* Lock the watchdog and all related features. * Calls all the other watchdog_lock_* functions (clk_src, clk_src_power, timer_val, enable). */ @@ -98,12 +126,13 @@ void watchdog_lock_full(void) watchdog_lock_clk_src_power(); } + + +/***************************************************************************** */ + /* * Configure the watchdog. - * clk_sel is either 0 (IRC) or 1 (WDTCLK). The corresponding clock source will be powered on. - * Note : only WDTCLK is running in deep power down mode - * Note : protecting the clock source power will prevent turning off the IRC for power saving - * if it is selected as main clock source. + * The clock to the Watchdog timer is set to 1MHz */ void watchdog_config(const struct wdt_config* wd_conf) { @@ -111,26 +140,34 @@ void watchdog_config(const struct wdt_config* wd_conf) struct lpc_watchdog* wdt = LPC_WDT; NVIC_DisableIRQ(WDT_IRQ); + /* Power wadchdog block before changing it's configuration */ subsystem_power(LPC_SYS_AHB_CLK_CTRL_Watchdog, 1); + /* Configure the watchdog clock source frequency */ + sys_config->WDT_osc_ctrl = LPC_WDT_CLK_DIVIDER(4) | LPC_WDT_FREQSEL_4MHz; /* 1MHz */ + /* Power ON Watchdog clock */ + sys_config->powerdown_run_cfg &= ~(LPC_POWER_DOWN_WDT_OSC); + /* Configure watchdog timeout for normal operation */ wdt->timer_const = ((wd_conf->nb_clk >> 2) & LPC_WDT_TIMER_MAX); + /* If intr_mode_only is set, a watchdog timeout will trigger an interrupt instead of a reset */ if (wd_conf->intr_mode_only == 1) { wdt->mode = LPC_WDT_EN; } else { wdt->mode = LPC_WDT_EN | LPC_WDT_RESET_ON_TIMEOUT; } + /* Register the callback for the interrupt */ wdt_callback = wd_conf->callback; - /* Power ON Watchdog clock */ - sys_config->powerdown_run_cfg &= ~(LPC_POWER_DOWN_WDT_OSC); + /* Use the windows functionnality ? */ if (wd_conf->wdt_window > 0x100) { wdt->window_compare = (wd_conf->wdt_window & LPC_WDT_TIMER_MAX); } else { wdt->window_compare = LPC_WDT_TIMER_MAX; } + /* Warning interrupt ? */ if (wd_conf->wdt_warn != 0) { if (wd_conf->wdt_warn > LPC_WDT_WARNINT_MAXVAL) { @@ -139,7 +176,18 @@ void watchdog_config(const struct wdt_config* wd_conf) wdt->warning_int_compare = wd_conf->wdt_warn; } } + + /* Feed sequence to validate the configuration */ + watchdog_feed(); + + /* FIXME : Always enable the interupt ? */ + NVIC_EnableIRQ(WDT_IRQ); + + /* Wait for watchdog to start before locking (if requested) */ + do { } while (wdt->timer_value == 0x0000ff); + /* Protect any of the watchdog functions now ? */ + /* FIXME : not working - not tested */ if (wd_conf->locks != 0) { uint32_t mode = wdt->mode; if (wd_conf->locks & WDT_CLK_POWER_LOCK) { @@ -148,11 +196,11 @@ void watchdog_config(const struct wdt_config* wd_conf) if (wd_conf->locks & WDT_TIMER_VAL_LOCK) { mode |= LPC_WDT_TIMER_VAL_PROTECT; } + /* Wait at least 6 Watchdog clocks before locking */ + /* FIXME : sleep set to an arbitrary value */ + usleep(100); wdt->mode = mode; } - /* Feed sequence to validate the configuration */ - watchdog_feed(); - NVIC_EnableIRQ(WDT_IRQ); } diff --git a/include/core/watchdog.h b/include/core/watchdog.h index 6f54169..8cbf288 100644 --- a/include/core/watchdog.h +++ b/include/core/watchdog.h @@ -33,15 +33,19 @@ #include "core/lpc_regs.h" + #define WDT_CLK_POWER_LOCK (0x01 << 0) -#define WDT_EN_LOCK (0x01 << 1) +#define WDT_EN_LOCK (0x01 << 1) /* Unused for LPC82x */ #define WDT_TIMER_VAL_LOCK (0x01 << 2) + +/* NOTE : The clock to the Watchdog timer is set to 1MHz */ + struct wdt_config { uint8_t clk_sel; /* Unused, only here for API compatibility */ uint8_t intr_mode_only; /* If set to 1, a watchdog timeout will trigger an interrupt instead of a reset */ void (*callback)(void); - uint32_t locks; /* Bitfield from WDT_*_LOCK defined in watchdog.h */ + uint32_t locks; /* Bitfield from WDT_*_LOCK defined above this struct */ /* Number of clk_src clocks before the watchdog timer times out. Will be divided by 4 to give * the watchdog reload value */ uint32_t nb_clk; /* 0x3FF to 0x03FFFFFF */ @@ -50,10 +54,31 @@ struct wdt_config { uint16_t wdt_warn; /* 0x00 to 0x3FF */ }; + + /***************************************************************************** */ void watchdog_feed(void); +/***************************************************************************** */ +/* Return 0 if flag is not set, or LPC_WDT_TIMEOUT_FLAG if flag is set. + * This function does not clear the flag + */ +uint32_t watchdog_check_timeout_flag(void); + +/* Clear the timeout flag. + * No checks performed, clear even if flag is not set + */ +void watchdog_clear_timeout_flag(void); + +/* Return current watchdog timer value */ +uint32_t watchdog_get_timer_val(void); + +/* Change the watchdog timer value, if not protected */ +void watchdog_set_timer_val(uint32_t nb_clk); + + +/***************************************************************************** */ /* Lock the watchdog clock source power. * Once locked, writes to the current watchdog clock power bits in powerdown_*_cfg will * have no effect. @@ -65,24 +90,19 @@ void watchdog_lock_clk_src_power(void); /* Lock the watchdog timer value */ void watchdog_lock_timer_val(void); -/* Change the watchdog timer value, if not protected */ -void watchdog_set_timer_val(uint32_t nb_clk); - /* Lock the watchdog and all related features. * Calls all the other watchdog_lock_* functions (clk_src, clk_src_power, timer_val, enable). */ void watchdog_lock_full(void); + +/***************************************************************************** */ /* * Configure the watchdog. - * clk_sel is either 0 (IRC) or 1 (WDTCLK). The corresponding clock source will be powered on. - * Note : only WDTCLK is running in deep power down mode - * Note : protecting the clock source power will prevent turning off the IRC for power saving - * if it is selected as main clock source. + * The clock to the Watchdog timer is set to 1MHz */ void watchdog_config(const struct wdt_config* wd_conf); - /* * Stop the watchdog * This function can be used during system operation to stop the watchdog if it has not @@ -95,7 +115,6 @@ void watchdog_config(const struct wdt_config* wd_conf); */ int stop_watchdog(void); - /* * Disable the watchdog * This function can be used upon system startup to disable watchdog operation -- 2.43.0