11

組み込みプログラミングで最もよく聞かれるアドバイスは、「割り込みを短くする」ことです。

今の私の状況では、main()ループで非常に長時間実行されているタスク(SDカードに大きなデータブロックを書き込む)があり、100ミリ秒かかることがあります。そのため、システムの応答性を維持するために、他のすべてのものを割り込みハンドラーに移動しました。

たとえば、通常は、割り込みで着信UARTデータを処理し、main()ループで着信コマンドを処理してから、応答を送り返します。しかし、私の場合、main()ループは(比較的)長期間ブロックされる可能性があるため、コマンドの処理/処理全体も割り込みで行われます。

最適な解決策はRTOSに切り替えることですが、RAMがありません。割り込みを短くすることができる私の設計の代替案はありますか?

4

4 に答える 4

10

これに対する従来のアプローチは、割り込みが延期された手順をスケジュールし、できるだけ早く割り込みを終了することです。

割り込みが完了すると、延期されたプロシージャのリストが最も重要なものから最も重要でないものへと移動します。

メイン (優先度の低い) アクションと、2 つの割り込み I1 と I2 がある場合を考えてみましょう。ここで、I2 はメインよりも重要ですが、I1 よりも重要ではありません。

この場合、メインを実行していて、I1 が起動しているとします。I1 は延期された手順をスケジュールし、I1 が完了したことをハードウェアに通知します。I1 の DPC が実行を開始します。突然 I2 がハードウェアから入ってきます。I2 の割り込みは、I1 の DPC から引き継ぎ、I2 の DPC をスケジュールし、それが完了したことをハードウェアに通知します。

その後、スケジューラは I1 の DPC に戻り (重要であるため)、I1 の DPC が完了すると、I2 の DPC が開始され (メインよりも重要であるため)、最終的に実行がメインに戻ります。

この設計により、さまざまな割り込みの重要性をスケジュールし、割り込みを小さく保つことを奨励し、順序付けられた順序で優先順位付けされた方法で DPC を完了することができます。

于 2013-02-02T19:20:28.273 に答える
10

CPU アーキテクチャ (割り込みのネスティングと優先順位付け、ソフトウェア割り込みのサポートなど) に応じて、この猫の皮を剥ぐ方法は 100 通りありますが、比較的簡単に理解でき、競合状態やリソース共有のない非常に単純なアプローチを採用しましょう。プリエンプティブ カーネルの危険性。

(免責事項: 通常、最初に選択するのはプリエンプティブなリアルタイム カーネルです。それらの多くは、リソースが非常に制約されたシステムで実行できます... SecurityMatt の提案は適切ですが、独自のプリエンプティブル カーネル/タスク スイッチャー、特に 1 つを実装することに慣れていない場合非同期 (割り込みによってトリガーされる) プリエンプションを処理するカーネルを使用すると、かなり迅速に車軸に取り掛かることができます. したがって、以下で提案しているものは、プリエンプション ベースのカーネルほど応答性が高くありませんが、はるかに単純で、多くの場合適切です)。

3 つのイベント/ワーク キューを作成します。

  • Q1 は優先度が最も低く、低速のバックグラウンド SD カード書き込みを処理します。
  • Q2 は、着信 UART パケットを処理するための要求を保持します
  • Q3 (最高の優先順位) は、UART RX FIFO 読み取り要求を保持します。

UART RX FIFO の読み取りと読み取りパケットの処理を分割して、FIFO の読み取りが常にパケット処理の前に処理されるようにします。多分あなたはそれらを一緒に保ちたいと思うでしょう、あなたの選択。

これを機能させるには、大規模な (〜 100 ミリ秒) SD カード書き込みプロセスを、一連の小さな個別の完了ステップに分割します

たとえば、5 つのブロックをそれぞれ 20 ミリ秒で書き込むには、最初のブロックを書き込み、次に「次のブロックを書き込む」を Q1 にエンキューします。各ステップの最後にスケジューラに戻り、Q3 から始まる優先順位でキューをスキャンします。Q2 と Q3 が空の場合、Q1 から次のイベントを引き出し (「次のブロックを書き込む」)、そのコマンドをさらに 20 ミリ秒実行してから、戻ってキューを再度スキャンします。20 ミリ秒では応答が不十分な場合は、各 20 ミリ秒のブロック書き込みをより細かい一連のステップに分割し、次の作業ステップを継続的に Q1 に送信します。

次に、受信する UART について説明します。UART RX ISR では、Q3 で「UART FIFO の読み取り」コマンドを単純にエンキューし、割り込みから、中断された 20ms の「ブロックの書き込み」ステップに戻ります。CPU が書き込みを終了するとすぐに、優先順位に従ってキューをスキャンします (ブロック書き込みが割り込み時に開始された場合、最悪の場合の応答は 20 ミリ秒になります)。キュー スキャナー (スケジューラー) は、Q3 に実行すべき作業があることを認識し、そのコマンドを実行してから、戻って再度スキャンします。

最悪の場合、システムの応答性は、優先度に関係なく、システム内の実行から完了までの最長ステップによって決まります。小規模で個別の実行から完了までのステップで作業を行うことにより、システムの応答性を非常に高く保ちます。

ここでは一般論で話さなければならないことに注意してください。ISR で UART RX FIFO を読み取り、データをバッファーに入れ、FIFO の実際の読み取りではなく、パケット処理のみを延期したい場合があります (その場合、キューは 2 つしかありません)。これは自分で解決する必要があります。しかし、私はアプローチが理にかなっていることを願っています。

キューに優先順位を付けたこのイベント ドリブン アプローチは、まさにQuantum Platform (QP) イベント ドリブン フレームワークで使用されるアプローチです。QP は実際には、ここで説明したような基本的な非プリエンプティブ (協調) スケジューラ、またはイベントがキューに入れられるたびにスケジューラを実行するプリエンプティブ スケジューラ (SecurityMatt によって提案されたアプローチと同様) をサポートします。QP の Web サイトで、QP の協調スケジューラのコード/実装を確認できます。

于 2013-02-02T20:18:19.227 に答える
2

誰もこの端からそれに来ることを提案していないので、私はそれを帽子に入れます:

SD カード サービス ルーチンを優先度の低い割り込みに固執し、可能であれば DMA をスローすると、main() ループの待機中に固執するのではなく、メイン ループとその他の割り込みが解放されて応答性が向上する可能性があります。何かが終わるまで長い間。

これに対する注意点は、SD カードの準備が整ったときにハードウェアが割り込みをトリガーする方法があるかどうかわからないことです。ただし、予備のハードウェアタイマーと割り込みがあれば、オーバーヘッドはほとんどありません。

このような目的で RTOS に頼るのは、やり過ぎであり、失敗を認めているように思えます... ;)

于 2013-02-04T10:46:17.757 に答える