ARM嵌入式延迟硬件定时器与CPU周期计数器

ARM嵌入式延迟硬件定时器与CPU周期计数器,arm,embedded,Arm,Embedded,我正在做一个嵌入式项目,它运行在基于ARM Cortex M3的微控制器上。我们的供应商提供的一些代码使用延迟功能,设置内置硬件计时器,然后旋转直到计时器过期。通常,这用于等待1到几百微秒。这些延迟几乎是因为它们正在等待某个寄存器、芯片或总线来完成某个操作,并且至少需要等待给定的微秒数。硬件定时器的设置开销至少为6微秒 在多线程环境中,这是一个问题,因为有N个线程,但只有1个硬件计时器。我可以在定时器被用来防止上下文切换和竞争条件时禁用中断,但这看起来有点难看。我正在考虑将使用硬件定时器的功能替

我正在做一个嵌入式项目,它运行在基于ARM Cortex M3的微控制器上。我们的供应商提供的一些代码使用延迟功能,设置内置硬件计时器,然后旋转直到计时器过期。通常,这用于等待1到几百微秒。这些延迟几乎是因为它们正在等待某个寄存器、芯片或总线来完成某个操作,并且至少需要等待给定的微秒数。硬件定时器的设置开销至少为6微秒


在多线程环境中,这是一个问题,因为有N个线程,但只有1个硬件计时器。我可以在定时器被用来防止上下文切换和竞争条件时禁用中断,但这看起来有点难看。我正在考虑将使用硬件定时器的功能替换为使用ARM CPU周期计数器(CCNT)的功能。是否有我遗漏的陷阱或其他选择?显然,周期计数器功能需要将其调整到适当的CPU频率,这对于我们的系统来说是永远不会改变的,但我认为可以使用硬件计时器在启动时以编程方式检测到。您可以多路复用计时器,这样您就有了一个表,其中列出了每个线程何时要触发,以及一个用于执行的函数指针/向量。当计时器中断发生时,触发该线程的中断,然后将计时器设置为列表中的下一个,减去经过的时间。这就是我看到的许多*nix操作系统在其内核代码中所做的,因此应该有代码作为示例


一个更大的问题是,您正在旋转锁定线程以等待计时器。除了CPU使用之外,根据您拥有的操作系统(或者如果您拥有操作系统),您还可以很容易地引入线程反转问题,甚至完全锁定。最好改用线程原语,这样任何操作系统都可以真正睡眠线程并在需要时唤醒它们。

在启动时设置一次计时器,让计数器连续运行。当您想要启动延迟时,读取计数器值并记住该启动值。然后在延迟循环中再次读取计数器值并循环,直到计数器值减去起始值大于或等于请求的延迟滴答声。(如果正确执行减法,则翻滚将被清除,您不需要特殊处理来检查它们。)

例如,请参阅Raymond Chen的总结:。使用无符号类型,数学就解决了。另一件事-您可能希望延迟比请求的时间多一个滴答数(除非请求等待零滴答数),以处理第一个计时器读取可能在计时器滴答数增加前仅一纳秒的事实。@kkrambo这听起来不错。你能解释一下为什么这个解决方案比使用CPU周期计数器更可取吗?我认为它更好,因为这不需要根据CPU频率进行任何调整。@Satura9Nine,不,我不熟悉CPU周期计数器,因此无法进行对比/比较。如果计时器时钟频率基于CPU频率,则还需要进行调整。这就是我将如何解决使用单个硬件定时器进行多个异步延迟周期的问题。对我来说,这实际上似乎比为每个延迟重新配置计时器更简单。哪种ARMM3有一个硬件计时器?您是说您有一个多线程环境,因此需要调度程序的计时器:您是说您唯一拥有的计时器是分配给调度程序的计时器吗?实际上有两个硬件计时器,还有一个系统时钟中断,以1毫秒的间隔触发。系统时钟中断不是计时器,您无法查询经过了多少时间,您只需每隔1毫秒获得一个中断,该中断用于通知抢占式调度程序。对于我感兴趣的延迟来说,1毫秒的分辨率也太长了。对于现代MCU来说,如此长的时间忙于旋转是一种非常糟糕的方法。如果他们用这种东西,我会怀疑其他东西的质量。。