この質問に関連するパラメータは次のとおりです。
1. IDE: S32 DS for ARM v 2.2 (これは古いですが、問題の製品自体も古いので、既存のコードのサポートが必要です)
2. チップ: S32K148
3. OS: Windows 11
4. システムOS: ベアメタル
ISR であらゆる種類の SPI マスター転送を実行しようとするとハングし、通常、中断された API はブロッキング I/O (I2C または SPI) 呼び出しです。
ブロッキング呼び出し (LPSPI_DRV_MasterTransferBlocking() へ) では、sysTick 割り込みが発生していないように見えるため呼び出しがハングし、MCU は経過時間を把握できません。
非ブロッキング呼び出し (LPSPI_DRV_MasterTransfer() の後に LPSPI_DRV_MasterGetTransferStatus(SPI1, &byte_remaining) が続く) では、byte_remaining は元の値のままになります。非同期転送のために LPSPI_DRV_MasterTransfer() を呼び出す前に LPSPI_DRV_MasterAbortTransfer(SPI1) への呼び出しを追加しようとしましたが、結果は同じです。
少し関連する質問ですが、SysTick_Handler() をトリガーするものは何ですか?私の直感では、1 ミリ秒ごとにティック カウントを増やしながら常に実行されているはずですが、その本体にブレーク ポイントを設定すると、一部の時間しかヒットしないようです。不思議なことに、ブロッキング SPI 転送が成功した場合でもヒットしないことがあります。これは、システム タイマーが以前は解除されていた場合は、システム タイマーが起動される必要があるためです。
もう 1 つの関連する質問は、SPI の S32 クックブックのサンプル コードでは、SDKs が提供する API が使用されていないことです。サンプルでは、すべてのレジスタ ビットを直接操作します。車輪の再発明ではなく、少なくとも NXP API を呼び出すという点で、本番環境に適したコードに近い例はありますか?
こんにちは@PetrS
どうもありがとうございます。割り込み優先度によって、問題は確かに解決しました。しかし、私は疑問を持っています。
ISR 内でブロックするのは良いアイデアではないことに同意しますが、シングル スレッド アプリケーションでは代替手段は何でしょうか?SPI 転送が完了するまで、アプリケーション コンテキストでスピンできます。これにより、他の I/O 割り込みが発生するようになります (私の理解では、負の優先度の割り込みはいずれにせよ発生します。正の優先度の ISR に入っても、それらは無効になりません)。しかし、私の状況では、重複する I/O を実行することは不可能であり、望ましくもありません。
1.S32K148 はすべてのバスのバス・マスタであるため、これは不可能です。SO、ISR で SPI 転送を実行している場合、別の I/O バスを駆動することはできず、したがって割り込みをトリガーすることはできません。
2. ISR 間でグローバルが共有される可能性があるため、現在の I/O が完了するまで新しい I/O を開始したくない、SO これは望ましくありません。
シングル Thread のベア メタル アプリケーションの場合、この状況に対処するにはどのような方法をお勧めしますか?
こんにちは、
OK、では単純に優先順位を中断すると、この動作が発生する可能性があります。両方の割り込みの優先度が同じ場合、GPIO ISR がアクティブな間は LPSPI ISR を実行できないため、ブロッキング API がハングします。ブロッキング呼び出しは、ISR が転送を完了してセマフォをポストするまで待機しますが、その ISR は GPIO ISR が終了するまで CPU 時間を取得しません。SDKs のドライバは実際には LPSPI 割り込みで転送を終了し、その後でセマフォをポストしてブロッキング呼び出しを解放します。SO、優先順位が同じ ISR はこのように転送をデッドロックします。
非ブロッキング API の動作は同じです。同じ優先度の GPIO ISR から呼び出された場合、LPSPI ISR はそれをプリエンプトすることができないSO、ドライバ ステート マシンは LPSPI IRQ によって処理されないSO、byte_remaining は変更されません。LPSPI の優先度を高く(数値的に低い値に)した後にのみ、LPSPI 割り込みが直ちに発生し、転送が完了し、ブロッキング API と非ブロッキング API の両方が期待どおりに動作できるようになります。試す
こんにちは@PetrS
ご返答ありがとうございます。しかし、よく理解できていないようで申し訳ありません。
あなたが言っているのは、ISR 内でブロッキング I/O を実行するのは悪い考えだということのようですが、私も同感です。しかし、なぜそれが機能しないのでしょうか?ティック カウンタは、優先度 -1 の割り込みハンドラ内で増加します。これは、どの I/O 割り込み優先度よりも高い優先度です。また、コード内の割り込みマスクは変更していませんが、ドライバが内部的にそれを変更するのでしょうか?
私たちのアプリケーションはベアメタル (シングル スレッド) なので、ISR コンテキストとアプリケーション コンテキストで待機することはほぼ同じです。唯一の違いは、ISR コンテキストでは、他の I/O 割り込みがブロックされることです。しかし、これはまさに私が望んでいるものなのです。ただし、優先度が高いため、タイマー ISR をブロックしてはなりません。ISR の最初の行に ENABLE_INTERRPUTS() の呼び出しを追加してみましたが、違いはありませんでした。
非ブロッキング バージョンも試してみましたが、これも別の方法でハングします。非ブロッキング呼び出し(LPSPI_DRV_MasterTransfer() の後に LPSPI_DRV_MasterGetTransferStatus(SPI1, &byte_remaining) )では、byte_remaining は元の値のままです。非同期転送のために LPSPI_DRV_MasterTransfer() を呼び出す前に LPSPI_DRV_MasterAbortTransfer(SPI1) の呼び出しを追加しようとしましたが、結果は同じでした。上記のAPI呼び出しはどちらもISRから実行されます。ユースケースとしては、ユーザーがボタンを押すとGPIO割り込みが発生し、SPI経由で値を読み取るというものです。
もう一度指摘しておく価値のあることは、ISR が中断している API はブロッキング SPI 転送であるということです。新しい転送を開始する前に ISR に LPSPI_DRV_MasterAbortTransfer() の呼び出しを追加しても、効果はありませんでした。
この問題に関しては期限が非常に迫っているため、どんな助けでも大歓迎です。
こんにちは、
こんにちは、
ISR はトリガーとしてのみ使用し、SPI 転送を main() で同期的に実行するか、ISR で開始されて LPSPI ISR によって完了する非ブロッキング転送として実行し、main は完了フラグを待機します。
BR、ペトル