Gcc LPC1768/ARM Cortex-M3微秒延迟
我试图在裸机arm环境(LPC1768)/GCC中实现微秒延迟。我看过一些例子,这些例子使用SysTimer生成一个中断,然后用C进行一些计数,C用作时基 然而,在12MHz的系统时钟下,我认为这种延迟不会很好地扩展到微秒级。基本上,处理器将花费所有的时间为中断服务 是否可以查询循环中SYSTICK_GetCurrentValue的值,并确定一微秒内有多少滴答声,一旦滴答声的数量超过计算的数量,就退出循环Gcc LPC1768/ARM Cortex-M3微秒延迟,gcc,arm,delay,Gcc,Arm,Delay,我试图在裸机arm环境(LPC1768)/GCC中实现微秒延迟。我看过一些例子,这些例子使用SysTimer生成一个中断,然后用C进行一些计数,C用作时基 然而,在12MHz的系统时钟下,我认为这种延迟不会很好地扩展到微秒级。基本上,处理器将花费所有的时间为中断服务 是否可以查询循环中SYSTICK_GetCurrentValue的值,并确定一微秒内有多少滴答声,一旦滴答声的数量超过计算的数量,就退出循环 我不想为此使用单独的硬件计时器(但如果没有其他选择,我会这样做)一种方法就是使用循环来创
我不想为此使用单独的硬件计时器(但如果没有其他选择,我会这样做)一种方法就是使用循环来创建延迟,如下所示。你需要校准你的因子。更通用的方法是根据一些已知的时基计算启动时的系数
#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"
:::
);
}
}
定义校准系数(100)
无效延迟(uint32\t间隔)
{
uint32\u t迭代次数=间隔/校准系数;
对于(int i=0;i来说,一种方法就是使用一个循环来创建延迟,如下所示。您需要校准您的因数。更通用的方法是在启动时根据一些已知的时基计算因数
#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"
:::
);
}
}
定义校准系数(100)
无效延迟(uint32\t间隔)
{
uint32\u t迭代次数=间隔/校准系数;
对于(int i=0;i这类事情不需要先中断,你可以轮询计时器,不需要用中断过度杀戮。是的,这些示例使用中断的原因是,但这并不意味着这是使用计时器的唯一方法 Guy Sirton的答案是合理的,但我更喜欢汇编程序,因为我可以精确地控制时钟周期(只要没有中断或其他阻碍)。计时器通常更容易,因为代码更易于移植(更改处理器时钟频率,您必须使用计时器重新调整循环,有时您所要做的就是更改init代码以使用不同的预分频器,或者更改查找计算计数的一行),并允许系统中出现中断等情况 在这种情况下,虽然你说的是12mhz,1微秒,也就是12条指令,是吗?输入12个NOP。或者用10个NOP或8个NOP分支到某个汇编器,不管结果如何,以补偿两个分支上的管道刷新。一个定时器和中断将消耗超过12个指令周期的开销。甚至polli在循环中取消计时器将是草率的。计数器循环也会起作用,但您需要了解分支成本并为此进行调整:
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秒是30000000微秒,理想情况下是3000万个环路,但我需要12/15个环路来补偿。如果你有一个时基比较精确的示波器,这要容易得多,或至少与您希望的延迟一样准确
我自己没有研究过ARM的分支成本,否则我会对此发表评论。它可能是两个或三个时钟。所以mov是一个,sub是循环数的一倍,bne是循环数的两倍。两个分支到这里,两个返回。5+(3*循环)+nops=12。(3*循环)+nops=7循环是2,nops是1,是吗?我认为将多个NOP串在一起要容易得多:
delay_one_ms:
nop
nop
nop
nop
nop
nop
nop
nop
bx lr
如果您使用中断,您可能需要再刻录一些指令来暂时禁用中断。如果您正在寻找“至少”一微秒就不用担心了。这类事情不需要先中断,你可以轮询计时器,不需要用中断过多。是的,这些示例使用中断的原因是肯定的,但这并不意味着这是使用计时器的唯一方法 Guy Sirton的答案是合理的,但我更喜欢汇编程序,因为我可以精确地控制时钟周期(只要没有中断或其他阻碍)。计时器通常更容易,因为代码更易于移植(更改处理器时钟频率,您必须使用计时器重新调整循环,有时您所要做的就是更改init代码以使用不同的预分频器,或者更改查找计算计数的一行),并允许系统中出现中断等情况 在这种情况下,虽然你说的是12mhz,1微秒,也就是12条指令,是吗?输入12个NOP。或者用10个NOP或8个NOP分支到某个汇编器,不管结果如何,以补偿两个分支上的管道刷新。一个定时器和中断将消耗超过12个指令周期的开销。甚至polli在循环中取消计时器将是草率的。计数器循环也会起作用,但您需要了解分支成本并为此进行调整:
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秒是30000000微秒,理想情况下是3000万个环路,但我需要12/15个环路来补偿。如果你有一个时基比较精确的示波器,这要容易得多,或至少与您希望的延迟一样准确
我自己没有研究过ARM的分支成本,否则我会对此进行评论。它可能是两个或三个时钟。所以mov是一个,sub是循环数的一倍,bne是循环数的两倍。两个分支到这里,两个用于返回