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 */
}
}
来源:oschina
链接:https://my.oschina.net/u/4256408/blog/3520793