こんにちは、
ENET_QOSのDMAの機能について理解しようとしているだけです。現在、DMA_CHx_RXDESC_TAIL_POINTERレジスタに問題が発生しています。レジスターの説明の中で、リファレンスマニュアルに以下の記述を見つけました。
61.7.1.479.2関数
チャネル0の受信ディスクリプタの末尾ポインタは、ベースからのオフセットを指し、最後に有効なディスクリプタの位置を示します。
したがって、ここに最後に有効なディスクリプタのアドレスを入力する必要があります。8つのエントリーがあるリングの場合、最後のエントリーはここでは7番目になります。0から7まで数える。
しかし、ENET_QOS_ReadFrameの末尾を見てみると、次のコード行が使用されています。
/* Always try to start receive, in case it had stopped */
rxDescTail = (uint32_t)(uintptr_t)&rxBdRing->rxBdBase[rxBdRing->rxRingLen];
#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
rxDescTail = MEMORY_ConvertMemoryMapAddress(rxDescTail, kMEMORY_Local2DMA);
#endif
base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR = rxDescTail;
base->DMA_CH[channel].DMA_CHX_RX_CTRL |= ENET_QOS_DMA_CHX_RX_CTRL_SR_MASK;しかし、ここでは rxDescTail に有効な記述子が設定されておらず、「範囲外」アクセスが使用されています。rxBdRing ->rxRingLenはリングのサイズです。
これは他の場所でも起こっている。これは間違いでしょうか、それともDMA_CHx_RXDESC_TAIL_POINTERは正確にはどのように使用すべきでしょうか?
よろしくお願いします、
マイケル
こんにちは、 @Gavin_Jia さん。
「MCUXpresso SDKは、Current == TailによってRx DMAが停止しないように、これをone past-endに設定します。」
したがって、テールポインタはリングの外側に設定されるため、 Current == Tail の場合でも DMA は停止しません。
しかし、ENET_QOS_SendFrame の場合は、これは紛らわしい。そこでは、末尾ポインタは現在のエントリより1つ先のエントリに配置されます。これは、現在のフレームが送信された時点でDMA処理を停止させるための措置なのでしょうか?つまり、例えば送信リングのサイズも8で、送信する新しいフレームがインデックス5にある場合、テールポインタは6に設定されます。
しかし、送信する新しいフレームがインデックス 7 にある場合、テール ポインタはインデックス 0 には設定されず、インデックス 8 に設定されます。その後、7の後にインデックス0が使用されると、末尾ポインタはx+1、つまり0+1にリセットされます。
なぜここでテールポインタが設定されているのか、全く理解できません。この場合も、インデックスを8に設定するだけで十分ではないでしょうか?次のインデックスに対してOWNビットが設定されていない場合、DMAは送信後に実行を継続しないためです。
よろしくお願いします、
マイケル
こんにちは、 @michael_fischer さん。
NXP MIMXRTシリーズにご関心をお寄せいただきありがとうございます!
SDKのコードは意図的に作成されたものです。&rxBdBase[rxRingLen] は、ソフトウェアや DMA によってアクセスされる記述子としてではなく、終端の 1 つ過ぎたテール境界/ドアベル値として使用されます。ENET_QOS DMAリングモードでは、ディスクリプタリング長レジスタが実際の有効なディスクリプタ範囲を定義し、テールポインタは境界を示すため、またDMAが停止した場合に再起動するために使用されます。
したがって、8 つの記述子のリングの場合、有効な記述子は依然としてインデックス 0~7 であり、値 &rxBdBase[8] は末尾境界としてのみ使用されます。
リファレンスマニュアルの「最後に有効な記述子」という表現は、誤解を招きやすい。より正確に言うと、テールポインタはディスクリプタの境界/DMA再開ポイントを示すものです。MCUXpresso SDKは、Current == TailによってRx DMAが停止しないように、これをone-past-endに設定します。DMAはプログラムされたリング長に従ってラップアラウンドし、範囲外のディスクリプタをフェッチしません。
よろしくお願いします、
ギャビン
こんにちは、 @Gavin_Jia さん。
ENET_QOS_SendFrameFunktionに関連して、この件に関して何か新しい情報はありますか?
よろしくお願いします、
マイケル
こんにちは、 @Gavin_Jia さん。
詳細なご説明をありがとうございました。
よろしくお願いします、
マイケル
こんにちは、 @michael_fischer さん。
返信が遅くなり申し訳ありません。数日前から休暇でオフィスを不在にしていました。心よりお詫び申し上げます。
受信側に関するあなたの理解は正しいです。SDKは受信リングの終端アドレスの1つ先のアドレスを終端境界として使用します。これは、DMAが範囲外の記述子にアクセスすることを意味するものではありません。
Tx パスの場合、 ENET_QOS_SendFrame()のテール ポインタの動的な更新も意図的なものです。ENET_QOSリングモードでは、ディスクリプタの末尾ポインタは、DMAがフェッチしなければならないディスクリプタではなく、DMAが利用可能なディスクリプタウィンドウの終了境界として理解されるべきです。DMAは、末尾ポインタまでの記述子を処理しますが、末尾ポインタ自体は処理しません。現在のディスクリプタポインタがテールポインタに到達すると、DMAはソフトウェアがさらにディスクリプタを発行するまで一時停止または待機します。
例えば、8つの記述子からなるTxリングの場合:
- 有効な記述子: インデックス 0 ~ インデックス 7
- 1つ先の終端境界: &ring[8]
ソフトウェアが送信用に記述子インデックス 5 のみを準備する場合、テールポインタは&ring[6]に設定されます。これは、DMAが範囲[5, 6)を処理することが許可されていることを意味するため、記述子5のみを処理します。その後、現在のポインタがテール境界に到達し、DMAは次のテール更新を待ちます。
ソフトウェアが記述子インデックス 7 を準備する場合、テール ポインタは&ring[8]に設定されます。値&ring[8]は、末尾の1つ先の境界アドレスに過ぎません。これはDMAによって取得できる有効な記述子ではありません。実際のラップアラウンドはプログラムされた記述子のリング長によって制御されるため、有効な記述子はインデックス0からインデックス7までとなります。
リングがラップされ、ソフトウェアが後で記述子インデックス 0 を準備すると、新しい送信範囲は[0, 1)になり、したがってテール ポインタは&ring[1]に更新されます。
OWNビットについて:OWNビットとテールポインタは異なる役割を担っています。OWNビットは、個々のディスクリプタがDMAによって所有されているか、アプリケーションによって所有されているかを示します。テールポインタは、ソフトウェアがDMAにディスクリプタをどれだけ公開したかを定義するものであり、テールポインタを書き込むことは、リングモードでのドアベル/再開表示としても機能します。
したがって、Tx テール ポインタを常に&ring[8]に保持することは、SDK の実装と同等ではなく、推奨される解釈ではありません。DMAはOWNビットが設定されていないディスクリプタに到達すると停止する可能性がありますが、新しく準備されたTxディスクリプタを公開し、DMAを通知/再開するためには、テールポインタの更新が依然として必要です。
要約すると:
&ring[ringLen]に保たれます。よろしくお願いします、
ギャビン