补偿ARM中断的延迟?

补偿ARM中断的延迟?,arm,counter,interrupt,stm32,low-latency,Arm,Counter,Interrupt,Stm32,Low Latency,我在STM32F4 CPU上做一个项目,生成信号 我在STM32上有一个通用的CPU时钟定时器(没有预分频器),在溢出时触发中断,以生成GPIO的周期信号 我需要在非常精确的时间触发thr GPIO(基本上降低到一个CPU周期的精度)。我已经设法通过设置优先级将抖动减少到+-5个周期&al,但是这种抖动是存在的,这取决于CPU在做什么 我需要补偿这几个周期的抖动。只要我在一个精确的时间切换GPIOs,增加几个周期的延迟就不是问题 我的想法是读取计数器的当前值,并有一个固定数量-当前值时间的活动循

我在STM32F4 CPU上做一个项目,生成信号

我在STM32上有一个通用的CPU时钟定时器(没有预分频器),在溢出时触发中断,以生成GPIO的周期信号

我需要在非常精确的时间触发thr GPIO(基本上降低到一个CPU周期的精度)。我已经设法通过设置优先级将抖动减少到+-5个周期&al,但是这种抖动是存在的,这取决于CPU在做什么

我需要补偿这几个周期的抖动。只要我在一个精确的时间切换GPIOs,增加几个周期的延迟就不是问题

我的想法是读取计数器的当前值,并有一个固定数量-当前值时间的活动循环,确保在精确的时间退出循环

然而,在C中做一个简单的循环——作为一个FOR循环,或者一段时间(counter->value 我是不是做错了什么/太天真了?我应该在组装时做吗?这与C有什么不同(我用GCC检查了反汇编,以检查循环没有优化,也没有命中内存?)

(我使用空的、未优化但未命中内存循环体的方式确保)

编辑:在AVR上看这个例子(我知道它更稳定),按例子看(搜索“抖动”)

edit2:我在汇编中尝试了一个简单的循环,例如(r0是我的计数器,要等待的周期数,在寄存器中)

同样,没有它抖动会更好

总而言之,我已经知道我应该推迟多少时间了。我只需要一种方法,让一个代码分支在一种情况下可靠地消耗N个周期,在另一种情况下消耗M个周期。不幸的是,分支本身似乎不起作用,因为管道重新填充似乎没有可靠的周期数,而条件表达式也不起作用,因为它们总是采用相同的周期数(有时什么也不做)

从RAM而不是闪存运行会提高一致性吗?(NB stm32f4有一个闪存预取…)

(讽刺的是,一个关于减少响应延迟的问题花了三年时间才得到答案。)

+/-5个周期听起来非常熟悉。在中断调度期间,您可能正在访问闪存控制器的等待状态

CPU在中断调度期间需要做三件事:

  • 加载向量表条目
  • 加载中断例程的初始代码
  • 将一些寄存器写入堆栈
  • 如果向量表和/或中断例程代码在闪存中,则第1项和第2项中的回迁将转到闪存。当以最高额定速度(高达168MHz)运行CPU时,访问闪存需要五种等待状态。这意味着对闪存的访问可能需要1或6个周期,这取决于所请求的数据是否在闪存缓存中。如果您正好看到0或5个延迟周期,那么这很可能是罪魁祸首。通过将ISR代码和向量表移动到RAM中,最容易解决此问题。您还可以通过禁用闪存缓存来“修复”它,这将导致闪存访问速度降低

    还有一个更隐秘的因素也可能会困扰您:如果被中断的代码也在使用闪存,则中断调度可能必须等待其闪存访问完成,假设它未命中缓存。您也可以通过将中断的代码移动到RAM中来解决这个问题,但是在这一点上,听起来好像Flash中没有任何东西存在。我在下面提到了一种将代码保存在Flash中的方法

    最后,还有一件更隐蔽的事情:如果在延迟敏感的中断之前可能发生其他中断,则该中断可能会由于延迟而获得-5个延迟周期

    对于我列出的后两个问题,我的解决方案有点奇怪:确保处理器处于空闲状态,即当中断发生时,不要再进行中断或从闪存获取数据。我这样做的方式是配置一个较低优先级的中断,使其刚好在延迟敏感中断之前到达(使用定时器);ISR只执行等待中断指令,
    wfi

    这些都是可以克服的问题。我不同意评论说你需要放弃C语言而用汇编语言编写;我的系统几乎不包含汇编语言,抖动非常低


    我将在中更详细地讨论这些问题和我的解决方案。

    克里夫是正确的,在具有中断、闪存等待状态和管道的CPU内核上,无法获得单一CPU周期精度。顺便说一句,有点奇怪的视差“推进器”是为数不多的能够保证周期时间一致性的“高性能”MCU内核之一,因为它不支持中断(而是“旋转”访问集线器中的8个内核)。

    你知道你无法获得单个周期的精度是吗?如果您希望达到这种精度,请让计时器直接向gpio馈电或直接使用计时器输出。不管您使用的是什么处理器,它们都倾向于在开始处理中断之前完成当前指令。完成一条指令所需的时钟周期数因指令而异,即使只有一个异常,您也无法满足周期计时要求。如果您希望获得极高的性能或精度,C或任何编译语言都绝对是您的敌人。您正在使用的处理器可以运行速度高达168mhz或在该范围内的某个地方,并具有数据和指令缓存,如果您的速度远未达到该速度(请注意,如果从缓存运行,闪存不会更快,您仍然会受到它的限制),则提高速度,将您的要求更改为+/-多个周期。对于dwelch-是,多个长度指令将被中断,从而产生抖动。但是,从中断处理程序获取计数器的值可以告诉我应该等待多少时间。在这里,我不应该被打断,所以从理论上讲,实现固定的延迟似乎是可行的
    loop : SUBS r0,#1 ; tried with 2 also
           BGE loop