サンプル::MDMA

サンプル::MDMA

ADSP-BF533のメモリー間DMAです。

下準備など

BF53x用のシンボル・ファイルとイベント処理ファイルをインクルードします。

#include <cdefBF53x.h>
#include <sys/exception.h>

転送に使うデータです。ソース・バッファの値がデスティネーション・バッファにコピーされます。

char srcBuf[20] = "Chiba City Blues";
char dstBuf[20];

このサンプルの最大のポイントは、DMAデスクリプタです。DMAデスクリプタはメモリー上の変数で、DMAコントローラーに仕事の内容を伝えるためのデータ群です。BF533のデスクリプタには複数の型があり、かつ、それぞれの型が可変長になっています。詳しくはHRのFlex Descriptor Structureを参照してください。

自由度が高いため難しく聞こえますが、実はDMAデスクリプタを高級言語から使おうとすると、それほど多くの種類を使えるわけではありません。まず、アライメントの都合でスモール・デスクリプタのリンクは使わないでしょう。Flex Descriptor にしても最低config要素までは含むでしょうから、長さとしての最低値はあります。

よほどメモリーが逼迫しているならともかく、DMAデスクリプタはラージ・デスクリプタ・リンクを使用し、xmodまで含めておくのがお奨めです。ymodまで含んだ2次元DMA版は別に用意してもいいでしょう。

構造体変数srcはソース・デスクリプタ、dstはデスティネーション・デスクリプタです。

struct {
    void * ndp;                 // 次のデスクリプタ
    void * sa;                  // バッファ・アドレス
    unsigned short config;
    unsigned short xcnt;        // 転送データ数
             short xmod;        // アドレス増減値
}src, dst;

割り込みハンドラの宣言はsys/exception.hから読み込んだマクロ、EX_INTERRUPT_HANDLERによって行います。引数として与えた識別し、intHandlerが割り込みハンドラのプロトタイプ名として宣言されます。

EX_INTERRUPT_HANDLER(intHandler);

main(void)

main関数の先頭ではSIC_IMASKを使ってデバイス割り込みをすべて受け付け可能にします。次にregister_handler関数を使って割り込みハンドラを登録します。ik_ivg13はsys/exception.hで定義されている識別子で、汎用割り込み13に相当します。

MDMA_xx_NEXT_DESC_PTRはDMAコントローラのMMRです。このMMRはDMAコントローラに対して次に読み込むべきデスクリプタのアドレスを与える32ビットレジスタです。

main(void)
{
        
    *pSIC_IMASK = 0xffffffff;
    register_handler( ik_ivg13, intHandler );

        // デスクリプタ・アドレス指定
    *pMDMA_D0_NEXT_DESC_PTR? = &dst;
    *pMDMA_S0_NEXT_DESC_PTR? = &src;

デスクリプタの設定は単調です。.saにはバッファアドレス、.xcntには転送数を指定します。ここは転送数であって転送バイト数ではないことに気をつけてください。一回の転送で運ぶデータのサイズは.configのWDSIZEで指定します。

FLOWとNDSIZEがともに0であることに気をつけてください。これは、デスクリプタで指定する処理が終ったら、DMAを停止することをコントローラに教えます。

割り込みの発生はデスティネーションへの書き込みによって行います。

        // デスティネーション
        // 転送後、DMAを終了
    dst.ndp = 0;
    dst.sa = dstBuf;
    dst.xcnt = 20;
    dst.xmod = 1;
    dst.config = DI_EN | DMAEN | WNR | WDSIZE_8;
        
        // ソース
        // 転送後DMAを終了
    src.ndp = 0;
    src.sa = srcBuf;
    src.xcnt = 20;
    src.xmod = 1;
    src.config = DMAEN | WDSIZE_8;

DMA転送を開始するには、DMAコントローラのMMRである、MDMA_xx_CONFIGに引き金となる書き込みを行います。この書き込みはコントローラによりDMA開始の合図として解釈され、FLOWとNDSIZEの値から次に行うDMA転送の種類が解釈されます。なお、MDMAの場合ソースCONFIGのほうからレジスタに書き込みます。

DMA転送が始まると、あとはすることはありません。このプログラムでは無限ループを実行します。

    // キックスタート
    // ラージ・デスクリプタ・リンク&デスクリプタサイズ=7
    *pMDMA_S0_CONFIG? = DMAEN |       WDSIZE_8 | 0x7700;
    *pMDMA_D0_CONFIG? = DMAEN | WNR | WDSIZE_8 | 0x7700;
    while(1)
                ;
        
}

EX_INTERRUPT_HANDLER(intHandler)

DMA終了とともに割り込みが発生します。割り込みハンドラはDMA終了割り込みによって呼び出されます。ハンドラ内部ではDMA終了割り込みをクリアして戻ります。DMA_DONEビットはW1Cです。

        // 割り込みハンドラ
EX_INTERRUPT_HANDLER(intHandler)
{
        // 割り込みクリア
    *pMDMA_D0_IRQ_STATUS? = DMA_DONE;
}