/* * Copyright (c) 2006-2022, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes */ #include #ifdef BSP_USING_CAPTURE #include "drv_config.h" #define CAPTURE1_CONFIG \ { \ .timer.Instance = TIM1, \ .iqrn = TIM1_CC_IRQn, \ .timerx = 1, \ .advanced = RT_TRUE, \ } #define CAPTURE2_CONFIG \ { \ .timer.Instance = TIM2, \ .iqrn = TIM2_IRQn, \ .timerx = 2, \ } #define CAPTURE12_CONFIG \ { \ .timer.Instance = TIM12, \ .iqrn = TIM8_BRK_TIM12_IRQn, \ .timerx = 12, \ } #define LOG_TAG "drv.tcap" #include #define MAX_PERIOD 65535 #define MAX_PULSE 1000 typedef enum { POLARITY_BOTHEDGE, POLARITY_RISING, POLARITY_FALLING, }trigger_polarity; struct pulse_data { rt_uint32_t last_overflow; rt_uint32_t last_cnt; trigger_polarity polarity; }; struct stm32_capture_device; struct stm32_capture { TIM_HandleTypeDef timer; IRQn_Type iqrn; rt_uint8_t timerx; rt_uint8_t advanced; rt_uint8_t inited; rt_uint32_t tim_overflow; struct stm32_capture_device *channels[4]; }; enum { #ifdef BSP_USING_CAPTURE1 CAPTURE1_INDEX, #endif #ifdef BSP_USING_CAPTURE2 CAPTURE2_INDEX, #endif #ifdef BSP_USING_CAPTURE3 CAPTURE3_INDEX, #endif #ifdef BSP_USING_CAPTURE4 CAPTURE4_INDEX, #endif #ifdef BSP_USING_CAPTURE5 CAPTURE5_INDEX, #endif #ifdef BSP_USING_CAPTURE6 CAPTURE6_INDEX, #endif #ifdef BSP_USING_CAPTURE7 CAPTURE7_INDEX, #endif #ifdef BSP_USING_CAPTURE8 CAPTURE8_INDEX, #endif #ifdef BSP_USING_CAPTURE9 CAPTURE9_INDEX, #endif #ifdef BSP_USING_CAPTURE10 CAPTURE10_INDEX, #endif #ifdef BSP_USING_CAPTURE11 CAPTURE11_INDEX, #endif #ifdef BSP_USING_CAPTURE12 CAPTURE12_INDEX, #endif }; static struct stm32_capture stm32_capture_obj[] = { #ifdef BSP_USING_CAPTURE1 CAPTURE1_CONFIG, #endif #ifdef BSP_USING_CAPTURE2 CAPTURE2_CONFIG, #endif #ifdef BSP_USING_CAPTURE3 CAPTURE3_CONFIG, #endif #ifdef BSP_USING_CAPTURE4 CAPTURE4_CONFIG, #endif #ifdef BSP_USING_CAPTURE5 CAPTURE5_CONFIG, #endif #ifdef BSP_USING_CAPTURE6 CAPTURE6_CONFIG, #endif #ifdef BSP_USING_CAPTURE7 CAPTURE7_CONFIG, #endif #ifdef BSP_USING_CAPTURE8 CAPTURE8_CONFIG, #endif #ifdef BSP_USING_CAPTURE9 CAPTURE9_CONFIG, #endif #ifdef BSP_USING_CAPTURE10 CAPTURE10_CONFIG, #endif #ifdef BSP_USING_CAPTURE11 CAPTURE11_CONFIG, #endif #ifdef BSP_USING_CAPTURE12 CAPTURE12_CONFIG, #endif }; struct stm32_capture_device { struct rt_inputcapture_device parent; struct stm32_capture *timer; rt_uint8_t ch; rt_uint8_t opend; struct pulse_data data; rt_uint32_t pulsewidth_us; }; static struct stm32_capture_device stm32_capture_devices[] = { #ifdef BSP_USING_CAPTURE1_CH1 {{0}, &stm32_capture_obj[CAPTURE1_INDEX], 1, {0}}, #endif #ifdef BSP_USING_CAPTURE1_CH2 {{0}, &stm32_capture_obj[CAPTURE1_INDEX], 2, {0}}, #endif #ifdef BSP_USING_CAPTURE1_CH3 {{0}, &stm32_capture_obj[CAPTURE1_INDEX], 3, {0}}, #endif #ifdef BSP_USING_CAPTURE1_CH4 {{0}, &stm32_capture_obj[CAPTURE1_INDEX], 4, {0}}, #endif #ifdef BSP_USING_CAPTURE2_CH1 {{0}, &stm32_capture_obj[CAPTURE2_INDEX], 1, {0}}, #endif #ifdef BSP_USING_CAPTURE2_CH2 {{0}, &stm32_capture_obj[CAPTURE2_INDEX], 2, {0}}, #endif #ifdef BSP_USING_CAPTURE2_CH3 {{0}, &stm32_capture_obj[CAPTURE2_INDEX], 3, {0}}, #endif #ifdef BSP_USING_CAPTURE2_CH4 {{0}, &stm32_capture_obj[CAPTURE2_INDEX], 4, {0}}, #endif #ifdef BSP_USING_CAPTURE3_CH1 {{0}, &stm32_capture_obj[CAPTURE3_INDEX], 1, {0}}, #endif #ifdef BSP_USING_CAPTURE3_CH2 {{0}, &stm32_capture_obj[CAPTURE3_INDEX], 2, {0}}, #endif #ifdef BSP_USING_CAPTURE3_CH3 {{0}, &stm32_capture_obj[CAPTURE3_INDEX], 3, {0}}, #endif #ifdef BSP_USING_CAPTURE3_CH4 {{0}, &stm32_capture_obj[CAPTURE3_INDEX], 4, {0}}, #endif #ifdef BSP_USING_CAPTURE4_CH1 {{0}, &stm32_capture_obj[CAPTURE4_INDEX], 1, {0}}, #endif #ifdef BSP_USING_CAPTURE4_CH2 {{0}, &stm32_capture_obj[CAPTURE4_INDEX], 2, {0}}, #endif #ifdef BSP_USING_CAPTURE4_CH3 {{0}, &stm32_capture_obj[CAPTURE4_INDEX], 3, {0}}, #endif #ifdef BSP_USING_CAPTURE4_CH4 {{0}, &stm32_capture_obj[CAPTURE4_INDEX], 4, {0}}, #endif #ifdef BSP_USING_CAPTURE5_CH1 {{0}, &stm32_capture_obj[CAPTURE5_INDEX], 1, {0}}, #endif #ifdef BSP_USING_CAPTURE5_CH2 {{0}, &stm32_capture_obj[CAPTURE5_INDEX], 2, {0}}, #endif #ifdef BSP_USING_CAPTURE5_CH3 {{0}, &stm32_capture_obj[CAPTURE5_INDEX], 3, {0}}, #endif #ifdef BSP_USING_CAPTURE5_CH4 {{0}, &stm32_capture_obj[CAPTURE5_INDEX], 4, {0}}, #endif #ifdef BSP_USING_CAPTURE6_CH1 {{0}, &stm32_capture_obj[CAPTURE6_INDEX], 1, {0}}, #endif #ifdef BSP_USING_CAPTURE6_CH2 {{0}, &stm32_capture_obj[CAPTURE6_INDEX], 2, {0}}, #endif #ifdef BSP_USING_CAPTURE6_CH3 {{0}, &stm32_capture_obj[CAPTURE6_INDEX], 3, {0}}, #endif #ifdef BSP_USING_CAPTURE6_CH4 {{0}, &stm32_capture_obj[CAPTURE6_INDEX], 4, {0}}, #endif #ifdef BSP_USING_CAPTURE7_CH1 {{0}, &stm32_capture_obj[CAPTURE7_INDEX], 1, {0}}, #endif #ifdef BSP_USING_CAPTURE7_CH2 {{0}, &stm32_capture_obj[CAPTURE7_INDEX], 2, {0}}, #endif #ifdef BSP_USING_CAPTURE7_CH3 {{0}, &stm32_capture_obj[CAPTURE7_INDEX], 3, {0}}, #endif #ifdef BSP_USING_CAPTURE7_CH4 {{0}, &stm32_capture_obj[CAPTURE7_INDEX], 4, {0}}, #endif #ifdef BSP_USING_CAPTURE8_CH1 {{0}, &stm32_capture_obj[CAPTURE8_INDEX], 1, {0}}, #endif #ifdef BSP_USING_CAPTURE8_CH2 {{0}, &stm32_capture_obj[CAPTURE8_INDEX], 2, {0}}, #endif #ifdef BSP_USING_CAPTURE8_CH3 {{0}, &stm32_capture_obj[CAPTURE8_INDEX], 3, {0}}, #endif #ifdef BSP_USING_CAPTURE8_CH4 {{0}, &stm32_capture_obj[CAPTURE8_INDEX], 4, {0}}, #endif #ifdef BSP_USING_CAPTURE9_CH1 {{0}, &stm32_capture_obj[CAPTURE9_INDEX], 1, {0}}, #endif #ifdef BSP_USING_CAPTURE9_CH2 {{0}, &stm32_capture_obj[CAPTURE9_INDEX], 2, {0}}, #endif #ifdef BSP_USING_CAPTURE9_CH3 {{0}, &stm32_capture_obj[CAPTURE9_INDEX], 3, {0}}, #endif #ifdef BSP_USING_CAPTURE9_CH4 {{0}, &stm32_capture_obj[CAPTURE9_INDEX], 4, {0}}, #endif #ifdef BSP_USING_CAPTURE10_CH1 {{0}, &stm32_capture_obj[CAPTURE10_INDEX], 1, {0}}, #endif #ifdef BSP_USING_CAPTURE10_CH2 {{0}, &stm32_capture_obj[CAPTURE10_INDEX], 2, {0}}, #endif #ifdef BSP_USING_CAPTURE10_CH3 {{0}, &stm32_capture_obj[CAPTURE10_INDEX], 3, {0}}, #endif #ifdef BSP_USING_CAPTURE10_CH4 {{0}, &stm32_capture_obj[CAPTURE10_INDEX], 4, {0}}, #endif #ifdef BSP_USING_CAPTURE12_CH1 {{0}, &stm32_capture_obj[CAPTURE12_INDEX], 1, {0}}, #endif #ifdef BSP_USING_CAPTURE12_CH2 {{0}, &stm32_capture_obj[CAPTURE12_INDEX], 2, {0}}, #endif }; static rt_uint64_t get_timer_clock(TIM_HandleTypeDef *htim) { rt_uint64_t tim_clock = 0; #if defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) if (htim->Instance == TIM9 || htim->Instance == TIM10 || htim->Instance == TIM11 || htim->Instance == TIM1 || htim->Instance == TIM8) #elif defined(SOC_SERIES_STM32L4) if (htim->Instance == TIM15 || htim->Instance == TIM16 || htim->Instance == TIM17) #elif defined(SOC_SERIES_STM32MP1) if (htim->Instance == TIM4) #elif defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0) if (0) #endif { #if !defined(SOC_SERIES_STM32F0) && !defined(SOC_SERIES_STM32G0) #ifdef STM32F413xx tim_clock = HAL_RCC_GetPCLK2Freq(); #else tim_clock = HAL_RCC_GetPCLK2Freq() * 2; #endif #endif } else { #if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0) tim_clock = HAL_RCC_GetPCLK1Freq(); #else tim_clock = HAL_RCC_GetPCLK1Freq() * 2; #endif } return tim_clock; } static void rt_hw_capture_timer_init(struct stm32_capture *device) { TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_IC_InitTypeDef sConfigIC = {0}; rt_uint64_t tim_clock; if (device->inited) { return; } tim_clock = get_timer_clock(&device->timer) / 1000000; /* configure the timer to ic mode */ device->timer.Init.Prescaler = tim_clock-1; device->timer.Init.CounterMode = TIM_COUNTERMODE_UP; device->timer.Init.Period = MAX_PERIOD-1; device->timer.Init.AutoReloadPreload = MAX_PERIOD-1; device->timer.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; #if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32L4) device->timer.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; #else device->timer.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; #endif if (device->advanced && HAL_TIM_Base_Init(&device->timer) != HAL_OK) { Error_Handler(); } if (HAL_TIM_IC_Init(&device->timer) != HAL_OK) { Error_Handler(); } HAL_NVIC_SetPriority(device->iqrn, 0, 0); HAL_NVIC_EnableIRQ(device->iqrn); sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&device->timer, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&device->timer, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; sConfigIC.ICFilter = 0; if (device->channels[0] != RT_NULL && HAL_TIM_IC_ConfigChannel(&device->timer, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } if (device->channels[1] != RT_NULL && HAL_TIM_IC_ConfigChannel(&device->timer, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } if (device->channels[2] != RT_NULL && HAL_TIM_IC_ConfigChannel(&device->timer, &sConfigIC, TIM_CHANNEL_3) != HAL_OK) { Error_Handler(); } if (device->channels[3] != RT_NULL && HAL_TIM_IC_ConfigChannel(&device->timer, &sConfigIC, TIM_CHANNEL_4) != HAL_OK) { Error_Handler(); } __HAL_TIM_DISABLE(&device->timer); __HAL_TIM_SET_COUNTER(&device->timer,0); __HAL_TIM_ENABLE_IT(&device->timer,TIM_IT_UPDATE); __HAL_TIM_ENABLE(&device->timer); device->inited = RT_TRUE; } static rt_err_t rt_hw_capture_open(struct rt_inputcapture_device *inputcapture) { struct stm32_capture_device *device_ch; rt_uint32_t ch; rt_enter_critical(); device_ch = rt_container_of(inputcapture, struct stm32_capture_device, parent); if (device_ch->opend) { rt_exit_critical(); return RT_EOK; } device_ch->opend = RT_TRUE; rt_hw_capture_timer_init(device_ch->timer); rt_exit_critical(); switch (device_ch->ch) { case 1: ch = TIM_CHANNEL_1; break; case 2: ch = TIM_CHANNEL_2; break; case 3: ch = TIM_CHANNEL_3; break; default: ch = TIM_CHANNEL_4; break; } HAL_TIM_IC_Start_IT(&device_ch->timer->timer, ch); return RT_EOK; } void TIM2_IRQHandler(void) { /* enter interrupt */ rt_interrupt_enter(); HAL_TIM_IRQHandler(&stm32_capture_obj[CAPTURE2_INDEX].timer); /* leave interrupt */ rt_interrupt_leave(); } void TIM1_CC_IRQHandler(void) { /* enter interrupt */ rt_interrupt_enter(); HAL_TIM_IRQHandler(&stm32_capture_obj[CAPTURE1_INDEX].timer); /* leave interrupt */ rt_interrupt_leave(); } void TIM8_BRK_TIM12_IRQHandler(void) { /* enter interrupt */ rt_interrupt_enter(); HAL_TIM_IRQHandler(&stm32_capture_obj[CAPTURE12_INDEX].timer); /* leave interrupt */ rt_interrupt_leave(); } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { int i = 0; for (i = 0; i < sizeof(stm32_capture_obj) / sizeof(stm32_capture_obj[0]); i++) { if (stm32_capture_obj[i].timer.Instance == htim->Instance) { stm32_capture_obj[i].tim_overflow ++; } } } static void _capture_computer(struct stm32_capture_device *dev, rt_uint32_t channel) { rt_uint32_t trigger_overflow = 0; rt_uint32_t trigger_cnt = 0; if (dev->data.polarity == POLARITY_RISING) { TIM_RESET_CAPTUREPOLARITY(&dev->timer->timer, channel); TIM_SET_CAPTUREPOLARITY(&dev->timer->timer,channel, TIM_ICPOLARITY_FALLING); dev->data.polarity = POLARITY_FALLING; } else { TIM_RESET_CAPTUREPOLARITY(&dev->timer->timer, channel); TIM_SET_CAPTUREPOLARITY(&dev->timer->timer,channel, TIM_ICPOLARITY_RISING); dev->data.polarity = POLARITY_RISING; } trigger_cnt = HAL_TIM_ReadCapturedValue(&dev->timer->timer, channel); trigger_overflow = dev->timer->tim_overflow; if((trigger_overflow < dev->data.last_overflow) || ((trigger_overflow - dev->data.last_overflow) > MAX_PULSE)) { dev->data.last_overflow = trigger_overflow; dev->data.last_cnt = trigger_cnt; return; } dev->pulsewidth_us = (trigger_overflow - dev->data.last_overflow)*MAX_PERIOD + trigger_cnt - dev->data.last_cnt; rt_hw_inputcapture_isr(&dev->parent, dev->data.polarity != POLARITY_FALLING); dev->data.last_overflow = trigger_overflow; dev->data.last_cnt = trigger_cnt; return; } void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { int i = 0; rt_uint32_t ch, to; for (i = 0; i < sizeof(stm32_capture_devices) / sizeof(stm32_capture_devices[0]); i++) { switch (stm32_capture_devices[i].ch) { case 1: ch = HAL_TIM_ACTIVE_CHANNEL_1; to = TIM_CHANNEL_1; break; case 2: ch = HAL_TIM_ACTIVE_CHANNEL_2; to = TIM_CHANNEL_2; break; case 3: ch = HAL_TIM_ACTIVE_CHANNEL_3; to = TIM_CHANNEL_3; break; default: ch = HAL_TIM_ACTIVE_CHANNEL_4; to = TIM_CHANNEL_4; break; } if (htim->Channel == ch && htim->Instance == stm32_capture_devices[i].timer->timer.Instance) { _capture_computer(&stm32_capture_devices[i], to); } } } static rt_err_t rt_hw_capture_get_pulsewidth (struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us) { struct stm32_capture_device *device; device = rt_container_of(inputcapture, struct stm32_capture_device, parent); *pulsewidth_us = device->pulsewidth_us; return RT_EOK; } static rt_err_t rt_hw_capture_init (struct rt_inputcapture_device *inputcapture) { return RT_EOK; } static rt_err_t rt_hw_capture_close (struct rt_inputcapture_device *inputcapture) { struct stm32_capture_device *device_ch; rt_uint32_t ch; rt_enter_critical(); device_ch = rt_container_of(inputcapture, struct stm32_capture_device, parent); if (!device_ch->opend) { rt_exit_critical(); return RT_EOK; } switch (device_ch->ch) { case 1: ch = TIM_CHANNEL_1; break; case 2: ch = TIM_CHANNEL_2; break; case 3: ch = TIM_CHANNEL_3; break; default: ch = TIM_CHANNEL_4; break; } HAL_TIM_IC_Stop_IT(&device_ch->timer->timer, ch); device_ch->opend = RT_FALSE; rt_exit_critical(); return RT_EOK; } static const struct rt_inputcapture_ops _drv_ops = { .init = rt_hw_capture_init, .open = rt_hw_capture_open, .close = rt_hw_capture_close, .get_pulsewidth = rt_hw_capture_get_pulsewidth, }; int stm32_capture_init(void) { int i = 0; char name[] = "tc00ch0"; for (i = 0; i < sizeof(stm32_capture_devices) / sizeof(stm32_capture_devices[0]); i++) { stm32_capture_devices[i].timer->channels[stm32_capture_devices[i].ch - 1] = &stm32_capture_devices[i]; stm32_capture_devices[i].parent.ops = &_drv_ops; rt_snprintf(name, sizeof(name),"tc%dch%d", stm32_capture_devices[i].timer->timerx, stm32_capture_devices[i].ch); rt_device_inputcapture_register(&stm32_capture_devices[i].parent, name, RT_NULL); } return RT_EOK; } #endif