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 

AudioFrameWorkに対してMon Apr 9 15:44:05 2007に生成されました。  doxygen 1.5.1-p1