基于gd32f4xx的rtthread使用hwtimer遇到的问题

1、问题描述

使用rtthread框架自带的hwtimer实现硬件定时时,会出现如下问题:

  1. 用hwtimer默认的频率rt_hwtimer_device.freq(即1000000)时,发现设置的超时时间会减半。比如设置10秒超时,实际是5秒就超时。
  2. 为了减少硬件定时器的中断次数,将rt_hwtimer_device.freq设置为1000,超时时间变得很诡异。比如设置5秒超时,实际是860毫秒就超时,而且启动定时器后会立马进入一次ISR。

2、查找问题的原因

先说结论:

  1. rtthread设置硬件定时器的分频时,使用的定时器时钟不准确,导致最终的超时时间不是预想的值。
  2. 定时器的分频寄存器是16位,当设置的rt_hwtimer_device.freq太小时,会导致分频值超过65535,从而实际设置到分配寄存器的值被截断。

查看drv_hwtimer.c源码的__set_timerx_freq函数的实现,如下:

static void __set_timerx_freq(uint32_t timerx, uint32_t freq)
{
    uint32_t ap1freq, ap2freq;
    uint16_t prescaler;
    uint32_t temp;
 
    if (timerx == TIMER0 || timerx == TIMER7 || timerx == TIMER8 \
        || timerx == TIMER9 || timerx == TIMER10)
    {
        ap2freq = rcu_clock_freq_get(CK_APB2);
        temp = RCU_CFG0 & RCU_CFG0_APB2PSC;
        temp >>= 11;  // 此处错误,应该改为 temp >>= 13。因为APB2 Prescaler的分频在RCU_CFG0寄存器的[13:15]位
        /* whether should frequency doubling */
        temp = (temp < 4) ? 0 : 1;
 
        prescaler = (ap2freq << temp) / freq - 1;
    }
    else
    {
        ap1freq = rcu_clock_freq_get(CK_APB1);
        temp = RCU_CFG0 & RCU_CFG0_APB1PSC;
        temp >>= 8;    // 此处错误,应该改为 temp >>= 10。因为APB1 Prescaler的分频在RCU_CFG0寄存器的[10:12]位
        /* whether should frequency doubling */
        temp = (temp < 4) ? 0 : 1;
 
        prescaler = (ap1freq << temp) / freq - 1;
    }
 
    timer_prescaler_config(timerx, prescaler, TIMER_PSC_RELOAD_NOW);
}

此函数的作用是根据freq设置定时器的分频值prescaler。

定时器的时钟设置如下图所示

TIMER1/2/3/4/5/6/11/12/13属于APB1;TIMER0/7/8/9/10属于APB2。以TIMER4为例,它的时钟由CK_AHB、APB1 Prescaler的分频(由RCU_CFG0寄存器的[10:12]位(APB1PSC[2:0])设置)和CK_APB1的倍频(由RCU_CFG1寄存器的[24]位(TIMERSEL))实现。

而__set_timerx_freq函数只考虑了APB1的分频值。且获取分频值的寄存器移位错误,上面的函数中已标注。

rcu_clock_freq_get(CK_APB1)函数获取CK_APB1的值,即CK_AHB经过APB1 Prescaler分频后的值,由它决定prescaler的值。而实际上还需考虑CK_APB1的倍频值。并不能简单的用表达式temp = (temp < 4) ? 0 : 1;获取定时器的时钟。

当rtthread使用硬件PWM时,会调用 rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);将定时器频率重新设置为与CK_AHB一样的值(APB1分频值为4,此函数倍频为4)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值