RISC-V MCU中文社区

【分享】 HbirdV2-SoC微秒级延时实现

发表于 全国大学生集成电路创新创业大赛 2021-06-09 23:51:48
1
2879
0

1    队伍介绍

参赛队名:0 ERROR         队伍编号:CICC1957

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

2    TIM0配置

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

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

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

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

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

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

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

void TIM0_Init()

{

  TIMNum timer  = TIM_0;

  TIM_set_prescaler(timer0);

  TIM_updown_sel(timerTIM_COUNT_UP_RST);

  TIM_clk_sel(timerTIM_CORE_CLK);

  //TIM_InputSource_sel(timer, 0);

  TIM_set_mode(timerTIM_MODE_CYCLE);

  TIM_set_StartValue(timer0);

  TIM_set_EndValue(timer0Xffff);

  //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(timerTIM_CMD_UPDATA);

  TIM_cmd(timerTIM_CMD_RST);

  TIM_cmd(timerTIM_CMD_START);

  SOC_CORE_FREQ = get_cpu_freq();

}

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

void delay_50us(uint32_t count)

{

    uint16_t start_timedelta_time;

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

    for(uint32_t i=0i<counti++)

    {

      TIM_cmd(TIM_0TIM_CMD_RST);

      TIM_cmd(TIM_0TIM_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,以减小微秒级延迟函数误差。

喜欢0
用户评论 (1)
  • 陈洪玮

    2021-06-10 09:30:34 陈洪玮 1#

    补充:
            经过验证,将延迟函数修改为e203delay_1ms()函数样式后,delay_50us()精度可以达到0.7%(最大延时4ms,count为80),该误差大部分是由RTC的精度引起的,可以认为设计的延迟函数比较精准。下附代码和测试结果:

    修改后的delay_50us()函数:

    void delay_50us(uint32_t count)
    {
        uint16_t start_timedelta_time;

        uint16_t delay_ticks = (uint16_t) (count*SOC_CORE_FREQ / 20000);
        TIM_cmd(TIM_0TIM_CMD_RST);
        TIM_cmd(TIM_0TIM_CMD_START);
        start_time = TIM_get_cnt(TIM_0);
        do
        {
          delta_time = TIM_get_cnt(TIM_0) - start_time;
        } while (delta_time < delay_ticks);

    }

    测试用代码:

      uint32_t start_mtime, delta_mtime;
      start_mtime = SysTimer_GetLoadValue();
      delay_50us(80);
      delta_mtime = SysTimer_GetLoadValue() - start_mtime;
      printf("expected delay is 4ms, actual delay is %dnsrn", delta_mtime*30517);

    测试结果:


陈洪玮

陈洪玮 实名认证

懒的都不写签名

积分
问答
粉丝
关注
  • RV-STAR 开发板
  • RISC-V处理器设计系列课程
  • 培养RISC-V大学土壤 共建RISC-V教育生态
RV-STAR 开发板