/** ****************************************************************************** * File Name : hw_timerserver.c * Description : Hardware timerserver source file for STM32WPAN Middleware. * ****************************************************************************** * @attention * *

© Copyright (c) 2020 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "app_common.h" #include "hw_conf.h" /* Private typedef -----------------------------------------------------------*/ typedef enum { TimerID_Free, TimerID_Created, TimerID_Running }TimerIDStatus_t; typedef enum { SSR_Read_Requested, SSR_Read_Not_Requested }RequestReadSSR_t; typedef enum { WakeupTimerValue_Overpassed, WakeupTimerValue_LargeEnough }WakeupTimerLimitation_Status_t; typedef struct { HW_TS_pTimerCb_t pTimerCallBack; uint32_t CounterInit; uint32_t CountLeft; TimerIDStatus_t TimerIDStatus; HW_TS_Mode_t TimerMode; uint32_t TimerProcessID; uint8_t PreviousID; uint8_t NextID; }TimerContext_t; /* Private defines -----------------------------------------------------------*/ #define SSR_FORBIDDEN_VALUE 0xFFFFFFFF #define TIMER_LIST_EMPTY 0xFFFF /* Private macros ------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ /** * START of Section TIMERSERVER_CONTEXT */ PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile TimerContext_t aTimerContext[CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER]; PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile uint8_t CurrentRunningTimerID; PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile uint8_t PreviousRunningTimerID; PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile uint32_t SSRValueOnLastSetup; PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile WakeupTimerLimitation_Status_t WakeupTimerLimitation; /** * END of Section TIMERSERVER_CONTEXT */ static RTC_HandleTypeDef *phrtc; /**< RTC handle */ static uint8_t WakeupTimerDivider; static uint8_t AsynchPrescalerUserConfig; static uint16_t SynchPrescalerUserConfig; static volatile uint16_t MaxWakeupTimerSetup; /* Global variables ----------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ static void RestartWakeupCounter(uint16_t Value); static uint16_t ReturnTimeElapsed(void); static void RescheduleTimerList(void); static void UnlinkTimer(uint8_t TimerID, RequestReadSSR_t RequestReadSSR); static void LinkTimerBefore(uint8_t TimerID, uint8_t RefTimerID); static void LinkTimerAfter(uint8_t TimerID, uint8_t RefTimerID); static uint16_t linkTimer(uint8_t TimerID); static uint32_t ReadRtcSsrValue(void); __weak void HW_TS_RTC_CountUpdated_AppNot(void); /* Functions Definition ------------------------------------------------------*/ /** * @brief Read the RTC_SSR value * As described in the reference manual, the RTC_SSR shall be read twice to ensure * reliability of the value * @param None * @retval SSR value read */ static uint32_t ReadRtcSsrValue(void) { uint32_t first_read; uint32_t second_read; first_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS)); second_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS)); while(first_read != second_read) { first_read = second_read; second_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS)); } return second_read; } /** * @brief Insert a Timer in the list after the Timer ID specified * @param TimerID: The ID of the Timer * @param RefTimerID: The ID of the Timer to be linked after * @retval None */ static void LinkTimerAfter(uint8_t TimerID, uint8_t RefTimerID) { uint8_t next_id; next_id = aTimerContext[RefTimerID].NextID; if(next_id != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) { aTimerContext[next_id].PreviousID = TimerID; } aTimerContext[TimerID].NextID = next_id; aTimerContext[TimerID].PreviousID = RefTimerID ; aTimerContext[RefTimerID].NextID = TimerID; return; } /** * @brief Insert a Timer in the list before the ID specified * @param TimerID: The ID of the Timer * @param RefTimerID: The ID of the Timer to be linked before * @retval None */ static void LinkTimerBefore(uint8_t TimerID, uint8_t RefTimerID) { uint8_t previous_id; if(RefTimerID != CurrentRunningTimerID) { previous_id = aTimerContext[RefTimerID].PreviousID; aTimerContext[previous_id].NextID = TimerID; aTimerContext[TimerID].NextID = RefTimerID; aTimerContext[TimerID].PreviousID = previous_id ; aTimerContext[RefTimerID].PreviousID = TimerID; } else { aTimerContext[TimerID].NextID = RefTimerID; aTimerContext[RefTimerID].PreviousID = TimerID; } return; } /** * @brief Insert a Timer in the list * @param TimerID: The ID of the Timer * @retval None */ static uint16_t linkTimer(uint8_t TimerID) { uint32_t time_left; uint16_t time_elapsed; uint8_t timer_id_lookup; uint8_t next_id; if(CurrentRunningTimerID == CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) { /** * No timer in the list */ PreviousRunningTimerID = CurrentRunningTimerID; CurrentRunningTimerID = TimerID; aTimerContext[TimerID].NextID = CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER; SSRValueOnLastSetup = SSR_FORBIDDEN_VALUE; time_elapsed = 0; } else { time_elapsed = ReturnTimeElapsed(); /** * update count of the timer to be linked */ aTimerContext[TimerID].CountLeft += time_elapsed; time_left = aTimerContext[TimerID].CountLeft; /** * Search for index where the new timer shall be linked */ if(aTimerContext[CurrentRunningTimerID].CountLeft <= time_left) { /** * Search for the ID after the first one */ timer_id_lookup = CurrentRunningTimerID; next_id = aTimerContext[timer_id_lookup].NextID; while((next_id != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) && (aTimerContext[next_id].CountLeft <= time_left)) { timer_id_lookup = aTimerContext[timer_id_lookup].NextID; next_id = aTimerContext[timer_id_lookup].NextID; } /** * Link after the ID */ LinkTimerAfter(TimerID, timer_id_lookup); } else { /** * Link before the first ID */ LinkTimerBefore(TimerID, CurrentRunningTimerID); PreviousRunningTimerID = CurrentRunningTimerID; CurrentRunningTimerID = TimerID; } } return time_elapsed; } /** * @brief Remove a Timer from the list * @param TimerID: The ID of the Timer * @param RequestReadSSR: Request to read the SSR register or not * @retval None */ static void UnlinkTimer(uint8_t TimerID, RequestReadSSR_t RequestReadSSR) { uint8_t previous_id; uint8_t next_id; if(TimerID == CurrentRunningTimerID) { PreviousRunningTimerID = CurrentRunningTimerID; CurrentRunningTimerID = aTimerContext[TimerID].NextID; } else { previous_id = aTimerContext[TimerID].PreviousID; next_id = aTimerContext[TimerID].NextID; aTimerContext[previous_id].NextID = aTimerContext[TimerID].NextID; if(next_id != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) { aTimerContext[next_id].PreviousID = aTimerContext[TimerID].PreviousID; } } /** * Timer is out of the list */ aTimerContext[TimerID].TimerIDStatus = TimerID_Created; if((CurrentRunningTimerID == CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) && (RequestReadSSR == SSR_Read_Requested)) { SSRValueOnLastSetup = SSR_FORBIDDEN_VALUE; } return; } /** * @brief Return the number of ticks counted by the wakeuptimer since it has been started * @note The API is reading the SSR register to get how many ticks have been counted * since the time the timer has been started * @param None * @retval Time expired in Ticks */ static uint16_t ReturnTimeElapsed(void) { uint32_t return_value; uint32_t wrap_counter; if(SSRValueOnLastSetup != SSR_FORBIDDEN_VALUE) { return_value = ReadRtcSsrValue(); /**< Read SSR register first */ if (SSRValueOnLastSetup >= return_value) { return_value = SSRValueOnLastSetup - return_value; } else { wrap_counter = SynchPrescalerUserConfig - return_value; return_value = SSRValueOnLastSetup + wrap_counter; } /** * At this stage, ReturnValue holds the number of ticks counted by SSR * Need to translate in number of ticks counted by the Wakeuptimer */ return_value = return_value*AsynchPrescalerUserConfig; return_value = return_value >> WakeupTimerDivider; } else { return_value = 0; } return (uint16_t)return_value; } /** * @brief Set the wakeup counter * @note The API is writing the counter value so that the value is decreased by one to cope with the fact * the interrupt is generated with 1 extra clock cycle (See RefManuel) * It assumes all condition are met to be allowed to write the wakeup counter * @param Value: Value to be written in the counter * @retval None */ static void RestartWakeupCounter(uint16_t Value) { /** * The wakeuptimer has been disabled in the calling function to reduce the time to poll the WUTWF * FLAG when the new value will have to be written * __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); */ if(Value == 0) { SSRValueOnLastSetup = ReadRtcSsrValue(); /** * Simulate that the Timer expired */ HAL_NVIC_SetPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); } else { if((Value > 1) ||(WakeupTimerDivider != 1)) { Value -= 1; } while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET); /** * make sure to clear the flags after checking the WUTWF. * It takes 2 RTCCLK between the time the WUTE bit is disabled and the * time the timer is disabled. The WUTWF bit somehow guarantee the system is stable * Otherwise, when the timer is periodic with 1 Tick, it may generate an extra interrupt in between * due to the autoreload feature */ __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */ __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */ HAL_NVIC_ClearPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Clear pending bit in NVIC */ MODIFY_REG(RTC->WUTR, RTC_WUTR_WUT, Value); /** * Update the value here after the WUTWF polling that may take some time */ SSRValueOnLastSetup = ReadRtcSsrValue(); __HAL_RTC_WAKEUPTIMER_ENABLE(phrtc); /**< Enable the Wakeup Timer */ HW_TS_RTC_CountUpdated_AppNot(); } return ; } /** * @brief Reschedule the list of timer * @note 1) Update the count left for each timer in the list * 2) Setup the wakeuptimer * @param None * @retval None */ static void RescheduleTimerList(void) { uint8_t localTimerID; uint32_t timecountleft; uint16_t wakeup_timer_value; uint16_t time_elapsed; /** * The wakeuptimer is disabled now to reduce the time to poll the WUTWF * FLAG when the new value will have to be written */ if((READ_BIT(RTC->CR, RTC_CR_WUTE) == (RTC_CR_WUTE)) == SET) { /** * Wait for the flag to be back to 0 when the wakeup timer is enabled */ while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == SET); } __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); /**< Disable the Wakeup Timer */ localTimerID = CurrentRunningTimerID; /** * Calculate what will be the value to write in the wakeuptimer */ timecountleft = aTimerContext[localTimerID].CountLeft; /** * Read how much has been counted */ time_elapsed = ReturnTimeElapsed(); if(timecountleft < time_elapsed ) { /** * There is no tick left to count */ wakeup_timer_value = 0; WakeupTimerLimitation = WakeupTimerValue_LargeEnough; } else { if(timecountleft > (time_elapsed + MaxWakeupTimerSetup)) { /** * The number of tick left is greater than the Wakeuptimer maximum value */ wakeup_timer_value = MaxWakeupTimerSetup; WakeupTimerLimitation = WakeupTimerValue_Overpassed; } else { wakeup_timer_value = timecountleft - time_elapsed; WakeupTimerLimitation = WakeupTimerValue_LargeEnough; } } /** * update ticks left to be counted for each timer */ while(localTimerID != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) { if (aTimerContext[localTimerID].CountLeft < time_elapsed) { aTimerContext[localTimerID].CountLeft = 0; } else { aTimerContext[localTimerID].CountLeft -= time_elapsed; } localTimerID = aTimerContext[localTimerID].NextID; } /** * Write next count */ RestartWakeupCounter(wakeup_timer_value); return ; } /* Public functions ----------------------------------------------------------*/ /** * For all public interface except that may need write access to the RTC, the RTC * shall be unlock at the beginning and locked at the output * In order to ease maintainability, the unlock is done at the top and the lock at then end * in case some new implementation is coming in the future */ void HW_TS_RTC_Wakeup_Handler(void) { HW_TS_pTimerCb_t ptimer_callback; uint32_t timer_process_id; uint8_t local_current_running_timer_id; #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) uint32_t primask_bit; #endif #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */ __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/ #endif /* Disable the write protection for RTC registers */ __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc ); /** * Disable the Wakeup Timer * This may speed up a bit the processing to wait the timer to be disabled * The timer is still counting 2 RTCCLK */ __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); local_current_running_timer_id = CurrentRunningTimerID; if(aTimerContext[local_current_running_timer_id].TimerIDStatus == TimerID_Running) { ptimer_callback = aTimerContext[local_current_running_timer_id].pTimerCallBack; timer_process_id = aTimerContext[local_current_running_timer_id].TimerProcessID; /** * It should be good to check whether the TimeElapsed is greater or not than the tick left to be counted * However, due to the inaccuracy of the reading of the time elapsed, it may return there is 1 tick * to be left whereas the count is over * A more secure implementation has been done with a flag to state whereas the full count has been written * in the wakeuptimer or not */ if(WakeupTimerLimitation != WakeupTimerValue_Overpassed) { if(aTimerContext[local_current_running_timer_id].TimerMode == hw_ts_Repeated) { UnlinkTimer(local_current_running_timer_id, SSR_Read_Not_Requested); #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ #endif HW_TS_Start(local_current_running_timer_id, aTimerContext[local_current_running_timer_id].CounterInit); /* Disable the write protection for RTC registers */ __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc ); } else { #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ #endif HW_TS_Stop(local_current_running_timer_id); /* Disable the write protection for RTC registers */ __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc ); } HW_TS_RTC_Int_AppNot(timer_process_id, local_current_running_timer_id, ptimer_callback); } else { RescheduleTimerList(); #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ #endif } } else { /** * We should never end up in this case * However, if due to any bug in the timer server this is the case, the mistake may not impact the user. * We could just clean the interrupt flag and get out from this unexpected interrupt */ while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET); /** * make sure to clear the flags after checking the WUTWF. * It takes 2 RTCCLK between the time the WUTE bit is disabled and the * time the timer is disabled. The WUTWF bit somehow guarantee the system is stable * Otherwise, when the timer is periodic with 1 Tick, it may generate an extra interrupt in between * due to the autoreload feature */ __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */ __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */ #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ #endif } /* Enable the write protection for RTC registers */ __HAL_RTC_WRITEPROTECTION_ENABLE( phrtc ); return; } void HW_TS_Init(HW_TS_InitMode_t TimerInitMode, RTC_HandleTypeDef *hrtc) { uint8_t loop; uint32_t localmaxwakeuptimersetup; /** * Get RTC handler */ phrtc = hrtc; /* Disable the write protection for RTC registers */ __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc ); SET_BIT(RTC->CR, RTC_CR_BYPSHAD); /** * Readout the user config */ WakeupTimerDivider = (4 - ((uint32_t)(READ_BIT(RTC->CR, RTC_CR_WUCKSEL)))); AsynchPrescalerUserConfig = (uint8_t)(READ_BIT(RTC->PRER, RTC_PRER_PREDIV_A) >> (uint32_t)POSITION_VAL(RTC_PRER_PREDIV_A)) + 1; SynchPrescalerUserConfig = (uint16_t)(READ_BIT(RTC->PRER, RTC_PRER_PREDIV_S)) + 1; /** * Margin is taken to avoid wrong calculation when the wrap around is there and some * application interrupts may have delayed the reading */ localmaxwakeuptimersetup = ((((SynchPrescalerUserConfig - 1)*AsynchPrescalerUserConfig) - CFG_HW_TS_RTC_HANDLER_MAX_DELAY) >> WakeupTimerDivider); if(localmaxwakeuptimersetup >= 0xFFFF) { MaxWakeupTimerSetup = 0xFFFF; } else { MaxWakeupTimerSetup = (uint16_t)localmaxwakeuptimersetup; } /** * Configure EXTI module */ LL_EXTI_EnableRisingTrig_0_31(RTC_EXTI_LINE_WAKEUPTIMER_EVENT); LL_EXTI_EnableIT_0_31(RTC_EXTI_LINE_WAKEUPTIMER_EVENT); if(TimerInitMode == hw_ts_InitMode_Full) { WakeupTimerLimitation = WakeupTimerValue_LargeEnough; SSRValueOnLastSetup = SSR_FORBIDDEN_VALUE; /** * Initialize the timer server */ for(loop = 0; loop < CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER; loop++) { aTimerContext[loop].TimerIDStatus = TimerID_Free; } CurrentRunningTimerID = CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER; /**< Set ID to non valid value */ __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); /**< Disable the Wakeup Timer */ __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */ __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */ HAL_NVIC_ClearPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Clear pending bit in NVIC */ __HAL_RTC_WAKEUPTIMER_ENABLE_IT(phrtc, RTC_IT_WUT); /**< Enable interrupt in RTC module */ } else { if(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTF) != RESET) { /** * Simulate that the Timer expired */ HAL_NVIC_SetPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); } } /* Enable the write protection for RTC registers */ __HAL_RTC_WRITEPROTECTION_ENABLE( phrtc ); 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 */ HAL_NVIC_EnableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Enable NVIC */ return; } HW_TS_ReturnStatus_t HW_TS_Create(uint32_t TimerProcessID, uint8_t *pTimerId, HW_TS_Mode_t TimerMode, HW_TS_pTimerCb_t pftimeout_handler) { HW_TS_ReturnStatus_t localreturnstatus; uint8_t loop = 0; #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) uint32_t primask_bit; #endif #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */ __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/ #endif while((loop < CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) && (aTimerContext[loop].TimerIDStatus != TimerID_Free)) { loop++; } if(loop != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) { aTimerContext[loop].TimerIDStatus = TimerID_Created; #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ #endif aTimerContext[loop].TimerProcessID = TimerProcessID; aTimerContext[loop].TimerMode = TimerMode; aTimerContext[loop].pTimerCallBack = pftimeout_handler; *pTimerId = loop; localreturnstatus = hw_ts_Successful; } else { #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ #endif localreturnstatus = hw_ts_Failed; } return(localreturnstatus); } void HW_TS_Delete(uint8_t timer_id) { HW_TS_Stop(timer_id); aTimerContext[timer_id].TimerIDStatus = TimerID_Free; /**< release ID */ return; } void HW_TS_Stop(uint8_t timer_id) { uint8_t localcurrentrunningtimerid; #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) uint32_t primask_bit; #endif #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */ __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/ #endif HAL_NVIC_DisableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Disable NVIC */ /* Disable the write protection for RTC registers */ __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc ); if(aTimerContext[timer_id].TimerIDStatus == TimerID_Running) { UnlinkTimer(timer_id, SSR_Read_Requested); localcurrentrunningtimerid = CurrentRunningTimerID; if(localcurrentrunningtimerid == CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) { /** * List is empty */ /** * Disable the timer */ if((READ_BIT(RTC->CR, RTC_CR_WUTE) == (RTC_CR_WUTE)) == SET) { /** * Wait for the flag to be back to 0 when the wakeup timer is enabled */ while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == SET); } __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); /**< Disable the Wakeup Timer */ while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET); /** * make sure to clear the flags after checking the WUTWF. * It takes 2 RTCCLK between the time the WUTE bit is disabled and the * time the timer is disabled. The WUTWF bit somehow guarantee the system is stable * Otherwise, when the timer is periodic with 1 Tick, it may generate an extra interrupt in between * due to the autoreload feature */ __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */ __HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */ HAL_NVIC_ClearPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Clear pending bit in NVIC */ } else if(PreviousRunningTimerID != localcurrentrunningtimerid) { RescheduleTimerList(); } } /* Enable the write protection for RTC registers */ __HAL_RTC_WRITEPROTECTION_ENABLE( phrtc ); HAL_NVIC_EnableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Enable NVIC */ #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ #endif return; } void HW_TS_Start(uint8_t timer_id, uint32_t timeout_ticks) { uint16_t time_elapsed; uint8_t localcurrentrunningtimerid; #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) uint32_t primask_bit; #endif if(aTimerContext[timer_id].TimerIDStatus == TimerID_Running) { HW_TS_Stop( timer_id ); } #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */ __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/ #endif HAL_NVIC_DisableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Disable NVIC */ /* Disable the write protection for RTC registers */ __HAL_RTC_WRITEPROTECTION_DISABLE( phrtc ); aTimerContext[timer_id].TimerIDStatus = TimerID_Running; aTimerContext[timer_id].CountLeft = timeout_ticks; aTimerContext[timer_id].CounterInit = timeout_ticks; time_elapsed = linkTimer(timer_id); localcurrentrunningtimerid = CurrentRunningTimerID; if(PreviousRunningTimerID != localcurrentrunningtimerid) { RescheduleTimerList(); } else { aTimerContext[timer_id].CountLeft -= time_elapsed; } /* Enable the write protection for RTC registers */ __HAL_RTC_WRITEPROTECTION_ENABLE( phrtc ); HAL_NVIC_EnableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Enable NVIC */ #if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1) __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ #endif return; } uint16_t HW_TS_RTC_ReadLeftTicksToCount(void) { uint32_t primask_bit; uint16_t return_value, auro_reload_value, elapsed_time_value; primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */ __disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/ if((READ_BIT(RTC->CR, RTC_CR_WUTE) == (RTC_CR_WUTE)) == SET) { auro_reload_value = (uint32_t)(READ_BIT(RTC->WUTR, RTC_WUTR_WUT)); elapsed_time_value = ReturnTimeElapsed(); if(auro_reload_value > elapsed_time_value) { return_value = auro_reload_value - elapsed_time_value; } else { return_value = 0; } } else { return_value = TIMER_LIST_EMPTY; } __set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/ return (return_value); } __weak void HW_TS_RTC_Int_AppNot(uint32_t TimerProcessID, uint8_t TimerID, HW_TS_pTimerCb_t pTimerCallBack) { pTimerCallBack(); return; } /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/