SSブログ

beagleboard を触ろう - UART DMA モード [組み込みソフト]


UART を DMA モードで使用してみましょう。

OMAP35x TRM では、The System Direct Memory Access (SDMA) と呼ばれている、システムで汎用的に使用できる DMA デバイスがあります。
UART で DMA 転送を行う場合は、SDMA を使います。

SDMA は、32 チャンネルあります。
つまり、32 個、別々の DMA 転送を同時に設定できるわけです。

SDMA の使用方法は、概略、以下のような感じです。

・DMA リクエスト番号を設定する
・転送サイズを設定する
・転送元のアドレスとアドレッシングモードを設定する
・転送先のアドレスとアドレッシングモードを設定する
・転送元のバーストサイズを設定する
・転送先のバーストサイズを設定する
・デバイスとの同期方法を設定する
・必要ならば、割り込み設定をする
・イネーブルビットを立てて DMA を有効にする

この状態で、デバイスから DMA 要求が上がると、DMA 転送が行われます。
逆に言えば、デバイスから DMA 要求が上がらない限り、何も行われません。
(厳密に言えば、RAM からデバイスに転送する場合は、デバイスから DMA 要求が上がらなくても、RAM からプリフェッチされることはあるかもですが。)

DMA リクエスト番号は、モジュール毎に専用の値が割り当てられています。
UART3 の場合、送信リクエストは 52 番、受信リクエストは 53 番です。
RAM から UART3 にデータを転送したい場合は 52 番を、UART3 から RAM に転送したい場合は 53 番を使います。

アドレッシングモードは、Constant, Post-increment, Single-index, Double-index の 4通りから選択できます。
Constant は、ずっと同じアドレスに対して読み/書きをします。
Post-increment は、1 バイト読み/書きしたら、1 バイトアドレスを進めます。
Single-index と Double-index は、ここでは省略です。

デバイスとの同期方法は、ブロック同期、フレーム同期、パケット同期、あともう一つ、呼び方がよう分からんですが、シングルエレメント同期(?)の 4通りから選択できます。
これらは、デバイスから DMA 要求が SDMA に上がってきた場合に、何バイトデータを転送するかを指定するものです。

DMA_block_frame_element.png

DMA 全体で転送されるサイズは、この図の block 分です。
block は、n 個の frame で成り立っています。
また、frame は、m 個の element で成り立っています。
DMA 全体で転送されるサイズは、(element のサイズ) x (frame 中の element 数) x (block 中の frame 数) ということになります。

element のサイズ、frame 中の element 数、block 中の frame 数は、SDMA のレジスタで設定することができます。
element のサイズは、8/16/32 ビットの 3通りから選択できます。
frame 中の element 数、block 中の frame 数は、好きな値を設定することができます。


同期方法の話に戻りますが、デバイスから DMA 要求が上がってきた際に、

・一気に block 分転送してしまうのがブロック同期
・1 frame だけ転送するのがフレーム同期
・1 element だけ転送するのがシングルエレメント同期(呼び方不明)
・別途指定したパケット数分だけ転送するのがパケット同期

ということになります。
パケット同期が、一番フレキシブルな方法ですね。


SDMA は、割り込みを上げることができます。
パケットの転送完了、ブロックの転送完了、フレームの転送完了等々のイベントで、割り込みを上げることが可能です。
転送が完了した時を知りたい時は、割り込みを使えばいいですね。

割り込みで使用するレジスタは、4種類です。

・DMA4_IRQENABLE_L
・DMA4_IRQSTATUS_L
・DMA4_CICRi
・DMA4_CSRi

DMA_intreg.png

DMA4_IRQENABLE_L は、32 ビットのレジスタですが、各ビットが各チャネルを表します。
対応するビットに 1 を立てると、そのチャネルでの割り込みがイネーブルされます。
例えば、DMA チャネル n を使用する場合は、DMA4_IRQENABLE_L のビット n に 1 を立てます。

DMA4_CICRi は、32 ビットのレジスタで、DMA4_CICRi は全体でチャネル分、32 本あります。
このレジスタで、どのようなタイプの割り込みを上げるかを指定します。
例えば、ブロック完了割り込みを上げたい場合は、ビット 5 に 1 を立てます。

