電気回路/zynq/割り込み処理 の変更点

更新


[[公開メモ]]

#contents

* Xilinx の XAxiDma ドライバの説明書き日本語訳 [#b6740db8]

以下は AXI DMA エンジンドライバの API です。

DMA 機能の全詳細はハードウェアのスペックを参照してください。
このドライバでは次の機能を利用できます。

- Scatter-Gather DMA (SGDMA)
- Simple DMA
- Interrupts
- Programmable interrupt coalescing for SGDMA
- APIs to manage Buffer Descriptors (BD) movement to and from the SGDMA engine

** Simple DMA [#b0d504bd]

Simple DMA API を使うと DMA とデバイスとの間の単一の転送処理を設定できます。
2つのチャンネルを利用可能で、1つは DMA からデバイスへ、もう1つはデバイスから DMA 
へのチャンネルになります。転送処理を開始するには対応するチャンネルに対応する
バッファーアドレスとバッファー長さの2つのフィールドを設定する必要があります。

** 転送処理 [#lef55eb5]

転送処理を記述するのに使われる構造体は Buffer Descriptor (BD) と呼ばれます。
ユーザーアプリケーションは BD を malloc し、転送処理に用いるバッファーアドレス、
転送長、制御情報を設定します。制御情報は SOF や EOF を含みます。
これらの定数は xaxidma_hw.h に定義されています。

** Scatter-Gather DMA (SGDMA) [#q9fc2618]

SGDMA ではユーザーアプリケーションがメモリ上に次善に準備した一連の転送処理設定を、
ハードウェアが順に処理します。この処理中にユーザーアプリケーションが介在する
必要はありません。また、処理中に新たな処理内容を追加することも可能であり、
ハードウェアを常に働かせておくことができます。

ユーザーはハードウェアをポーリングする、あるいは割り込みを使うことで
転送処理の完了を知ることができます。

SGDMA はすべてのパケットを処理します。パケットは一続きのバイトデータで、1つの
メッセージを表します。SGDMA を使えば1つのパケットを複数の転送処理に分割できます。
例えば、14バイトのヘッダーと、それに続く1バイト以上のペイロードからなるIP
パケットを思い浮かべてください。SGDMA を使えばアプリケーションはヘッダーに対応する
BD と、ペイロードに対応する BD とを指定して、それらを1つのメッセージとして転送処理
することができます。この方法を使うと TCP/IP スタックをより効率的に作成できます。
なぜならパケットヘッダーとデータを異なるメモリ領域においたまま処理できるからです。
そうでなければパケットを一つの連続するメモリブロック上に組み立て直さなければなりません。

** BD リングの管理 [#r0a72f92]

BD リングはソフトとハードとで共用されます。

ハードウェアは BD が連結リストの形で提供されることを期待します。DMA ハードウェアは
1つの BD の処理が終わるごとにその next pointer フィールドの値をたどることでリストを
次々に処理します。そして、ハードウェアの Tail Ptr レジスタに指定された BD を処理したら
停止します。

BD リングでは最終 BD は最初の BD へリンクされています(ので、処理は自動では停止しません)。

BD の管理はすべてドライバ内で行われます。ユーザーアプリケーションは BD のフィールドを
直接変更すべきではありません。BD フィールドの変更は常に対応する API 関数を通じて
行うようにしてください。

BD リング中ではドライバーは4つの BD グループを管理します。それぞれのグループは
0 個以上の連続する BD から構成されます。

:Free|
アプリケーションが XAxiDma_BdRingAlloc() で確保可能な(現在使われていない)BD
:Pre-process|
XAxiDma_BdRingAlloc() で確保済みの BD。
これらの BD はアプリケーションの管理下にあります。
アプリケーションはドライバ API を用いて BD の内容を編集し、DMA 転送の準備をします。
:Hardware|
XAxiDma_BdRingToHw() でハードウェアに渡され、処理待ちになっている BD。
これらの BD はハードウェアの管理下にあり、処理を待ち、処理中、処理済み、
のいずれかの状態にあります。
この状態の BD をアプリケーションが変更することはできません。
変更した場合にはデータが壊れたり、システムが不安定になったりしかねません。
:Post-process|
XAxiDma_BdRingFromHw() により Hardware グループから取り出された処理済みの BD。
これらの BD はアプリケーションの管理下にあります。アプリケーションは BD 
の転送処理結果を確認することができます。アプリケーションは XAxiDma_BdRingFree()
することで BD を Free グループに戻せます。

連続して転送処理を行うには、BD は下記のような状態変化をすることが期待されています。

&uml(
[*]-r->Free
Free: under Driver control
Free: to be alloc for use
Free-r->Preprocess : XAxiDma_BdRingAlloc() 
state "Pre-process" as Preprocess
Preprocess: under Application control
Preprocess: setup for Transaction
Preprocess-d->Free :  XAxiDma_BdRingUnAlloc()
Preprocess-d->Hardware :  XAxiDma_BdRingToHw()
state Hardware {
[*]-r->Queuing
Queuing-->InProcess
InProcess-->Processed
Processed-l->[*]
}
Hardware-l->PostProcess :  XAxiDma_BdRingFromHw()
state "Post-process" as PostProcess
PostProcess: under Application control
PostProcess: Transaction status can be checked
PostProcess-u->Free :  XAxiDma_BdRingFree()
);

Pre-process 段階で、DMA 転送をハードウェアのキューに入れる前にキャンセルするには、
アプリケーションは XAxiDma_BdRingUnAlloc() を呼んで BD を Free に戻すことができます。

API は BD リストを渡り歩くため、以下の関数を提供しています。
- XAxiDma_BdRingNext()
- XAxiDma_BdRingPrev()

これらの関数はどこでグループが終了し、次のグループが始まるかを認識しないため、
使う際には注意が必要です。

** SGDMA デスクリプタリングの作成 [#lbc8babe]

BD リングは XAxiDma_BdRingCreate() で作成されます。BD リングのためのメモリは
アプリケーションが割り当てます。この領域は連続していなければなりません。
BD リングの設定には物理アドレスが必要となります。

アプリケーションは XAxiDma_BdRingMemCalc() で所望の数の BD を用意するのに必要な
メモリの大きさを計算できます。逆に、XAxiDma_BdRingCntCalc() により指定のメモリサイズに
何個の BD を格納可能か計算できます。

XAxiDma_BdRingClone() というヘルパ関数を使うことで、同じタイプの指示、例えば
SOF や EOF を持つ、複数の BD を含む BD リングを高速に準備できます。
XAxiDma_BdRingClone() した後、アプリケーションはバッファアドレスと転送長のみ
設定すれば良いことになります。1つのパケットのうちいくつかの BD、例えば
最初と最後のものは、特別な制御情報を設定する必要があるかもしれません。

** デスクリプタリングのステートマシン [#c4c82e49]

BD リングには2つの状態があります。

- HALTED (H) : ハードウェアは停止中です。
- NOT HALTED (NH) : ハードウェアは動作中です。

DMA エンジンの状態遷移は次のようになります。

&uml(
[*]-->HALTED
HALTED-r->NOT_HALTED : StartBdRingHw() or BdRingStart() or Resume() 
HALTED: 停止中
NOT_HALTED-l->HALTED : Pause() or Reset()
NOT_HALTED: 動作中
);

** 割り込みの併合 [#u6ae311d]

SGDMA は割り込み頻度を制御するために割り込みの併合機能を提供します。
DMA エンジンは割り込み併合を最適化するために2種類の方法を提供しています。

- パケット臨界値カウンタ:
エンジンにより指定された数のパケットが処理されるごとに1回割り込みを発生させます。
- パケット遅延時間カウンタ:
最後のパケットが処理された後、新しいパケットが処理されないまま指定の時間が
経過したら1回割り込みを発生させます。最低1つのパケットが処理されないと
割り込みは発生しないことに注意してください。

** 割り込み [#c3a4d1c3]

割り込みはユーザーアプリケーションで処理されます。
DMA チャンネルごとに割り込みIDを持っています。
ドライバは割り込みを許可・拒否し、また、パケット処理の頻度に応じて割り込み頻度を
最適化するための API を提供します。

** ソフトウェア初期化 [#y0e186bc]

Simple mode DMA エンジンを使い転送を行うには、次の設定手順に従います。

+ XAxiDma_CfgInitialize() により DMA を初期化します。
これにより指定された DMA エンジンに対するドライバインスタンスを初期化し、
エンジンをリセットします。
+ 割り込みモードを使う場合、割り込みを許可します。
割り込みシステムを適切に設定するのはアプリケーションの責任です。
少なくとも、エンジンが実際に割り込みを発行する前に割り込みハンドラを用意し、
適切に登録することが必要です。
+ 該当のチャンネルのバッファアドレスと転送長フィールドを設定し、DMA 転送を開始します。

SG モードで DMA エンジンを使い転送処理を行うには、次の手順に従います。

- XAxiDma_CfgInitialize() にて DMA を初期化します。
- BD リングを作成します。DMA チャンネルごとに XAxiDma_BdRingCreate().
により BD リングを作る必要があります。
- 割り込みモードを使うのであれば割り込みを許可します。
- DMA 転送を開始します: 一番始め、あるいはリセット後には XAxiDma_BdRingStart() 
により転送を開始します。チャンネルがすでに転送を開始しているなら、
XAxiDma_BdRingToHw() を使います。DMA チャンネルが動作していないときに
XAxiDma_BdRingToHw() しても BD はハードウェアに送られません。かわりに、
後に DMA チャンネルが XAxiDma_BdRingStart() で開始されてから処理されます。

** DMA 転送処理の開始方法 [#c337e9e1]

ユーザーアプリケーションは XAxiDma_BdRingToHw() により BD をハードウェアに送り、
DMA 転送を開始します。

どちら向きのチャンネルにおいても、DMA エンジンが(XAxiDma_Pause() により)
現在停止中であれば、新たに追加された BD は受理されるものの、
XAxiDma_BdRingStart() により DMA エンジンが転送を開始する、あるいは
XAxiDma_Resume() により転送を再開するまで、処理されることはありません。

** DMA 転送が終了した後の処理 [#e1700e04]

割り込みが設定され、許可されたなら、DMA チャンネルは
転送終了をソフトウェアへ通知するのために割り込みを行います。
割り込みを使わない場合、ユーザーアプリケーションは
BD の完了を XAxiDma_BdRingFromHw() あるいは 
XAxiDma_BdHwCompleted() によりポーリングすることもできます。

- BD が DMA チャンネルにより処理済みとなったら、
アプリケーションはまずそれらを XAxiDma_BdRingFromHw() 
により回収する必要があります。
- TX 側では、その時点でアプリケーションはその BD に関連づけられていた
データバッファーを解放することができます。なぜならバッファー中のデータは
すでに転送されたからです。
- RX 側では、その時点でアプリケーションは BD に関連づけられたデータ
バッファーのデータを利用可能になります。
- どちらのチャンネルにおいても、処理済みの BD は XAxiDma_BdRingFree()
により Free 状態に戻してやる必要があります。そうすることで以降の
転送処理で再利用することが可能になります。
- RX 側では、アプリケーションは常にいずれかの DB がデータ受け入れ
可能な状態にあるよう手配する責任があります。そうでないと、その RX 
チャンネルはデータを受け入れられなくなってしまいます。

** 使用例 [#sbf3c318]

ドライバ API の使用方法を示すため、5つの例が挙げられています。
- SG 割り込みモード (xaxidma_example_sg_intr.c)~
複数の BD/パケットを転送します
- SB ポーリングモード (xaxidma_example_sg_poll.c) ~
単一 の BD を転送をします
- SB ポーリングモード (xaxidma_poll_multi_pkts.c) ~
複数の BD/パケットを転送します
- Simple ポーリングモード (xaxidma_example_simple_poll.c)
- Simple 割り込みモード (xaxidma_example_simple_intr.c)

** アドレス変換 [#af60eac5]

ハードウェアに与えるすべてのバッファーアドレスおよび BD アドレスは物理アドレスです。

** キャッシュの整合性 [#g5401c99]

このドライバは BD で指定されるすべてのアプリケーションバッファーは
キャッシュと整合性の取れたメモリ空間にあると仮定しています。
システムでキャッシュが使われている場合、データの送信元として
用いるバッファメモリはドライバに BD を渡す前にキャッシュを
フラッシュ(メモリへの書き戻し)する必要があります。
また、データの受信先として用いるバッファメモリは、受信された
データにアクセスする前にキャッシュを無効化しなければなりません。

** データアラインメント [#s54707ff]

BD に対して:~
アラインメントの最小単位は XAXIDMA_BD_MINIMUM_ALIGNMENT 定数で
定義されています。

これはハードウェアとソフトウェアの両方が正しく動作するために
必要な最小アラインメントです。

デスクリプタリングがキャッシュメモリに置かれる場合、
アラインメントは最低限プロセッサーのキャッシュライン
サイズでなければなりません。
キャッシュサイズより大きいアラインメントを使う場合、
キャッシュラインの整数倍のアラインメントが必要です。
(訳注:XAXIDMA_BD_MINIMUM_ALIGNMENT とキャッシュライン
サイズの両方の倍数となるように取れということ)

デスクリプタリングを最初に作るとき(XAxiDma_BdRingCreate()
を参照)以外、BD のアラインメントが正しいかどうかランタイムの
チェックは働きません。

アプリケーションデータバッファについて:~
ハードウェアに DRE が実装されている限り、アプリケーション
データバッファは任意のアラインメントに基づくもので構いません。
そうでなければアプリケーションデータバッファはワードアラインメント
でなければなりません。ワードサイズは送信用には
XPAR_AXIDMA_0_M_AXIS_MM2S_TDATA_WIDTH で、受信用には
XPAR_AXIDMA_0_S_AXIS_S2MM_TDATA_WIDTH で定義されています。

複数の BD からなる BD チェインに対する SG 転送では、
それぞれの BD 転送長もワード単位でなければなりません。
さもないとハードウェア内で内部エラーが生じます。

** エラーの取り扱い [#v52ea731]

DMA エンジンは任意のエラーに対して停止します。
ソフトウェアは新しい転送要求を開始できるようにするために
リセットをかける必要があります。

** 停止後の再開 [#cc34cfe0]

DMA エンジンがリセットや、エラー後にリセットにより停止状態に
あるとき、ソフトウェアはリセットがかかった時点の DB ポインタを確認し、
XAxiDma_BdRingStart() により BD の処理を再開することができます。

** 制限事項 [#oc640014]

このドライバは同時利用の排他処理機能を持っていません。
この種の保護はアプリケーション側で行う必要があります。

** ハードウェアの初期設定と独占的使用 [#yc4fdc18]

初期化後、あるいはリセット後には DMA エンジンは以下のモードに初期設定されます。

- すべての割り込みは禁止されます
- 割り込み併合カウンタは1になります
- DMA エンジンは停止状態になります。
それぞれの DMA チャンネルは独立して処理を開始します。
それには、転送に BD が設定されていない状態であれば 
XAxiDma_StartBdRingHw() を使って、そうでなければ
XAxiDma_BdRingStart() を使います。

ドライバはレジスタや BD を独占的に使用します。
レジスタや BD へのすべてのアクセスはドライバインターフェースを
介して行われるべきです。

** デバッグ表示 [#ec635106]

ドライバに対するデバッグ用メッセージを表示するには、
コンパイル時に -DDEBUG フラグを付けて下さい。
さらに、xdebug.h の中の "#undef DEBUG" という行をコメントアウトして下さい。

* 情報集め [#c0b36512]

** ZYBO : I2S コントローラの作成 11 [#nee23df7]

Standalone で割り込みを使う例:~
http://bravo-fpga.blogspot.jp/2015/02/zybo-20-i2s-11.html


** ZynqのPLロジックからARMへの割り込み実験 [#w6c75b9a]

https://formalism.github.io/blog/posts/2014/05/zynq-pl-arm/

>IRQがHighになるとCPUに割り込みがかかる。AXIバスを通してレジスタをクリアするとIRQがLowになる。これを見ると、たったの31クロック(=310ns)で割り込みがクリアされている。
>
>これはStandalone(Linuxではなく、ベアメタル)で実験した。割り込みを有効にする部分だけ、参考に貼っておく。
>
>  Status = XScuGic_Connect(IntcInstancePtr, XPS_FPGA0_INT_ID,(Xil_ExceptionHandler)IrqHandler, NULL);
>      if (Status != XST_SUCCESS){
>          return Status;
>      }
>  XScuGic_Enable(IntcInstancePtr, XPS_FPGA0_INT_ID);
>
>これでXPS_FPGA0_INT_ID(61)番の割り込みが発生すると、 IrqHandler関数が呼ばれる。IrqHandler関数の中で、PLロジックにアクセスして、割り込みをクリアしている。

** シンプルな AMP : 2 つの Cortex-A9 プロセッサ上で動作するベアメタルシステム [#w24b900b]

https://japan.xilinx.com/support/documentation/application_notes/j_xapp1079-amp-bare-metal-cortex-a9.pdf

> 2 つの Cortex®-A9 プロセッサ、各々に独立したベアメタルソ フ トウェアアプ リケーションを実行させると共に、共有メモリを介して両者間の通信を可能にする方法について説明します。

これは割り込み処理とはちょっと違うか。でも興味ある。

Counter: 6640 (from 2010/06/03), today: 1, yesterday: 1