我正在尝试在裸机arm环境( LPC1768 )中实现微秒级延迟/ GCC我已经看到了使用SysTimer生成中断的示例,然后在C中执行一些计数,C用作时基
https://bitbucket.org/jpc/lpc1768/src/dea43fb213ff/main.c
然而,在12 don的系统时钟下,我认为这不会很好地扩展到微秒级的延迟。基本上,处理器将花费所有的时间来处理中断。
是否可以在循环中查询SYSTICK_GetCurrentValue的值,并确定在一微秒内有多少滴答,并在滴答的数量超过计算出的数字时跳出循环?
我不想为此使用单独的硬件计时器(但如果没有其他选择,我会使用的)
发布于 2011-06-26 13:59:22
首先,这种事情不需要中断,你可以轮询计时器,不需要通过中断来过度杀伤力。是的,这是为什么这些例子使用中断的原因,但这并不意味着这是使用计时器的唯一方法。
Guy Sirton的回答是合理的,但我更喜欢汇编程序,因为我可以精确地控制它的时钟周期(只要没有中断或其他项目)。定时器通常更容易,因为代码更容易移植(更改处理器时钟频率,您必须重新调整循环,使用定时器,有时您需要做的所有事情是更改初始化代码以使用不同的预分频器,或者更改一行查找计算的计数),并允许系统中的中断等事情。
在这种情况下,你说的是12 yes,1微秒,那就是12条指令,是吗?输入12个nops。或者分支到某个汇编程序,比如10NOPS或8,无论它产生什么,以补偿两个分支上的流水线刷新。定时器和中断将消耗超过12个指令周期的开销。即使在循环中轮询计时器也会很草率。计数器循环也会起作用,你需要了解分支开销,并针对此进行调整:
delay_one_ms:
mov r0,#3
wait:
sub r0,#1 @cortex-m3 means thumb/thumb2 and gas complains about subs.
bne wait
nop @might need some nops to tune the loop accurately
nop
bx lr调用此函数,使用gpio led或uart输出和秒表在循环中调用3000万次,并查看闪烁间隔为30秒。
ldr r4,=uart_tx_register_address
mov r5,#0x55
again:
ldr r6,=24000000
str r5,[r4]
top:
bl delay_one_ms
sub r6,#1
bne top
str r5,[r4]
b again实际上,由于我假设每个分支有2个时钟,所以测试环路有3个时钟,延迟假设为总共12个时钟,因此每个环路15个时钟,30秒是30,000,000微秒,理想情况下是3000万个环路,但我需要12/15倍的环路数量来进行补偿。如果你有一个时基比较精确的示波器,或者至少和你想要的延迟一样精确,这就容易多了。
我自己没有研究过ARM的分支机构成本,否则我会对此发表评论。很可能是两到三个时钟。所以mov是1,sub是bne的1倍,也就是2倍。两个分支到达这里,两个返回。5+(3* loops )+nops=12。(3*loops)+nops=7 loops是2,nops是1,对吗?我认为将多个nops串在一起要容易得多:
delay_one_ms:
nop
nop
nop
nop
nop
nop
nop
nop
bx lr如果您使用中断,您可能需要再烧录一些临时禁用中断的指令。如果你正在寻找“至少”1微秒,那么不用担心。
发布于 2011-06-26 08:14:20
一种方法是使用循环来创建延迟,如下所示。你需要校准你的因子。一种更通用的方法是根据一些已知的时基来计算启动时的因子。
#define CAL_FACTOR ( 100 )
void delay (uint32_t interval)
{
uint32_t iterations = interval / CAL_FACTOR;
for(int i=0; i<iterations; ++i)
{
__asm__ volatile // gcc-ish syntax, don't know what compiler is used
(
"nop\n\t"
"nop\n\t"
:::
);
}
}发布于 2011-07-13 09:00:33
你可以在ARM处理器中使用SYSTICK来实现这一点。只需将其编程为计数每个1U,或者更少,如果你有足够的时钟速度,并做一个循环,直到你的延迟值到期。如下所示:
void WaitUs(int us) {
unsigned int cnt;
while(us-- >0) {
cnt = STK_VAL; // get systick counter, ticking each 500nS
while( (STK_VAL-cnt) < 2); // repeat till 2 ticks
}
}请记住,这只是一个示例,您需要调整它以进行计数器翻转等操作。
https://stackoverflow.com/questions/6480939
复制相似问题