ARM Cortex M3(STM32F101と同様)のリアルタイムアプリケーションでは、内部ペリフェラルのレジスタのビットをゼロになるまでポーリングし、ループをできるだけタイトにします。ビットバンディングを使用して適切なビットにアクセスします。(動作する)Cコードは
while (*(volatile uint32_t*)kMyBit != 0);
そのコードは、オンチップ実行可能RAMにコピーされます。手動で最適化した後²、ポーリングループは次のようになり、6サイクルに設定しました。
0x00600200 681A LDR r2,[r3,#0x00]
0x00600202 2A00 CMP r2,#0x00
0x00600204 D1FC BNE 0x00600200
ポーリングの不確実性をどのようにして下げることができますか?5サイクルのループは私の目標に適合します。ゼロになった後、同じビットを15.5サイクルにできるだけ近づけてサンプリングします。
私の仕様では、少なくとも6.5 CPUクロックサイクルの低パルスを確実に検出することを求めています。持続時間が12.5サイクル未満の場合、確実に短いと分類します。そして、それが18.5サイクル以上続く限り、確実に分類します。パルスには、CPUクロックとの位相関係が定義されていません。これは、私の唯一の正確なタイミング基準です。これには、最大で5クロックのポーリングループが必要です。実際、私は5クロックサイクルでポーリングできる数十年前の8ビットCPUで実行されるコードをエミュレートしており、それが仕様になっています。
ループの前にNOPを挿入することでコードアライメントをオフセットしようとしましたが、多くのバリエーションで試しましたが、変化は見られませんでした。
CMPとLDRを反転させようとしましたが、それでも6サイクルが得られます。
0x00600200 681A LDR r2,[r3,#0x00]
; we loop here
0x00600202 2A00 CMP r2,#0x00
0x00600204 681A LDR r2,[r3,#0x00]
0x00600206 D1FC BNE 0x00600202
これは8サイクルです
0x00600200 681A LDR r2,[r3,#0x00]
0x00600202 681A LDR r2,[r3,#0x00]
0x00600204 2A00 CMP r2,#0x00
0x00600206 D1FB BNE 0x00600200
しかし、これは9サイクルです。
0x00600200 681A LDR r2,[r3,#0x00]
0x00600202 2A00 CMP r2,#0x00
0x00600204 681A LDR r2,[r3,#0x00]
0x00600206 D1FB BNE 0x00600200
interrupt割り込みが発生しない状況で、ビットが低い時間を測定します。
²最初のコンパイラ生成コードは、宛先レジスタとしてr12を使用し、ループに4コードバイトを追加したため、1サイクルかかりました。
given与えられた数値は、レジスターのアドレスでの読み取り時に、サイクルが正確であると思われるリアルタイムSTIceエミュレーターとそのエミュレータートリガー機能で取得されます。以前はループのブレークポイントで「状態」カウンターを試しましたが、結果はブレークポイントの場所によって異なります。シングルステップはさらに悪いことです。LDRには常に4サイクルが与えられますが、それが少なくとも3になる場合があります。
gcc -Os -mcpu=cortex-m3
か?
ldr
/ cbz reg, end_of_loop
を内側に展開し、cmp
/ bnz
を一番下に展開することができます。しかし、それはあなたに不均一なポーリング間隔を与えるでしょう。