RISC-V技术论坛
直播中

岳臻俊

9年用户 1167经验值
私信 关注
[经验]

如何利用蜂鸟HbirdV2-SoC自带外设PWM进行毫秒级的延时和计时

1    队伍介绍

本篇主要介绍如何利用蜂鸟HbirdV2-SoC自带外设PWM进行毫秒级的延时和计时。

2    tiM0配置




在上一个帖子中,介绍了HbirdV2-SoC自带外设PWM的寄存器配置,并在文末贴上了详细的源码。本次以该源码为基础,完成毫秒级的定时。

首先,利用源码中提供的函数,将TIM0配置为如下所示:

本配置中,先配置TIM0的预分频为0,以原生时钟进行计数。

其次,设置TIM0计数到阈值后,重置计数值为startvalue

选择高速主时钟作为TIM0时钟源,原生e203主时钟为16MHz,若修改过硬件源码,则应注意修改后频率。

设置TIM0在每个时钟都触发事件。并设置初始计数值为0,计数阈值为0xffff,之后使能TIM0,更新TIM0寄存器配置,重置并启动计数。

最后一步中,利用e203自带函数获取当前主时钟频率,赋值给全局变量SOC_CORE_FREQ(注:该全局变量需要自己提前声明)

void TIM0_Init()

{

  TIMNum timer  = TIM_0;

  TIM_set_prescaler(timer, 0);

  TIM_updown_sel(timer, TIM_COUNT_UP_RST);

  TIM_clk_sel(timer, TIM_CORE_CLK);

  //TIM_InputSource_sel(timer, 0);

  TIM_set_mode(timer, TIM_MODE_CYCLE);

  TIM_set_StartValue(timer, 0);

  TIM_set_EndValue(timer, 0Xffff);

  //TIM_set_CHxThreshold(timer, TIM_TH_CHANNEL0, 10000);

  //TIM_set_CHxMode(timer, TIM_TH_CHANNEL0, TIM_TH_TOGGLE);



  //TIM_interruptSource_sel(TIM_TH_CHANNEL2, 1);

  //TIM_interrput_disable(TIM_TH_CHANNEL2);

  //TIM_interrput_enable(TIM_TH_CHANNEL2);

  TIM_enable(timer);

  //TIM_disable(TIM_0);

  TIM_cmd(timer, TIM_CMD_UPDATA);

  TIM_cmd(timer, TIM_CMD_RST);

  TIM_cmd(timer, TIM_CMD_START);

  SOC_CORE_FREQ = get_cpu_freq();

}

完成TIM0配置后,就可以设置一个微秒级的延时函数了,本例中模仿e203自带的delay_1ms()函数,实现了delay_50us()函数,该延时函数定义如下:

void delay_50us(uint32_t count)

{

    uint16_t start_time, delta_time;

    uint16_t delay_ticks = (uint16_t) (SOC_CORE_FREQ / 20000);

    for(uint32_t i=0; i<count; i++)

    {

      TIM_cmd(TIM_0, TIM_CMD_RST);

      TIM_cmd(TIM_0, TIM_CMD_START);

      start_time = TIM_get_cnt(TIM_0);



      do

      {

        delta_time = TIM_get_cnt(TIM_0) - start_time;

      } while (delta_time < delay_ticks);

    }

}

值得注意的是,e203主频仅为16MHz,也就是说,计数16次为1us。然而,在获取start_time之后运行do while语句以及获取delta_time,都要经过复数个机器周期,显然,计数16次实现1us延迟是极不精准的。为了达到一定了精度要求,本例中仅实现50us的延时。

其次,TIM0的计数寄存器仅为16位,用在16MHz主时钟对其进行计数时,最大delay仅为4.096ms,因此,改用一个for循环来实现长时间计数。

3    验证所设计的延时函数




本节为了验证所设计的延时函数的性能,利用e203自带的RTC时钟来验证设计的delay_50us()函数。相关代码如下

    uint32_t start_mtime, delta_mtime;

    start_mtime = SysTimer_GetLoadValue();

    delay_50us(200);

    delta_mtime = SysTimer_GetLoadValue() - start_mtime;

printf("expected delay is 10ms, actual delay is %dns n", (delta_mtime*30517));

该段代码输出结果如下:



可以看到,进行微秒级延迟时,精度误差比较大,约为15.04%,该微秒级延迟能在一些对时序精度要求不那么高的应用,例如OV5640摄像头配置中SCCB协议信号的延迟。

同时,若要达到更高的精度要求,可以参考e203自带delay_1ms()函数设计,但是延时时间不宜超过4ms。其次,可以增大延迟步长为100us200us,以减小微秒级延迟函数误差。



更多回帖

发帖
×
20
完善资料,
赚取积分