- メインページ
- ネームスペース
- クラス
- ファイル

- ファイル一覧
- ファイルメンバ

# afw.cpp

説明を見る。

    00001 #include "afw.h"
    00002 /** \file afw.cpp
    00003  *  \brief オーディオ・フレームワーク・ファイル
    00004  *  \author アナログ・デバイセズ株式会社
    00005  *
    00006  * このファイルはVisualDSP++ 4.5のサンプル・アプリケーション、TalkTrhoughから
    00007  * 複製して変更したものである。EZ-KIT BF537のオーディオ・コーディックを利用する
    00008  * ための関数群からなる。。
    00009  */
    00010 namespace afw{
    00011
    00012     //--------------------------------------------------------------------------//
    00013     // Symbolic constants                                                       //
    00014     //--------------------------------------------------------------------------//
    00015     /** 左チャンネル指定定数
    00016       *
    00017       * afw::rxBufferおよび、 afw::txBufferにアクセスする際、最下位の添え字を指定
    00018       * するときに使う。
    00019       *
    00020       */
    00021     const int LEFT_CH = 0;
    00022     /** 右チャンネル指定定数
    00023       *
    00024      * afw::rxBufferおよび、 afw::txBufferにアクセスする際、最下位の添え字を指定
    00025       * するときに使う。
    00026       *
    00027       */
    00028     const int RIGHT_CH = 1;
    00029
    00030     /** バッファ数宣言定数
    00031       *
    00032       * DMA用のバッファ領域を afw::txBufferおよび afw::rxBufferとして
    00033       * 確保する際に、割り込みいくつ分のバッファを用意するかを宣言する。
    00034       * 具体的にいえば、トリプルバッファなので3を宣言する。過去3回の割り込み分のデータをバッファに
    00035       * 格納できるということである。
    00036       *
    00037       */
    00038     const int INTR_PER_BUFFER  = 3; // 変更してはならない。トリプルバッファのために3つの領域を確保
    00039
    00040     /** サンプルあたりチャンネル数の宣言
    00041       *
    00042       * サンプルあたり何チャンネルのデータを伝送するか宣言する。I2Sはステレオなので、この値は2である。
    00043       * この値はユーザーが変更してはならない。
    00044       *
    00045       */
    00046     const int CH_PER_SAMPLE  = 2;   // 変更してはならない。I2Sはサンプルあたり2チャンネルのデータを持つ
    00047
    00048     /** 割り込みあたりのサンプル数
    00049       *
    00050       * 何サンプルのデータを受信したら割り込みをかけるかを指定する。この値を大きくするほど
    00051       * 効率がよくなるが、遅延も増大し、また、必要なメモリ量も増える。したがって、これらの
    00052       * バランスを考えながらユーザーが値を決めることになる。
    00053       */
    00054     const int SAMPLE_PER_INTR = 8;  // 変更可能。何サンプルごとに割り込みをかけるか指定する。
    00055
    00056     /** オーディオ・コーデックのリセット時間
    00057       *
    00058       * EZ-KIT Lite BF537では、オーディオ・コーデックのリセット信号がADSP-BF537のPF12に
    00059       * 接続されている。コーデックの使用に先立って、この信号をアサートしなければならない。
    00060       *
    00061       * このマクロは、リセット信号をアサートする時間を与える。時間はループの繰り返し
    00062       * 回数なので、あまり精度は高くない。注意深い値が必要である。
    00063       */
    00064     const int CODEC_RESET_PULS_WIDTH  = 0x10000;
    00065
    00066     /** SPORT0のワード長
    00067       *
    00068       * SPORT0設定時に使うワード長である。EZ-KIT BF537に搭載されているコーデックは
    00069       * 32bit長のI2S回線を使うので、ワード長が32になるよう指定する。
    00070       * 32bit長にする場合は、31と設定することに注意。
    00071       */
    00072     const int SPORT0_SLEN_32 = 31;
    00073
    00074
    00075     //--------------------------------------------------------------------------//
    00076     // 大域変数                                                                 //
    00077     //--------------------------------------------------------------------------//
    00078
    00079     /** SPORT0 DMA 送信バッファ
    00080        *
    00081        * 送信DMAがアクセスし、SPORT TXチャンネルにデータを送り込むためのバッファ
    00082        *
    00083        * 最下位の次元はL, Rチャンネル用に2つの要素を格納する。下から2番目の次元は、
    00084        * 割込み1回ごとに送信されるサンプル数を指定する。1回の割り込みの間にDMA転送
    00085        * されるデータの量は、 afw::SAMPLE_PER_INTR * afw::CH_PER_SAMPLE で決まる。
    00086        *
    00087        * 最上位の次元は、このバッファが割込み何回分のデータを
    00088        * 格納するかを表す。
    00089        */
    00090     volatile int txBuffer[INTR_PER_BUFFER][SAMPLE_PER_INTR][CH_PER_SAMPLE];
    00091     /** SPORT0 DMA 受信バッファ
    00092        *
    00093        * 受信DMAがアクセスし、SPORT RXチャンネルからデータを受け取るのバッファ
    00094        *
    00095        * 最下位の次元はL, Rチャンネル用に2つの要素を格納する。下から2番目の次元は、
    00096        * 割込み1回ごとに送信されるサンプル数を指定する。1回の割り込みの間にDMA転送
    00097          * されるデータの量は、 afw::SAMPLE_PER_INTR * afw::CH_PER_SAMPLE で決まる。
    00098        *
    00099        * afw::INTR_PER_BUFFER だけ用意される次元は、このバッファが割込み何回分のデータを
    00100        * 格納するかを表す。
    00101        */
    00102     volatile int rxBuffer[INTR_PER_BUFFER][SAMPLE_PER_INTR][CH_PER_SAMPLE];
    00103
    00104     /** GPIOの初期化
    00105        *
    00106        * PORT Fに割り当てられているGPIO（フラグピン）の初期化を行う。
    00107        * PORT Fのピン割り当ては以下のとおり（カッコ内はマスク）
    00108        *  - pin 2..5  (0x003C) プッシュボタン
    00109        *  - pin 6..11 (0x0FC0) LED
    00110        *  - pin 12    (0x1000) コーデックのRESETピン
    00111
    00112        * afw::init()が自動的に呼び出すので、プログラマがこの関数を明示的に呼ぶ必要はない。
    00113        */
    00114     void initGPIO(void)
    00115     {
    00116         *pPORTF_FER   &= ~PF12;         // ポート Fのプログラマブル・フラグを利用できるようにする。
    00117         *pPORTFIO_DIR |=  PF12;         // ポートFの方向設定。LEDとコーデックのRESET制御を出力に
    00118     }
    00119
    00120
    00121     /** オーディオ・コーデックのリセット
    00122        *
    00123        * PORT Fに割り当てられているコーデック・リセット信号(PF12)をトグルする。
    00124        * afw::init()が自動的に呼び出すので、プログラマがこの関数を明示的に呼ぶ必要はない。
    00125        */
    00126     void resetCODEC(void)
    00127     {
    00128         *pPORTFIO_CLEAR = PF12;             // リセット・ピンをアサートする。
    00129
    00130         for( int i = 0; i< CODEC_RESET_PULS_WIDTH;i++)          // アサート状態を一定時間保持
    00131             asm volatile( "nop;" );
    00132
    00133         *pPORTFIO_SET = PF12;               // リセット・ピンをデアサートする。
    00134
    00135
    00136     }
    00137
    00138     /** SPORT0の初期化
    00139        *
    00140        * オーディオコーデックに接続されているSPORT0を初期化する。シリアル回線の
    00141        * フォーマットはI2Sで、クロックおよびLR信号は外部生成。この関数を読んだ段階
    00142        * では、ポートはディセーブルのままにしておく。
    00143        *
    00144        * 設定は送受信とも以下のとおり
    00145        * - 外部クロック
    00146        * - 外部LR信号
    00147        * - I2S設定
    00148        *  - xCKFE = 1
    00149        *  - xFSR = 1
    00150        *  - LAxFS = 0
    00151        *  - LxFS = 0
    00152        *  - xRFST = 0
    00153        *  - xDTYPE = 0
    00154        * - 24bit データ
    00155        * - セカンダリ・チャンネル無効
    00156        *
    00157        * 詳細はADSP-BF537 Hardware Referenceの "Stereo Serial Operation" を参照のこと。
    00158        * afw::init()が自動的に呼び出すので、プログラマがこの関数を明示的に呼ぶ必要はない。
    00159        *
    00160        * 注意：EZ-KIT Lite BF537 Rev 1.0のユーザーはSPORTのクロックおよびフレーム同期
    00161        * 信号を自分で生成する設定に変更しなければならない。
    00162        */
    00163     void initSPORT(void)
    00164     {
    00165                 // Sport0 受信設定
    00166         *pSPORT0_RCR1 = RFSR | RCKFE;
    00167         *pSPORT0_RCR2 = SPORT0_SLEN_32 | RSFSE;
    00168
    00169                 // Sport0 送信設定
    00170         *pSPORT0_TCR1 = TFSR | TCKFE;
    00171         *pSPORT0_TCR2 = SPORT0_SLEN_32 | TSFSE;
    00172
    00173
    00174     }
    00175
    00176     /** SPORT DMAの初期化
    00177        *
    00178        * SPORT0に接続されているDMAを設定する。DMA3が受信、DMA4が送信である。
    00179        * オーディオ信号は16ビット以上の長さがあるのでワードサイズは32bit,
    00180        * 連続送受信のためにオートバッファ、モードを使う。また、トリプル・バッファを
    00181        * 実装するために、DMA転送は2次元で行い、3ライン分のバッファを確保して各ラインの
    00182        * 転送を終えるたびに割り込みを発生させる。
    00183        * afw::init()が自動的に呼び出すので、プログラマがこの関数を明示的に呼ぶ必要はない。
    00184        */
    00185     void initDMA(void)
    00186     {
    00187
    00188                 // DMA3の設定
    00189         *pDMA3_CONFIG = WNR | WDSIZE_32 | DI_EN | DI_SEL | FLOW_AUTO | DMA2D ; // 32bit, 2DDMA, 各ライン割り込み、オートバッファ
    00190         *pDMA3_START_ADDR = (void *) rxBuffer;                  // 受信DMAバッファへのポインタ
    00191         *pDMA3_X_COUNT = CH_PER_SAMPLE * SAMPLE_PER_INTR;       // 2次元DMAの桁数
    00192         *pDMA3_X_MODIFY = sizeof(int);                          // 転送ごとのインクリメント量
    00193         *pDMA3_Y_COUNT = INTR_PER_BUFFER;                       // 2次元DMAの行数
    00194         *pDMA3_Y_MODIFY = sizeof(int);                          // 1行転送後のインクリメント量
    00195
    00196                 // DMA4の設定
    00197         *pDMA4_CONFIG = WDSIZE_32 | FLOW_AUTO | DMA2D;          // 32bit, 2DDMA, オートバッファ
    00198         *pDMA4_START_ADDR = (void *)txBuffer;                   // 受信DMAバッファへのポインタ
    00199         *pDMA4_X_COUNT = CH_PER_SAMPLE * SAMPLE_PER_INTR;       // 2次元DMAの桁数
    00200         *pDMA4_X_MODIFY = sizeof(int);                          // 転送ごとのインクリメント量
    00201         *pDMA4_Y_COUNT = INTR_PER_BUFFER;                       // 2次元DMAの行数
    00202         *pDMA4_Y_MODIFY = sizeof(int);                          // 1行転送後のインクリメント量
    00203
    00204     }
    00205
    00206     /** 割り込みのイネーブル
    00207        *
    00208        * SPORT0 受信割込みを有効化する。SPORT0 受信割り込みはデフォルトでは
    00209        * DMA3に割り当てられているので、DMA3割込みを有効にする。
    00210        */
    00211     void initInterrupt(void)
    00212     {
    00213
    00214                 // SPORT0 RX 割込みを有効に。デフォルトはDMA3
    00215         *pSIC_IMASK |= IRQ_DMA3;
    00216     }
    00217
    00218
    00219
    00220     void init()
    00221     {
    00222         initGPIO();
    00223         resetCODEC();
    00224         initSPORT();
    00225         initDMA();
    00226         initInterrupt();
    00227
    00228         initProcessData(SAMPLE_PER_INTR);
    00229     }
    00230
    00231
    00232     void start(void)
    00233     {
    00234                 // DMA開始
    00235         *pDMA4_CONFIG   |= DMAEN;   // 送信
    00236         *pDMA3_CONFIG   |= DMAEN;   // 受信
    00237
    00238                 // SPORT開始
    00239         *pSPORT0_TCR1   |= TSPEN;
    00240         *pSPORT0_RCR1   |= RSPEN;
    00241     }
    00242
    00243
    00244     /** 左チャンネル入力バッファ
    00245      *
    00246      * afw::processDataに引数として渡すための一時バッファ。 afw::rxBufferのデータは
    00247      * L,R,L,Rになっているので、左チャンネルだけ取り出してこのバッファに格納する。
    00248      */
    00249         short lchIn[SAMPLE_PER_INTR];
    00250     /** 左チャンネル出力バッファ
    00251      *
    00252      * afw::processDataに引数として渡すための一時バッファ。 afw::txBufferのデータは
    00253      * L,R,L,Rになっているので、 afw::processDataが返してきた値の左チャンネルデータを
    00254      * このバッファから読み出して afw::txBufferに格納する。
    00255      */
    00256         short lchOut[SAMPLE_PER_INTR];
    00257     /** 右チャンネル入力バッファ
    00258      *
    00259      * afw::processDataに引数として渡すための一時バッファ。 afw::rxBufferのデータは
    00260      * L,R,L,Rになっているので、右チャンネルだけ取り出してこのバッファに格納する。
    00261      */
    00262         short rchIn[SAMPLE_PER_INTR];
    00263     /** 右チャンネル出力バッファ
    00264      *
    00265      * afw::processDataに引数として渡すための一時バッファ。 afw::txBufferのデータは
    00266      * L,R,L,Rになっているので、 afw::processDataが返してきた値の右チャンネルデータを
    00267      * このバッファから読み出して afw::txBufferに格納する。
    00268      */
    00269         short rchOut[SAMPLE_PER_INTR];
    00270
    00271     bool ISR( void )
    00272     {
    00273         if ( *pSIC_ISR & IRQ_DMA3 ){        // SPORT0_RX割込みか?
    00274             static unsigned int bufferIdx = 0;       // トリプル・バッファ操作用インデックス
    00275
    00276             *pDMA3_IRQ_STATUS = 0x0001;         // 割込みクリア
    00277
    00278                     // トリプルバッファのどのバッファを使うか決める
    00279             if ( *pDMA3_CURR_Y_COUNT == 2 )     // 2次元DMAの最初の行の転送が終了した場合
    00280                 bufferIdx = 0;
    00281             else if ( bufferIdx < 2 )           // それ以外の場合
    00282                 bufferIdx ++;
    00283             else
    00284                 bufferIdx = 0;                  // 値が異常な場合の処理
    00285
    00286                     // DMAが格納した受信データを入力バッファにコピーする
    00287                     // 受信データバッファは24bit データを左詰めで32bit 変数に格納しているので
    00288                     // 16bit右シフトして入力バッファにコピーする
    00289             for( int i =0; i< SAMPLE_PER_INTR; i++ ){
    00290                 lchIn[i] = rxBuffer[bufferIdx][i][LEFT_CH]  >>16;
    00291                 rchIn[i] = rxBuffer[bufferIdx][i][RIGHT_CH] >>16;
    00292             }
    00293
    00294                     // ユーザー・コールバック関数の呼び出し
    00295             processData(
    00296                             (shortfract *)lchIn,       // short型とshortfract型は
    00297                             (shortfract *)rchIn,      // 同じ大きさなので、
    00298                             (shortfract *)lchOut,      // キャストによって強制変換していい
    00299                             (shortfract *)rchOut,
    00300                             SAMPLE_PER_INTR
    00301                         );
    00302
    00303                     // 出力バッファのデータを送信データバッファにコピーする
    00304                     // 送信データバッファは24bit データを左詰めで32bit 変数に格納しているので
    00305                     // 出力バッファから16bit左シフトして送信バッファにコピーする
    00306             for( int i =0; i< SAMPLE_PER_INTR; i++ ){
    00307                 txBuffer[bufferIdx][i][LEFT_CH] = lchOut[i] <<16;
    00308                 txBuffer[bufferIdx][i][RIGHT_CH]= rchOut[i] <<16;
    00309             }
    00310             return (true);         // 割込み処理を行った
    00311         }
    00312         else
    00313             return(false);          // 割込み処理を行わなかった
    00314
    00315     }
    00316
    00317
    00318 };      // namespace afw
    00319
    00320
    00321