afw.cpp

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

IIR filter sample by wrapper classに対してMon Dec 18 17:29:47 2006に生成されました。  doxygen 1.5.1-p1