248 lines
6.0 KiB
C
248 lines
6.0 KiB
C
/*
|
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2019-04-20 tyustli the first version.
|
|
* 2019-07-15 Magicoe The first version for LPC55S6x, timeout unit is S not mS
|
|
*
|
|
*/
|
|
#include <rtthread.h>
|
|
|
|
#ifdef BSP_USING_WDT
|
|
|
|
#if !defined(BSP_USING_WDT)
|
|
#error "Please define at least one BSP_USING_WDOGx"
|
|
#endif
|
|
|
|
#define LOG_TAG "drv.wdt"
|
|
#include <drv_log.h>
|
|
|
|
#include "drv_wdt.h"
|
|
#include <rthw.h>
|
|
#include "rtdevice.h"
|
|
|
|
#if defined(BSP_USING_WDT)
|
|
#include "fsl_wwdt.h"
|
|
|
|
struct lpc_wdt_obj
|
|
{
|
|
rt_watchdog_t watchdog;
|
|
rt_uint16_t is_start;
|
|
};
|
|
|
|
static struct lpc_wdt_obj lpc_wdt;
|
|
static wwdt_config_t WWDT1_config =
|
|
{
|
|
/* Enable the watch dog */
|
|
.enableWwdt = true,
|
|
/* Disable the watchdog timeout reset */
|
|
.enableWatchdogReset = false,
|
|
/* Disable the watchdog protection for updating the timeout value */
|
|
.enableWatchdogProtect = false,
|
|
/* Windowing is not in effect */
|
|
.windowValue = 0xFFFFFFU,
|
|
/* Set the timeout value to the max */
|
|
.timeoutValue = 0xFFFFFFU,
|
|
/* No warning is provided */
|
|
.warningValue = 0,
|
|
/* Set clock frequency. */
|
|
.clockFreq_Hz = 0U,
|
|
};
|
|
|
|
void WDT_BOD_IRQHandler(void)
|
|
{
|
|
uint32_t wdtStatus = WWDT_GetStatusFlags(WWDT);
|
|
|
|
/* The chip will reset before this happens */
|
|
if (wdtStatus & kWWDT_TimeoutFlag)
|
|
{
|
|
/* A watchdog feed didn't occur prior to window timeout */
|
|
/* Stop WDT */
|
|
WWDT_Disable(WWDT);
|
|
WWDT_ClearStatusFlags(WWDT, kWWDT_TimeoutFlag);
|
|
/* Needs restart */
|
|
WWDT_Enable(WWDT);
|
|
}
|
|
|
|
/* Handle warning interrupt */
|
|
if (wdtStatus & kWWDT_WarningFlag)
|
|
{
|
|
/* A watchdog feed didn't occur prior to warning timeout */
|
|
WWDT_ClearStatusFlags(WWDT, kWWDT_WarningFlag);
|
|
/* User code. User can do urgent case before timeout reset.
|
|
* IE. user can backup the ram data or ram log to flash.
|
|
* the period is set by config.warningValue, user need to
|
|
* check the period between warning interrupt and timeout.
|
|
*/
|
|
}
|
|
}
|
|
|
|
static rt_err_t lpc_wwdt_close(rt_watchdog_t *wdt)
|
|
{
|
|
rt_uint32_t level;
|
|
WWDT_Type *base;
|
|
base = (WWDT_Type *)wdt->parent.user_data;
|
|
|
|
level = rt_hw_interrupt_disable();
|
|
WWDT_Disable(base);
|
|
rt_hw_interrupt_enable(level);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t lpc_wwdt_open(rt_watchdog_t *wdt, rt_uint16_t oflag)
|
|
{
|
|
WWDT_Type *base;
|
|
base = (WWDT_Type *)wdt->parent.user_data;
|
|
rt_uint32_t level;
|
|
|
|
level = rt_hw_interrupt_disable();
|
|
WWDT_Enable(base);
|
|
rt_hw_interrupt_enable(level);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t lpc_wwdt_init(rt_watchdog_t *wdt)
|
|
{
|
|
WWDT_Type *base;
|
|
base = (WWDT_Type *)wdt->parent.user_data;
|
|
|
|
/* Enable FRO 1M clock for WWDT module. */
|
|
SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_FRO1MHZ_CLK_ENA_MASK;
|
|
/* Set clock divider for WWDT clock source. */
|
|
CLOCK_SetClkDiv(kCLOCK_DivWdtClk, 1U, true);
|
|
|
|
WWDT_GetDefaultConfig(&WWDT1_config);
|
|
|
|
/*
|
|
* Set watchdog feed time constant to approximately 4s
|
|
* Set watchdog warning time to 512 ticks after feed time constant
|
|
* Set watchdog window time to 1s
|
|
*/
|
|
/* The WDT divides the input frequency into it by 4 */
|
|
WWDT1_config.timeoutValue = (CLOCK_GetWdtClkFreq() / 4) * 4;
|
|
WWDT1_config.warningValue = 512;
|
|
WWDT1_config.windowValue = (CLOCK_GetWdtClkFreq() / 4) * 1;
|
|
/* Configure WWDT to reset on timeout */
|
|
WWDT1_config.enableWatchdogReset = true;
|
|
/* Setup watchdog clock frequency(Hz). */
|
|
WWDT1_config.clockFreq_Hz = CLOCK_GetWdtClkFreq();
|
|
|
|
WWDT_Init(base, &WWDT1_config);
|
|
lpc_wwdt_close(wdt);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static rt_err_t lpc_wwdt_refresh(rt_watchdog_t *wdt)
|
|
{
|
|
WWDT_Type *base;
|
|
base = (WWDT_Type *)wdt->parent.user_data;
|
|
|
|
rt_uint32_t level;
|
|
|
|
level = rt_hw_interrupt_disable();
|
|
WWDT_Refresh(base);
|
|
rt_hw_interrupt_enable(level);
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
/**
|
|
* @function control wdog
|
|
*
|
|
* @param
|
|
* wdt whick wdog used
|
|
* cmd control wdog options
|
|
* args argument of conrtol
|
|
* @retval rt_err_t the status of control result
|
|
*
|
|
* @attention wdog1 is can not get left time(register not exist) and wdogs unit is seconds
|
|
*
|
|
*/
|
|
static rt_err_t lpc_wwdt_control(rt_watchdog_t *wdt, int cmd, void *args)
|
|
{
|
|
RT_ASSERT(wdt != NULL);
|
|
|
|
WWDT_Type *base;
|
|
base = (WWDT_Type *)wdt->parent.user_data;
|
|
|
|
switch(cmd)
|
|
{
|
|
case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
|
|
{
|
|
*(uint16_t *)args = WWDT1_config.timeoutValue;
|
|
}
|
|
break;
|
|
case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
|
|
{
|
|
RT_ASSERT(*(uint16_t *)args != 0);
|
|
|
|
WWDT1_config.timeoutValue = (CLOCK_GetWdtClkFreq() / 4) * (*(uint16_t *)args) * 2;
|
|
WWDT1_config.warningValue = 512;
|
|
WWDT1_config.windowValue = (CLOCK_GetWdtClkFreq() / 4) * (*(uint16_t *)args) * 2 / 4;
|
|
|
|
base->TC = WWDT_TC_COUNT(WWDT1_config.timeoutValue);
|
|
base->WINDOW = WWDT_WINDOW_WINDOW(WWDT1_config.windowValue);
|
|
base->WARNINT = WWDT_WARNINT_WARNINT(WWDT1_config.warningValue);
|
|
WWDT_Refresh(base);
|
|
|
|
lpc_wwdt_close(wdt);
|
|
}
|
|
break;
|
|
case RT_DEVICE_CTRL_WDT_KEEPALIVE:
|
|
{
|
|
lpc_wwdt_refresh(wdt);
|
|
}
|
|
break;
|
|
case RT_DEVICE_CTRL_WDT_START:
|
|
{
|
|
lpc_wwdt_open(wdt, *(rt_uint32_t *)args);
|
|
}
|
|
break;
|
|
case RT_DEVICE_CTRL_WDT_STOP:
|
|
{
|
|
lpc_wwdt_close(wdt);
|
|
}
|
|
break;
|
|
default:
|
|
return -RT_EINVAL;
|
|
}
|
|
|
|
return RT_EOK;
|
|
}
|
|
|
|
static struct rt_watchdog_ops lpc_wwdt_ops =
|
|
{
|
|
.init = lpc_wwdt_init,
|
|
.control = lpc_wwdt_control,
|
|
};
|
|
|
|
#endif /* BSP_USING_WDT */
|
|
|
|
int rt_hw_wdt_init(void)
|
|
{
|
|
rt_err_t ret = RT_EOK;
|
|
|
|
#if defined (BSP_USING_WDT)
|
|
lpc_wdt.watchdog.ops = &lpc_wwdt_ops;
|
|
|
|
ret = rt_hw_watchdog_register(&lpc_wdt.watchdog, "wdt", RT_DEVICE_FLAG_RDWR, WWDT);
|
|
|
|
if (ret != RT_EOK)
|
|
{
|
|
LOG_E("rt device register failed %d\n", ret);
|
|
}
|
|
#endif /* BSP_USING_WDT */
|
|
|
|
return ret;
|
|
}
|
|
|
|
INIT_DEVICE_EXPORT(rt_hw_wdt_init);
|
|
|
|
#endif /* BSP_USING_WDT */
|