2011-06-25 20 views
1

私は、ベアメタルアーム環境(LPC1768)/ GCCでマイクロ秒の遅延を実装しようとしています。私はそれはないと思うしかし、12MHzのシステムクロックでタイムベースLPC1768/ARM Cortex-M3マイクロ秒の遅延

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

として使用され、その後Cでいくつかのカウントを行い、割り込みを生成するSysTimerを使用する例を見てきました非常にうまくマイクロ秒遅延にスケールします。基本的に、プロセッサは割り込みを処理するすべての時間を費やします。

ループ内のSYSTICK_GetCurrentValueの値を照会して、ティックの数が計算された数を超えたら、マイクロ秒で何回目のティックがループから抜けるかを判断できますか?

私はむしろ、このために別のハードウェアタイマーを使用していないと思います(ただし、他に選択肢はありません場合)

+1

正確さはどれくらい必要ですか?あなたはnopsでループを作り、ハードウェアのためにそれを較正することができます。つまり、繰り返しあたりのサイクル数を計算し、反復回数を計算します。 –

+1

12MHzは(通常)クリスタル周波数であることに注意してください。実際のプロセッサクロックレートを得るにはクロック回路を掛けます。 LPC1768は最大100MHzで動作します。 –

答えて

3

まずオフ割り込みはこの種のもののために必要されていない、あなたはタイマー割り込みで行き過ぎする必要はありませんをポーリングすることができます。これらの例で割り込みを使用する理由はありますが、タイマーを使用する唯一の方法ではありません。

Guy Sirtonの答えは音ですが、クロックサイクルに正確に制御できるので、アセンブラを好む(割り込みやその他の項目が途切れない限り)。通常、タイマーは簡単ですが、コードは移植性があります(プロセッサクロックの周波数を変更して、タイマーでループを再調整する必要があります。別のプリスケーラを使用するようにinitコードを変更するだけです)。 、または計算されたカウントを探して1行を変更する)、システム内の割り込みなどを許可します。

この場合、12mhz、1マイクロ秒ということになりますが、それは12命令ですか? 12ノットを入れてください。または、2つのブランチ上でパイプラインが一直線になるのを補うために出てくるものであれば、10 nopsや8などのアセンブラに分岐してください。タイマーと割り込みはオーバーヘッドで12命令サイクルを超える時間を消費します。ループでタイマーをポーリングすることさえ邪魔になります。カウンターループがあまりにも仕事と、あなたはしかし、分岐コストを理解する必要があり、そのためのチューニング:LED GPIOまたはUART出力とストップウォッチを使用して

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 

この関数を呼び出し、何3000万回のループでと点滅は30秒離れていることを確認してください。 Iブランチあたり2つのクロックを想定しているので、テストループは3つのクロックを有する

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 

は実際には、遅延が合計12のクロックであると仮定されるので、ループ当たり15のクロック、30秒3000万マイクロ秒、理想的30millionループであるが、私は12/15thsを補うためにループの数を必要としました。オシロスコープのタイムベースが多少正確である場合、または少なくともこの遅延が望む精度のオシロスコープを使用すると、これははるかに簡単です。

私はARMの支店コストを自分で勉強していませんが、そうでなければ私はそれについてコメントします。おそらく2〜3クロックです。したがって、movは1つで、subはループの数の2倍と言えます。ブランチのための2つは、ここで2つ戻ってくる。 5+(3 *ループ)+ nops = 12。 (3 *ループ)+ nops = 7ループは2で、nopsは1です、はい?私は一緒のNOPの数を糸引きがはるかに簡単だと思う:

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

あなたがそれらを使用する場合、いくつかのより多くの命令を一時的に、割り込みを無効に燃焼させる必要がある場合があります。あなたが "少なくとも" 1マイクロ秒を探しているなら、それについて心配しないでください。

+0

私はチャンスがあれば、これを今日行くつもりです。私は自由に使い分けることができるので、gpioを使って測定します。 – user815719

4

一つの方法は、単に遅れ、次に示すようなものを作成するためにループを使用することです。あなたはあなたの要因を較正する必要があります。より一般的な目的のアプローチは、既知のタイムベースに基づいて起動時の係数を計算することです。

#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" 
     ::: 
    ); 
    } 
} 
+1

これはベアメタルプログラミングのための良い/典型的なアプローチです。しかし、アームCPUでは、慎重な較正をしても正確なタイミングを得ることを期待しています。あなたが '約' 1usの遅延を必要とする場合、これは良いアプローチです。 – zdav

+2

Cortex-M3ユーザガイドによると、「NOPは何もしません.NOPは必ずしも時間がかかるNOPではありません。プロセッサは実行ステージに達する前にパイプラインからプロセッサを削除する可能性があります。それは遅れのためにNOPを使用して私を怖がらせるのに十分です。 – goertzenator

3

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

ベア心​​の中で、これは例であることは、あなたが他のものの間でカウンターのロールオーバーのためにそれを調整する必要があります。

関連する問題