/** ************************************************************************** * @file general_tim.c * @brief Модуль для инициализации таймеров и работы с ними. ************************************************************************** Реализация функций для работы с TIM: - Инициализация таймера и его каналов - Формирование задержек через таймеры - Считывание энкодера *************************************************************************/ #include "general_tim.h" //------------------------------------------------------------------- //-------------------------TIM INIT FUNCTIONS------------------------ /** * @brief Инициализация таймера. * @param stim Указатель на структуру с настройками таймера. * @return HAL status. * @details * Инициализирует таймер исходя из настроек верхнего уровня: * - Длительность одного тика @ref TIM_MHzTickBaseTypeDef * - Частота таймера (в Гц, float) * - Частота тактирования таймера от шины (в Гц, float) * * При невозможности выставления частоты при заданой длительности тика * длительность тика увеличивается до тех пор, пока частота не будет достигнута. * * При выставлении дефайна @ref UPDATE_TIM_PARAMS_AFTER_INITIALIZATION * новая длительность тика записывается в структуру. * * Также остается возможность низкоуровневой настройки по структурам @ref TIM_SettingsTypeDef. * Для этого надо высокоуровневые настройки приравнять к нулю */ HAL_StatusTypeDef TIM_Base_Init(TIM_SettingsTypeDef *stim) { // function takes structure for init // check that htim is defined if(check_null_ptr_2(stim, stim->htim.Instance)) return HAL_ERROR; if(stim->sTickBaseUS) // if tickbase isnt disable { if(stim->sTimAHBFreqMHz == NULL) return HAL_ERROR; stim->htim.Init.Prescaler = (stim->sTimAHBFreqMHz*stim->sTickBaseUS) - 1; if ((stim->sTimFreqHz != NULL)) stim->htim.Init.Period = ((1000000/stim->sTickBaseUS) / stim->sTimFreqHz) - 1; else if (stim->htim.Init.Period == NULL) stim->htim.Init.Period = 0xFFFF; if(stim->sTickBasePrescaler) { stim->htim.Init.Prescaler = (stim->htim.Init.Prescaler + 1)/stim->sTickBasePrescaler - 1; stim->htim.Init.Period = (stim->htim.Init.Period + 1)*stim->sTickBasePrescaler - 1; } else stim->sTickBasePrescaler = 1; } // fix overflow of presc and period if need for(int i = 0; (stim->htim.Init.Prescaler > 0xFFFF) || (stim->htim.Init.Period > 0xFFFF); i++) { if (i>10) // if it isnt fixed after 10 itteration - return HAL_ERRPOR { return HAL_ERROR; } // if timbase is too big (prescaller too big for choosen base from MHZ) if(stim->htim.Init.Prescaler > 0xFFFF) { // переносим часть пресскалера в период stim->htim.Init.Prescaler = ((stim->htim.Init.Prescaler + 1)/2) - 1; stim->htim.Init.Period = ((stim->htim.Init.Period + 1)*2) - 1; // обновляем TickBase, если есть куда обновлять if(stim->sTickBaseUS > 1) stim->sTickBaseUS /= 2; // обновляем sTickBasePrescaler, если sTickBaseUS - уже в минимуме else if (stim->sTickBaseUS == 1) stim->sTickBasePrescaler *= 2; else // if TickBase = 0 - return error return HAL_ERROR; } // if freq is too low (period too big for choosen base) if(stim->htim.Init.Period > 0xFFFF) { // переносим часть периода в прескалер stim->htim.Init.Period = ((stim->htim.Init.Period + 1)/2) - 1; stim->htim.Init.Prescaler = ((stim->htim.Init.Prescaler + 1)*2) - 1; // обновляем TickBase stim->sTickBaseUS *= 2; } } //-------------TIM BASE INIT---------------- // tim base init TIM_Base_MspInit(&stim->htim, stim->sTimMode); if (HAL_TIM_Base_Init(&stim->htim) != HAL_OK) { MyLibs_Error_Handler(); return HAL_ERROR; } //-------------CLOCK SRC INIT--------------- // fill sClockSourceConfig if its NULL if (stim->sClockSourceConfig.ClockSource == NULL) stim->sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; // clock source init if (HAL_TIM_ConfigClockSource(&stim->htim, &stim->sClockSourceConfig) != HAL_OK) { MyLibs_Error_Handler(); return HAL_ERROR; } //--------------SLAVE INIT------------------ // if slave mode enables - config it if (stim->sSlaveConfig.SlaveMode) { // slave mode init if (HAL_TIM_SlaveConfigSynchro(&stim->htim, &stim->sSlaveConfig) != HAL_OK) { MyLibs_Error_Handler(); return HAL_ERROR; } } //--------------MASTER INIT----------------- // master mode init if (HAL_TIMEx_MasterConfigSynchronization(&stim->htim, &stim->sMasterConfig) != HAL_OK) { MyLibs_Error_Handler(); return HAL_ERROR; } //--------------BDTR INIT----------------- if (HAL_TIMEx_ConfigBreakDeadTime(&stim->htim, &stim->sBreakDeadTimeConfig) != HAL_OK) { MyLibs_Error_Handler(); return HAL_ERROR; } //----------------IT CLEAR------------------- __HAL_TIM_CLEAR_IT(&stim->htim, TIM_IT_UPDATE); // обновляем TickBase #ifdef UPDATE_TIM_PARAMS_AFTER_INITIALIZATION stim->sTickBaseUS = (stim->htim.Instance->PSC+1)*stim->sTickBasePrescaler/(stim->sTimAHBFreqMHz); if(stim->sTickBaseUS == 0) // if prescaler is too high { // recalc what is prescaler irl stim->sTickBaseUS = 1; stim->sTickBasePrescaler = stim->sTimAHBFreqMHz/(stim->htim.Instance->PSC+1); } #endif stim->htim.Instance->CNT = 0; return HAL_OK; } /** * @brief Инициализация режима энкодер у таймера. * @param henc Указатель на хендл энкодера. * @param htim Указатель на хендл таймера. * @return HAL status. * @note Предварительно надо инициализировать таймер @ref TIM_Base_Init. */ HAL_StatusTypeDef TIM_Encoder_Init(TIM_EncoderTypeDef *henc, TIM_HandleTypeDef *htim) { if(check_null_ptr_3(henc, htim, htim->Instance)) return HAL_ERROR; if(check_null_ptr_3(henc->GPIOx, henc->GPIO_PIN_TI1, henc->GPIO_PIN_TI2)) return HAL_ERROR; GPIO_InitTypeDef GPIO_InitStruct = {0}; HAL_StatusTypeDef RES = HAL_ERROR; henc->htim = htim; // setup channel for pwm RES = HAL_TIM_Encoder_Init(henc->htim, &henc->sConfig); if (RES != HAL_OK) { MyLibs_Error_Handler(); return RES; } // choose port for enable clock RES = GPIO_Clock_Enable(henc->GPIOx); if(RES != HAL_OK) { MyLibs_Error_Handler(); return RES; } GPIO_InitStruct.Pin = henc->GPIO_PIN_TI1|henc->GPIO_PIN_TI2; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_TIM_Alternate_Mapping(henc->htim->Instance); if(GPIO_InitStruct.Alternate) HAL_GPIO_Init(henc->GPIOx, &GPIO_InitStruct); if(henc->GPIO_PIN_SW) { /*Configure switch pin */ GPIO_InitStruct.Pin = henc->GPIO_PIN_SW; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(henc->GPIOx, &GPIO_InitStruct); GPIO_Switch_Init(&henc->Sw, henc->GPIOx, henc->GPIO_PIN_SW, 0); } return HAL_OK; } /** * @brief Инициализация выхода ШИМ таймера. * @param htim Указатель на хендл таймера. * @param sConfigOC Указатель на настрйоки канала таймера. * @param TIM_CHANNEL Канал таймера для настройки. * @param GPIOx Порт для вывода ШИМ. * @param GPIO_PIN Пин для вывода ШИМ. * @return HAL status. * @note Предварительно надо инициализировать таймер @ref TIM_Base_Init. */ HAL_StatusTypeDef TIM_Output_PWM_Init(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef *sConfigOC, uint32_t TIM_CHANNEL, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN) { if(check_null_ptr_3(htim, htim->Instance, sConfigOC)) return HAL_ERROR; if(check_null_ptr_2(GPIOx, GPIO_PIN)) return HAL_ERROR; GPIO_InitTypeDef GPIO_InitStruct = {0}; HAL_StatusTypeDef RES = HAL_ERROR; // setup channel for pwm RES = HAL_TIM_PWM_ConfigChannel(htim, sConfigOC, TIM_CHANNEL); if (RES != HAL_OK) { MyLibs_Error_Handler(); return RES; } // choose port for enable clock RES = GPIO_Clock_Enable(GPIOx); if(RES != HAL_OK) { MyLibs_Error_Handler(); return RES; } GPIO_InitStruct.Pin = GPIO_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; if(sConfigOC->OCPolarity == TIM_OCNPOLARITY_HIGH) GPIO_InitStruct.Pull = GPIO_PULLDOWN; else GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_TIM_Alternate_Mapping(htim->Instance); if(GPIO_InitStruct.Alternate) HAL_GPIO_Init(GPIOx, &GPIO_InitStruct); return HAL_OK; } /** * @brief Инициализация OC компаратора таймера. * @param htim Указатель на хендл таймера. * @param TIM_CHANNEL Канал таймера для настройки. * @return HAL status. * @note Предварительно надо инициализировать таймер @ref TIM_Base_Init. */ HAL_StatusTypeDef TIM_OC_Comparator_Init(TIM_HandleTypeDef *htim, uint32_t TIM_CHANNEL) { if(check_null_ptr_2(htim, htim->Instance)) return HAL_ERROR; TIM_OC_InitTypeDef sConfigOC = {0}; HAL_StatusTypeDef RES = HAL_ERROR; sConfigOC.OCMode = TIM_OCMODE_ACTIVE; sConfigOC.Pulse = 0; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; RES = HAL_TIM_OC_ConfigChannel(htim, &sConfigOC, TIM_CHANNEL); if (RES != HAL_OK) { MyLibs_Error_Handler(); return RES; } return RES; } //------------------------------------------------------------------- //-------------------------TIM USER FUNCTIONS------------------------ /** * @brief Считать энкодер. * @param henc Указатель на хендл энкодера. * @return HAL status. * @details Читает разницу энкодера, которую он накопил после * предыдущего вызова этой функции. */ HAL_StatusTypeDef TIM_Encoder_Read(TIM_EncoderTypeDef *henc) { if(check_null_ptr_3(henc, henc->htim, henc->htim->Instance)) return HAL_ERROR; uint16_t cnt_now = (uint16_t)henc->htim->Instance->CNT; int16_t diff = (int16_t)(cnt_now - henc->Encoder_Shdw); // переполнение корректно обрабатывается henc->Encoder_Diff = diff; henc->Encoder_Shdw = cnt_now; return HAL_OK; } /** * @brief Считать кнопку энкодера. * @param henc Указатель на хендл энкодера. * @return 1 - если кнопка нажата, * 0 - если отжата, * -1 - если ошибка */ int TIM_Encoder_ReadSwitch(TIM_EncoderTypeDef *henc) { if(check_null_ptr_1(henc)) return -1; return GPIO_Read_Switch(&henc->Sw); } /** * @brief Задержка в тиках таймера (блокирующая). * @param htim Указатель на хендл таймера. * @param delay Задержка в тиках таймера. * @return HAL status. * @details Формирует задержку с блокировкой программы. */ HAL_StatusTypeDef TIM_Delay(TIM_HandleTypeDef *htim, uint16_t delay) { if(check_null_ptr_2(htim, htim->Instance)) return HAL_ERROR; if(delay >= htim->Instance->ARR) { return HAL_ERROR; } htim->Instance->CNT = 0; while(1) { if(htim->Instance->CNT > delay) { return HAL_OK; } } } /** * @brief Начать отсчет неблокирующей задержки. * @param htim Указатель на хендл таймера. * @return HAL status. * @details Сбрасывает счетчик для начала отсчета неблокирующей задержки. * @ref TIM_Delay_NonBlocking для проверки статуса задержки */ HAL_StatusTypeDef TIM_Delay_Start(TIM_HandleTypeDef *htim) { if(check_null_ptr_2(htim, htim->Instance)) return HAL_ERROR; htim->Instance->CNT = 0; return HAL_OK; } /** * @brief Задержка в тиках таймера (неблокирующая). * @param htim Указатель на хендл таймера. * @param delay Задержка в тиках таймера. * @return HAL status. * @details Формирует задержку с блокировкой программы. * Перед ожиданием задержки надо запутстить таймер @ref TIM_Delay_Start * @note Таймер не должен использоваться на время этой задержки */ HAL_StatusTypeDef TIM_Delay_NonBlocking(TIM_HandleTypeDef *htim, uint16_t delay) { if(check_null_ptr_2(htim, htim->Instance)) return HAL_ERROR; if(delay >= htim->Instance->ARR) { return HAL_ERROR; } if(htim->Instance->CNT <= delay) { return HAL_BUSY; } else { return HAL_OK; } } /** * @brief Инициализация CLK и NVIC таймеров. * @param htim Указатель на хендл таймера. * @note Чтобы не генерировать функцию с иницилизацией неиспользуемых таймеров, дефайнами в general_tim.h определяются используемые таймеры. */ void TIM_Base_MspInit(TIM_HandleTypeDef* htim, TIM_ITModeTypeDef it_mode) { if(check_null_ptr_2(htim, htim->Instance)) return; it_mode = it_mode&TIM_IT_CONF; #ifdef USE_TIM1 if(htim->Instance==TIM1) { /* TIM2 clock enable */ __HAL_RCC_TIM1_CLK_ENABLE(); /* TIM2 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn); } } #endif #ifdef USE_TIM2 if(htim->Instance==TIM2) { /* TIM2 clock enable */ __HAL_RCC_TIM2_CLK_ENABLE(); /* TIM2 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM2_IRQn); } } #endif #ifdef USE_TIM3 if(htim->Instance==TIM3) { /* TIM3 clock enable */ __HAL_RCC_TIM3_CLK_ENABLE(); /* TIM3 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM3_IRQn); } } #endif #ifdef USE_TIM4 if(htim->Instance==TIM4) { /* TIM4 clock enable */ __HAL_RCC_TIM4_CLK_ENABLE(); /* TIM4 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM4_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM4_IRQn); } } #endif #ifdef USE_TIM5 if(htim->Instance==TIM5) { /* TIM5 clock enable */ __HAL_RCC_TIM5_CLK_ENABLE(); /* TIM5 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM5_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM5_IRQn); } } #endif #ifdef USE_TIM6 if(htim->Instance==TIM6) { /* TIM6 clock enable */ __HAL_RCC_TIM6_CLK_ENABLE(); /* TIM6 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn); } } #endif #ifdef USE_TIM7 if(htim->Instance==TIM7) { /* TIM7 clock enable */ __HAL_RCC_TIM7_CLK_ENABLE(); /* TIM7 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM7_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM7_IRQn); } } #endif #ifdef USE_TIM8 if(htim->Instance==TIM8) { /* TIM8 clock enable */ __HAL_RCC_TIM8_CLK_ENABLE(); /* TIM8 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn); } } #endif #ifdef USE_TIM9 if(htim->Instance==TIM9) { /* TIM9 clock enable */ __HAL_RCC_TIM9_CLK_ENABLE(); /* TIM9 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM1_BRK_TIM9_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn); } } #endif #ifdef USE_TIM10 if(htim->Instance==TIM10) { /* TIM10 clock enable */ __HAL_RCC_TIM10_CLK_ENABLE(); /* TIM10 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn); } } #endif #ifdef USE_TIM11 if(htim->Instance==TIM11) { /* TIM11 clock enable */ __HAL_RCC_TIM11_CLK_ENABLE(); /* TIM11 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn); } } #endif #ifdef USE_TIM12 if(htim->Instance==TIM12) { /* TIM12 clock enable */ __HAL_RCC_TIM12_CLK_ENABLE(); /* TIM12 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM8_BRK_TIM12_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn); } } #endif #ifdef USE_TIM13 if(htim->Instance==TIM13) { /* TIM13 clock enable */ __HAL_RCC_TIM13_CLK_ENABLE(); /* TIM13 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn); } } #endif #ifdef USE_TIM14 if(htim->Instance==TIM14) { /* TIM14 clock enable */ __HAL_RCC_TIM14_CLK_ENABLE(); /* TIM14 interrupt Init */ if(it_mode) { HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn); } } #endif } /** * @brief Деинициализация CLK и NVIC таймеров. * @param htim Указатель на хендл таймера. * @note Чтобы не генерировать функцию с деиницилизацией неиспользуемых таймеров, дефайнами в general_tim.h определяются используемые таймеры. */ void TIM_Base_MspDeInit(TIM_HandleTypeDef* htim) { if(check_null_ptr_2(htim, htim->Instance)) return; #ifdef USE_TIM1 if(htim->Instance==TIM1) { __HAL_RCC_TIM1_FORCE_RESET(); __HAL_RCC_TIM1_RELEASE_RESET(); } #endif #ifdef USE_TIM2 if(htim->Instance==TIM2) { __HAL_RCC_TIM2_FORCE_RESET(); __HAL_RCC_TIM2_RELEASE_RESET(); } #endif #ifdef USE_TIM3 if(htim->Instance==TIM3) { __HAL_RCC_TIM3_FORCE_RESET(); __HAL_RCC_TIM3_RELEASE_RESET(); } #endif #ifdef USE_TIM4 if(htim->Instance==TIM4) { __HAL_RCC_TIM4_FORCE_RESET(); __HAL_RCC_TIM4_RELEASE_RESET(); } #endif #ifdef USE_TIM5 if(htim->Instance==TIM5) { __HAL_RCC_TIM5_FORCE_RESET(); __HAL_RCC_TIM5_RELEASE_RESET(); } #endif #ifdef USE_TIM6 if(htim->Instance==TIM6) { __HAL_RCC_TIM6_FORCE_RESET(); __HAL_RCC_TIM6_RELEASE_RESET(); } #endif #ifdef USE_TIM7 if(htim->Instance==TIM7) { __HAL_RCC_TIM7_FORCE_RESET(); __HAL_RCC_TIM7_RELEASE_RESET(); } #endif #ifdef USE_TIM8 if(htim->Instance==TIM8) { __HAL_RCC_TIM8_FORCE_RESET(); __HAL_RCC_TIM8_RELEASE_RESET(); } #endif #ifdef USE_TIM9 if(htim->Instance==TIM9) { __HAL_RCC_TIM9_FORCE_RESET(); __HAL_RCC_TIM9_RELEASE_RESET(); } #endif #ifdef USE_TIM10 if(htim->Instance==TIM10) { __HAL_RCC_TIM10_FORCE_RESET(); __HAL_RCC_TIM10_RELEASE_RESET(); } #endif #ifdef USE_TIM11 if(htim->Instance==TIM11) { __HAL_RCC_TIM11_FORCE_RESET(); __HAL_RCC_TIM11_RELEASE_RESET(); } #endif #ifdef USE_TIM12 if(htim->Instance==TIM12) { __HAL_RCC_TIM12_FORCE_RESET(); __HAL_RCC_TIM12_RELEASE_RESET(); } #endif #ifdef USE_TIM13 if(htim->Instance==TIM13) { __HAL_RCC_TIM13_FORCE_RESET(); __HAL_RCC_TIM13_RELEASE_RESET(); } #endif #ifdef USE_TIM14 if(htim->Instance==TIM14) { __HAL_RCC_TIM14_FORCE_RESET(); __HAL_RCC_TIM14_RELEASE_RESET(); } #endif } //-------------------------TIM INIT FUNCTIONS------------------------ //-------------------------------------------------------------------