RT-Thread 設備驅動-硬件定時器淺析與使用


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 */
  }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM