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