【问题标题】:ARM embedded delay hardware timer vs CPU cycle counterARM嵌入式延迟硬件计时器与CPU周期计数器
【发布时间】:2016-11-14 23:37:54
【问题描述】:

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

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

【问题讨论】:

  • 哪种ARM M3有一个硬件定时器?您是说您有一个多线程环境,因此需要调度程序的计时器:您是说您拥有的唯一计时器是分配给调度程序的计时器吗?
  • 实际上有 2 个硬件计时器和一个系统滴答中断,它以 1 毫秒的间隔触发。系统滴答中断不是计时器,您无法查询已经过去了多少时间,您只需每 1 毫秒获得一个中断,用于通知抢占式调度程序。对于我感兴趣的延迟来说,1 毫秒的分辨率也太长了。
  • 忙于旋转这么长时间对于现代 MCU 来说是一种非常糟糕的方法。如果他们使用这样的东西,我会怀疑其余的质量..

标签: arm embedded


【解决方案1】:

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

【讨论】:

  • 例如,请参阅 Raymond Chen 的文章:Using modular arithmetic to avoid timing overflow problems。使用无符号类型,数学就可以了。
  • 另一件事-您可能希望延迟一个比请求的滴答计数多一个(除非请求是等待零滴答)以处理第一个计时器读取可能仅在计时器滴答增量。
  • @kkrambo 这听起来不错。你能解释一下为什么这个解决方案比使用 CPU 周期计数器更可取吗?我认为它更好,因为这不需要根据 CPU 频率进行任何调整。
  • @satur9nine,不,我不熟悉 CPU 周期计数器,所以无法对比/比较。如果定时器时钟频率基于 CPU 频率,那么它也需要进行调整。这就是我将如何解决您将单个硬件计时器用于多个异步延迟周期的问题。对我来说,这实际上似乎比为每次延迟重新配置计时器更简单。
【解决方案2】:

你可以多路复用你的定时器,这样你就有一个每个线程想要何时触发的表和一个用于执行的函数指针/向量。当定时器中断发生时,触发该线程的中断,然后将定时器设置为列表中的下一个,减去经过的时间。这就是我看到许多 *nix 操作系统在其内核代码中所做的事情,因此应该有代码可以从中提取作为示例。

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

【讨论】:

    猜你喜欢
    • 2015-12-13
    • 2012-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-23
    • 2012-07-16
    • 2010-09-23
    相关资源
    最近更新 更多