afw.cpp

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

AudioFrameWorkに対してWed Jan 17 09:13:07 2007に生成されました。  doxygen 1.4.7