割り込みを上げるには、DMA4_IRQENABLE_L, DMA4_CICRi の両方への設定が必要です。
片方だけではダメです。

割り込みが上がった時、割り込みハンドラーで参照するのが DMA4_IRQSTATUS_L レジスタと DMA4_CSRi レジスタです。
DMA4_IRQSTATUS_L には、割り込みを上げたチャネルに対応するビットが立っています。
例えば、DMA チャネル n を使用する場合は、DMA4_IRQSTATUS_L のビット n に 1 が立ちます。

DMA4_CSRi は、その割り込みを上げたチャネルで、どのような種類のイベントが発生したのかを示しています。
例えば、ブロック完了割り込みが発生した場合は、DMA4_CSRi のビット 5 に 1 が立ちます。

割り込みハンドラーでは、DMA4_IRQSTATUS_L と DMA4_CSRi、それぞれのビットの立っている位置に 1 を書き込んで、割り込み要因をクリアする必要があります。
これもまた、片方だけではダメで、DMA4_IRQSTATUS_L と DMA4_CSRi の両方に、書き込んでやる必要があります。
でないと、割り込み要因がクリアされません。


今まで説明したことを含め、SDMA の設定方法詳細は、OMAP35x TRM に載っています。
DMA 章の SDMA Basic Programming Model 節です。

・・・

UART で DMA 転送をするには、UART の方にもちょっと設定をしてやる必要があります。
といっても、閾値の設定と DMA モードの設定だけです。
閾値は、UART 割り込みモードで見た閾値とまったく同じです。
設定方法も同じです。

UART が転送元になる場合、即ち UART から RAM へデータ転送する場合、設定した閾値の分だけ受信 FIFO にデータがたまった時に、DMA 要求が上がります。
SDMA は、これを受けて、受信 FIFO からデータを取り出し、RAM へ転送します。

DMA 要求が上がった際に、何バイト読み出すかは、デバイスとの同期方法に依ります。
ブロック同期、フレーム同期、パケット同期、シングルエレメント同期、どれを使ってもいいんですが、パケット同期を使った場合は、設定したパケット数分だけ転送されます。

DMA 転送のパケット数と、UART の閾値は、同じ値にしておくとよいです。
例えば、パケット数、UART の閾値をともに 4 にした場合、

・受信 FIFO に 4 バイトたまると、DMA 要求が上がる
・SDMA は、4 バイト分(=パケット数)、受信 FIFO から RAM に DMA 転送する
・受信 FIFO は空になる

となって、いい塩梅です。


それでは、また簡単なテストです。
UART3 から RAM へ、DMA 転送を行います。

SDMA の初期化を、以下のように行っておきます。

・DMA チャネル 0 番を使用
・DMA リクエスト番号は 53 (UART3 RX) を設定
・転送元のアドレスは UART3 の RHR に、アドレッシングモードは Constant に設定
・転送先のアドレスは 適当な RAM 領域に、アドレッシングモードは Post-increment に設定
・element のサイズは 8 ビット
・frame 中の element 数は 8
・block 中の frame 数は 1
・デバイスとの同期はパケット同期
・パケット数は 4 バイト
・割り込み設定は、ブロック完了割り込みをイネーブル

DMA 転送サイズは、(element のサイズ) x (frame 中の element 数) x (block 中の frame 数) なので、8 バイトです。
パケット数は 4 バイトなので、DMA 要求が上がってきた際に転送するサイズは 4 バイトです。
DMA 転送完了までに、2 パケット転送することになります。
ブロック完了割り込みをイネーブルしているので、DMA 転送が完了した時に割り込みが上がります。


UART3 の方は、以下のように設定しておきます。

・受信 FIFO の閾値を 4 に設定
・DMA モードを 1 に設定


このように SDMA, UART3 を設定しておくと、

