Cortex(ARM)マイクロコントローラーでのWFI(割り込み待機)の最適なパターン


18

EFM Gekkoコントローラー(http://energymicro.com/)を使用したバッテリー駆動ソフトウェアの開発を検討しており、実行するのに役立つものがない場合はコントローラーをスリープ状態にしたいと考えています。この目的には、WFI(割り込み待ち)命令が使用されます。割り込みが発生するまでプロセッサをスリープ状態にします。

何かをどこかに格納することでスリープが行われた場合、ロード専用/ストア専用操作を使用して次のようなことができます。

  //何かが起こるとdont_sleepに2がロードされます
  //メインループを少なくとも1回繰り返します。割り込みの場合
  //次のステートメント中に2にリセットされる原因となります。
  //割り込みはその後に発生したかのように振る舞います。

  store_exclusive(load_exclusive(dont_sleep)>> 1);

  while(!dont_sleep)
  {
    //次のステートメントとstore_exclusiveの間に割り込みが発生した場合、スリープしない
    load_exclusive(SLEEP_TRIGGER);
    if(!dont_sleep)             
      store_exclusive(SLEEP_TRIGGER);
  }

load_exclusive操作とstore_exclusive操作の間に割り込みが発生すると、store_exclusiveをスキップし、システムがもう一度ループを実行するようになります(割り込みがdont_sleepを設定したかどうかを確認します)。残念ながら、Gekkoはスリープモードをトリガーするために書き込みアドレスではなくWFI命令を使用します。のようなコードを書く

  if(!dont_sleep)
    WFI();

「if」と「wfi」の間に割り込みが発生し、dont_sleepを設定するリスクが発生しますが、wfiは先に進み、とにかく実行されます。それを防ぐための最良のパターンは何ですか?PRIMASKを1に設定して、WFIを実行する直前に割り込みがプロセッサに割り込まないようにし、すぐにクリアしますか?または、より良いトリックがありますか?

編集

私はイベントビットについて疑問に思っています。一般的な説明では、マルチプロセッサのサポートを目的としているようですが、次のようなものが機能するかどうか疑問に思っていました。

  if(dont_sleep)
    SEV(); / *次のWFEはイベントフラグをクリアしますが、スリープはしません* /
  WFE();

don't_sleepを設定するすべての割り込みもSEV命令を実行する必要があるため、「if」テストの後に割り込みが発生すると、WFEはイベントフラグをクリアしますが、スリープ状態にはなりません。それは良いパラダイムのように聞こえますか?


1
WFI命令は、命令の実行時にウェイク条件が真の場合、コアをスリープ状態にしません。たとえば、WFIの実行時に未クリアのIRQがある場合、NOPとして機能します。
マーク

@マーク:問題は、「if(!dont_sleep)」と「WFI」の間で割り込みが発生した場合、WFIの実行時に割り込み条件が保留されなくなることですが、割り込みによりdont_sleepが設定される可能性があります。別の反復を実行するメインループを正当化する何かをしました。私のサイプレスPSOCアプリケーションでは、メインラインコードがスリープしようとしていた場合、長時間のウェイクアップを引き起こす割り込みはスタックをジンクしますが、それはかなり厄介なようで、ARMはそのようなスタック操作を推奨していません。
-supercat

@supercat割り込みは、WFIの実行時にクリアされる場合とされない場合があります。それはあなた次第で、いつ/どこで割り込みをクリアするかを選択します。dont_sleep変数を取り除き、マスクされた割り込みを使用して、目覚めたまままたはスリープしたいことを示します。ifステートメントをまとめて削除し、メインループの最後でWFIを終了できます。すべての要求を処理した場合、スリープできるようにIRQをクリアします。目を覚ましておく必要がある場合は、IRQをトリガーします。IRQはマスクされているため何も起こりませんが、WFIが実行しようとするとNOPになります。
マーク

2
@supercatより基本的なレベルでは、割り込み駆動型の設計と「大きなメインループ」設計を混在させようとしているようです。これは通常、時間に依存せず、ポーリングベースで割り込みが最小限です。これらを混ぜると、かなりくて速くなります。可能な場合は、使用する設計パラダイムを選択します。最新の割り込みコントローラーを使用すると、基本的に、割り込みとタスクキュー(1つの割り込みをサービスし、次に優先順位が高いなど)の間にプリエンプティブマルチタスクを取得することに注意してください。あなたの利点にそれを使用してください。
マーク

@Mark:バッテリー駆動のアプリケーションでPIC 18xを使用するシステムを開発しました。スタックの制限により、割り込み内であまり多くの処理を行うことができなかったため、大部分のものはメインループで都合の良い方法で処理されます。動作が長時間続くために1〜2秒間ブロックされる場所がいくつかありますが、ほとんどの場合、かなりうまく機能します。ARMに移行する場合、単純なRTOSを使用して長時間実行される操作を分割しやすくすることができますが、プリエンプティブマルチタスクと協調マルチタスクのどちらを使用するかはわかりません。
-supercat

回答:


3

私はそのdont_sleepことを完全には理解していませんでしたが、試すことができることの1つは、PendSVハンドラーで「メイン作業」を行い、最も低い優先度に設定することです。次に、何かが必要になるたびに、他のハンドラーからPendSVをスケジュールします。ここでそれを行う方法を参照してください(M1向けですが、M3もそれほど違いはありません)。

(おそらく以前のアプローチと一緒に)使用できる別の機能は、Sleep-on-exit機能です。有効にすると、WFIを呼び出さなくても、プロセッサは最後のISRハンドラーを終了した後にスリープ状態になります。こちらの例をご覧ください


5
WFI命令では、割り込みを有効にしてプロセッサをウェイクアップする必要はありません。CPSRのFビットとIビットは無視されます。
マーク

1
@Mark私はドキュメントでそのビットを見逃したに違いありません、あなたはそれについていくつかのリンク/ポインタを持っていますか?コアを起動した割り込み信号はどうなりますか?割り込みが再び有効になるまで保留のままですか?
イゴールスコチンスキー

ASMリファレンスマニュアルはこちらです:infocenter.arm.com/help/index.jsp?topic =/ com.arm.doc.dui0489c / cortex-m3の詳細情報はこちら:infocenter.arm.com/help/ index.jsp?topic = / com.arm.doc.dui0552a /…要するに、マスクされた割り込みが保留になると、コアはウェイクアップし、WFI命令の後に動作を継続します。保留中の割り込みをクリアせずに別のWFIを発行しようとすると、WFIはNOPとして機能します(WFIのウェイク条件がtrueであるため、コアはスリープしません)。
マーク

@Mark:dont_sleepを設定する割り込みハンドラーでSEV(「イベントの設定」)命令を実行し、WFIではなくWFE(「イベントの待機」)を使用することを検討していました。Gekkoの例ではWFIを使用しているように見えますが、WFEも機能すると思います。何かご意見は?
-supercat

10

クリティカルセクション内に配置します。ISRは実行されないため、WFIの前にdont_sleepが変更されるリスクはありませんが、プロセッサを引き続きウェイクし、クリティカルセクションが終了するとすぐにISRが実行されます。

uint8 interruptStatus;
interruptStatus = EnterCriticalSection();
if (!dont_sleep)
  WFI();
ExitCriticalSection(interruptStatus);

開発環境にはおそらくクリティカルセクション機能がありますが、おおよそ次のようになります。

EnterCriticalSectionは次のとおりです。

MRS r0, PRIMASK /* Save interrupt state. */
CPSID i /* Turn off interrupts. */
BX lr /* Return. */

ExitCriticalSectionは次のとおりです。

MSR PRIMASK, r0 /* Restore interrupt states. */
BX lr /* Return. */

2
不思議なことに、多くのARMライブラリは、ステータスをローカルに保持する代わりにグローバルカウンタを使用するクリティカルセクションの実装を使用しています。カウンターのアプローチはより複雑で、システム全体のすべてのコードが同じカウンターを使用する場合にのみ機能するため、気が遠くなるでしょう。
-supercat

1
クリティカルセクションを終了するまで、割り込みは無効になりませんか?その場合、WFIはCPUを無期限に待機させませんか?
コルネリューズズ

1
@Kenzi Shrimpの回答は、私の以前の質問に答えるLinuxディスカッションスレッドを指しています。それを明確にするために、彼の答えとあなたの答えを編集しました。
コルネリューズズ

@CorneliuZuzu他の人の答えを編集して自分の議論を割り込むことは素晴らしい考えではありません。「リンクのみ」の回答を改善するために引用を追加することは別の問題です。ウォンの本当の質問がある場合は、質問として質問して、これにリンクしてください。
ショーンフーリハネ

1
@SeanHoulihane私は彼女の回答から無効化も削除もしていません。これがなぜ機能するかについての簡単な説明は、個別の議論ではありません。正直なところ、この答えはWFIの明確化なしには賛成票に値するとは思わないが、それにはもっとも値する。

7

あなたの考えは素晴らしいです、これはまさにLinuxが実装するものです。こちらをご覧ください

割り込みが無効になっている場合でもWFIが機能する理由を明確にするための、上記のディスカッションスレッドからの有用な引用:

次の割り込みまでアイドル状態にする場合は、準備を行う必要があります。その準備中に、割り込みがアクティブになる場合があります。このような割り込みは、探しているウェイクアップイベントである可能性があります。

コードがどれほど優れていても、割り込みを無効にしないと、スリープの準備と実際のスリープの間に常に競合が発生し、ウェイクアップイベントが失われます。

これが、コアCPU(CPSR Iビット)でマスクされていても、認識しているすべてのARM CPUが起動する理由です。

それ以外の場合は、アイドルモードの使用を忘れてください。


1
WFIまたはWFE命令の時点で割り込みを無効にすることを参照していますか?目的にWFIまたはWFEを使用することの間に有意な違いがありますか?
-supercat

1
@supercat:私は間違いなくWFIを使用します。WFE IMOは主に、マルチコアシステムのコア間の同期のヒント用です(たとえば、スピンロックでWFEを実行して失敗し、スピンロックから出た後にSEVを発行する)。また、WFEは割り込みマスキングフラグを考慮に入れるため、ここではWFIほど有用ではありません。このパターンはLinuxで本当にうまく機能します。
エビ

2

仮定して:

  1. メインスレッドはバックグラウンドタスクを実行します
  2. 割り込みは優先度の高いタスクのみを実行し、バックグラウンドタスクは実行しません
  3. メインスレッドはいつでも中断できます(通常は割り込みをマスクしません)

次に、解決策は、PRIMASKを使用して、フラグ検証とWFIの間の割り込みをブロックすることです。

mask_interrupts();
if (!dont_sleep)
    wfi();
unmask_interrupts();

0

終了モードでのスリープはどうですか?これは、IRQハンドラが終了するたびに自動的にスリープ状態になるため、設定後に「通常モード」が実行されることはありません。IRQが発生し、起動してハンドラーを実行し、スリープ状態に戻ります。WFIは必要ありません。


2
プロセッサが入るべきスリープのタイプは、割り込み中に発生する何かに基づいて変化する可能性があるという事実をどのように最適に処理する必要がありますか?たとえば、ピン変更イベントは、シリアルデータが近づいている可能性があることを示している可能性があるため、プロセッサはデータを待機している間、プライマリクロックオシレータを実行し続ける必要があります。メインループがイベントフラグをクリアし、何が起こっているのかを調べ、WFIでプロセッサを適切なスリープモードにすると、どのモードが適切であるかに影響を与える可能性のある割り込みがイベントフラグを設定します...
supercat

...そしてスリープを中止します。1つのメインループハンドラーがスリープモードを制御することは、すべての割り込みでそれを心配するよりもクリーンに見えます。割り込みごとにメインループのその部分を「スピン」することは最適な効率ではないかもしれませんが、特にスリープ動作に影響を与える可能性のあるすべての割り込みが何らかのフラグにヒットする場合は、それほど悪くないはずです。
-supercat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.