hw_timerserver.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. /**
  2. ******************************************************************************
  3. * File Name : hw_timerserver.c
  4. * Description : Hardware timerserver source file for STM32WPAN Middleware.
  5. *
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  10. * All rights reserved.</center></h2>
  11. *
  12. * This software component is licensed by ST under Ultimate Liberty license
  13. * SLA0044, the "License"; You may not use this file except in compliance with
  14. * the License. You may obtain a copy of the License at:
  15. * www.st.com/SLA0044
  16. *
  17. ******************************************************************************
  18. */
  19. /* Includes ------------------------------------------------------------------*/
  20. #include "app_common.h"
  21. #include "hw_conf.h"
  22. /* Private typedef -----------------------------------------------------------*/
  23. typedef enum
  24. {
  25. TimerID_Free,
  26. TimerID_Created,
  27. TimerID_Running
  28. }TimerIDStatus_t;
  29. typedef enum
  30. {
  31. SSR_Read_Requested,
  32. SSR_Read_Not_Requested
  33. }RequestReadSSR_t;
  34. typedef enum
  35. {
  36. WakeupTimerValue_Overpassed,
  37. WakeupTimerValue_LargeEnough
  38. }WakeupTimerLimitation_Status_t;
  39. typedef struct
  40. {
  41. HW_TS_pTimerCb_t pTimerCallBack;
  42. uint32_t CounterInit;
  43. uint32_t CountLeft;
  44. TimerIDStatus_t TimerIDStatus;
  45. HW_TS_Mode_t TimerMode;
  46. uint32_t TimerProcessID;
  47. uint8_t PreviousID;
  48. uint8_t NextID;
  49. }TimerContext_t;
  50. /* Private defines -----------------------------------------------------------*/
  51. #define SSR_FORBIDDEN_VALUE 0xFFFFFFFF
  52. #define TIMER_LIST_EMPTY 0xFFFF
  53. /* Private macros ------------------------------------------------------------*/
  54. /* Private variables ---------------------------------------------------------*/
  55. /**
  56. * START of Section TIMERSERVER_CONTEXT
  57. */
  58. PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile TimerContext_t aTimerContext[CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER];
  59. PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile uint8_t CurrentRunningTimerID;
  60. PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile uint8_t PreviousRunningTimerID;
  61. PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile uint32_t SSRValueOnLastSetup;
  62. PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile WakeupTimerLimitation_Status_t WakeupTimerLimitation;
  63. /**
  64. * END of Section TIMERSERVER_CONTEXT
  65. */
  66. static RTC_HandleTypeDef *phrtc; /**< RTC handle */
  67. static uint8_t WakeupTimerDivider;
  68. static uint8_t AsynchPrescalerUserConfig;
  69. static uint16_t SynchPrescalerUserConfig;
  70. static volatile uint16_t MaxWakeupTimerSetup;
  71. /* Global variables ----------------------------------------------------------*/
  72. /* Private function prototypes -----------------------------------------------*/
  73. static void RestartWakeupCounter(uint16_t Value);
  74. static uint16_t ReturnTimeElapsed(void);
  75. static void RescheduleTimerList(void);
  76. static void UnlinkTimer(uint8_t TimerID, RequestReadSSR_t RequestReadSSR);
  77. static void LinkTimerBefore(uint8_t TimerID, uint8_t RefTimerID);
  78. static void LinkTimerAfter(uint8_t TimerID, uint8_t RefTimerID);
  79. static uint16_t linkTimer(uint8_t TimerID);
  80. static uint32_t ReadRtcSsrValue(void);
  81. __weak void HW_TS_RTC_CountUpdated_AppNot(void);
  82. /* Functions Definition ------------------------------------------------------*/
  83. /**
  84. * @brief Read the RTC_SSR value
  85. * As described in the reference manual, the RTC_SSR shall be read twice to ensure
  86. * reliability of the value
  87. * @param None
  88. * @retval SSR value read
  89. */
  90. static uint32_t ReadRtcSsrValue(void)
  91. {
  92. uint32_t first_read;
  93. uint32_t second_read;
  94. first_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS));
  95. second_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS));
  96. while(first_read != second_read)
  97. {
  98. first_read = second_read;
  99. second_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS));
  100. }
  101. return second_read;
  102. }
  103. /**
  104. * @brief Insert a Timer in the list after the Timer ID specified
  105. * @param TimerID: The ID of the Timer
  106. * @param RefTimerID: The ID of the Timer to be linked after
  107. * @retval None
  108. */
  109. static void LinkTimerAfter(uint8_t TimerID, uint8_t RefTimerID)
  110. {
  111. uint8_t next_id;
  112. next_id = aTimerContext[RefTimerID].NextID;
  113. if(next_id != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER)
  114. {
  115. aTimerContext[next_id].PreviousID = TimerID;
  116. }
  117. aTimerContext[TimerID].NextID = next_id;
  118. aTimerContext[TimerID].PreviousID = RefTimerID ;
  119. aTimerContext[RefTimerID].NextID = TimerID;
  120. return;
  121. }
  122. /**
  123. * @brief Insert a Timer in the list before the ID specified
  124. * @param TimerID: The ID of the Timer
  125. * @param RefTimerID: The ID of the Timer to be linked before
  126. * @retval None
  127. */
  128. static void LinkTimerBefore(uint8_t TimerID, uint8_t RefTimerID)
  129. {
  130. uint8_t previous_id;
  131. if(RefTimerID != CurrentRunningTimerID)
  132. {
  133. previous_id = aTimerContext[RefTimerID].PreviousID;
  134. aTimerContext[previous_id].NextID = TimerID;
  135. aTimerContext[TimerID].NextID = RefTimerID;
  136. aTimerContext[TimerID].PreviousID = previous_id ;
  137. aTimerContext[RefTimerID].PreviousID = TimerID;
  138. }
  139. else
  140. {
  141. aTimerContext[TimerID].NextID = RefTimerID;
  142. aTimerContext[RefTimerID].PreviousID = TimerID;
  143. }
  144. return;
  145. }
  146. /**
  147. * @brief Insert a Timer in the list
  148. * @param TimerID: The ID of the Timer
  149. * @retval None
  150. */
  151. static uint16_t linkTimer(uint8_t TimerID)
  152. {
  153. uint32_t time_left;
  154. uint16_t time_elapsed;
  155. uint8_t timer_id_lookup;
  156. uint8_t next_id;
  157. if(CurrentRunningTimerID == CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER)
  158. {
  159. /**
  160. * No timer in the list
  161. */
  162. PreviousRunningTimerID = CurrentRunningTimerID;
  163. CurrentRunningTimerID = TimerID;
  164. aTimerContext[TimerID].NextID = CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER;
  165. SSRValueOnLastSetup = SSR_FORBIDDEN_VALUE;
  166. time_elapsed = 0;
  167. }
  168. else
  169. {
  170. time_elapsed = ReturnTimeElapsed();
  171. /**
  172. * update count of the timer to be linked
  173. */
  174. aTimerContext[TimerID].CountLeft += time_elapsed;
  175. time_left = aTimerContext[TimerID].CountLeft;
  176. /**
  177. * Search for index where the new timer shall be linked
  178. */
  179. if(aTimerContext[CurrentRunningTimerID].CountLeft <= time_left)
  180. {
  181. /**
  182. * Search for the ID after the first one
  183. */
  184. timer_id_lookup = CurrentRunningTimerID;
  185. next_id = aTimerContext[timer_id_lookup].NextID;
  186. while((next_id != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) && (aTimerContext[next_id].CountLeft <= time_left))
  187. {
  188. timer_id_lookup = aTimerContext[timer_id_lookup].NextID;
  189. next_id = aTimerContext[timer_id_lookup].NextID;
  190. }
  191. /**
  192. * Link after the ID
  193. */
  194. LinkTimerAfter(TimerID, timer_id_lookup);
  195. }
  196. else
  197. {
  198. /**
  199. * Link before the first ID
  200. */
  201. LinkTimerBefore(TimerID, CurrentRunningTimerID);
  202. PreviousRunningTimerID = CurrentRunningTimerID;
  203. CurrentRunningTimerID = TimerID;
  204. }
  205. }
  206. return time_elapsed;
  207. }
  208. /**
  209. * @brief Remove a Timer from the list
  210. * @param TimerID: The ID of the Timer
  211. * @param RequestReadSSR: Request to read the SSR register or not
  212. * @retval None
  213. */
  214. static void UnlinkTimer(uint8_t TimerID, RequestReadSSR_t RequestReadSSR)
  215. {
  216. uint8_t previous_id;
  217. uint8_t next_id;
  218. if(TimerID == CurrentRunningTimerID)
  219. {
  220. PreviousRunningTimerID = CurrentRunningTimerID;
  221. CurrentRunningTimerID = aTimerContext[TimerID].NextID;
  222. }
  223. else
  224. {
  225. previous_id = aTimerContext[TimerID].PreviousID;
  226. next_id = aTimerContext[TimerID].NextID;
  227. aTimerContext[previous_id].NextID = aTimerContext[TimerID].NextID;
  228. if(next_id != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER)
  229. {
  230. aTimerContext[next_id].PreviousID = aTimerContext[TimerID].PreviousID;
  231. }
  232. }
  233. /**
  234. * Timer is out of the list
  235. */
  236. aTimerContext[TimerID].TimerIDStatus = TimerID_Created;
  237. if((CurrentRunningTimerID == CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) && (RequestReadSSR == SSR_Read_Requested))
  238. {
  239. SSRValueOnLastSetup = SSR_FORBIDDEN_VALUE;
  240. }
  241. return;
  242. }
  243. /**
  244. * @brief Return the number of ticks counted by the wakeuptimer since it has been started
  245. * @note The API is reading the SSR register to get how many ticks have been counted
  246. * since the time the timer has been started
  247. * @param None
  248. * @retval Time expired in Ticks
  249. */
  250. static uint16_t ReturnTimeElapsed(void)
  251. {
  252. uint32_t return_value;
  253. uint32_t wrap_counter;
  254. if(SSRValueOnLastSetup != SSR_FORBIDDEN_VALUE)
  255. {
  256. return_value = ReadRtcSsrValue(); /**< Read SSR register first */
  257. if (SSRValueOnLastSetup >= return_value)
  258. {
  259. return_value = SSRValueOnLastSetup - return_value;
  260. }
  261. else
  262. {
  263. wrap_counter = SynchPrescalerUserConfig - return_value;
  264. return_value = SSRValueOnLastSetup + wrap_counter;
  265. }
  266. /**
  267. * At this stage, ReturnValue holds the number of ticks counted by SSR
  268. * Need to translate in number of ticks counted by the Wakeuptimer
  269. */
  270. return_value = return_value*AsynchPrescalerUserConfig;
  271. return_value = return_value >> WakeupTimerDivider;
  272. }
  273. else
  274. {
  275. return_value = 0;
  276. }
  277. return (uint16_t)return_value;
  278. }
  279. /**
  280. * @brief Set the wakeup counter
  281. * @note The API is writing the counter value so that the value is decreased by one to cope with the fact
  282. * the interrupt is generated with 1 extra clock cycle (See RefManuel)
  283. * It assumes all condition are met to be allowed to write the wakeup counter
  284. * @param Value: Value to be written in the counter
  285. * @retval None
  286. */
  287. static void RestartWakeupCounter(uint16_t Value)
  288. {
  289. /**
  290. * The wakeuptimer has been disabled in the calling function to reduce the time to poll the WUTWF
  291. * FLAG when the new value will have to be written
  292. * __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc);
  293. */
  294. if(Value == 0)
  295. {
  296. SSRValueOnLastSetup = ReadRtcSsrValue();
  297. /**
  298. * Simulate that the Timer expired
  299. */
  300. HAL_NVIC_SetPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID);
  301. }
  302. else
  303. {
  304. if((Value > 1) ||(WakeupTimerDivider != 1))
  305. {
  306. Value -= 1;
  307. }
  308. while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET);
  309. /**
  310. * make sure to clear the flags after checking the WUTWF.
  311. * It takes 2 RTCCLK between the time the WUTE bit is disabled and the
  312. * time the timer is disabled. The WUTWF bit somehow guarantee the system is stable
  313. * Otherwise, when the timer is periodic with 1 Tick, it may generate an extra interrupt in between
  314. * due to the autoreload feature
  315. */
  316. __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */
  317. __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */
  318. HAL_NVIC_ClearPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Clear pending bit in NVIC */
  319. MODIFY_REG(RTC->WUTR, RTC_WUTR_WUT, Value);
  320. /**
  321. * Update the value here after the WUTWF polling that may take some time
  322. */
  323. SSRValueOnLastSetup = ReadRtcSsrValue();
  324. __HAL_RTC_WAKEUPTIMER_ENABLE(phrtc); /**< Enable the Wakeup Timer */
  325. HW_TS_RTC_CountUpdated_AppNot();
  326. }
  327. return ;
  328. }
  329. /**
  330. * @brief Reschedule the list of timer
  331. * @note 1) Update the count left for each timer in the list
  332. * 2) Setup the wakeuptimer
  333. * @param None
  334. * @retval None
  335. */
  336. static void RescheduleTimerList(void)
  337. {
  338. uint8_t localTimerID;
  339. uint32_t timecountleft;
  340. uint16_t wakeup_timer_value;
  341. uint16_t time_elapsed;
  342. /**
  343. * The wakeuptimer is disabled now to reduce the time to poll the WUTWF
  344. * FLAG when the new value will have to be written
  345. */
  346. if((READ_BIT(RTC->CR, RTC_CR_WUTE) == (RTC_CR_WUTE)) == SET)
  347. {
  348. /**
  349. * Wait for the flag to be back to 0 when the wakeup timer is enabled
  350. */
  351. while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == SET);
  352. }
  353. __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); /**< Disable the Wakeup Timer */
  354. localTimerID = CurrentRunningTimerID;
  355. /**
  356. * Calculate what will be the value to write in the wakeuptimer
  357. */
  358. timecountleft = aTimerContext[localTimerID].CountLeft;
  359. /**
  360. * Read how much has been counted
  361. */
  362. time_elapsed = ReturnTimeElapsed();
  363. if(timecountleft < time_elapsed )
  364. {
  365. /**
  366. * There is no tick left to count
  367. */
  368. wakeup_timer_value = 0;
  369. WakeupTimerLimitation = WakeupTimerValue_LargeEnough;
  370. }
  371. else
  372. {
  373. if(timecountleft > (time_elapsed + MaxWakeupTimerSetup))
  374. {
  375. /**
  376. * The number of tick left is greater than the Wakeuptimer maximum value
  377. */
  378. wakeup_timer_value = MaxWakeupTimerSetup;
  379. WakeupTimerLimitation = WakeupTimerValue_Overpassed;
  380. }
  381. else
  382. {
  383. wakeup_timer_value = timecountleft - time_elapsed;
  384. WakeupTimerLimitation = WakeupTimerValue_LargeEnough;
  385. }
  386. }
  387. /**
  388. * update ticks left to be counted for each timer
  389. */
  390. while(localTimerID != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER)
  391. {
  392. if (aTimerContext[localTimerID].CountLeft < time_elapsed)
  393. {
  394. aTimerContext[localTimerID].CountLeft = 0;
  395. }
  396. else
  397. {
  398. aTimerContext[localTimerID].CountLeft -= time_elapsed;
  399. }
  400. localTimerID = aTimerContext[localTimerID].NextID;
  401. }
  402. /**
  403. * Write next count
  404. */
  405. RestartWakeupCounter(wakeup_timer_value);
  406. return ;
  407. }
  408. /* Public functions ----------------------------------------------------------*/
  409. /**
  410. * For all public interface except that may need write access to the RTC, the RTC
  411. * shall be unlock at the beginning and locked at the output
  412. * In order to ease maintainability, the unlock is done at the top and the lock at then end
  413. * in case some new implementation is coming in the future
  414. */
  415. void HW_TS_RTC_Wakeup_Handler(void)
  416. {
  417. HW_TS_pTimerCb_t ptimer_callback;
  418. uint32_t timer_process_id;
  419. uint8_t local_current_running_timer_id;
  420. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  421. uint32_t primask_bit;
  422. #endif
  423. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  424. primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
  425. __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
  426. #endif
  427. /* Disable the write protection for RTC registers */
  428. __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc );
  429. /**
  430. * Disable the Wakeup Timer
  431. * This may speed up a bit the processing to wait the timer to be disabled
  432. * The timer is still counting 2 RTCCLK
  433. */
  434. __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc);
  435. local_current_running_timer_id = CurrentRunningTimerID;
  436. if(aTimerContext[local_current_running_timer_id].TimerIDStatus == TimerID_Running)
  437. {
  438. ptimer_callback = aTimerContext[local_current_running_timer_id].pTimerCallBack;
  439. timer_process_id = aTimerContext[local_current_running_timer_id].TimerProcessID;
  440. /**
  441. * It should be good to check whether the TimeElapsed is greater or not than the tick left to be counted
  442. * However, due to the inaccuracy of the reading of the time elapsed, it may return there is 1 tick
  443. * to be left whereas the count is over
  444. * A more secure implementation has been done with a flag to state whereas the full count has been written
  445. * in the wakeuptimer or not
  446. */
  447. if(WakeupTimerLimitation != WakeupTimerValue_Overpassed)
  448. {
  449. if(aTimerContext[local_current_running_timer_id].TimerMode == hw_ts_Repeated)
  450. {
  451. UnlinkTimer(local_current_running_timer_id, SSR_Read_Not_Requested);
  452. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  453. __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
  454. #endif
  455. HW_TS_Start(local_current_running_timer_id, aTimerContext[local_current_running_timer_id].CounterInit);
  456. /* Disable the write protection for RTC registers */
  457. __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc );
  458. }
  459. else
  460. {
  461. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  462. __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
  463. #endif
  464. HW_TS_Stop(local_current_running_timer_id);
  465. /* Disable the write protection for RTC registers */
  466. __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc );
  467. }
  468. HW_TS_RTC_Int_AppNot(timer_process_id, local_current_running_timer_id, ptimer_callback);
  469. }
  470. else
  471. {
  472. RescheduleTimerList();
  473. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  474. __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
  475. #endif
  476. }
  477. }
  478. else
  479. {
  480. /**
  481. * We should never end up in this case
  482. * However, if due to any bug in the timer server this is the case, the mistake may not impact the user.
  483. * We could just clean the interrupt flag and get out from this unexpected interrupt
  484. */
  485. while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET);
  486. /**
  487. * make sure to clear the flags after checking the WUTWF.
  488. * It takes 2 RTCCLK between the time the WUTE bit is disabled and the
  489. * time the timer is disabled. The WUTWF bit somehow guarantee the system is stable
  490. * Otherwise, when the timer is periodic with 1 Tick, it may generate an extra interrupt in between
  491. * due to the autoreload feature
  492. */
  493. __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */
  494. __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */
  495. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  496. __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
  497. #endif
  498. }
  499. /* Enable the write protection for RTC registers */
  500. __HAL_RTC_WRITEPROTECTION_ENABLE( phrtc );
  501. return;
  502. }
  503. void HW_TS_Init(HW_TS_InitMode_t TimerInitMode, RTC_HandleTypeDef *hrtc)
  504. {
  505. uint8_t loop;
  506. uint32_t localmaxwakeuptimersetup;
  507. /**
  508. * Get RTC handler
  509. */
  510. phrtc = hrtc;
  511. /* Disable the write protection for RTC registers */
  512. __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc );
  513. SET_BIT(RTC->CR, RTC_CR_BYPSHAD);
  514. /**
  515. * Readout the user config
  516. */
  517. WakeupTimerDivider = (4 - ((uint32_t)(READ_BIT(RTC->CR, RTC_CR_WUCKSEL))));
  518. AsynchPrescalerUserConfig = (uint8_t)(READ_BIT(RTC->PRER, RTC_PRER_PREDIV_A) >> (uint32_t)POSITION_VAL(RTC_PRER_PREDIV_A)) + 1;
  519. SynchPrescalerUserConfig = (uint16_t)(READ_BIT(RTC->PRER, RTC_PRER_PREDIV_S)) + 1;
  520. /**
  521. * Margin is taken to avoid wrong calculation when the wrap around is there and some
  522. * application interrupts may have delayed the reading
  523. */
  524. localmaxwakeuptimersetup = ((((SynchPrescalerUserConfig - 1)*AsynchPrescalerUserConfig) - CFG_HW_TS_RTC_HANDLER_MAX_DELAY) >> WakeupTimerDivider);
  525. if(localmaxwakeuptimersetup >= 0xFFFF)
  526. {
  527. MaxWakeupTimerSetup = 0xFFFF;
  528. }
  529. else
  530. {
  531. MaxWakeupTimerSetup = (uint16_t)localmaxwakeuptimersetup;
  532. }
  533. /**
  534. * Configure EXTI module
  535. */
  536. LL_EXTI_EnableRisingTrig_0_31(RTC_EXTI_LINE_WAKEUPTIMER_EVENT);
  537. LL_EXTI_EnableIT_0_31(RTC_EXTI_LINE_WAKEUPTIMER_EVENT);
  538. if(TimerInitMode == hw_ts_InitMode_Full)
  539. {
  540. WakeupTimerLimitation = WakeupTimerValue_LargeEnough;
  541. SSRValueOnLastSetup = SSR_FORBIDDEN_VALUE;
  542. /**
  543. * Initialize the timer server
  544. */
  545. for(loop = 0; loop < CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER; loop++)
  546. {
  547. aTimerContext[loop].TimerIDStatus = TimerID_Free;
  548. }
  549. CurrentRunningTimerID = CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER; /**< Set ID to non valid value */
  550. __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); /**< Disable the Wakeup Timer */
  551. __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */
  552. __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */
  553. HAL_NVIC_ClearPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Clear pending bit in NVIC */
  554. __HAL_RTC_WAKEUPTIMER_ENABLE_IT(phrtc, RTC_IT_WUT); /**< Enable interrupt in RTC module */
  555. }
  556. else
  557. {
  558. if(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTF) != RESET)
  559. {
  560. /**
  561. * Simulate that the Timer expired
  562. */
  563. HAL_NVIC_SetPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID);
  564. }
  565. }
  566. /* Enable the write protection for RTC registers */
  567. __HAL_RTC_WRITEPROTECTION_ENABLE( phrtc );
  568. HAL_NVIC_SetPriority(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID, CFG_HW_TS_NVIC_RTC_WAKEUP_IT_PREEMPTPRIO, CFG_HW_TS_NVIC_RTC_WAKEUP_IT_SUBPRIO); /**< Set NVIC priority */
  569. HAL_NVIC_EnableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Enable NVIC */
  570. return;
  571. }
  572. HW_TS_ReturnStatus_t HW_TS_Create(uint32_t TimerProcessID, uint8_t *pTimerId, HW_TS_Mode_t TimerMode, HW_TS_pTimerCb_t pftimeout_handler)
  573. {
  574. HW_TS_ReturnStatus_t localreturnstatus;
  575. uint8_t loop = 0;
  576. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  577. uint32_t primask_bit;
  578. #endif
  579. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  580. primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
  581. __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
  582. #endif
  583. while((loop < CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) && (aTimerContext[loop].TimerIDStatus != TimerID_Free))
  584. {
  585. loop++;
  586. }
  587. if(loop != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER)
  588. {
  589. aTimerContext[loop].TimerIDStatus = TimerID_Created;
  590. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  591. __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
  592. #endif
  593. aTimerContext[loop].TimerProcessID = TimerProcessID;
  594. aTimerContext[loop].TimerMode = TimerMode;
  595. aTimerContext[loop].pTimerCallBack = pftimeout_handler;
  596. *pTimerId = loop;
  597. localreturnstatus = hw_ts_Successful;
  598. }
  599. else
  600. {
  601. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  602. __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
  603. #endif
  604. localreturnstatus = hw_ts_Failed;
  605. }
  606. return(localreturnstatus);
  607. }
  608. void HW_TS_Delete(uint8_t timer_id)
  609. {
  610. HW_TS_Stop(timer_id);
  611. aTimerContext[timer_id].TimerIDStatus = TimerID_Free; /**< release ID */
  612. return;
  613. }
  614. void HW_TS_Stop(uint8_t timer_id)
  615. {
  616. uint8_t localcurrentrunningtimerid;
  617. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  618. uint32_t primask_bit;
  619. #endif
  620. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  621. primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
  622. __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
  623. #endif
  624. HAL_NVIC_DisableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Disable NVIC */
  625. /* Disable the write protection for RTC registers */
  626. __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc );
  627. if(aTimerContext[timer_id].TimerIDStatus == TimerID_Running)
  628. {
  629. UnlinkTimer(timer_id, SSR_Read_Requested);
  630. localcurrentrunningtimerid = CurrentRunningTimerID;
  631. if(localcurrentrunningtimerid == CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER)
  632. {
  633. /**
  634. * List is empty
  635. */
  636. /**
  637. * Disable the timer
  638. */
  639. if((READ_BIT(RTC->CR, RTC_CR_WUTE) == (RTC_CR_WUTE)) == SET)
  640. {
  641. /**
  642. * Wait for the flag to be back to 0 when the wakeup timer is enabled
  643. */
  644. while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == SET);
  645. }
  646. __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); /**< Disable the Wakeup Timer */
  647. while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET);
  648. /**
  649. * make sure to clear the flags after checking the WUTWF.
  650. * It takes 2 RTCCLK between the time the WUTE bit is disabled and the
  651. * time the timer is disabled. The WUTWF bit somehow guarantee the system is stable
  652. * Otherwise, when the timer is periodic with 1 Tick, it may generate an extra interrupt in between
  653. * due to the autoreload feature
  654. */
  655. __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */
  656. __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */
  657. HAL_NVIC_ClearPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Clear pending bit in NVIC */
  658. }
  659. else if(PreviousRunningTimerID != localcurrentrunningtimerid)
  660. {
  661. RescheduleTimerList();
  662. }
  663. }
  664. /* Enable the write protection for RTC registers */
  665. __HAL_RTC_WRITEPROTECTION_ENABLE( phrtc );
  666. HAL_NVIC_EnableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Enable NVIC */
  667. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  668. __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
  669. #endif
  670. return;
  671. }
  672. void HW_TS_Start(uint8_t timer_id, uint32_t timeout_ticks)
  673. {
  674. uint16_t time_elapsed;
  675. uint8_t localcurrentrunningtimerid;
  676. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  677. uint32_t primask_bit;
  678. #endif
  679. if(aTimerContext[timer_id].TimerIDStatus == TimerID_Running)
  680. {
  681. HW_TS_Stop( timer_id );
  682. }
  683. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  684. primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
  685. __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
  686. #endif
  687. HAL_NVIC_DisableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Disable NVIC */
  688. /* Disable the write protection for RTC registers */
  689. __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc );
  690. aTimerContext[timer_id].TimerIDStatus = TimerID_Running;
  691. aTimerContext[timer_id].CountLeft = timeout_ticks;
  692. aTimerContext[timer_id].CounterInit = timeout_ticks;
  693. time_elapsed = linkTimer(timer_id);
  694. localcurrentrunningtimerid = CurrentRunningTimerID;
  695. if(PreviousRunningTimerID != localcurrentrunningtimerid)
  696. {
  697. RescheduleTimerList();
  698. }
  699. else
  700. {
  701. aTimerContext[timer_id].CountLeft -= time_elapsed;
  702. }
  703. /* Enable the write protection for RTC registers */
  704. __HAL_RTC_WRITEPROTECTION_ENABLE( phrtc );
  705. HAL_NVIC_EnableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Enable NVIC */
  706. #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
  707. __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
  708. #endif
  709. return;
  710. }
  711. uint16_t HW_TS_RTC_ReadLeftTicksToCount(void)
  712. {
  713. uint32_t primask_bit;
  714. uint16_t return_value, auro_reload_value, elapsed_time_value;
  715. primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
  716. __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
  717. if((READ_BIT(RTC->CR, RTC_CR_WUTE) == (RTC_CR_WUTE)) == SET)
  718. {
  719. auro_reload_value = (uint32_t)(READ_BIT(RTC->WUTR, RTC_WUTR_WUT));
  720. elapsed_time_value = ReturnTimeElapsed();
  721. if(auro_reload_value > elapsed_time_value)
  722. {
  723. return_value = auro_reload_value - elapsed_time_value;
  724. }
  725. else
  726. {
  727. return_value = 0;
  728. }
  729. }
  730. else
  731. {
  732. return_value = TIMER_LIST_EMPTY;
  733. }
  734. __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
  735. return (return_value);
  736. }
  737. __weak void HW_TS_RTC_Int_AppNot(uint32_t TimerProcessID, uint8_t TimerID, HW_TS_pTimerCb_t pTimerCallBack)
  738. {
  739. pTimerCallBack();
  740. return;
  741. }
  742. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/