5

我需要在我的 n 个 CPU 周期(~30)的代码中添加延迟。我目前的解决方案是下面的解决方案,它有效但不是很优雅。

此外,延迟必须在编译时知道。我可以使用它,但如果我可以在运行时更改延迟,那将是理想的。(如果有一些开销也没关系,但我需要 1 个周期的分辨率。)

我没有任何可以使用的外围计时器,所以它需要是一个软件解决方案。

do_something();
#define NUMBER_OF_NOPS   (SOME_DELAY + 3)
#include "nops.h"
#undef NUMBER_OF_NOPS
do_the_next_thing();

nops.h:

#if NUMBER_OF_NOPS > 0
    __ASM volatile ("nop");
#endif
#if NUMBER_OF_NOPS > 1
    __ASM volatile ("nop");
#endif
#if NUMBER_OF_NOPS > 2
    __ASM volatile ("nop");
#endif
...
4

3 回答 3

1

编辑:这里有另一个 SO Q&A 的更好答案。然而,它是在组装中,使用像 SysTick 这样的计数器的 AFAIK 是保证任何相似的循环精度的唯一方法。

编辑 2:为避免计数器溢出,这会导致非常长的延迟,请在使用前清除 SysTick 计数器,即。SysTick->VAL = 0;

原来的:

Cortex-M 有一个称为 SysTick 的内置计时器,可用于周期精确计时目的。

首先启用定时器:

SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
               SysTick_CTRL_ENABLE_Msk;

VAL然后您可以使用寄存器读取当前计数。然后,您可以通过这种方式实现周期精确延迟:

int count = SysTick->VAL;
while(SysTick->VAL < (count+30));

请注意,由于循环中的加载、比较和分支,这将引入一些开销,因此最终的循环计数会有所偏差,在我的估计中不会超过几个滴答声。

于 2017-06-21T08:30:04.057 回答
1

在皮层设备中,NOP 是字面上没有任何意义的东西。不能保证 NOP 会消耗任何时间。它们仅用于填充。我将有几个连续的 NOP,它们将被从管道中清除。

有关详细信息,请参阅 Cortex-M0 文档。http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/CHDJJGFB.html

Cortex 设备中的软件延迟非常棘手,您应该使用其他指令 + 可能的屏障指令。

使用 ISB 指令 4 个时钟 + 闪存访问时间,这取决于内核运行的速度。对于非常精确的延迟,将这部分代码放在 SRAM 中

于 2017-06-20T15:59:23.263 回答
-1

您可以使用自由运行的向上计数器,如下所示:

uint32_t t = <periph>.count;
while ((<periph>.count - t) < delay);

只要delay小于计数器周期的一半,就不会受到计数器值回绕的影响——无符号运算会产生正确的时间增量。

请注意,由于您不需要以任何方式控制计数器的值,因此您可以在系统中使用任何此类计数器 - 即使它被用于其他目的(当然,只要它确实连续且自由地运行, 并以一定的速度为您提供所需的时间分辨率)。

于 2017-07-08T17:52:33.273 回答