 734820c137
			
		
	
	
		734820c137
		
			
		
	
	
	
	
		
			
			* Targets: add F6 * F6: Update linker script for use with internal storage * F6: synchronize with F5, add all changes arriving in V9 board, update cube project. Github workflow: add multi-target build, add F6 to build targets. * CI: fix full assembly * CI: better artifact naming scheme * CI: fix artifacts wildcard * F6: Swap C10 - A15, vibro and sdcard detect pins
		
			
				
	
	
		
			894 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			894 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|  ******************************************************************************
 | |
|   * File Name          : hw_timerserver.c
 | |
|   * Description        : Hardware timerserver source file for STM32WPAN Middleware.
 | |
|   *
 | |
|  ******************************************************************************
 | |
|   * @attention
 | |
|   *
 | |
|   * <h2><center>© Copyright (c) 2020 STMicroelectronics.
 | |
|   * All rights reserved.</center></h2>
 | |
|   *
 | |
|   * 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****/
 |