3

これは実際には、組み込みシステムのファームウェアの設計上の質問です。2つのISR(同じ優先度)を個別に実行しています。これらのISRは、h/wがデータを生成するときにトリガーされます。task1とtask2を同期するために配置する必要のあるメカニズムが必要です。タスク2は、タスク1で計算された特定の値について知っている必要があります。この値は、タスク2で特定の値を計算するときに考慮する必要があります。使用するOSプリミティブがありません。つまり、システムにオペレーティングシステムがありません。Task1はISR1のコンテキスト内で実行され、task2はISR2のコンテキスト内で実行されます。私たちが使用しているプロセッサはSTMicroelectronics32コントローラです

編集:追加情報プロセッサは、データの準備ができたときに割り込みをトリガーする特定のIPに接続されています。これらのIPは、入力ストリーミングフレームデータの一種のアキュムレータとして機能します。

4

4 に答える 4

4

割り込みコンテキストで重い処理を行うのではなく、データを読み取ってフラグを設定するだけです。

その後、必要に応じてタスクを実行するために、メイン ループの単純なスケジューラでフラグをチェックできます。そのため、タスクは互いに割り込むことができず、他のタスクの一貫性のない出力を見ることができません。

タスクは、そのようなフラグを設定して、別のタスクをアクティブにすることもできます。たとえば、Task2 は Task1 からの値を必要とするため、Task1 は Task2 をアクティブ化できます。

ISR で読み取られるデータには、バッファが必要です。着信データのタイミングに応じて、リング バッファーまたはダブル バッファーになる可能性があります。

于 2009-08-03T13:25:02.893 に答える
2
  • 共有値の読み取りまたは書き込みの前に割り込みを無効にする
  • 共有値の読み取りまたは書き込みに割り込みを再度有効にする
于 2009-08-03T10:32:52.017 に答える
2

私は、OS がなく、C やレジスタなど以外の実際のフレームワークがないという観点からこれに取り組んでいます。私がそれを行う方法は、他の ISR から見ることができる各 ISR の状態変数を持つことです。次に、ISR1 に入ると、ISR2 のタスクの状態を確認し、必要に応じて操作します。次に、ISR2 が呼び出され、自身の状態と ISR1 の状態をチェックし、適切と判断したとおりに動作します。わかりやすくするためにヘッダー ファイルで ENUM を使用して状態 (INIT、WAITONDATA など) を列挙し、ISR でスイッチを使用して各状態を処理します。次に、共有する必要があるデータが両方の ISR から参照できることを確認するだけで、準備は完了です。

もちろん、他の人が言ったように、ISR で多くの計算をしたくありません。イベントが発生したか、何らかのデータが存在するというフラグを設定し、メインループでデータを処理したいだけです。そうすれば、ISR の処理が長すぎてもシステムがブロックされることはありません。これは同じ方法で行います。つまり、メイン ループ (または少なくともメイン ループからデータ操作を行うために呼び出す関数) と ISR で確認できる状態変数です。ISR でその状態を変更し、メイン ループ関数でその状態を確認します。必要に応じて雑用を行います。

忘れないでください - ISR で変数を更新する場合、それらは volatile として定義する必要があります!

揮発性 uint8 状態 = INIT;

例えば。

于 2009-08-03T14:00:16.977 に答える
2

限られた情報に基づいて、次のことを前提として回答を試みます。

  • 単純な自作スケジューラを使用して、単純な基準に基づいて task1 と task2 を呼び出します。
  • task1 と task2 は完了するまで実行されます (つまり、互いに先取りされません)。
  • データはバイトベースのストリームです (パケットが必要な場合は、わずかに異なる実装が必要です)

組み込みシステムを設計するときに私が通常試みていることは、セマフォの使用を最小限に抑え、ロックのないデータ フローをモデル化することです。これを以下に説明します。

非同期 (ロックフリー) 通信キュー http://www.freeimagehosting.net/uploads/477741db06.gif ISR は、スレッドセーフな FIFO キューを使用してタスクから切り離すことができます。例はhttp://msmvps.com/blogs/vandooren/archive/2007/01/05/creating-a-thread-safe-producer-consumer-queue-in-c-without-using-locks にあります。 aspx

このような実装 (ロックなし) には OS の依存関係がなく、簡単にサポートできるはずです。これにより、デッドロックのない明確な生産者と消費者の設計も実現します。

タスクが自作のスケジューラーによってトリガーされると仮定すると、そこでイベント (空でない fifo) をチェックすることを選択できます。つまり、if (TRUE == fifo_filled(my_read_queue)) { タスク 1 を呼び出す }

次に、タスク 1 とタスク 2 の同期について説明します。task1 がデータを生成しているだけの場合は、同じメカニズムを使用できます。タスク 1 がデータを書き込み、タスク 2 が読み取ることができるキュー (fifo) がある場合、タスクは分離されます。繰り返しますが、これはスケジューラーで確認できます (if (TRUE==fifo_filled(task1_to_2_queue() ) { invoke task2) }

さらに必要な場合 (つまり、タスクが完了まで実行されず、プリエンプトされる場合) は、同期するための何らかのメカニズムが必要になります。オプションには以下が含まれます: - とにかく (無料の) オペレーティング システムまたは単純なスケジューラを使用する - 独自に作成する (私の経験: for ループといくつかの if ステートメントと同じくらい単純な場合にのみ実行する必要があります) - 単純なスケジューラを使用します (はるかに多くの完全な RTOS よりも軽量) - コードをリファクタリングして、タスク 1 とタスク 2 を 1 つに統合します。その場合、効果的にスケジューラーをアプリケーション コードの一部にします。

注: この説明で使用したサンプル関数 (fifo_filled() ) は、サンプル コードの一部ではありません。(read != write) の場合は true を返す必要があります。また、サンプル コードではグローバル変数 read と write を使用しています。複数のキューを処理できる関数をグーグルで検索するか、読み取り/書き込み変数とバッファ変数を構造体に移動して、パラメーターで構造体を参照することができます。

別の方法として、割り込みを無効にしてクリティカル セクションを作成する方法があります。ただし、システムの結合が強くなり、コードの再利用が難しくなるため、これを制限するようにしています。

于 2009-08-03T10:36:13.147 に答える