mirror of https://github.com/ARMmbed/mbed-os.git
[Nuvoton] Support watchdog timer
parent
6e514b6e08
commit
84440531f1
|
@ -0,0 +1,205 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017-2018 Nuvoton
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "watchdog_api.h"
|
||||
|
||||
#if DEVICE_WATCHDOG
|
||||
|
||||
#include "cmsis.h"
|
||||
|
||||
/* Micro seconds per second */
|
||||
#define NU_US_PER_SEC 1000000
|
||||
|
||||
/* Watchdog clock per second */
|
||||
#define NU_WDTCLK_PER_SEC (__LIRC)
|
||||
|
||||
/* Convert watchdog clock to nearest ms */
|
||||
#define NU_WDTCLK2MS(WDTCLK) (((WDTCLK) * 1000 + ((NU_WDTCLK_PER_SEC) / 2)) / (NU_WDTCLK_PER_SEC))
|
||||
|
||||
/* Convert ms to nearest watchdog clock */
|
||||
#define NU_MS2WDTCLK(MS) (((MS) * (NU_WDTCLK_PER_SEC) + 500) / 1000)
|
||||
|
||||
/* List of hardware-supported watchdog timeout in clocks */
|
||||
#define NU_WDT_16CLK 16
|
||||
#define NU_WDT_64CLK 64
|
||||
#define NU_WDT_256CLK 256
|
||||
#define NU_WDT_1024CLK 1024
|
||||
#define NU_WDT_4096CLK 4096
|
||||
#define NU_WDT_16384CLK 16384
|
||||
#define NU_WDT_65536CLK 65536
|
||||
#define NU_WDT_262144CLK 262144
|
||||
|
||||
/* Watchdog reset delay */
|
||||
#define NU_WDT_RESET_DELAY_RSTDSEL WDT_RESET_DELAY_3CLK
|
||||
|
||||
/* Support watchdog timeout values beyond H/W
|
||||
*
|
||||
* Watchdog Timer H/W just supports timeout values of 2^4, 2^6, ..., 2^18 clocks.
|
||||
* To extend the support range to 1 and UINT32_MAX, we cascade multiple small timeouts to
|
||||
* reach one large timeout specified in hal_watchdog_init.
|
||||
*/
|
||||
|
||||
/* Track if WDT H/W has been initialized */
|
||||
static bool wdt_hw_inited = 0;
|
||||
/* Hold initially-configured timeout in hal_watchdog_init */
|
||||
static uint32_t wdt_timeout_reload_ms = 0;
|
||||
/* Track remaining timeout for cascading */
|
||||
static uint32_t wdt_timeout_rmn_clk = 0;
|
||||
|
||||
static void watchdog_setup_cascade_timeout(void);
|
||||
static void WDT_IRQHandler(void);
|
||||
|
||||
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||
{
|
||||
/* Check validity of arguments */
|
||||
if (! config || ! config->timeout_ms) {
|
||||
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
wdt_timeout_reload_ms = config->timeout_ms;
|
||||
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||
|
||||
if (! wdt_hw_inited) {
|
||||
wdt_hw_inited = 1;
|
||||
|
||||
/* Enable IP module clock */
|
||||
CLK_EnableModuleClock(WDT_MODULE);
|
||||
|
||||
/* Select IP clock source */
|
||||
CLK_SetModuleClock(WDT_MODULE, CLK_CLKSEL1_WDTSEL_LIRC, 0);
|
||||
|
||||
/* Set up IP interrupt */
|
||||
NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler);
|
||||
NVIC_EnableIRQ(WDT_IRQn);
|
||||
}
|
||||
|
||||
watchdog_setup_cascade_timeout();
|
||||
|
||||
return WATCHDOG_STATUS_OK;
|
||||
}
|
||||
|
||||
void hal_watchdog_kick(void)
|
||||
{
|
||||
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||
watchdog_setup_cascade_timeout();
|
||||
}
|
||||
|
||||
watchdog_status_t hal_watchdog_stop(void)
|
||||
{
|
||||
SYS_UnlockReg();
|
||||
|
||||
/* Clear all flags & Disable interrupt & Disable WDT */
|
||||
WDT->CTL = (WDT->CTL & ~(WDT_CTL_WDTEN_Msk | WDT_CTL_INTEN_Msk)) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||
|
||||
SYS_LockReg();
|
||||
|
||||
return WATCHDOG_STATUS_OK;
|
||||
}
|
||||
|
||||
uint32_t hal_watchdog_get_reload_value(void)
|
||||
{
|
||||
return wdt_timeout_reload_ms;
|
||||
}
|
||||
|
||||
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||
{
|
||||
watchdog_features_t wdt_feat;
|
||||
|
||||
/* We can support timeout values between 1 and UINT32_MAX by cascading. */
|
||||
wdt_feat.max_timeout = UINT32_MAX;
|
||||
/* Support re-configuring watchdog timer */
|
||||
wdt_feat.update_config = 1;
|
||||
/* Support stopping watchdog timer */
|
||||
wdt_feat.disable_watchdog = 1;
|
||||
|
||||
return wdt_feat;
|
||||
}
|
||||
|
||||
static void watchdog_setup_cascade_timeout(void)
|
||||
{
|
||||
uint32_t wdt_timeout_clk_toutsel;
|
||||
|
||||
if (wdt_timeout_rmn_clk >= NU_WDT_262144CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_262144CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW18;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_65536CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_65536CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW16;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_16384CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_16384CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW14;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_4096CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_4096CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW12;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_1024CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_1024CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW10;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_256CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_256CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW8;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_64CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_64CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW6;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_16CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_16CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||
} else if (wdt_timeout_rmn_clk) {
|
||||
wdt_timeout_rmn_clk = 0;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||
} else {
|
||||
/* WDT has timed-out and will restart system soon. We just disable interrupt to escape
|
||||
* getting stuck in WDT ISR. */
|
||||
SYS_UnlockReg();
|
||||
|
||||
/* Clear all flags & Disable interrupt */
|
||||
WDT->CTL = (WDT->CTL & ~WDT_CTL_INTEN_Msk) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||
|
||||
SYS_LockReg();
|
||||
return;
|
||||
}
|
||||
|
||||
SYS_UnlockReg();
|
||||
|
||||
/* Configure reset delay on timeout */
|
||||
WDT->ALTCTL = NU_WDT_RESET_DELAY_RSTDSEL;
|
||||
|
||||
/* Configure another piece of cascaded WDT timeout */
|
||||
WDT->CTL = wdt_timeout_clk_toutsel | // Timeout interval
|
||||
WDT_CTL_WDTEN_Msk | // Enable watchdog timer
|
||||
WDT_CTL_INTEN_Msk | // Enable interrupt
|
||||
WDT_CTL_WKF_Msk | // Clear wake-up flag
|
||||
WDT_CTL_WKEN_Msk | // Enable wake-up on timeout
|
||||
WDT_CTL_IF_Msk | // Clear interrupt flag
|
||||
WDT_CTL_RSTF_Msk | // Clear reset flag
|
||||
(wdt_timeout_rmn_clk ? 0 : WDT_CTL_RSTEN_Msk) | // Enable reset on last cascaded timeout
|
||||
WDT_CTL_RSTCNT_Msk; // Reset watchdog timer
|
||||
|
||||
SYS_LockReg();
|
||||
}
|
||||
|
||||
void WDT_IRQHandler(void)
|
||||
{
|
||||
/* Check WDT interrupt flag */
|
||||
if (WDT_GET_TIMEOUT_INT_FLAG()) {
|
||||
/* Continue another piece of cascaded WDT timeout */
|
||||
watchdog_setup_cascade_timeout();
|
||||
} else {
|
||||
/* Clear all flags */
|
||||
WDT->CTL |= (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,205 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017-2018 Nuvoton
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "watchdog_api.h"
|
||||
|
||||
#if DEVICE_WATCHDOG
|
||||
|
||||
#include "cmsis.h"
|
||||
|
||||
/* Micro seconds per second */
|
||||
#define NU_US_PER_SEC 1000000
|
||||
|
||||
/* Watchdog clock per second */
|
||||
#define NU_WDTCLK_PER_SEC (__LIRC)
|
||||
|
||||
/* Convert watchdog clock to nearest ms */
|
||||
#define NU_WDTCLK2MS(WDTCLK) (((WDTCLK) * 1000 + ((NU_WDTCLK_PER_SEC) / 2)) / (NU_WDTCLK_PER_SEC))
|
||||
|
||||
/* Convert ms to nearest watchdog clock */
|
||||
#define NU_MS2WDTCLK(MS) (((MS) * (NU_WDTCLK_PER_SEC) + 500) / 1000)
|
||||
|
||||
/* List of hardware-supported watchdog timeout in clocks */
|
||||
#define NU_WDT_16CLK 16
|
||||
#define NU_WDT_64CLK 64
|
||||
#define NU_WDT_256CLK 256
|
||||
#define NU_WDT_1024CLK 1024
|
||||
#define NU_WDT_4096CLK 4096
|
||||
#define NU_WDT_16384CLK 16384
|
||||
#define NU_WDT_65536CLK 65536
|
||||
#define NU_WDT_262144CLK 262144
|
||||
|
||||
/* Watchdog reset delay */
|
||||
#define NU_WDT_RESET_DELAY_RSTDSEL WDT_RESET_DELAY_3CLK
|
||||
|
||||
/* Support watchdog timeout values beyond H/W
|
||||
*
|
||||
* Watchdog Timer H/W just supports timeout values of 2^4, 2^6, ..., 2^18 clocks.
|
||||
* To extend the support range to 1 and UINT32_MAX, we cascade multiple small timeouts to
|
||||
* reach one large timeout specified in hal_watchdog_init.
|
||||
*/
|
||||
|
||||
/* Track if WDT H/W has been initialized */
|
||||
static bool wdt_hw_inited = 0;
|
||||
/* Hold initially-configured timeout in hal_watchdog_init */
|
||||
static uint32_t wdt_timeout_reload_ms = 0;
|
||||
/* Track remaining timeout for cascading */
|
||||
static uint32_t wdt_timeout_rmn_clk = 0;
|
||||
|
||||
static void watchdog_setup_cascade_timeout(void);
|
||||
static void WDT_IRQHandler(void);
|
||||
|
||||
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||
{
|
||||
/* Check validity of arguments */
|
||||
if (! config || ! config->timeout_ms) {
|
||||
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
wdt_timeout_reload_ms = config->timeout_ms;
|
||||
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||
|
||||
if (! wdt_hw_inited) {
|
||||
wdt_hw_inited = 1;
|
||||
|
||||
/* Enable IP module clock */
|
||||
CLK_EnableModuleClock(WDT_MODULE);
|
||||
|
||||
/* Select IP clock source */
|
||||
CLK_SetModuleClock(WDT_MODULE, CLK_CLKSEL1_WDTSEL_LIRC, 0);
|
||||
|
||||
/* Set up IP interrupt */
|
||||
NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler);
|
||||
NVIC_EnableIRQ(WDT_IRQn);
|
||||
}
|
||||
|
||||
watchdog_setup_cascade_timeout();
|
||||
|
||||
return WATCHDOG_STATUS_OK;
|
||||
}
|
||||
|
||||
void hal_watchdog_kick(void)
|
||||
{
|
||||
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||
watchdog_setup_cascade_timeout();
|
||||
}
|
||||
|
||||
watchdog_status_t hal_watchdog_stop(void)
|
||||
{
|
||||
SYS_UnlockReg();
|
||||
|
||||
/* Clear all flags & Disable interrupt & Disable WDT */
|
||||
WDT->CTL = (WDT->CTL & ~(WDT_CTL_WDTEN_Msk | WDT_CTL_INTEN_Msk)) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||
|
||||
SYS_LockReg();
|
||||
|
||||
return WATCHDOG_STATUS_OK;
|
||||
}
|
||||
|
||||
uint32_t hal_watchdog_get_reload_value(void)
|
||||
{
|
||||
return wdt_timeout_reload_ms;
|
||||
}
|
||||
|
||||
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||
{
|
||||
watchdog_features_t wdt_feat;
|
||||
|
||||
/* We can support timeout values between 1 and UINT32_MAX by cascading. */
|
||||
wdt_feat.max_timeout = UINT32_MAX;
|
||||
/* Support re-configuring watchdog timer */
|
||||
wdt_feat.update_config = 1;
|
||||
/* Support stopping watchdog timer */
|
||||
wdt_feat.disable_watchdog = 1;
|
||||
|
||||
return wdt_feat;
|
||||
}
|
||||
|
||||
static void watchdog_setup_cascade_timeout(void)
|
||||
{
|
||||
uint32_t wdt_timeout_clk_toutsel;
|
||||
|
||||
if (wdt_timeout_rmn_clk >= NU_WDT_262144CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_262144CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW18;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_65536CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_65536CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW16;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_16384CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_16384CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW14;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_4096CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_4096CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW12;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_1024CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_1024CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW10;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_256CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_256CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW8;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_64CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_64CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW6;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_16CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_16CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||
} else if (wdt_timeout_rmn_clk) {
|
||||
wdt_timeout_rmn_clk = 0;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||
} else {
|
||||
/* WDT has timed-out and will restart system soon. We just disable interrupt to escape
|
||||
* getting stuck in WDT ISR. */
|
||||
SYS_UnlockReg();
|
||||
|
||||
/* Clear all flags & Disable interrupt */
|
||||
WDT->CTL = (WDT->CTL & ~WDT_CTL_INTEN_Msk) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||
|
||||
SYS_LockReg();
|
||||
return;
|
||||
}
|
||||
|
||||
SYS_UnlockReg();
|
||||
|
||||
/* Configure reset delay on timeout */
|
||||
WDT->ALTCTL = NU_WDT_RESET_DELAY_RSTDSEL;
|
||||
|
||||
/* Configure another piece of cascaded WDT timeout */
|
||||
WDT->CTL = wdt_timeout_clk_toutsel | // Timeout interval
|
||||
WDT_CTL_WDTEN_Msk | // Enable watchdog timer
|
||||
WDT_CTL_INTEN_Msk | // Enable interrupt
|
||||
WDT_CTL_WKF_Msk | // Clear wake-up flag
|
||||
WDT_CTL_WKEN_Msk | // Enable wake-up on timeout
|
||||
WDT_CTL_IF_Msk | // Clear interrupt flag
|
||||
WDT_CTL_RSTF_Msk | // Clear reset flag
|
||||
(wdt_timeout_rmn_clk ? 0 : WDT_CTL_RSTEN_Msk) | // Enable reset on last cascaded timeout
|
||||
WDT_CTL_RSTCNT_Msk; // Reset watchdog timer
|
||||
|
||||
SYS_LockReg();
|
||||
}
|
||||
|
||||
void WDT_IRQHandler(void)
|
||||
{
|
||||
/* Check WDT interrupt flag */
|
||||
if (WDT_GET_TIMEOUT_INT_FLAG()) {
|
||||
/* Continue another piece of cascaded WDT timeout */
|
||||
watchdog_setup_cascade_timeout();
|
||||
} else {
|
||||
/* Clear all flags */
|
||||
WDT->CTL |= (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,211 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017-2018 Nuvoton
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "watchdog_api.h"
|
||||
|
||||
#if DEVICE_WATCHDOG
|
||||
|
||||
#include "cmsis.h"
|
||||
|
||||
/* Micro seconds per second */
|
||||
#define NU_US_PER_SEC 1000000
|
||||
|
||||
/* Watchdog clock per second */
|
||||
#define NU_WDTCLK_PER_SEC (__LIRC)
|
||||
|
||||
/* Convert watchdog clock to nearest ms */
|
||||
#define NU_WDTCLK2MS(WDTCLK) (((WDTCLK) * 1000 + ((NU_WDTCLK_PER_SEC) / 2)) / (NU_WDTCLK_PER_SEC))
|
||||
|
||||
/* Convert ms to nearest watchdog clock */
|
||||
#define NU_MS2WDTCLK(MS) (((MS) * (NU_WDTCLK_PER_SEC) + 500) / 1000)
|
||||
|
||||
/* List of hardware-supported watchdog timeout in clocks */
|
||||
#define NU_WDT_16CLK 16
|
||||
#define NU_WDT_64CLK 64
|
||||
#define NU_WDT_256CLK 256
|
||||
#define NU_WDT_1024CLK 1024
|
||||
#define NU_WDT_4096CLK 4096
|
||||
#define NU_WDT_16384CLK 16384
|
||||
#define NU_WDT_65536CLK 65536
|
||||
#define NU_WDT_262144CLK 262144
|
||||
|
||||
/* Watchdog reset delay */
|
||||
#define NU_WDT_RESET_DELAY_RSTDSEL WDT_RESET_DELAY_3CLK
|
||||
|
||||
/* Support watchdog timeout values beyond H/W
|
||||
*
|
||||
* Watchdog Timer H/W just supports timeout values of 2^4, 2^6, ..., 2^18 clocks.
|
||||
* To extend the support range to 1 and UINT32_MAX, we cascade multiple small timeouts to
|
||||
* reach one large timeout specified in hal_watchdog_init.
|
||||
*/
|
||||
|
||||
/* Track if WDT H/W has been initialized */
|
||||
static bool wdt_hw_inited = 0;
|
||||
/* Hold initially-configured timeout in hal_watchdog_init */
|
||||
static uint32_t wdt_timeout_reload_ms = 0;
|
||||
/* Track remaining timeout for cascading */
|
||||
static uint32_t wdt_timeout_rmn_clk = 0;
|
||||
|
||||
static void watchdog_setup_cascade_timeout(void);
|
||||
/* NOTE: Don't add static modifier here. These IRQ handler symbols are for linking.
|
||||
Vector table relocation is not actually supported for low-resource target. */
|
||||
void WDT_IRQHandler(void);
|
||||
|
||||
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||
{
|
||||
/* Check validity of arguments */
|
||||
if (! config || ! config->timeout_ms) {
|
||||
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
wdt_timeout_reload_ms = config->timeout_ms;
|
||||
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||
|
||||
if (! wdt_hw_inited) {
|
||||
wdt_hw_inited = 1;
|
||||
|
||||
/* Enable IP module clock */
|
||||
CLK_EnableModuleClock(WDT_MODULE);
|
||||
|
||||
/* Select IP clock source */
|
||||
CLK_SetModuleClock(WDT_MODULE, 0, 0);
|
||||
|
||||
/* Set up IP interrupt */
|
||||
NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler);
|
||||
NVIC_EnableIRQ(WDT_IRQn);
|
||||
}
|
||||
|
||||
watchdog_setup_cascade_timeout();
|
||||
|
||||
return WATCHDOG_STATUS_OK;
|
||||
}
|
||||
|
||||
void hal_watchdog_kick(void)
|
||||
{
|
||||
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||
watchdog_setup_cascade_timeout();
|
||||
}
|
||||
|
||||
watchdog_status_t hal_watchdog_stop(void)
|
||||
{
|
||||
SYS_UnlockReg();
|
||||
|
||||
/* Clear all flags */
|
||||
WDT->ISR = WDT_ISR_IS_Msk | WDT_ISR_RST_IS_Msk | WDT_ISR_WAKE_IS_Msk;
|
||||
/* Disable interrupt */
|
||||
WDT->IER &= ~WDT_IER_IE_Msk;
|
||||
/* Disable WDT */
|
||||
WDT->CTL &= ~WDT_CTL_WTE_Msk;
|
||||
|
||||
SYS_LockReg();
|
||||
|
||||
return WATCHDOG_STATUS_OK;
|
||||
}
|
||||
|
||||
uint32_t hal_watchdog_get_reload_value(void)
|
||||
{
|
||||
return wdt_timeout_reload_ms;
|
||||
}
|
||||
|
||||
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||
{
|
||||
watchdog_features_t wdt_feat;
|
||||
|
||||
/* We can support timeout values between 1 and UINT32_MAX by cascading. */
|
||||
wdt_feat.max_timeout = UINT32_MAX;
|
||||
/* Support re-configuring watchdog timer */
|
||||
wdt_feat.update_config = 1;
|
||||
/* Support stopping watchdog timer */
|
||||
wdt_feat.disable_watchdog = 1;
|
||||
|
||||
return wdt_feat;
|
||||
}
|
||||
|
||||
static void watchdog_setup_cascade_timeout(void)
|
||||
{
|
||||
uint32_t wdt_timeout_clk_toutsel;
|
||||
|
||||
if (wdt_timeout_rmn_clk >= NU_WDT_262144CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_262144CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW18;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_65536CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_65536CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW16;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_16384CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_16384CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW14;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_4096CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_4096CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW12;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_1024CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_1024CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW10;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_256CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_256CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW8;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_64CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_64CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW6;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_16CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_16CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||
} else if (wdt_timeout_rmn_clk) {
|
||||
wdt_timeout_rmn_clk = 0;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||
} else {
|
||||
/* WDT has timed-out and will restart system soon. We just disable interrupt to escape
|
||||
* getting stuck in WDT ISR. */
|
||||
SYS_UnlockReg();
|
||||
|
||||
/* Clear all flags */
|
||||
WDT->ISR = WDT_ISR_IS_Msk | WDT_ISR_RST_IS_Msk | WDT_ISR_WAKE_IS_Msk;
|
||||
/* Disable interrupt */
|
||||
WDT->IER &= ~WDT_IER_IE_Msk;
|
||||
|
||||
SYS_LockReg();
|
||||
return;
|
||||
}
|
||||
|
||||
SYS_UnlockReg();
|
||||
|
||||
/* Clear all flags */
|
||||
WDT->ISR = WDT_ISR_IS_Msk | WDT_ISR_RST_IS_Msk | WDT_ISR_WAKE_IS_Msk;
|
||||
/* Enable interrupt */
|
||||
WDT->IER = WDT_IER_IE_Msk;
|
||||
/* Configure another piece of cascaded WDT timeout */
|
||||
WDT->CTL = NU_WDT_RESET_DELAY_RSTDSEL | // Reset delay on timeout
|
||||
wdt_timeout_clk_toutsel | // Timeout interval
|
||||
WDT_CTL_WTE_Msk | // Enable watchdog timer
|
||||
WDT_CTL_WTWKE_Msk | // Enable wake-up on timeout
|
||||
(wdt_timeout_rmn_clk ? 0 : WDT_CTL_WTRE_Msk) | // Enable reset on last cascaded timeout
|
||||
WDT_CTL_WTR_Msk; // Reset watchdog timer
|
||||
|
||||
SYS_LockReg();
|
||||
}
|
||||
|
||||
void WDT_IRQHandler(void)
|
||||
{
|
||||
/* Check WDT interrupt flag */
|
||||
if (WDT_GET_TIMEOUT_INT_FLAG()) {
|
||||
/* Continue another piece of cascaded WDT timeout */
|
||||
watchdog_setup_cascade_timeout();
|
||||
} else {
|
||||
/* Clear all flags */
|
||||
WDT->ISR = WDT_ISR_IS_Msk | WDT_ISR_RST_IS_Msk | WDT_ISR_WAKE_IS_Msk;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,205 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2017-2018 Nuvoton
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "watchdog_api.h"
|
||||
|
||||
#if DEVICE_WATCHDOG
|
||||
|
||||
#include "cmsis.h"
|
||||
|
||||
/* Micro seconds per second */
|
||||
#define NU_US_PER_SEC 1000000
|
||||
|
||||
/* Watchdog clock per second */
|
||||
#define NU_WDTCLK_PER_SEC (__LIRC)
|
||||
|
||||
/* Convert watchdog clock to nearest ms */
|
||||
#define NU_WDTCLK2MS(WDTCLK) (((WDTCLK) * 1000 + ((NU_WDTCLK_PER_SEC) / 2)) / (NU_WDTCLK_PER_SEC))
|
||||
|
||||
/* Convert ms to nearest watchdog clock */
|
||||
#define NU_MS2WDTCLK(MS) (((MS) * (NU_WDTCLK_PER_SEC) + 500) / 1000)
|
||||
|
||||
/* List of hardware-supported watchdog timeout in clocks */
|
||||
#define NU_WDT_16CLK 16
|
||||
#define NU_WDT_64CLK 64
|
||||
#define NU_WDT_256CLK 256
|
||||
#define NU_WDT_1024CLK 1024
|
||||
#define NU_WDT_4096CLK 4096
|
||||
#define NU_WDT_16384CLK 16384
|
||||
#define NU_WDT_65536CLK 65536
|
||||
#define NU_WDT_262144CLK 262144
|
||||
|
||||
/* Watchdog reset delay */
|
||||
#define NU_WDT_RESET_DELAY_RSTDSEL WDT_RESET_DELAY_3CLK
|
||||
|
||||
/* Support watchdog timeout values beyond H/W
|
||||
*
|
||||
* Watchdog Timer H/W just supports timeout values of 2^4, 2^6, ..., 2^18 clocks.
|
||||
* To extend the support range to 1 and UINT32_MAX, we cascade multiple small timeouts to
|
||||
* reach one large timeout specified in hal_watchdog_init.
|
||||
*/
|
||||
|
||||
/* Track if WDT H/W has been initialized */
|
||||
static bool wdt_hw_inited = 0;
|
||||
/* Hold initially-configured timeout in hal_watchdog_init */
|
||||
static uint32_t wdt_timeout_reload_ms = 0;
|
||||
/* Track remaining timeout for cascading */
|
||||
static uint32_t wdt_timeout_rmn_clk = 0;
|
||||
|
||||
static void watchdog_setup_cascade_timeout(void);
|
||||
static void WDT_IRQHandler(void);
|
||||
|
||||
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
|
||||
{
|
||||
/* Check validity of arguments */
|
||||
if (! config || ! config->timeout_ms) {
|
||||
return WATCHDOG_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
wdt_timeout_reload_ms = config->timeout_ms;
|
||||
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||
|
||||
if (! wdt_hw_inited) {
|
||||
wdt_hw_inited = 1;
|
||||
|
||||
/* Enable IP module clock */
|
||||
CLK_EnableModuleClock(WDT_MODULE);
|
||||
|
||||
/* Select IP clock source */
|
||||
CLK_SetModuleClock(WDT_MODULE, CLK_CLKSEL1_WDTSEL_LIRC, 0);
|
||||
|
||||
/* Set up IP interrupt */
|
||||
NVIC_SetVector(WDT_IRQn, (uint32_t) WDT_IRQHandler);
|
||||
NVIC_EnableIRQ(WDT_IRQn);
|
||||
}
|
||||
|
||||
watchdog_setup_cascade_timeout();
|
||||
|
||||
return WATCHDOG_STATUS_OK;
|
||||
}
|
||||
|
||||
void hal_watchdog_kick(void)
|
||||
{
|
||||
wdt_timeout_rmn_clk = NU_MS2WDTCLK(wdt_timeout_reload_ms);
|
||||
watchdog_setup_cascade_timeout();
|
||||
}
|
||||
|
||||
watchdog_status_t hal_watchdog_stop(void)
|
||||
{
|
||||
SYS_UnlockReg();
|
||||
|
||||
/* Clear all flags & Disable interrupt & Disable WDT */
|
||||
WDT->CTL = (WDT->CTL & ~(WDT_CTL_WDTEN_Msk | WDT_CTL_INTEN_Msk)) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||
|
||||
SYS_LockReg();
|
||||
|
||||
return WATCHDOG_STATUS_OK;
|
||||
}
|
||||
|
||||
uint32_t hal_watchdog_get_reload_value(void)
|
||||
{
|
||||
return wdt_timeout_reload_ms;
|
||||
}
|
||||
|
||||
watchdog_features_t hal_watchdog_get_platform_features(void)
|
||||
{
|
||||
watchdog_features_t wdt_feat;
|
||||
|
||||
/* We can support timeout values between 1 and UINT32_MAX by cascading. */
|
||||
wdt_feat.max_timeout = UINT32_MAX;
|
||||
/* Support re-configuring watchdog timer */
|
||||
wdt_feat.update_config = 1;
|
||||
/* Support stopping watchdog timer */
|
||||
wdt_feat.disable_watchdog = 1;
|
||||
|
||||
return wdt_feat;
|
||||
}
|
||||
|
||||
static void watchdog_setup_cascade_timeout(void)
|
||||
{
|
||||
uint32_t wdt_timeout_clk_toutsel;
|
||||
|
||||
if (wdt_timeout_rmn_clk >= NU_WDT_262144CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_262144CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW18;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_65536CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_65536CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW16;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_16384CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_16384CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW14;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_4096CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_4096CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW12;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_1024CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_1024CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW10;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_256CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_256CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW8;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_64CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_64CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW6;
|
||||
} else if (wdt_timeout_rmn_clk >= NU_WDT_16CLK) {
|
||||
wdt_timeout_rmn_clk -= NU_WDT_16CLK;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||
} else if (wdt_timeout_rmn_clk) {
|
||||
wdt_timeout_rmn_clk = 0;
|
||||
wdt_timeout_clk_toutsel = WDT_TIMEOUT_2POW4;
|
||||
} else {
|
||||
/* WDT has timed-out and will restart system soon. We just disable interrupt to escape
|
||||
* getting stuck in WDT ISR. */
|
||||
SYS_UnlockReg();
|
||||
|
||||
/* Clear all flags & Disable interrupt */
|
||||
WDT->CTL = (WDT->CTL & ~WDT_CTL_INTEN_Msk) | (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||
|
||||
SYS_LockReg();
|
||||
return;
|
||||
}
|
||||
|
||||
SYS_UnlockReg();
|
||||
|
||||
/* Configure reset delay on timeout */
|
||||
WDT->ALTCTL = NU_WDT_RESET_DELAY_RSTDSEL;
|
||||
|
||||
/* Configure another piece of cascaded WDT timeout */
|
||||
WDT->CTL = wdt_timeout_clk_toutsel | // Timeout interval
|
||||
WDT_CTL_WDTEN_Msk | // Enable watchdog timer
|
||||
WDT_CTL_INTEN_Msk | // Enable interrupt
|
||||
WDT_CTL_WKF_Msk | // Clear wake-up flag
|
||||
WDT_CTL_WKEN_Msk | // Enable wake-up on timeout
|
||||
WDT_CTL_IF_Msk | // Clear interrupt flag
|
||||
WDT_CTL_RSTF_Msk | // Clear reset flag
|
||||
(wdt_timeout_rmn_clk ? 0 : WDT_CTL_RSTEN_Msk) | // Enable reset on last cascaded timeout
|
||||
WDT_CTL_RSTCNT_Msk; // Reset watchdog timer
|
||||
|
||||
SYS_LockReg();
|
||||
}
|
||||
|
||||
void WDT_IRQHandler(void)
|
||||
{
|
||||
/* Check WDT interrupt flag */
|
||||
if (WDT_GET_TIMEOUT_INT_FLAG()) {
|
||||
/* Continue another piece of cascaded WDT timeout */
|
||||
watchdog_setup_cascade_timeout();
|
||||
} else {
|
||||
/* Clear all flags */
|
||||
WDT->CTL |= (WDT_CTL_WKF_Msk | WDT_CTL_IF_Msk | WDT_CTL_RSTF_Msk);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -7397,7 +7397,8 @@
|
|||
"CAN",
|
||||
"FLASH",
|
||||
"EMAC",
|
||||
"MPU"
|
||||
"MPU",
|
||||
"WATCHDOG"
|
||||
],
|
||||
"release_versions": ["5"],
|
||||
"device_name": "NUC472HI8AE",
|
||||
|
@ -7525,7 +7526,8 @@
|
|||
"SPI_ASYNCH",
|
||||
"CAN",
|
||||
"FLASH",
|
||||
"MPU"
|
||||
"MPU",
|
||||
"WATCHDOG"
|
||||
],
|
||||
"components_add": ["FLASHIAP"],
|
||||
"release_versions": ["2", "5"],
|
||||
|
@ -7592,7 +7594,8 @@
|
|||
"SLEEP",
|
||||
"SPI",
|
||||
"SPISLAVE",
|
||||
"SPI_ASYNCH"
|
||||
"SPI_ASYNCH",
|
||||
"WATCHDOG"
|
||||
],
|
||||
"release_versions": ["5"],
|
||||
"device_name": "NANO130KE3BN",
|
||||
|
@ -7950,7 +7953,8 @@
|
|||
"FLASH",
|
||||
"CAN",
|
||||
"EMAC",
|
||||
"MPU"
|
||||
"MPU",
|
||||
"WATCHDOG"
|
||||
],
|
||||
"release_versions": ["5"],
|
||||
"bootloader_supported": true,
|
||||
|
|
Loading…
Reference in New Issue