9

我们有一个使用 3.2 内核的 ARM9——一切似乎都运行良好。最近我被要求添加一些代码,以便在启动时在一些 GPIO 线上添加一个 50ms 的脉冲。脉码没问题;正如预期的那样,我可以看到线条上下起伏。没有按我预期的方式工作的是udelay()功能。阅读文档让我觉得单位是微秒,但在逻辑分析仪中测量它太短了。所以我最后添加了这段代码来获得 50ms。

// wait 50ms to be sure PCIE reset takes
for (i=0;i<6100;i++) // measured on logic analyzer - seems wrong to me!!
{
   __udelay(2000); // 2000 is max
}

我不喜欢它,但它工作正常。代码中有一些奇怪的常量和指令udelay。有人可以告诉我这应该如何工作吗?初始化所有时钟后调用此代码,因此其他一切似乎都正常。

4

1 回答 1

4

根据 Linus 在此线程中的说法:

如果是 1% 左右的折扣,那就没问题了。如果有人选择了一个对延迟中的小错误非常敏感的延迟值,以至于他们注意到了——或者甚至注意到了 5% 之类的东西——那么他们选择的延迟太短了。

udelay() 从来没有真正打算成为某种精密仪器。尤其是在 CPU 以不同频率运行的情况下,我们历来都会有一些相当剧烈的波动。传统的繁忙循环最终不仅受到中断的影响,而且还受到缓存对齐(我们曾经内联它)之类的影响,然后基于 TSC 的循环显然依赖于 TSC 的稳定(它们不是为了尽管)。

所以从历史上看,我们已经看到 udelay()真的关闭(即 50% 关闭等),我不会担心 1% 范围内的事情。

莱纳斯

所以它不会是完美的。它会关闭。多少取决于很多因素。不要使用for循环,mdelay而是考虑使用。可能会更准确一些。来自O'Reilly Linux 设备驱动程序书:

udelay调用应该只在很短的时间内调用,因为 的精度只有loops_per_second8 位,并且在计算长延迟时会累积明显的错误。即使最大允许延迟接近一秒(因为计算会因更长的延迟而溢出),但建议的udelay最大值为 1000 微秒(一毫秒)。在延迟必须长于一毫秒的情况下,函数mdelay 会有所帮助。

同样重要的是要记住udelay是一个忙等待函数(因此mdelay也是如此);在时间流逝期间无法运行其他任务。因此,您必须非常小心,尤其是使用mdelay时,除非没有其他方法可以实现您的目标,否则请避免使用它。

目前,支持长于几微秒和短于计时器滴答的延迟是非常低效的。这通常不是问题,因为延迟需要足够长才能被人类或硬件注意到。对于与人类相关的时间间隔,百分之一秒是合适的精度,而对于硬件活动来说,一毫秒是足够长的延迟。

特别是“ udelay的建议最大值是 1000 微秒(一毫秒) ”这一行在我看来很突出,因为您声明 2000 是最大值。从此文档中插入延迟:

mdelay 是 udelay 的宏包装器,用于在将大参数传递给 udelay 时解决可能的溢出问题

因此,您可能会遇到溢出错误。虽然我通常不会认为 2000 年是一个“大争论”。

但是,如果您需要真正准确的计时,您需要像您一样处理偏移量,滚动您自己的或使用不同的内核。有关如何使用汇编程序或使用硬实时内核来滚动您自己的延迟函数的信息,请参阅这篇关于高分辨率时序的文章。

另请参阅:Linux 内核:udelay() 返回太早?

于 2012-11-16T14:31:31.950 回答