首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >LPC1768 / ARM Cortex-M3微秒延迟

LPC1768 / ARM Cortex-M3微秒延迟
EN

Stack Overflow用户
提问于 2011-06-26 06:35:19
回答 3查看 13.1K关注 0票数 1

我正在尝试在裸机arm环境( LPC1768 )中实现微秒级延迟/ GCC我已经看到了使用SysTimer生成中断的示例,然后在C中执行一些计数,C用作时基

https://bitbucket.org/jpc/lpc1768/src/dea43fb213ff/main.c

然而,在12 don的系统时钟下,我认为这不会很好地扩展到微秒级的延迟。基本上,处理器将花费所有的时间来处理中断。

是否可以在循环中查询SYSTICK_GetCurrentValue的值,并确定在一微秒内有多少滴答,并在滴答的数量超过计算出的数字时跳出循环?

我不想为此使用单独的硬件计时器(但如果没有其他选择,我会使用的)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-06-26 13:59:22

首先,这种事情不需要中断,你可以轮询计时器,不需要通过中断来过度杀伤力。是的,这是为什么这些例子使用中断的原因,但这并不意味着这是使用计时器的唯一方法。

Guy Sirton的回答是合理的,但我更喜欢汇编程序,因为我可以精确地控制它的时钟周期(只要没有中断或其他项目)。定时器通常更容易,因为代码更容易移植(更改处理器时钟频率,您必须重新调整循环,使用定时器,有时您需要做的所有事情是更改初始化代码以使用不同的预分频器,或者更改一行查找计算的计数),并允许系统中的中断等事情。

在这种情况下,你说的是12 yes,1微秒,那就是12条指令,是吗?输入12个nops。或者分支到某个汇编程序,比如10NOPS或8,无论它产生什么,以补偿两个分支上的流水线刷新。定时器和中断将消耗超过12个指令周期的开销。即使在循环中轮询计时器也会很草率。计数器循环也会起作用,你需要了解分支开销,并针对此进行调整:

代码语言:javascript
复制
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秒。

代码语言:javascript
复制
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串在一起要容易得多:

代码语言:javascript
复制
delay_one_ms:
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    bx lr

如果您使用中断,您可能需要再烧录一些临时禁用中断的指令。如果你正在寻找“至少”1微秒,那么不用担心。

票数 3
EN

Stack Overflow用户

发布于 2011-06-26 08:14:20

一种方法是使用循环来创建延迟,如下所示。你需要校准你的因子。一种更通用的方法是根据一些已知的时基来计算启动时的因子。

代码语言:javascript
复制
#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"
      :::
    );
  }
}
票数 4
EN

Stack Overflow用户

发布于 2011-07-13 09:00:33

你可以在ARM处理器中使用SYSTICK来实现这一点。只需将其编程为计数每个1U,或者更少,如果你有足够的时钟速度,并做一个循环,直到你的延迟值到期。如下所示:

代码语言:javascript
复制
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
    }
}

请记住,这只是一个示例,您需要调整它以进行计数器翻转等操作。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6480939

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档