簡體   English   中英

LPC1768 / ARM Cortex-M3微秒延遲

[英]LPC1768 / ARM Cortex-M3 microsecond delay

我正在嘗試在裸機手臂環境(LPC1768)/ GCC中實現微秒的延遲。 我已經看到了使用SysTimer生成中斷的示例,該中斷然后在C中進行了一些計數(用作時基)

https://bitbucket.org/jpc/lpc1768/src/dea43fb213ff/main.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"
      :::
    );
  }
}

此類事情不需要先中斷,您可以輪詢計時器,而無需因中斷而過度使用。 是的,這些示例使用中斷的原因,但這並不意味着這是使用計時器的唯一方法。

蓋·西頓(Guy Sirton)的回答是合理的,但我更喜歡匯編程序,因為我可以在時鍾周期內精確地控制它(只要沒有中斷或其他障礙物)。 計時器通常更容易一些,但是因為代碼更便於攜帶(更改處理器時鍾頻率,您必須使用計時器重新調整循環,有時您要做的就是更改初始化代碼以使用其他預分頻器,或更改一行以查找計算出的計數),並允許系統中發生中斷等。

在這種情況下,盡管您正在談論的是12MHz和1微秒,但這是12條指令,對嗎? 放置12次。 或分支到一些匯編程序,例如10點或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的循環數的一倍。bne是說循環數的兩倍。 兩個代表分支,兩個代表返回。 5+(3 *圈)+點數= 12。 (3 * loops)+ nops = 7 loops是2,nops是1,是嗎? 我認為將多個點連在一起會容易得多:

delay_one_ms:
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    bx lr

如果使用中斷,則可能需要刻錄一些其他指令以暫時禁用中斷。 如果您正在尋找“至少”一微秒,則不必擔心。

您可以在ARM處理器內部使用SYSTICK。 只需對其編程以每1uS計數一次,或者如果您有足夠的時鍾速度,則可以計數一次,然后循環執行直到您的延遲值到期。 像這樣:

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
    }
}

請記住,這是一個示例,您需要對其進行調整以實現計數器翻轉等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM