1
0

drv_wdt.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-08-25 AisinoChip First Version
  9. */
  10. #include <board.h>
  11. #include <rtthread.h>
  12. #include <rtdevice.h>
  13. #ifdef RT_USING_WDT
  14. #include "board.h"
  15. struct acm32_wdt_obj
  16. {
  17. union
  18. {
  19. WDT_HandleTypeDef wdt;
  20. IWDT_HandleTypeDef iwdt;
  21. } handle;
  22. rt_uint16_t is_start;
  23. rt_uint16_t type;
  24. rt_watchdog_t watchdog;
  25. };
  26. #define TYPE_WDT 0
  27. #define TYPE_IWDT 1
  28. #define IWDT_FREQ (32000)
  29. #ifdef BSP_USING_WDT
  30. #define WDT_NAME "wdt"
  31. static struct acm32_wdt_obj acm32_wdt;
  32. #endif
  33. #ifdef BSP_USING_IWDT
  34. #define IWDT_NAME "iwdt"
  35. static struct acm32_wdt_obj acm32_iwdt;
  36. #endif
  37. static struct rt_watchdog_ops ops;
  38. rt_inline rt_base_t calc_wdt_divisor_load(rt_uint32_t freq, rt_uint32_t sec, rt_uint32_t *divisor, rt_uint32_t *load)
  39. {
  40. rt_uint32_t freqMaxSec = 0;
  41. rt_uint32_t minFreqDiv = WDT_DIVISOR_NONE;
  42. freqMaxSec = RT_UINT32_MAX / freq;
  43. while (minFreqDiv <= WDT_DIVISOR_128)
  44. {
  45. if (sec < freqMaxSec)
  46. {
  47. break;
  48. }
  49. minFreqDiv ++;
  50. freqMaxSec = RT_UINT32_MAX / freq * (1 << minFreqDiv);
  51. }
  52. if (minFreqDiv > WDT_DIVISOR_128)
  53. {
  54. return -1;
  55. }
  56. *divisor = minFreqDiv;
  57. *load = sec * (freq >> minFreqDiv);
  58. return 0;
  59. }
  60. rt_inline rt_base_t calc_iwdt_divisor_load(rt_uint32_t freq, rt_uint32_t sec, rt_uint32_t *divisor, rt_uint32_t *load)
  61. {
  62. rt_uint32_t minFreqDiv = IWDT_CLOCK_PRESCALER_4;
  63. rt_uint32_t freqMaxMs = 0;
  64. freqMaxMs = IWDT_RELOAD_MAX_VALUE * 1000 / (freq >> (2 + minFreqDiv));
  65. while (minFreqDiv <= IWDT_CLOCK_PRESCALER_256)
  66. {
  67. if (sec * 1000 < freqMaxMs)
  68. {
  69. break;
  70. }
  71. minFreqDiv ++;
  72. freqMaxMs = IWDT_RELOAD_MAX_VALUE * 1000 / (freq >> (2 + minFreqDiv));
  73. }
  74. if (minFreqDiv > IWDT_CLOCK_PRESCALER_256)
  75. {
  76. return -1;
  77. }
  78. *divisor = minFreqDiv;
  79. if (sec < 1000)
  80. {
  81. *load = (sec * 1000) * IWDT_RELOAD_MAX_VALUE / freqMaxMs;
  82. }
  83. else
  84. {
  85. *load = (sec) * IWDT_RELOAD_MAX_VALUE / freqMaxMs / 1000;
  86. }
  87. return 0;
  88. }
  89. rt_inline rt_uint32_t calc_wdt_timeout(rt_uint32_t freq, rt_uint32_t divisor, rt_uint32_t count)
  90. {
  91. /* 1 / ( freq / (1<<divisor) ) * (count) */
  92. return (rt_uint32_t)(((rt_uint64_t)count) * (1 << divisor) / (freq));
  93. }
  94. rt_inline rt_uint32_t calc_iwdt_timeout(rt_uint32_t freq, rt_uint32_t divisor, rt_uint32_t count)
  95. {
  96. /* (freq >> (2+divisor)) / IWDT_RELOAD_MAX_VALUE * count */
  97. return count / (freq >> (2 + divisor));
  98. }
  99. static rt_err_t wdt_init(rt_watchdog_t *wdt)
  100. {
  101. return RT_EOK;
  102. }
  103. static rt_err_t wdt_control(rt_watchdog_t *wdt, int cmd, void *arg)
  104. {
  105. struct acm32_wdt_obj *wdtObj = NULL;
  106. rt_uint32_t timer_clk_hz;
  107. rt_uint32_t divisor, load;
  108. RT_ASSERT(wdt != RT_NULL);
  109. wdtObj = rt_container_of(wdt, struct acm32_wdt_obj, watchdog);
  110. timer_clk_hz = System_Get_APBClock();
  111. switch (cmd)
  112. {
  113. /* feed the watchdog */
  114. case RT_DEVICE_CTRL_WDT_KEEPALIVE:
  115. if (TYPE_WDT == wdtObj->type)
  116. {
  117. HAL_WDT_Feed(&wdtObj->handle.wdt);
  118. }
  119. else
  120. {
  121. HAL_IWDT_Kick_Watchdog_Wait_For_Done(&wdtObj->handle.iwdt);
  122. }
  123. break;
  124. /* set watchdog timeout, seconds */
  125. case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
  126. if (TYPE_WDT == wdtObj->type)
  127. {
  128. if (calc_wdt_divisor_load(timer_clk_hz, (*((rt_uint32_t *)arg)), &divisor, &load))
  129. {
  130. return -RT_ERROR;
  131. }
  132. wdtObj->handle.wdt.Init.WDTDivisor = (WDT_DIVISOR)divisor;
  133. wdtObj->handle.wdt.Init.WDTLoad = load;
  134. HAL_WDT_Init(&wdtObj->handle.wdt);
  135. }
  136. else
  137. {
  138. if (calc_iwdt_divisor_load(IWDT_FREQ, (*((rt_uint32_t *)arg)), &divisor, &load))
  139. {
  140. return -RT_ERROR;
  141. }
  142. wdtObj->handle.iwdt.Instance = IWDT;
  143. wdtObj->handle.iwdt.Init.Prescaler = divisor;
  144. wdtObj->handle.iwdt.Init.Reload = load;
  145. }
  146. if (wdtObj->is_start)
  147. {
  148. if (TYPE_WDT == wdtObj->type)
  149. {
  150. HAL_WDT_Init(&wdtObj->handle.wdt);
  151. }
  152. else
  153. {
  154. HAL_IWDT_Init(&wdtObj->handle.iwdt);
  155. }
  156. }
  157. break;
  158. case RT_DEVICE_CTRL_WDT_GET_TIMELEFT:
  159. if (TYPE_WDT == wdtObj->type)
  160. {
  161. (*((rt_uint32_t *)arg)) = calc_wdt_timeout(timer_clk_hz,
  162. wdtObj->handle.wdt.Init.WDTDivisor,
  163. wdtObj->handle.wdt.Instance->COUNT);
  164. }
  165. else
  166. {
  167. return -RT_EINVAL;
  168. }
  169. break;
  170. case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
  171. if (TYPE_WDT == wdtObj->type)
  172. {
  173. (*((rt_uint32_t *)arg)) = calc_wdt_timeout(timer_clk_hz,
  174. wdtObj->handle.wdt.Init.WDTDivisor,
  175. wdtObj->handle.wdt.Init.WDTLoad);
  176. }
  177. else
  178. {
  179. (*((rt_uint32_t *)arg)) = calc_iwdt_timeout(IWDT_FREQ,
  180. wdtObj->handle.iwdt.Init.Prescaler,
  181. wdtObj->handle.iwdt.Init.Reload);
  182. }
  183. break;
  184. case RT_DEVICE_CTRL_WDT_START:
  185. if (TYPE_WDT == wdtObj->type)
  186. {
  187. wdtObj->handle.wdt.Instance = WDT;
  188. wdtObj->handle.wdt.Init.WDTMode = WDT_MODE_RST;
  189. wdtObj->handle.wdt.Init.WDTINTCLRTIME = 0xffff;
  190. HAL_WDT_Init(&wdtObj->handle.wdt);
  191. HAL_WDT_Start(&wdtObj->handle.wdt);
  192. }
  193. else
  194. {
  195. wdtObj->handle.iwdt.Instance->CMDR = IWDT_ENABLE_COMMAND;
  196. wdtObj->handle.iwdt.Init.Window = IWDT_RELOAD_MAX_VALUE; /* window function disabled when window >= reload */
  197. wdtObj->handle.iwdt.Init.Wakeup = IWDT_RELOAD_MAX_VALUE; /* wakeup function disabled when wakeup >= reload */
  198. HAL_IWDT_Init(&wdtObj->handle.iwdt);
  199. }
  200. wdtObj->is_start = 1;
  201. break;
  202. case RT_DEVICE_CTRL_WDT_STOP:
  203. if (TYPE_WDT == wdtObj->type)
  204. {
  205. HAL_WDT_Stop(&wdtObj->handle.wdt);
  206. }
  207. else
  208. {
  209. wdtObj->handle.iwdt.Instance->CMDR = IWDT_DISABLE_COMMAND;
  210. }
  211. wdtObj->is_start = 0;
  212. break;
  213. default:
  214. return -RT_ERROR;
  215. }
  216. return RT_EOK;
  217. }
  218. int rt_wdt_init(void)
  219. {
  220. ops.init = &wdt_init;
  221. ops.control = &wdt_control;
  222. #ifdef BSP_USING_WDT
  223. acm32_wdt.type = TYPE_WDT;
  224. acm32_wdt.is_start = 0;
  225. acm32_wdt.watchdog.ops = &ops;
  226. if (rt_hw_watchdog_register(&acm32_wdt.watchdog, WDT_NAME, RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
  227. {
  228. return -RT_ERROR;
  229. }
  230. #endif
  231. #ifdef BSP_USING_IWDT
  232. acm32_iwdt.type = TYPE_IWDT;
  233. acm32_iwdt.is_start = 0;
  234. acm32_iwdt.watchdog.ops = &ops;
  235. if (rt_hw_watchdog_register(&acm32_iwdt.watchdog, IWDT_NAME, RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
  236. {
  237. return -RT_ERROR;
  238. }
  239. #endif
  240. return RT_EOK;
  241. }
  242. INIT_BOARD_EXPORT(rt_wdt_init);
  243. #endif /* RT_USING_WDT */