5

我正在 STM32F4 CPU 上开发一个项目,生成信号。

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

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

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

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

然而,在 C 中做一个简单的循环——作为一个 FOR 循环,或者一个 while(counter->value < TARGET) 不起作用,因为它增加了抖动而不是减少它。

我做错了什么/天真吗?我应该在汇编中这样做吗?这与 C 有何不同(我用 GCC 检查了反汇编以检查循环没有被优化掉,也没有达到内存?)

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

编辑:在 AVR 上查看这个示例(我知道更稳定) 参见示例http://lucidscience.com/pro-vga%20video%20generator-7.aspx (搜索“jitter”)

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

loop : SUBS r0,#1 ; tried with 2 also
       BGE loop

而且,没有它,抖动会更好。

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

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

4

2 回答 2

9

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

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

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

  1. 加载向量表条目。
  2. 加载中断例程的初始代码。
  3. 将一些寄存器写入堆栈。

如果您的向量表和/或中断程序代码在 Flash 中,则第 1 项和第 2 项中的取指将转到 Flash。当 CPU 以最高额定速度(高达 168MHz)运行时,对 Flash 的访问需要五个等待状态。这意味着对 Flash 的访问可能需要 1 或 6 个周期,具体取决于所请求的数据是否在 Flash 缓存中。如果您正好看到0 或 5 个延迟周期,这可能是罪魁祸首。通过将 ISR 代码和向量表移动到 RAM中最容易解决此问题。您还可以通过禁用 Flash 缓存来“修复”它,这将导致 Flash 访问速度变慢。

有一个隐秘的因素也可能会咬你:如果被中断的代码也在使用 Flash,那么中断调度可能必须等待Flash 访问完成,假设它未命中缓存。您也可以通过将中断的代码移动到 RAM 中来解决此问题,但此时它开始听起来好像 Flash 中没有任何内容。有一种方法可以将代码保存在我在下面提到的 Flash 中。

最后,还有一个更隐秘的事情:如果您有其他中断可能您的延迟敏感中断之前发生,那么该中断可能会由于尾链而获得 -5 个延迟周期。

我对我列出的后两个问题的解决方案有点奇怪:确保处理器处于空闲状态,即当您的中断发生时,不接受另一个中断或从 Flash 获取。我这样做的方法是通过配置一个较低优先级的中断在我的延迟敏感中断之前到达(使用计时器);ISR 只是执行一条等待中断指令,wfi.

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

我在博客上的一篇文章中更详细地讨论了这些相同的问题和我的解决方案。

于 2015-06-12T17:20:10.353 回答
1

Cliff 是正确的,没有办法在具有中断、闪存等待状态和流水线的 CPU 内核上获得单个 CPU 周期的精度。AFAIK,有点奇怪的视差“螺旋桨”是少数可以保证周期时间一致性的“高性能”MCU 内核之一,因为它不支持中断(而是“旋转”访问集线器中的 8 个内核)。

于 2019-04-30T20:32:48.677 回答