・シリアルコンソールからキー入力が 4 回行われると、受信 FIFO に 4 バイトたまる
・受信 FIFO にたまっているデータが、設定した閾値と同じになったので、UART3 は DMA 要求を上げる
・SDMA は、これを受けて、設定してあるパケット数、4 バイトを UART3 受信 FIFO から RAM へ転送する
・受信 FIFO が空になる
・再度シリアルコンソールからキー入力が 4 回行われると、受信 FIFO に 4 バイトたまる
・UART3 は DMA 要求を上げる
・SDMA は、4 バイトを受信 FIFO から RAM へ転送する
・DMA 転送サイズである 8バイト分の転送が終わったので、SDMA はブロック完了割り込みを上げる

という動作が行われます。

テストコードは、こんな感じです。

 90: static volatile int dma_completed;
 91: static unsigned char dma_buf[DMA_LEN];
	  :
106: static int uart_dma_test(void)
107: {
108:    int i;
109:
110:    dma_completed = 0;
               :
       (SDMA, UART3 の初期化)
               :
169:    while (!dma_completed)
170:        ;
171:	
172:    serial_reinit2(1, 1, 0);
173:
174:    for (i = 0; i < DMA_LEN; i++)
175:        printf("%c ", dma_buf[i]);
176:    printf("\n");
177: }


SDMA, UART3 の初期化をした後は、169-170 行目で dma_completed を見張りながらビジーループします。
dma_completed は、割り込みハンドラーが設定します。
172 行目は、UART3 の設定を元の状態 (送信 FIFO 閾値 = 1, 受信 FIFO 閾値 = 1, DMA モード = 0) に戻しています。
最後、dma_buf を先頭から 8 バイト分表示しておしまいです。
dma_buf は、DMA の転送先に設定してある領域です。
DMA が完了した後は、UART3 から転送されたデータが書き込まれているはずです。


割り込みハンドラーは、以下のような感じです。

 88: #define DMA_IT_TYPE   0x20
           :
 93: static void dma_handler(int irq)
 94: {
 95:    unsigned long dma4_csr;
 96:
 97:    dma4_csr = __raw_readl(DMA4_CSR(DMA_CHANNEL));
 98:    if(!(dma4_csr & DMA_IT_TYPE))
 99:        return;
100:    __raw_writel(dma4_csr, DMA4_CSR(DMA_CHANNEL));
101:    dma_clear_irq(DMA_IRQ_LINE, DMA_CHANNEL);
102:
103:    dma_completed = 1;
104: }


割り込みハンドラーは、DMA 転送完了時に呼び出されます。
やっていることは、割り込み要因のクリアと、dma_completed に 1 を設定していることだけです。
100 行目が DMA4_CSR のクリア、101 行目が DMA4_IRQSTATUS_L のクリアです。

SDMA の初期化時に、ブロック完了割り込みをイネーブルしています。
それ以外の割り込みはディセーブルしているので、ブロック完了割り込み以外は上がってこないはずなのですが、念のため 98 行目でチェックしています。


uart_dma_test() を実行し、シリアルコンソールから、'1', '2', '3', '4', '5', '6', '7', '8' を入力すると、以下のようになります。

dma_test.png

・・・

これで、DMA の確認もできました。
相変わらずしょうもないテストですが・・・。

でも、DMA と割り込みを抑えると、なんかちょっと、デバイスを動かしているなあという実感が湧いてきます (^-^)

nice!(0)  コメント(3)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 3

KelArok

Cialis One Day Terapia http://cialibuy.com - Buy Cialis Viagra Pas Cher Payement SСЂВ curisСЂВ  <a href=http://cialibuy.com>Cialis</a> Viagra A Quoi Ca Sert
by KelArok (2020-01-22 03:12) 

StevReok

Pharmacy Online No Prescription http://cialibuy.com - Cialis Cialis Gсђс–сѓв˜nstig Kaufen 40mg <a href=http://cialibuy.com>Cialis</a> Comprar Cialis Online Andorra
by StevReok (2020-01-23 10:50) 

StevReok

Cialis Lo Pueden Tomar Las Mujeres http://buycialisuss.com - п»їcialis Viagra Nell'Acqua <a href=http://buycialisuss.com>Buy Cialis</a> Viagra Kaufen Ohne
by StevReok (2020-02-10 13:16) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。