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