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