| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- /*
- * Copyright (C) 2022-2024, Xiaohua Semiconductor Co., Ltd.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2023-02-08 CDT first version
- * 2023-12-01 CDT added swdt support
- */
- #include "board.h"
- #ifdef BSP_USING_WDT_TMR
- #include <math.h>
- #include <string.h>
- // #define DRV_DEBUG
- #define LOG_TAG "drv_wdt"
- #include <drv_log.h>
- enum
- {
- WDT_INIT_ING,
- WDT_INIT_OVER,
- WDT_IS_ENABLE
- };
- static struct rt_watchdog_ops _ops;
- /* WDT */
- #ifdef BSP_USING_WDT
- struct hc32_wdt_obj
- {
- rt_watchdog_t watchdog;
- stc_wdt_init_t stcwdg;
- rt_uint32_t pclk3;
- rt_uint8_t sta;
- rt_uint8_t index;
- };
- static struct hc32_wdt_obj hc32_wdt;
- struct time_match
- {
- uint32_t u32ClockDiv;
- uint32_t u32CountPeriod;
- float timeout_s;
- };
- static uint32_t const Div[] = {4U, 64U, 128U, 256U, 512U, 1024U, 2048U, 8192U};
- static uint32_t const Peri[] = {256U, 4096U, 16384U, 65536U};
- static struct time_match wdt_match[(sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0]))];
- static void wdt_match_init(uint32_t clock)
- {
- int i, j;
- for (i = 0; i < (sizeof(Div) / sizeof(Div[0])); i++)
- {
- for (j = 0; j < (sizeof(Peri) / sizeof(Peri[0])); j++)
- {
- wdt_match[j + i * (sizeof(Peri) / sizeof(Peri[0]))].u32ClockDiv = Div[i];
- wdt_match[j + i * (sizeof(Peri) / sizeof(Peri[0]))].u32CountPeriod = Peri[j];
- wdt_match[j + i * (sizeof(Peri) / sizeof(Peri[0]))].timeout_s = (Div[i] * Peri[j]) / (float)clock;
- }
- }
- }
- static void wdt_match_sort(void)
- {
- int i, j;
- struct time_match Temp;
- /* bubble sort */
- for (i = 0; i < ((sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0])) - 1); i++)
- {
- for (j = 0; j < ((sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0])) - i - 1); j++)
- {
- if (wdt_match[j].timeout_s > wdt_match[j + 1].timeout_s)
- {
- memcpy(&Temp, &wdt_match[j], sizeof(struct time_match));
- memcpy(&wdt_match[j], &wdt_match[j + 1], sizeof(struct time_match));
- memcpy(&wdt_match[j + 1], &Temp, sizeof(struct time_match));
- }
- }
- }
- }
- static int wdt_match_find_index(uint32_t time_out)
- {
- int i;
- /* Min and Max case */
- if (time_out <= wdt_match[0].timeout_s)
- {
- return 0;
- }
- else if (time_out >= wdt_match[((sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0]))) - 1].timeout_s)
- {
- return (((sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0]))) - 1);
- }
- /* Other case */
- for (i = 1; i < (((sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0]))) - 1); i++)
- {
- if (time_out >= wdt_match[i].timeout_s && time_out < wdt_match[i + 1].timeout_s)
- {
- /* Min difference */
- if (time_out - wdt_match[i].timeout_s < wdt_match[i + 1].timeout_s - time_out)
- {
- return i;
- }
- else
- {
- return (i + 1);
- }
- }
- }
- /* Not match case */
- return (((sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0]))) - 1);
- }
- static rt_uint32_t wdt_match_find_period(rt_uint32_t Period)
- {
- rt_uint32_t CountPeriod = 0U;
- switch (Period)
- {
- case 256U:
- CountPeriod = WDT_CNT_PERIOD256;
- break;
- case 4096U:
- CountPeriod = WDT_CNT_PERIOD4096;
- break;
- case 16384U:
- CountPeriod = WDT_CNT_PERIOD16384;
- break;
- case 65536U:
- CountPeriod = WDT_CNT_PERIOD65536;
- break;
- default:
- break;
- }
- return CountPeriod;
- }
- static rt_uint32_t wdt_get_timeout_s(void)
- {
- /* timeout(s) = PERI * DIV / PCLK3 */
- return ((rt_uint32_t)(wdt_match[hc32_wdt.index].u32CountPeriod * wdt_match[hc32_wdt.index].u32ClockDiv / (float)hc32_wdt.pclk3));
- }
- static rt_uint32_t wdt_get_timeleft_s(void)
- {
- /* wdt is down counter */
- return ((rt_uint32_t)(WDT_GetCountValue() * wdt_match[hc32_wdt.index].u32ClockDiv / (float)hc32_wdt.pclk3));
- }
- static rt_err_t _wdt_init(rt_watchdog_t *wdt)
- {
- hc32_wdt.pclk3 = CLK_GetBusClockFreq(CLK_BUS_PCLK3);
- LOG_D("pclk3 = %dhz", hc32_wdt.pclk3);
- if (!hc32_wdt.pclk3)
- {
- LOG_E("pclk3 getbusclockfreq failed.");
- return -RT_ERROR;
- }
- wdt_match_init(hc32_wdt.pclk3);
- wdt_match_sort();
- hc32_wdt.stcwdg.u32RefreshRange = WDT_RANGE_0TO100PCT;
- #ifdef BSP_WDT_CONTINUE_COUNT
- hc32_wdt.stcwdg.u32LPMCount = WDT_LPM_CNT_CONT;
- #else
- hc32_wdt.stcwdg.u32LPMCount = WDT_LPM_CNT_STOP;
- #endif
- hc32_wdt.stcwdg.u32ExceptionType = WDT_EXP_TYPE_RST;
- hc32_wdt.sta = WDT_INIT_ING;
- /* WDT_CR register only support write once,so can't call WDT_Init of ther */
- return RT_EOK;
- }
- static rt_err_t _wdt_control(rt_watchdog_t *wdt, int cmd, void *arg)
- {
- switch (cmd)
- {
- /* feed the watchdog */
- case RT_DEVICE_CTRL_WDT_KEEPALIVE:
- /* Prevention of unexpected start-up when feed dog */
- if (hc32_wdt.sta == WDT_IS_ENABLE)
- {
- WDT_FeedDog();
- }
- break;
- /* set watchdog timeout */
- case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
- hc32_wdt.index = wdt_match_find_index((*((rt_uint32_t *)arg)));
- hc32_wdt.stcwdg.u32CountPeriod = wdt_match_find_period(wdt_match[hc32_wdt.index].u32CountPeriod);
- hc32_wdt.stcwdg.u32ClockDiv = ((uint32_t)log2(wdt_match[hc32_wdt.index].u32ClockDiv) << WDT_CR_CKS_POS);
- if (WDT_Init(&hc32_wdt.stcwdg) != LL_OK)
- {
- LOG_E("wdg set timeout failed.");
- return -RT_ERROR;
- }
- hc32_wdt.sta = WDT_INIT_OVER;
- LOG_D("wdg set timeout successful. timeout = %d s", wdt_get_timeout_s());
- break;
- case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
- (*((rt_uint32_t *)arg)) = wdt_get_timeout_s();
- break;
- case RT_DEVICE_CTRL_WDT_START:
- if (hc32_wdt.sta == WDT_INIT_ING)
- {
- LOG_E("please set the timeout values.");
- return -RT_ERROR;
- }
- /* First reload counter to start WDT */
- WDT_FeedDog();
- hc32_wdt.sta = WDT_IS_ENABLE;
- break;
- case RT_DEVICE_CTRL_WDT_GET_TIMELEFT:
- (*((rt_uint32_t *)arg)) = wdt_get_timeleft_s();
- break;
- default:
- LOG_W("This command is not supported.");
- return -RT_ERROR;
- }
- return RT_EOK;
- }
- int rt_wdt_init(void)
- {
- _ops.init = &_wdt_init;
- _ops.control = &_wdt_control;
- hc32_wdt.watchdog.ops = &_ops;
- /* register watchdog device */
- if (rt_hw_watchdog_register(&hc32_wdt.watchdog, "wdt", RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
- {
- LOG_E("wdt device register failed.");
- return -RT_ERROR;
- }
- LOG_D("wdt device register success.");
- return RT_EOK;
- }
- INIT_BOARD_EXPORT(rt_wdt_init);
- /* SWDT */
- #else /* BSP_USING_SWDT */
- struct hc32_swdt_obj
- {
- rt_watchdog_t watchdog;
- stc_swdt_init_t stcwdg;
- rt_uint32_t swdtclk;
- rt_uint8_t sta;
- rt_uint8_t index;
- };
- static struct hc32_swdt_obj hc32_swdt;
- struct time_match
- {
- uint32_t u32ClockDiv;
- uint32_t u32CountPeriod;
- float timeout_s;
- };
- static uint32_t const Div[] = {1U, 16U, 32U, 64U, 128U, 256U, 2048U};
- static uint32_t const Peri[] = {256U, 4096U, 16384U, 65536U};
- static struct time_match swdt_match[(sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0]))];
- static void swdt_match_init(uint32_t clock)
- {
- int i, j;
- for (i = 0; i < (sizeof(Div) / sizeof(Div[0])); i++)
- {
- for (j = 0; j < (sizeof(Peri) / sizeof(Peri[0])); j++)
- {
- swdt_match[j + i * (sizeof(Peri) / sizeof(Peri[0]))].u32ClockDiv = Div[i];
- swdt_match[j + i * (sizeof(Peri) / sizeof(Peri[0]))].u32CountPeriod = Peri[j];
- swdt_match[j + i * (sizeof(Peri) / sizeof(Peri[0]))].timeout_s = (Div[i] * Peri[j]) / (float)clock;
- }
- }
- }
- static void swdt_match_sort(void)
- {
- int i, j;
- struct time_match Temp;
- /* bubble sort */
- for (i = 0; i < ((sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0])) - 1); i++)
- {
- for (j = 0; j < ((sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0])) - i - 1); j++)
- {
- if (swdt_match[j].timeout_s > swdt_match[j + 1].timeout_s)
- {
- memcpy(&Temp, &swdt_match[j], sizeof(struct time_match));
- memcpy(&swdt_match[j], &swdt_match[j + 1], sizeof(struct time_match));
- memcpy(&swdt_match[j + 1], &Temp, sizeof(struct time_match));
- }
- }
- }
- }
- static int swdt_match_find_index(uint32_t time_out)
- {
- int i;
- /* Min and Max case */
- if (time_out <= swdt_match[0].timeout_s)
- {
- return 0;
- }
- else if (time_out >= swdt_match[((sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0]))) - 1].timeout_s)
- {
- return (((sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0]))) - 1);
- }
- /* Other case */
- for (i = 1; i < (((sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0]))) - 1); i++)
- {
- if (time_out >= swdt_match[i].timeout_s && time_out < swdt_match[i + 1].timeout_s)
- {
- /* Min difference */
- if (time_out - swdt_match[i].timeout_s < swdt_match[i + 1].timeout_s - time_out)
- {
- return i;
- }
- else
- {
- return (i + 1);
- }
- }
- }
- /* Not match case */
- return (((sizeof(Div) / sizeof(Div[0])) * (sizeof(Peri) / sizeof(Peri[0]))) - 1);
- }
- static rt_uint32_t swdt_match_find_period(rt_uint32_t Period)
- {
- rt_uint32_t CountPeriod = 0U;
- switch (Period)
- {
- case 256U:
- CountPeriod = SWDT_CNT_PERIOD256;
- break;
- case 4096U:
- CountPeriod = SWDT_CNT_PERIOD4096;
- break;
- case 16384U:
- CountPeriod = SWDT_CNT_PERIOD16384;
- break;
- case 65536U:
- CountPeriod = SWDT_CNT_PERIOD65536;
- break;
- default:
- break;
- }
- return CountPeriod;
- }
- static rt_uint32_t swdt_get_timeout_s(void)
- {
- /* timeout(s) = PERI * DIV / SWDTCLK */
- return ((rt_uint32_t)(swdt_match[hc32_swdt.index].u32CountPeriod * swdt_match[hc32_swdt.index].u32ClockDiv / (float)hc32_swdt.swdtclk));
- }
- static rt_uint32_t swdt_get_timeleft_s(void)
- {
- /* swdt is down counter */
- return ((rt_uint32_t)(SWDT_GetCountValue() * swdt_match[hc32_swdt.index].u32ClockDiv / (float)hc32_swdt.swdtclk));
- }
- static rt_err_t swdt_init(rt_watchdog_t *swdt)
- {
- hc32_swdt.swdtclk = 10000U;
- swdt_match_init(hc32_swdt.swdtclk);
- swdt_match_sort();
- hc32_swdt.stcwdg.u32RefreshRange = SWDT_RANGE_0TO100PCT;
- #ifdef BSP_WDT_CONTINUE_COUNT
- hc32_swdt.stcwdg.u32LPMCount = SWDT_LPM_CNT_CONT;
- #else
- hc32_swdt.stcwdg.u32LPMCount = SWDT_LPM_CNT_STOP;
- #endif
- hc32_swdt.stcwdg.u32ExceptionType = SWDT_EXP_TYPE_RST;
- hc32_swdt.sta = WDT_INIT_ING;
- /* SWDT_CR register only support write once,so can't call swdt_Init of ther */
- return RT_EOK;
- }
- static rt_err_t swdt_control(rt_watchdog_t *swdt, int cmd, void *arg)
- {
- switch (cmd)
- {
- /* feed the watchdog */
- case RT_DEVICE_CTRL_WDT_KEEPALIVE:
- /* Prevention of unexpected start-up when feed dog */
- if (hc32_swdt.sta == WDT_IS_ENABLE)
- {
- SWDT_FeedDog();
- }
- break;
- /* set watchdog timeout */
- case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
- hc32_swdt.index = swdt_match_find_index((*((rt_uint32_t *)arg)));
- hc32_swdt.stcwdg.u32CountPeriod = swdt_match_find_period(swdt_match[hc32_swdt.index].u32CountPeriod);
- hc32_swdt.stcwdg.u32ClockDiv = ((uint32_t)log2(swdt_match[hc32_swdt.index].u32ClockDiv) << SWDT_CR_CKS_POS);
- if (SWDT_Init(&hc32_swdt.stcwdg) != LL_OK)
- {
- LOG_E("swdg set timeout failed.");
- return -RT_ERROR;
- }
- hc32_swdt.sta = WDT_INIT_OVER;
- LOG_D("swdg set timeout successful. timeout = %d s", swdt_get_timeout_s());
- break;
- case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
- (*((rt_uint32_t *)arg)) = swdt_get_timeout_s();
- break;
- case RT_DEVICE_CTRL_WDT_START:
- if (hc32_swdt.sta == WDT_INIT_ING)
- {
- LOG_E("please set the timeout values.");
- return -RT_ERROR;
- }
- /* First reload counter to start swdt */
- SWDT_FeedDog();
- hc32_swdt.sta = WDT_IS_ENABLE;
- break;
- case RT_DEVICE_CTRL_WDT_GET_TIMELEFT:
- (*((rt_uint32_t *)arg)) = swdt_get_timeleft_s();
- break;
- default:
- LOG_W("This command is not supported.");
- return -RT_ERROR;
- }
- return RT_EOK;
- }
- static int rt_hw_swdt_init(void)
- {
- _ops.init = &swdt_init;
- _ops.control = &swdt_control;
- hc32_swdt.watchdog.ops = &_ops;
- /* register watchdog device */
- if (rt_hw_watchdog_register(&hc32_swdt.watchdog, "swdt", RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
- {
- LOG_E("swdt device register failed.");
- return -RT_ERROR;
- }
- LOG_D("swdt device register success.");
- return RT_EOK;
- }
- INIT_BOARD_EXPORT(rt_hw_swdt_init);
- #endif /* BSP_USING_SWDT */
- #endif
|