/** * @file hal_timer.c * * @copyright Nehemis SARL reserves all rights even in the event of industrial * property rights. We reserve all rights of disposal such as * copying and passing on to third parties. * * @brief HAL layer for the TIMER module. * */ /****************************************************************************** * Include Header Files ******************************************************************************/ #include "map_hal.h" #include "hal_timer.h" /* CubeMX */ #include "tim.h" /****************************************************************************** * Macro constant declarations ******************************************************************************/ #define HAL_TIMER_SEC_TO_MSEC 1000000uLL /**< Number of microseconds within a second */ /****************************************************************************** * Type declarations ******************************************************************************/ typedef struct { uint64 timerPeriod_u64; uint64 downCounter_u64; } HalTimerInstance_tst; /****************************************************************************** * Module Global Variable Declarations ******************************************************************************/ static HalTimerInstance_tst instance_gast[MAP_HAL_TIMER_NUMBER] = {0}; static void (*halTimerCallbacks[MAP_HAL_TIMER_NUMBER])(void); /****************************************************************************** * Static Function Declarations ******************************************************************************/ static uint32 HalTimerComputeTimerPeriod(MapHalTimerModule_en timerModule_en, uint64 * timerPeriod_u64); /****************************************************************************** * Extern Function Definition ******************************************************************************/ uint32 HalTimerInit(void) { uint32 error_u32 = NMS_ERR_NONE; for(uint8 i_u8 = 0u; i_u8 < MAP_HAL_TIMER_NUMBER; i_u8++) { uint64 timerPeriod_u64 = 0uLL; error_u32 = HalTimerComputeTimerPeriod((MapHalTimerModule_en)(i_u8), &timerPeriod_u64); if (error_u32 == NMS_ERR_NONE) { instance_gast[i_u8].timerPeriod_u64 = timerPeriod_u64; instance_gast[i_u8].downCounter_u64 = 0uLL; } } return error_u32; } uint32_t HalTimerGetCounter(MapHalTimerModule_en timerModule_en) { TIM_HandleTypeDef *targetModule_pst = NULL; /* Get the timer handle using MapHalTimerModule */ if (MapHalTimerModule(timerModule_en, &targetModule_pst) != NMS_ERR_NONE || targetModule_pst == NULL) { return 0; } return (uint32)(targetModule_pst->Instance->CNT); } void HalTimerSetCounter(MapHalTimerModule_en timerModule_en, uint32 counter_u32) { TIM_HandleTypeDef *targetModule_pst = NULL; if (MapHalTimerModule(timerModule_en, &targetModule_pst) != NMS_ERR_NONE || targetModule_pst == NULL) { return; } targetModule_pst->Instance->CNT = counter_u32; } void HalTimerSetCompare(MapHalTimerModule_en timerModule_en, uint32 channel_u32, uint32 compareValue_32) { TIM_HandleTypeDef *targetModule_pst = NULL; if (MapHalTimerModule(timerModule_en, &targetModule_pst) != NMS_ERR_NONE || targetModule_pst == NULL) { /* Handle the error (e.g., log it or return early) */ return; } switch (channel_u32) { case TIM_CHANNEL_1: targetModule_pst->Instance->CCR1 = compareValue_32; break; case TIM_CHANNEL_2: targetModule_pst->Instance->CCR2 = compareValue_32; break; case TIM_CHANNEL_3: targetModule_pst->Instance->CCR3 = compareValue_32; break; case TIM_CHANNEL_4: targetModule_pst->Instance->CCR4 = compareValue_32; break; #ifdef TIM_CHANNEL_5 case TIM_CHANNEL_5: targetModule_pst->Instance->CCR5 = compareValue_32; break; #endif #ifdef TIM_CHANNEL_6 case TIM_CHANNEL_6: targetModule_pst->Instance->CCR6 = compareValue_32; break; #endif default: /* Invalid channel case (log or handle the error) */ break; } } uint32 HalTimerGetAutoReload(MapHalTimerModule_en timerModule_en) { TIM_HandleTypeDef *targetModule_pst = NULL; if (MapHalTimerModule(timerModule_en, &targetModule_pst) != NMS_ERR_NONE || targetModule_pst == NULL) { /* Error */ } return (uint32)(targetModule_pst->Instance->ARR); } uint32 HalTimerEncoderStart(MapHalTimerModule_en timerModule_en) { uint32 error_u32 = NMS_ERR_DEFAULT; HAL_StatusTypeDef halTimerStatus_en = NMS_ERR_NONE; TIM_HandleTypeDef * targetModule_pst; error_u32 = MapHalTimerModule(timerModule_en, &targetModule_pst); if(error_u32 == NMS_ERR_NONE) { /* Start the requested timer */ halTimerStatus_en = HAL_TIM_Encoder_Start(targetModule_pst, TIM_CHANNEL_ALL); switch(halTimerStatus_en) { case HAL_BUSY: error_u32 = NMS_ERR_BUSY; break; case HAL_TIMEOUT: error_u32 = NMS_ERR_TIMEOUT; break; case HAL_ERROR: error_u32 = NMS_ERR_UNKNOWN; break; case HAL_OK: error_u32 = NMS_ERR_NONE; break; default: error_u32 = NMS_ERR_UNKNOWN; break; } } return error_u32; } uint32 HalTimerEncoderStop(MapHalTimerModule_en timerModule_en) { uint32 error_u32 = NMS_ERR_DEFAULT; HAL_StatusTypeDef halTimerStatus_en = NMS_ERR_NONE; TIM_HandleTypeDef * targetModule_pst; error_u32 = MapHalTimerModule(timerModule_en, &targetModule_pst); if(error_u32 == NMS_ERR_NONE) { /* Start the requested timer */ halTimerStatus_en = HAL_TIM_Encoder_Stop(targetModule_pst, TIM_CHANNEL_ALL); switch(halTimerStatus_en) { case HAL_BUSY: error_u32 = NMS_ERR_BUSY; break; case HAL_TIMEOUT: error_u32 = NMS_ERR_TIMEOUT; break; case HAL_ERROR: error_u32 = NMS_ERR_UNKNOWN; break; case HAL_OK: error_u32 = NMS_ERR_NONE; break; default: error_u32 = NMS_ERR_UNKNOWN; break; } } return error_u32; } uint32 HalTimerPwmStart(MapHalTimerModule_en timerModule_en, uint32 Channel_u32) { uint32 error_u32 = NMS_ERR_DEFAULT; HAL_StatusTypeDef halTimerStatus_en = NMS_ERR_NONE; TIM_HandleTypeDef * targetModule_pst; error_u32 = MapHalTimerModule(timerModule_en, &targetModule_pst); if(error_u32 == NMS_ERR_NONE) { /* Start the requested timer */ halTimerStatus_en = HAL_TIM_PWM_Start(targetModule_pst, Channel_u32); switch(halTimerStatus_en) { case HAL_BUSY: error_u32 = NMS_ERR_BUSY; break; case HAL_TIMEOUT: error_u32 = NMS_ERR_TIMEOUT; break; case HAL_ERROR: error_u32 = NMS_ERR_UNKNOWN; break; case HAL_OK: error_u32 = NMS_ERR_NONE; break; default: error_u32 = NMS_ERR_UNKNOWN; break; } } return error_u32; } uint32 HalTimerPwmStop(MapHalTimerModule_en timerModule_en, uint32 Channel_u32) { uint32 error_u32 = NMS_ERR_DEFAULT; HAL_StatusTypeDef halTimerStatus_en = NMS_ERR_NONE; TIM_HandleTypeDef * targetModule_pst; error_u32 = MapHalTimerModule(timerModule_en, &targetModule_pst); if(error_u32 == NMS_ERR_NONE) { /* Stop the requested timer */ halTimerStatus_en = HAL_TIM_PWM_Stop(targetModule_pst, Channel_u32); switch(halTimerStatus_en) { case HAL_BUSY: error_u32 = NMS_ERR_BUSY; break; case HAL_TIMEOUT: error_u32 = NMS_ERR_TIMEOUT; break; case HAL_ERROR: error_u32 = NMS_ERR_UNKNOWN; break; case HAL_OK: error_u32 = NMS_ERR_NONE; break; default: error_u32 = NMS_ERR_UNKNOWN; break; } } return error_u32; } uint32 HalTimerStart(MapHalTimerModule_en timerModule_en) { uint32 error_u32 = NMS_ERR_DEFAULT; HAL_StatusTypeDef halTimerStatus_en = NMS_ERR_NONE; TIM_HandleTypeDef * targetModule_pst; error_u32 = MapHalTimerModule(timerModule_en, &targetModule_pst); if(error_u32 == NMS_ERR_NONE) { /* Start the requested timer */ halTimerStatus_en = HAL_TIM_Base_Start_IT(targetModule_pst); switch(halTimerStatus_en) { case HAL_BUSY: error_u32 = NMS_ERR_BUSY; break; case HAL_TIMEOUT: error_u32 = NMS_ERR_TIMEOUT; break; case HAL_ERROR: error_u32 = NMS_ERR_UNKNOWN; break; case HAL_OK: error_u32 = NMS_ERR_NONE; break; default: error_u32 = NMS_ERR_UNKNOWN; break; } } return error_u32; } uint32 HalTimerStop(MapHalTimerModule_en timerModule_en) { uint32 error_u32 = NMS_ERR_DEFAULT; HAL_StatusTypeDef halTimerStatus_en = NMS_ERR_NONE; TIM_HandleTypeDef * targetModule_pst; error_u32 = MapHalTimerModule(timerModule_en, &targetModule_pst); if(error_u32 == NMS_ERR_NONE) { /* Stop the requested timer */ halTimerStatus_en = HAL_TIM_Base_Stop_IT(targetModule_pst); switch(halTimerStatus_en) { case HAL_BUSY: error_u32 = NMS_ERR_BUSY; break; case HAL_TIMEOUT: error_u32 = NMS_ERR_TIMEOUT; break; case HAL_ERROR: error_u32 = NMS_ERR_UNKNOWN; break; case HAL_OK: error_u32 = NMS_ERR_NONE; break; default: error_u32 = NMS_ERR_UNKNOWN; break; } } return error_u32; } uint32 HalTimerReloadUs(MapHalTimerModule_en timerModule_en, uint64 period_u64) { uint32 error_u32 = NMS_ERR_DEFAULT; TIM_HandleTypeDef * targetModule_pst; error_u32 = MapHalTimerModule(timerModule_en, &targetModule_pst); if(error_u32 == NMS_ERR_NONE) { if(period_u64 == 0uLL) { error_u32 = NMS_ERR_UNKNOWN; } else { /* Compute the number of step that we need to count */ instance_gast[timerModule_en].downCounter_u64 = period_u64 / instance_gast[timerModule_en].timerPeriod_u64; if((instance_gast[timerModule_en].downCounter_u64 * instance_gast[timerModule_en].timerPeriod_u64) < period_u64) { instance_gast[timerModule_en].downCounter_u64++; } else { error_u32 = NMS_ERR_UNKNOWN; } } } return error_u32; } uint32 HalTimerGetRemainingTimeUs(MapHalTimerModule_en timerModule_en, uint64 * remainingTime_pu64) { uint32 error_u32 = NMS_ERR_DEFAULT; TIM_HandleTypeDef * targetModule_pst; error_u32 = MapHalTimerModule(timerModule_en, &targetModule_pst); if(error_u32 == NMS_ERR_NONE) { /* Add the time corresponding to the number of interruption left for this timer */ *remainingTime_pu64 = instance_gast[timerModule_en].downCounter_u64; *remainingTime_pu64 *= instance_gast[timerModule_en].timerPeriod_u64; } else { error_u32 = NMS_ERR_UNKNOWN; } return error_u32; } uint32 HalTimerConfigureCallback(MapHalTimerModule_en timerModule_en, void (*callback_pfn)(void)) { uint32 error_u32 = NMS_ERR_DEFAULT; if (timerModule_en < MAP_HAL_TIMER_NUMBER ) { halTimerCallbacks[timerModule_en] = callback_pfn; error_u32 = NMS_ERR_NONE; } else { error_u32 = NMS_ERR_UNKNOWN; } return error_u32; } void HalTimerDeinit(MapHalTimerModule_en timerModule_en) { uint32 error_u32 = NMS_ERR_DEFAULT; TIM_HandleTypeDef * targetModule_pst; uint8 index_u8; uint8 startIndex_u8; uint8 iteration_u8 = 1u; /* Default to 1 loop iteration (deinit one module) */ if(timerModule_en == MAP_HAL_TIMER_NUMBER) { iteration_u8 = timerModule_en; startIndex_u8 = 0u; } else { iteration_u8 += timerModule_en; startIndex_u8 = timerModule_en; } for(index_u8 = startIndex_u8; index_u8 < iteration_u8; index_u8++) { error_u32 = MapHalTimerModule((MapHalTimerModule_en)index_u8, &targetModule_pst); if(error_u32 == NMS_ERR_NONE) { HAL_TIM_Base_DeInit(targetModule_pst); } } } /****************************************************************************** * Static Function Definitions ******************************************************************************/ /** * @brief Compute the timerPeriod of the requested timer * * @param timerModule_en The timer module to use * * @return The value of the timer period. If the timer module is invalid, the * value returned will be 0. * * @note CAUTION : The part to compute the actual time frequency is target * dependant, do not forget to update it to fit your needs. * This affects the calculation of the timerPeriod and so * can change the resolution that has been computed by the * user in cubeMX */ static uint32 HalTimerComputeTimerPeriod(MapHalTimerModule_en timerModule_en, uint64 * timerPeriod_u64) { uint32 error_u32 = NMS_ERR_DEFAULT; uint32 timerFrequency_u32 = 0uL; TIM_HandleTypeDef * targetModule_pst; error_u32 = MapHalTimerModule(timerModule_en, &targetModule_pst); if(error_u32 == NMS_ERR_NONE) { *timerPeriod_u64 = HAL_TIMER_SEC_TO_MSEC; *timerPeriod_u64 *= (targetModule_pst->Instance->PSC + 1UL); *timerPeriod_u64 *= (targetModule_pst->Instance->ARR + 1UL); *timerPeriod_u64 /= timerFrequency_u32; } else { timerPeriod_u64 = 0uLL; error_u32 = NMS_ERR_UNKNOWN; } return error_u32; } /****************************************************************************** * Callback Function Definitions ******************************************************************************/ /** * @brief CubeMX timer period elapsed callback * * @param[in] htim pointer to a TIM_HandleTypeDef structure that contains * the configuration information for the specified TIMER. * @return Error code in case there is one during the process. */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { MapHalTimerModule_en timerModule_en; uint32 error_u32 = NMS_ERR_DEFAULT; error_u32 = MapHalTimerCallback(&htim, &timerModule_en); if (error_u32 == NMS_ERR_NONE) { /* Check if we reach the interrupt enough to reach the goal counter */ if(instance_gast[timerModule_en].downCounter_u64 == 0uLL) { if(halTimerCallbacks[timerModule_en] != NULL) { /* Call the user callback */ halTimerCallbacks[timerModule_en](); } else { error_u32 = NMS_ERR_UNKNOWN; } } else { instance_gast[timerModule_en].downCounter_u64--; } } else { error_u32 = NMS_ERR_UNKNOWN; } } /** * @brief CubeMX timer error callback * * @param[in] htim pointer to a TIM_HandleTypeDef structure that contains * the configuration information for the specified TIMER. * @return Error code in case there is one during the process. */ void HAL_TIM_ErrorCallback(TIM_HandleTypeDef * htim) { uint32 error_u32 = NMS_ERR_DEFAULT; MapHalTimerModule_en timerModule_en; error_u32 = MapHalTimerCallback(&htim, &timerModule_en); if(error_u32 == NMS_ERR_NONE) { switch(htim->State) { case HAL_TIM_STATE_RESET: error_u32 = NMS_ERR_NOT_INITIALIZED; break; case HAL_TIM_STATE_BUSY: error_u32 = NMS_ERR_BUSY; break; case HAL_TIM_STATE_TIMEOUT: error_u32 = NMS_ERR_TIMEOUT; break; case HAL_TIM_STATE_ERROR: error_u32 = NMS_ERR_UNEXPECTED; break; case HAL_TIM_STATE_READY: error_u32 = NMS_ERR_NOT_RUNNING; break; default: error_u32 = NMS_ERR_UNKNOWN; break; } } else { error_u32 = NMS_ERR_INVALID_ARGUMENT; } }