この記事では、AUTOSAR MCAL SPI モジュールの知識と注意事項を詳しく紹介し、このモジュールの構成については他の記事で共有します。この記事の内容の大部分は標準に準拠しており、NXP S32K1 シリーズの MCAL SPI コードを参照しています。
この記事を辛抱強く読むと、AUTOSAR MCAL SPI について非常に深く理解できるようになります。
目次
1. モジュールの紹介
SPI ドライバーは、SPI バスを介して接続されたデバイスに読み取りおよび書き込みサービスを提供します。EEPROM、外部ウォッチドッグ、またはその他の特定用途向け集積回路 (ASIC) などの一般的なデバイス。もちろん、SPI ドライバーはオンチップ SPI ペリフェラルの構成と使用も提供します。
ドライバーは機能と構成を複数のレベルに分割し、高い拡張性と柔軟性を実現します。例えば機能的には3つのレベルに分かれています。さまざまなレベルに応じて、同期または非同期として構成できます。
もちろん、シーケンス、ジョブ、チャネルなど、他の多くの概念は抽象化されています。重要な概念/キーポイントについては、以下の図を参照してください。
2. モジュールの制限事項
- マスターモードのみがサポートされています。
- 全二重モードのみがサポートされています。
- レベル 2 は、少なくとも 2 つの SPI バスを個別に提供する必要があるチップ用に指定されています。それ以外の場合、このレベルの機能を使用する意味がありません。
- 周辺クロックの初期化と分周はMCUモジュールが担当
- 他の周辺機器と共有する必要があるレジスタがある場合、MCU がそのようなレジスタを担当します。
3. 主要概念: シーケンス/ジョブ/チャネル
まず最初に、ここでのチャネルはソフトウェア レベルにあり、ハードウェアの物理チャネル/チャネルとは何の関係もなく、バインディングも存在しないことを説明する必要があります。ソフトウェアレベルのチャネルはBUFFを設定するだけです。
ジョブは周辺機器にバインドされています。したがって、チャネルは、上記の CH2 と CH5 のように、同時に複数のジョブに属することができます。CH2 と CH5 の違いは、前者は異なるペリフェラルに使用されるのに対し、後者は同じペリフェラルを使用することです。管理が悪いとバフ内のデータが混乱しやすいので、個人的にはこのような使い方はお勧めしません。上記の Job0 のように、ジョブは同時に複数のシーケンスに属することもできます。
上の Job1、Job2、Job3 など、1 つのジョブの下に複数のチャネルを含めることができ、少なくとも 1 つのチャネルが存在する必要があります。そうでない場合は意味がなく、上記の Job5 は許可されません。この場合、ジョブ/シーケンスは通常複数のユーザーによって使用され、各ユーザーには独自の独立したチャネルが割り当てられます。
同様に、上記の Seq3 のように、シーケンスの下に複数のジョブが存在する可能性があります。少なくとも 1 つのジョブが存在する必要があり、そうでない場合は意味がなく、上記の Seq2 は許可されません。
同じ順序にある複数のジョブは同じ優先度を持ちます。
ペリフェラルには複数のジョブ バインディングを持つことができます。
上の図からわかるように、シーケンスにはさまざまなペリフェラル (バス) を備えたジョブを含めることができます。
送信はシーケンスベースであり、シーケンスのみ動作可能です。受信はチャネルに固有です。ステータスまたはコールバックを取得します。ジョブとシーケンスの両方が利用可能です (レベル 1、レベル 2)。
4. シーケンス/ジョブ/チャネルの送信タイミング
上の図に示すように、送信タスクは、バスが解放される (解放される) 前に、シーケンス内のすべてのジョブとすべてのチャネルが送信されるのを待つ必要があります。
複数のジョブがチャネルを共有する (シーケンスが同じ) 場合、ユーザーは送信プロセス中に読み取り/書き込み関連関数が呼び出されないようにする必要があります。そうしないと、データの一貫性が保証されません (データの混乱)。
送信プロセス中、読み取り/書き込み機能自体はデータの完全性を保証できません。
複数のシーケンス転送リクエストを同時に開始することができます。たとえば、Seq が送信されているときに、別の Seq 送信要求を開始することは許可されますが、同じ Seq を同時に複数回開始することはできません。ドライバーは現在の状況に基づいて受け入れるか拒否するかを選択します。たとえば、新しい Seq には元の Seq と共有ジョブがあります。この場合、競合を防ぐためにリクエストは受け入れられません。
シーケンス転送要求のキャンセル(Spi_Cancel)が可能であり、このオペレーションのキャンセルはジョブのアトミック単位で処理されます。キャンセル後も、ユーザーに通知するためにコールバック関数が呼び出されます (有効な場合)。キャンセル操作が周辺機器への損傷やその他の不定の動作を引き起こすかどうかは、ユーザーが制御する必要があり、ドライバーは責任を負わないことに注意してください。
シーケンスには複数のジョブを含めることができ、各ジョブは送信完了後に優先度ポリシー (後述) に従って再スケジュールされます。ポーリング モードでのスケジューリングは、ユーザーが定期的にSpi_MainFunction関数を呼び出すことによって実装されます。
5. MCAL SPI モードの分類
√: サポート/利用可能 ×: サポートなし/利用不可 IB/EB: 以下を参照
レベル 0:単純なアイソクロナス転送のみを処理する、簡素化されたサービスのセットを提供します。これは、高速外部デバイスを使用する ECU であっても、単純な SPI ネットワークを含む ECU で頻繁に発生します。
同期送信とは、送信サービス関数が呼び出されると、送信要求が完了するまでプログラムがブロックされることを意味します (適切なコード実装には通常、タイムアウト監視メカニズムがあり、タイムアウト後に CPU が解放されます)。
レベル 1:非同期転送のみを処理する簡素化されたサービスのセットを提供します。SPI を使用し、さまざまな優先順位を定義する関数の場合、非同期転送がよく使用されます。この非同期モードに適した低速ペリフェラルもいくつかあります。
非同期転送とは、転送サービスを呼び出すユーザーが転送の進行中にブロックされないことを意味します。ドライバーは、転送が完了したときにユーザーに通知できます (ユーザーが構成可能)。非同期転送モードはポーリングによる実現と割り込みによる実現に分けられます。
レベル 2:前の 2 つの組み合わせ。すべての機能が含まれています。さまざまな料金やさまざまな優先順位など、複雑な需要シナリオにも対応できます。これは、少なくとも 2 つの SPI バスを個別に提供する必要があるチップ向けに指定されています。それ以外の場合、このレベルの機能を使用する意味がありません。
(非同期) ポーリング モード (API レベルがレベル 2 の場合にのみ有効) として構成されている場合は、Spi_MainFunction を定期的に呼び出す必要があります。
上の表からわかるように、DMA は非同期モード (Async Mode) でのみ有効です。
6. SPIバッファ
IB: 内部バッファ EB: 外部バッファ
上の表の長所と短所は標準文書の翻訳に基づいており、一部の文章は滑らかではありません。以下のテキストの説明を参照してください。あなたの理解には影響しません。
IB: 静的に割り当てられます。EB: ユーザーの使用環境に応じて、静的割り当てまたは動的割り当てになります。
一部のハードウェア レベルでは比較的大きなバッファが提供されますが、この場合、IB タイプはハードウェアの特性を最大限に発揮し、パフォーマンスを向上させることができます (これが IB バッファの本来の設計意図です) (複数のチャネルが 1 つのチャネルに接続されている場合は注意してください)。同時にデバイスを使用すると、機能の使用が制限されます)。ハードウェアにバッファがない場合、実装をシミュレートするにはソフトウェアが必要です。
IBタイプのバッファのサイズは固定です。EBタイプのバッファはAPIから設定可能です。
SPI ドライバーは、IB バッファー内のデータの連続性を保証する責任を負いません。チャネルが複数のジョブ/シーケンスによって使用されている場合、SPI ドライバーは、バッファが複数のジョブ/シーケンスによって上書きされるシナリオを維持する責任を負いません。
ただし、送信バッファと受信バッファは別個で独立しています。つまり、送信バッファは受信データによって上書きされません。
EB バッファの本来の設計意図は、外部 (ここではユーザーを指します) バッファを可能な限り再利用することです。多くの場合、ユーザーは既にバッファを持っているため、EB タイプのバッファを使用するには、共有の目的を達成するための SPI ドライバーへのユーザー バッファーのポインター。したがって、SPI ドライバーはバッファーを管理できないため、ユーザーはバッファーの整合性を確保する必要があります。もう 1 つのシナリオは、バッファ サイズが変化する場合があります (たとえば、複数のユーザーのニーズが異なる場合や、ユーザーのデータ長が変化する場合など)。この状況も EB タイプのバッファを使用して解決する必要があります (IB タイプのバッファは固定サイズ)。もちろん、EB タイプの Buffer を固定サイズにすることもできます。ただし、バッファ サイズの最大値は静的に設定する必要があります。一般に、EB タイプのバッファの方が柔軟に使用できます。
チャネル送信には独自のパラメータ (Spi_SetupEB) がありますが、パラメータ (ソース/ターゲット) を NULL にすることもできます。送信時にソースが NULL の場合、デフォルトのパラメータ送信が使用されます。受信時にターゲットが NULL の場合、無視されます受信したデータ。長さ情報などの変更が必要な情報がない限り、各チャネルについて、Spi_SetupEB 関数は転送要求を開始する前に 1 回だけ呼び出すことができます。
データ幅も uint8、uint16、uint32 の 3 種類であれば、Data Buffer Type と一致しているため、そのまま転送できます。ただし、データ幅が 8 ~ 32 で、型が不一致の場合は注意が必要です。たとえば、データ幅が 12 ビットに設定されている場合。Data Buffer Typeはuint16のみ選択可能で、この場合送信時は下位12Bitのみ送信可能となり、上位4Bitは無視されます。受信時は下位12ビットのみを受信し、上位4ビットは0で埋められます。
7. SPI のその他の重要なメカニズム
- 優先度: 数字が小さいほど優先度が低くなります。
- シーケンスによってリンクされているジョブの優先度は同じか、それよりも低くする必要があります。
- シーケンスが中断される可能性がある
- 同時同期転送
ドライバーは、互いに独立していたり、異なる層に属していたりする複数のソフトウェア モジュールによって同時に使用される場合があります。同時アクセス時の競合を防ぐために、優先メカニズムが追加され、各ジョブに優先順位が割り当てられます。このシナリオは通常、非同期メカニズムに基づくリアルタイム システムで発生します。
シーケンス内の複数のジョブ、またはこれらのジョブはすべて同じ優先度を持ちます。優先順位が異なる場合、最初のジョブの優先順位が最も高く、最も低い優先順位が最後に配置されます (これは構成時に必要です)。ドライバー内には優先度ベースのスケジューラがありますが、このスケジューラは、中断されたシーケンスの実行中に開始できる、優先度の高い新しいシーケンス タスクのスケジューリングを処理するために使用されます。
レベル 1 とレベル 2 では、シーケンスをプリエンプトできるかどうかを設定できます。プリエンプト機能が有効な場合、シーケンスが送信を開始した後、途中で優先度の高いジョブが送信要求を開始すると、現在のシーケンスは優先度の高いジョブを実行するために一時停止(サスペンド)され、割り込みが発生します。ジョブはアトミック単位で実行されます。つまり、ジョブが実行されるまで待機し、次のスケジュール ポイントが実行されるときに切り替える必要があります。前のシーケンス図を参照してください。
プリエンプション機能が有効になっていない場合、シーケンスが送信を開始すると、送信が完了するまで他のシーケンスの送信要求は実行できません。
シーケンスがプリエンプトされる場合、ユーザーは同じチャネルを共有する複数のシーケンスがあるかどうかを知る必要があります。そうである場合、元のチャネルのジョブがより優先度の高いジョブに置き換えられないように、チャネルのデータを管理する必要があります。データはプリエンプション プロセス中に上書きされます (この構成は通常は推奨されません)。
同期送信では、複数の異なるシーケンス送信リクエストを同時に開始することもできますが、ユーザーはこの機能を有効にする必要があります (SPI_SUPPORT_CONCURRENT_SYNC_TRANSMIT: レベル 0 およびレベル 2 で有効)。
8. 注意事項
- このモジュールのサービスを使用する前に、Spi _Init() 関数を呼び出して初期化する必要があります。
- DMA 関数を使用する場合は、Port_Init() 関数および Mcl_Init() 関数の後に Spi _Init() 関数を呼び出す必要があります。
- (非同期) ポーリング モード (API レベルがレベル 2 の場合にのみ有効) として構成されている場合は、Spi_MainFunction を定期的に呼び出す必要があります。
- 固定優先順位戦略が使用される場合、SpiPhyRxDmaChannel の優先順位は SpiPhyTxDmaChannel の優先順位より大きくなければなりません。
- DMA が有効な (非同期) 割り込みモードに設定されている場合:
- DMA の対応するチャネル割り込みを有効にする必要があります。
- SPI モジュールの受信/送信割り込み関数は、DMA 完了コールバック関数に登録する必要があります。設定については、「DMA モジュールの設定」を参照してください。
SPI モジュール割り込み関数: Spi_LPspi_IsrRxDma_LPSPI_X/Spi_LPspi_IsrTxDma_LPSPI_X、X はチャネル番号です。
チャネル 0 を例に挙げると、割り込み関数は Spi_LPspi_IsrRxDma_LPSPI_0/Spi_LPspi_IsrTxDma_LPSPI_0 となります。
6. (非同期) 割り込みモードとして設定されているが FIFO を使用している場合は、割り込み関数 (Spi_LPspi_IsrTDF_LPSPI_X) を割り込みベクタ テーブルに登録する必要があります。X はチャネル番号です。
MCAL 自体は割り込みベクタ テーブル登録関数を提供していないため、SDK または MCAL サンプル プロジェクトの割り込み登録関数: sys_registerIsrHandler() を参照できます。
7. DMA 転送モードが有効で、D-CACHE が有効な場合、内部 buf (IB) を使用して送受信することはできません。また、送信元アドレスと宛先アドレスの buf は、NON-CACHE 領域に配置する必要があります。データの一貫性を避ける 性的な問題を回避します (CACHE 領域に配置すると、データの混乱が発生する可能性があります)。リンク ファイル (*.ld) でパーティション コマンドを使用すると、送受信する必要がある変数を分離できます。
8. SPI モジュールのコールバック関数では次の関数のみを呼び出すことができ、他の関数を呼び出すことはできません (プロトコル標準)。
- Spi_ReadIB
- Spi_WriteIB
- Spi_SetupEB
- Spi_GetJobResult
- Spi_GetSequenceResult
- Spi_GetHWUnitStatus
- スピ_キャンセル