2016-11-14 24 views
3

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

在多线程环境中,这是一个问题,因为有N个线程,但只有1个硬件定时器。我可以禁止中断,而定时器正在使用,以防止上下文切换,因此竞争条件,但它似乎有点难看。我想用一个使用ARM CPU周期计数器(CCNT)的函数替换使用硬件定时器的函数。我是否缺少缺陷或其他选择?很明显,周期计数器功能要求将其调整到适当的CPU频率,这对我们的系统来说永远不会改变,但我想可以在使用硬件定时器以编程方式引导时检测到。

+0

哪种ARM M3有单个硬件定时器?你说你有一个多线程环境,所以调度器的计时器是必需的:你是否说你唯一的计时器是分配给调度器的计时器? – LPs

+0

实际上有2个硬件定时器,还有一个系统时钟中断,每隔1毫秒触发一次。系统滴答中断不是一个计时器,你不能查询已经过了多少时间,你只需要每1毫秒获取一次中断,这通常用于通知抢先调度器。 1毫秒的分辨率对于我感兴趣的延迟来说也太长了。 – satur9nine

+0

对于现代MCU来说,忙碌的这么长时间是一个非常糟糕的方法。如果他们使用这样的东西,我会怀疑其余的质量.. – Olaf

回答

6

在启动时设置一次计时器,让计数器连续运行。当您想要开始延迟时,请阅读计数器值并记住该起始值。然后在延迟循环中再次读取计数器值并循环,直到计数器值减去起始值大于或等于请求的延迟滴答声为止。 (如果你正确地做了减法运算,那么翻滚会被洗掉,你不需要特殊处理来检查它们。)

+2

作为一个例子,请参阅雷蒙德陈的写作:[使用模块化算法,以避免时间溢出问题](https://blogs.msdn.microsoft的.com/oldnewthing/20050531-22/p = 35493)。使用无符号类型,数学就算了。 –

+0

另一件事 - 你可能想延迟一个更多的滴答计数比请求(除非请求是等待零滴答)来处理的事实,即第一次计时器读取可能只有一个纳秒秒之前计时器滴答声增加。 –

+0

@kkrambo听起来不错。你能解释为什么这个解决方案比使用CPU周期计数器更好吗?我认为这比较好,因为这不需要根据CPU频率进行任何调整。 – satur9nine

2

您可以复用您的计时器,以便您拥有每个线程想要关闭的表以及用于执行的函数指针/向量。当定时器中断发生时,触发该线程的中断,然后将定时器设置为列表中的下一个,减去经过的时间。这就是我看到许多* nix操作系统在其内核代码中执行的操作,因此应该有代码来作为示例。

更大的问题是您正在旋转锁定等待定时器的线程。除了CPU使用率以及根据您拥有的操作系​​统(或者您是否拥有操作系统),您可以轻松引入线程反转问题,甚至可以完全锁定。使用线程原语可能会更好,所以任何操作系统都可以实际上休眠线程并在需要时唤醒它们。