RT-Thread 4.0.0
訪問硬件定時器設備
應用程序通過 RT-Thread 提供的 I/O 設備管理接口來訪問硬件定時器設備,相關接口如下所示:
函數 | 描述 |
---|---|
rt_device_find() | 查找定時器設備 |
rt_device_open() | 以讀寫方式打開定時器設備 |
rt_device_set_rx_indicate() | 設置超時回調函數 |
rt_device_control() | 控制定時器設備,可以設置定時模式(單次/周期)/計數頻率,或者停止定時器 |
rt_device_write() | 設置定時器超時值,定時器隨即啟動 |
rt_device_read() | 獲取定時器當前值 |
rt_device_close() | 關閉定時器設備 |
RT-Thread 提供的 I/O 設備硬件定時器,示例僅提供最通用簡單的定時功能,其他定時器高級功能需自行在control中添加;
下面對基於CubeMX、Hal庫的BSP的硬件定時器的使用做簡單描述。
配置CubeMX
配置之后生成代碼,
在 stm32f4xx_hal_conf.h 中 會實現 hal模塊驅動
#define HAL_TIM_MODULE_ENABLED
修改工程目錄下的 Kconfig
在 Kconfig 中添加對 TIM的支持
menuconfig BSP_USING_TIM bool "Enable Hardware TIM" default n select RT_USING_HWTIMER if BSP_USING_TIM config BSP_USING_TIM1 bool "Enable TIM1" default n config BSP_USING_TIM2 bool "Enable TIM2" default n config BSP_USING_TIM3 bool "Enable TIM3" default n config BSP_USING_TIM4 bool "Enable TIM4" default n config BSP_USING_TIM5 bool "Enable TIM5" default n config BSP_USING_TIM6 bool "Enable TIM6" default n
然后使用Env工具 menuconfig 中使能 TIM3、TIM4
然后 scons --target=mdk5
用keil打開工程后在 tim_config.h 中 添加 TIM3、TIM4的配置
#ifdef BSP_USING_TIM3 #ifndef TIM3_CONFIG #define TIM3_CONFIG \ { \ .tim_handle.Instance = TIM3, \ .tim_irqn = TIM3_IRQn, \ .name = "timer3", \ } #endif /* TIM3_CONFIG */ #endif /* BSP_USING_TIM3 */ #ifdef BSP_USING_TIM4 #ifndef TIM4_CONFIG #define TIM4_CONFIG \ { \ .tim_handle.Instance = TIM4, \ .tim_irqn = TIM4_IRQn, \ .name = "timer4", \ } #endif /* TIM4_CONFIG */ #endif /* BSP_USING_TIM4 */
然后就可以在應用中直接操作設備名為 "timer3" 和 "timer4" 的設備了。
設備驅動分析
定時器設備 I/O 實現
hwtimer.c hwtimer.h
定時器底層驅動實現(操作Hal庫)
drv_hwtimer.c drv_hwtimer.h
下面主要追蹤以下定時器設備的注冊及其初始化
在 drv_hwtimer.c 中 定時器自動初始化,並注冊設備
static int stm32_hwtimer_init(void) INIT_BOARD_EXPORT(stm32_hwtimer_init);
其中 hwtimer_ops.rt_hwtimer_init 會 調用 timer_init
static void timer_init(struct rt_hwtimer_device *timer, rt_uint32_t state) { uint32_t prescaler_value = 0; TIM_HandleTypeDef *tim = RT_NULL; struct stm32_hwtimer *tim_device = RT_NULL; RT_ASSERT(timer != RT_NULL); if (state) { tim = (TIM_HandleTypeDef *)timer->parent.user_data; tim_device = (struct stm32_hwtimer *)timer; /* time init */ #if defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) if (tim->Instance == TIM9 || tim->Instance == TIM10 || tim->Instance == TIM11) #elif defined(SOC_SERIES_STM32L4) if (tim->Instance == TIM15 || tim->Instance == TIM16 || tim->Instance == TIM17) #elif defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32F0) if (0) #endif { #ifndef SOC_SERIES_STM32F0 prescaler_value = (uint32_t)(HAL_RCC_GetPCLK2Freq() * 2 / 10000) - 1; #endif } else { prescaler_value = (uint32_t)(HAL_RCC_GetPCLK1Freq() * 2 / 10000) - 1; } tim->Init.Period = 10000 - 1; tim->Init.Prescaler = prescaler_value; tim->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (timer->info->cntmode == HWTIMER_CNTMODE_UP) { tim->Init.CounterMode = TIM_COUNTERMODE_UP; } else { tim->Init.CounterMode = TIM_COUNTERMODE_DOWN; } tim->Init.RepetitionCounter = 0; #if defined(SOC_SERIES_STM32F1) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32F0) tim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; #endif if (HAL_TIM_Base_Init(tim) != HAL_OK) { LOG_E("%s init failed", tim_device->name); return; } else { /* set the TIMx priority */ HAL_NVIC_SetPriority(tim_device->tim_irqn, 3, 0); /* enable the TIMx global Interrupt */ HAL_NVIC_EnableIRQ(tim_device->tim_irqn); /* clear update flag */ __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); /* enable update request source */ __HAL_TIM_URS_ENABLE(tim); LOG_D("%s init success", tim_device->name); } } }
我們發現之前設置的配置並沒有使用,而是直接默認設置成頻率10K,周期1s的定時器;
可根據情況后面用control修改,或注釋掉 tim->Init. 的幾條賦值語句,使用 user_data 傳遞過來的默認配置;
同時 stm32f4xx_hal_msp.c 中的TIM硬件初始化,也僅僅只是打開TIM外設時鍾,所有鎖CubeMX中只要使能對應TIM即可,無需配置;
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base) { if(htim_base->Instance==TIM3) { /* USER CODE BEGIN TIM3_MspInit 0 */ /* USER CODE END TIM3_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_TIM3_CLK_ENABLE(); /* USER CODE BEGIN TIM3_MspInit 1 */ /* USER CODE END TIM3_MspInit 1 */ } else if(htim_base->Instance==TIM4) { /* USER CODE BEGIN TIM4_MspInit 0 */ /* USER CODE END TIM4_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_TIM4_CLK_ENABLE(); /* USER CODE BEGIN TIM4_MspInit 1 */ /* USER CODE END TIM4_MspInit 1 */ } }