【RT-Thread】nxp rt10xx 设备驱动框架之--hwtimer搭建和使用

17 篇文章 4 订阅
13 篇文章 2 订阅

hwtimer 为我们常用的硬件定时器,下面将使用gpt定时器实现设备驱动搭建

开发前准备

  • 硬件平台:nxp rt10xx单片机
  • IDE: Keil

1.Kconfig 修改和menuconfig配置

Env环境menuconfigRT-Thread Components->Device Drivers 设备驱动默认为n,所以需要开启

请添加图片描述

先在Kconfig中添加如下语句,然后在Env环境menuconfigHardware Drivers Config->On-Chip Peripheral Drivers,然后根据需要选择指定HWTIMER,笔者用的外设GPT1即:HWTIMER1

请添加图片描述

2.工程添加HWTIMER驱动框架和BSP驱动接口

设备驱动框架:hwtimer.c BSP接口:drv_hwtimer.c fsl_gpt.c

请添加图片描述

3.添加或修改drv_hwtimer.c

笔者查阅了文件,该驱动比较完善,笔者改动了时钟源,使用osc 24M做为时钟源,另外把一些多余配置删除掉了

  • 定义rt_hwtimer_ops结构
struct rt_hwtimer_ops
{
    void (*init)(struct rt_hwtimer_device *timer, rt_uint32_t state);
    rt_err_t (*start)(struct rt_hwtimer_device *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode);
    void (*stop)(struct rt_hwtimer_device *timer);
    rt_uint32_t (*count_get)(struct rt_hwtimer_device *timer);
    rt_err_t (*control)(struct rt_hwtimer_device *timer, rt_uint32_t cmd, void *args);
};
  • 实现ops
static const struct rt_hwtimer_ops imxrt_hwtimer_ops =
{
    .init = imxrt_hwtimer_init,
    .start = imxrt_hwtimer_start,
    .stop = imxrt_hwtimer_stop,
    .count_get = imxrt_hwtimer_count_get,
    .control = imxrt_hwtimer_control,
};
  • 设备创建注册
int rt_hw_hwtimer_init(void)
{
    int ret = RT_EOK;

#ifdef BSP_USING_HWTIMER1
    GPT_timer1.info = &imxrt_hwtimer_info;
    GPT_timer1.ops  = &imxrt_hwtimer_ops;
    ret = rt_device_hwtimer_register(&GPT_timer1, "gpt1", GPT1);

    if (ret != RT_EOK)
    {
        LOG_E("gpt1 register failed\n");
    }
#endif

#ifdef BSP_USING_HWTIMER2
    GPT_timer2.info = &imxrt_hwtimer_info;
    GPT_timer2.ops = &imxrt_hwtimer_ops;
    ret = rt_device_hwtimer_register(&GPT_timer2, "gpt2", GPT2);

    if (ret != RT_EOK)
    {
        LOG_E("gpt1 register failed\n");
    }
#endif

    return ret;
}
  • ops相关函数

时钟源选择和中断优先级是笔者改掉的地方,这里全部贴上代码

#define GPT_CLK_FREQ     CLOCK_GetFreq(kCLOCK_OscClk)
#define SAI_ISR_PRE      (14U)

static void NVIC_Configuration(void)
{
#ifdef BSP_USING_HWTIMER1
	NVIC_SetPriority(GPT1_IRQn,SAI_ISR_PRE);
    EnableIRQ(GPT1_IRQn);
#endif

#ifdef BSP_USING_HWTIMER2
	NVIC_SetPriority(GPT2_IRQn,SAI_ISR_PRE);
    EnableIRQ(GPT2_IRQn);
#endif
}

static rt_err_t imxrt_hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
{
    rt_err_t err = RT_EOK;
    GPT_Type *hwtimer_dev;
    hwtimer_dev = (GPT_Type *)timer->parent.user_data;

    RT_ASSERT(timer != RT_NULL);

    switch (cmd)
    {
        case HWTIMER_CTRL_FREQ_SET:
        {
            uint32_t clk;
            uint32_t pre;
            clk = GPT_CLK_FREQ;
            pre = clk / *((uint32_t *)args);
            GPT_SetClockDivider(hwtimer_dev, pre);
        }
        break;
        default:
            err = -RT_ENOSYS;
            break;
    }
    return err;
}

static rt_uint32_t imxrt_hwtimer_count_get(rt_hwtimer_t *timer)
{
    rt_uint32_t CurrentTimer_Count;
    GPT_Type *hwtimer_dev;
    hwtimer_dev = (GPT_Type *)timer->parent.user_data;

    RT_ASSERT(timer != RT_NULL);

    CurrentTimer_Count = GPT_GetCurrentTimerCount(hwtimer_dev);

    return CurrentTimer_Count;
}

