在MCU上的1微秒的延迟实现方案及测量方法

发布于:2025-06-20 ⋅ 阅读:(24) ⋅ 点赞:(0)

运行环境: stm32h743iit6; 主频480MHz; APB1; 240MHz; TIM5 240MHz; 预分频系数为1; 定时器计数频率240MHz;

应用需求:实现软件模拟IIC,延迟精度2个微秒;

量变引起质变,当延迟粒度太小时,需要考虑延迟的实现策略是否适合。

目前的延迟策略:

  1. 传统的基于定时器中断策略;

  2. polling轮询等待策略;

对于强迫症和完美主义的人来讲,可能首选考虑的是中断策略。但是当下形势变化了,由于延迟时间过于短(2个微秒)所以对延迟精度要求较高。

根据当前判断,采取的是执行polling轮询等待策略实现。

实现正确延迟的前提是,必须保证各个节点的时钟频率是计算正确的符合实际的!

polling轮询等待策略的实现

  1. 根据外部为 timer 提供的时钟源速率、内部预分频系数等计算得到定时器的计数器的运行时频率,也就得到了1秒内计数器累加多少次的节拍; 当然可以计算获得1微秒需要走多少个节拍,这个可能更加实用。

  2. 程序内延迟开始时,直接摘取定时器计数器的当前值,作为开始的测量点;延迟结束后,再次直接读取定时器的计数器的当前值作为结束的测量点; 由此得到,延迟过程中定时器的计数器走过多少个节拍,也就是累加的增量是多少个。

  3. 根据前两步得到的,延迟总节拍数除以1微秒的节拍数就可以知道此过程延迟了多少个微秒。

注意:延迟过程内的代码应该尽量简洁,就是不要执行过多的不处于测量范围内的CPU指令,否则这部分也会被算进去导致测量有误差。

测量时代码实现上:

  1. 计算延迟 n 微秒需要的总步长,n*STEP,也就是计数器应该累加的增量值N;

  2. 将当前定时器的计数器的数值设置为零,从零开始计数;

  3. polling轮询 计数器的值 与 N 作比较,使其在不少于N的范围内继续等待,否则延迟时间达到,跳出延迟代码;

  4. 可以将受保护的代码使⽤禁⽤中断保护起来,运⾏结束再开启中断;

void delay_us (uint32_t us)
{
    //可以禁用中断,保证不可打断
    
    volatile uint32_t ticks = us * STEP_OF_TIM5_CNT;
    
    TIM5->CNT = 0;
    
    while (TIM5->CNT < ticks);
    
    //可以禁用中断,保证不可打断,且需要覆盖下面延迟的目的代码:比如IIC的电平转换,以保证效果。
    
}

如何测量延迟是否准确

测量延迟节拍数是否符合预期

原理前面讲了,可以通过调试软件观察得到节拍数,进行验证。

使用keil仿真调试

可以使用keil仿真观察直接显示的时间结果数据。在此之前,需要正确设置好keil,且确保MCU内有ARM debug IP core 的DWT(debug watch point)IP core支持,因为keil就是通过 jlink、stlink 间接获取DWT的计时数据。那么如何设置好keil呢?这里参考了鱼鹰的微博写的很好,做简明描述:

实际测试数据

案例2

案例3

案例4

这次延迟5000个微秒,误差只有1.30个微秒,属于正常刚好跟上⾯的误差延迟对应。说明⽐较准确了。可能上次有进出中断导致误差太⼤了!。


网站公告

今日签到

点亮在社区的每一天
去签到