Cortex-M3の重要なセクション


10

タイミングの制約や同時実行の問題のために例外が許可されないCortex-M3に重要なコードセクションを実装することについて少し疑問に思っています。

私の場合、LPC1758を実行しており、TI CC2500トランシーバーを搭載しています。CC2500には、RXバッファー内のデータおよびTXバッファー内の空き領域の割り込みラインとして使用できるピンがあります。

例として、MCUのSRAMにTXバッファーを配置し、トランシーバーのTXバッファーに空き領域がある場合、そこにこのデータを書き込みます。しかし、SRAMバッファーにデータを配置するルーチンは、TXの空き領域割り込みによって割り込みできないことは明らかです。だから私がしたいのは、このバッファを埋めるこの手順を実行している間、一時的に割り込みを無効にしますが、この手順中に発生した割り込みは、それが終了した後に実行します。

Cortex-M3でこれをどのように行うのが最適ですか?

回答:


11

Cortex M3は、 "Load-Exclusive"(LDREX)および "Store-Exclusive"(STREX)と呼ばれる便利な操作ペア(他の多くのマシンでも一般的)をサポートしています。概念的には、LDREX操作はロードを実行し、ロードされた場所が他の何かによって書き込まれた可能性があるかどうかを監視するためにいくつかの特別なハードウェアを設定します。最後のLDREXで使用されたアドレスに対してSTREXを実行すると、他に何も最初に書き込まなかった場合にのみ、そのアドレスが書き込まれます。STREX命令は、ストアが行われた場合は0、中止された場合は1でレジスタをロードします。

STREXはしばしば悲観的であることに注意してください。問題の場所に実際には触れていなかったとしても、ストアを実行しないと決定するさまざまな状況があります。たとえば、LDREXとSTREXの間の割り込みにより、STREXは監視されている場所がヒットしたと想定します。このため、LDREXとSTREXの間のコード量を最小限に抑えることをお勧めします。たとえば、次のようなものを考えます。

インラインvoid safe_increment(uint32_t * addr)
{
  uint32_t new_value;
  行う
  {
    new_value = __ldrex(addr)+ 1;
  } while(__ strex(new_value、addr));
}

これは次のようにコンパイルされます:

; R0が問題のアドレスを保持していると想定します。r1を破棄しました
lp:
  ldrex r1、[r0]
  r1、r1、#1を追加
  strex r1、r1、[r0]
  cmp r1、#0; ゼロ以外かどうかをテスト
  bne lp
  ..コードが続く

コードが実行される時間の大部分は、LDREXとSTREXの間でそれらを「妨害」することは何も起こらないため、STREXはこれ以上問題なく成功します。ただし、LDREXまたはADD命令の直後に割り込みが発生した場合、STREXはストアを実行せず、コードは[r0]の(更新された可能性のある)値を読み取り、新しい増分値を計算します。それに基づいて。

LDREX / STREXを使用してsafe_incrementのような操作を作成すると、クリティカルセクションを管理できるだけでなく、多くの場合、それらの必要性を回避できます。


では、割り込みを「ブロック」する方法はないので、ブロックが解除されると、割り込みを再び処理できるようになりますか?おそらくこれはおそらく洗練されていない解決策だと思いますが、ARM割り込み処理について詳しく知りたいだけです。
Emil Eriksson

3
割り込みを無効にすることは可能であり、Cortex-M0では多くの場合、これを行うための実用的な代替手段はありません。LDREX / STREXのアプローチは、割り込みを無効にするよりもクリーンだと思いますが、確かに多くの場合それは問題にはなりません(有効化と無効化はそれぞれ1サイクルであり、5サイクルの割り込みを無効にすることはおそらく大したことではないと思います)。 。ldrex / strexアプローチは、コードがマルチコアCPUに移行される場合に機能しますが、割り込みを無効にするアプローチは機能しないことに注意してください。また、一部のRTOSは、割り込みを無効にすることを許可されていない、制限されたアクセス許可でコードを実行します。
スーパーキャット2012年

とにかくFreeRTOSを使うことになるので、自分でこれを行うことはありませんが、とにかく学びたいです。手順中に発生する割り込みを破棄するのではなく、説明されているように割り込みをブロックするためにどのような方法で割り込みを無効にする必要がありますか?それらを破棄したい場合はどうすればよいですか?
Emil Eriksson

関連するコードに括弧が欠落しているため、上記の1つの答えは信頼できませんwhile(STREXW(new_value, addr); 。コードがコンパイルされない場合、あなたの言うことが正しいとどうして信じることができますか?

@ティム:申し訳ありませんが私のタイピングは完璧ではありません。比較のために手元に書いた実際のコードはないので、使用しているシステムがSTREXWと__STREXWのどちらを使用しているかは覚えていませんが、コンパイラリファレンスでは__strexを組み込みとしてリストしています(STREXWとは異なり、 32ビットSTREX、__ strex組み込み関数は、指定されたポインターサイズに応じてSTREXB、STREXH、またはSTREXを生成します)
supercat

4

MCUソフトウェアに循環バッファまたはFIFOが必要なようです。読み取りと書き込みのために2つのインデックスまたはポインターを配列に追跡することで、フォアグラウンドとバックグラウンドの両方が同じバッファーに干渉することなくアクセスできます。

フォアグラウンドコードは、いつでも自由に循環バッファーに書き込むことができます。書き込みポインタにデータを挿入し、書き込みポインタをインクリメントします。

バックグラウンド(割り込み処理)コードは、読み取りポインターからデータを消費し、読み取りポインターをインクリメントします。

読み取りポインタと書き込みポインタが等しい場合、バッファは空であり、バックグラウンドプロセスはデータを送信しません。バッファがいっぱいになると、フォアグラウンドプロセスはそれ以上の書き込みを拒否します(または、必要に応じて古いデータを上書きする可能性があります)。

循環バッファーを使用してリーダーとライターを分離すると、割り込みを無効にする必要がなくなります。


はい、明らかに循環バッファを使用しますが、インクリメントとデクリメントはアトミック操作ではありません。
Emil Eriksson

3
@エミル:彼らはそうである必要はありません。2つのポインターと1つの「使用不可」スロットを備えた従来の循環バッファーの場合、必要なことは、メモリー書き込みがアトミックであり、順序どおりに実行されることだけです。リーダーは1つのポインターを所有し、ライターは他のポインターを所有します。どちらもどちらのポインターも読み取ることができますが、ポインターの所有者だけがポインターを書き込みます。その時点で必要なのは、アトミックな順序どおりの書き込みだけです。
ジョンR.ストローム2012年

2

正確な場所は思い出せませんが、ARMから提供されたライブラリ(TI、ARMではなく、CMSISなどの下にある必要があります。STを使用していますが、このファイルがARMからのものであることをどこかで読んだことを覚えているので、それも必要です。 )グローバル割り込み無効オプションがあります。関数呼び出しです。(私は仕事をしていませんが、明日は正確な機能を調べます)。私はあなたのシステムでそれを素敵な名前でラップし、割り込みを無効にし、あなたのことをしてもう一度有効にします。そうは言っても、より良いオプションは、グローバル割り込みを無効にするのではなく、セマフォまたはキュー構造を実装することです。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.