static void imxrt_hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state)
{
    GPT_Type *hwtimer_dev;
    gpt_config_t gptConfig;
    hwtimer_dev = (GPT_Type *)timer->parent.user_data;

    RT_ASSERT(timer != RT_NULL);

    if (state == 1)
    {
        /* Initialize GPT module by default config */
        GPT_GetDefaultConfig(&gptConfig);
        gptConfig.clockSource = kGPT_ClockSource_Osc; //选择外设时钟
        gptConfig.divider = 24;	                      //设置分频系数   24M/24 = 1M     
        GPT_Init(hwtimer_dev, &gptConfig);
    }
}

static rt_err_t imxrt_hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
{
    GPT_Type *hwtimer_dev;
    hwtimer_dev = (GPT_Type *)timer->parent.user_data;

    RT_ASSERT(timer != RT_NULL);

    hwtimer_dev->CR |= (mode != HWTIMER_MODE_PERIOD) ? GPT_CR_FRR_MASK : 0U;

    GPT_SetOutputCompareValue(hwtimer_dev, kGPT_OutputCompare_Channel1, cnt);

    GPT_EnableInterrupts(hwtimer_dev, kGPT_OutputCompare1InterruptEnable);

    NVIC_Configuration();

    GPT_StartTimer(hwtimer_dev);

    return RT_EOK;
}

static void imxrt_hwtimer_stop(rt_hwtimer_t *timer)
{
    GPT_Type *hwtimer_dev;
    hwtimer_dev = (GPT_Type *)timer->parent.user_data;

    RT_ASSERT(timer != RT_NULL);

    GPT_StopTimer(hwtimer_dev);
}

4.搭建应用层demo

开启定时器,查阅时间精度是否ok

/**************************************************START OF FILE*****************************************************/






/*------------------------------------------------------------------------------------------------------------------
Includes
*/
#include <rtthread.h>
#include <rtdevice.h>


/*------------------------------------------------------------------------------------------------------------------
Macros
*/
#define HWTIMER_DEVICE_NAME "gpt1" /* 硬件定时器设备名称 */


/*------------------------------------------------------------------------------------------------------------------
Variables
*/


/*------------------------------------------------------------------------------------------------------------------
Functions
*/
/* 定时器超时回调函数 */
static rt_err_t timer_callback(rt_device_t dev, rt_size_t size)
{
     rt_kprintf("this is hwtimer timeout callback fucntion!\n");
     rt_kprintf("tick is :%d !\n", rt_tick_get());

    return 0;
}

int xAPP_HwTimerInit(void)
{
    rt_err_t ret = RT_EOK;
    rt_hwtimerval_t timeout_s;      /* 定时器超时值 */
    rt_device_t hw_dev = RT_NULL;   /* 定时器设备句柄 */
    rt_hwtimer_mode_t mode;         /* 定时器模式 */
    rt_uint32_t freq = 100000;      /* 计数频率 */    

    hw_dev = rt_device_find(HWTIMER_DEVICE_NAME);
    if (hw_dev == RT_NULL)
    {
        rt_kprintf("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEVICE_NAME);
        return RT_ERROR;
    }

    ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
    if (ret != RT_EOK)
    {
        rt_kprintf("open %s device failed!\n", HWTIMER_DEVICE_NAME);
        return ret;
    }

    /* 设置超时回调函数 */
    rt_device_set_rx_indicate(hw_dev, timer_callback);

    /* 设置计数频率(若未设置该项,默认为1Mhz 或 支持的最小计数频率) */
    rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);
    mode = HWTIMER_MODE_PERIOD;
    ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
    if (ret != RT_EOK)
    {
        rt_kprintf("set mode failed! ret is :%d\n", ret);
        return ret;
    }

    /* 设置定时器超时值为5s并启动定时器 */
    timeout_s.sec = 5;      /* 秒 */
    timeout_s.usec = 0;     /* 微秒 */
    if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
    {
        rt_kprintf("set timeout value failed\n");
        return RT_ERROR;
    }

    /* 延时3200ms */
    rt_thread_mdelay(3200);
    rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
    rt_kprintf("Read: Sec = %d, Usec = %d\n", timeout_s.sec, timeout_s.usec);

    return ret;
}

/****************************************************END OF FILE*****************************************************/


请添加图片描述

补充一下,gpt换算方式:

时钟源为24M,分频系数 0xEF + 1 = 240,可得时钟为:100000Hz,COMP:0x7A120 即:500000

500000/100000=5s 所以5s中断一次

请添加图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值