ADSP-BF537 EZ-KIT Lite上で動作するオーディオフレームワーク関連の関数および変数を含む名前空間。 プログラマは以下の関数を呼んでオーディオ処理を開始する。
関数 | |
void | initGPIO (void) |
GPIOの初期化 | |
void | resetCODEC (void) |
オーディオ・コーデックのリセット | |
void | initSPORT (void) |
SPORT0の初期化 | |
void | initDMA (void) |
SPORT DMAの初期化 | |
void | initInterrupt (void) |
割り込みのイネーブル | |
void | init (void) |
afwの初期化 | |
void | start (void) |
SPORTとDMAのイネーブル | |
bool | ISR (void) |
SPORT0受信DMA割り込みサービス・ルーチン | |
void | initProcessData (int count) |
コールバック関数の処理化 | |
void | processData (const shortfract leftIn[], const shortfract rightIn[], shortfract leftOut[], shortfract rightOut[], int count) |
オーディオ・コールバック関数 | |
変数 | |
const int | LEFT_CH = 0 |
左チャンネル指定定数 | |
const int | RIGHT_CH = 1 |
右チャンネル指定定数 | |
const int | INTR_PER_BUFFER = 3 |
バッファ数宣言定数 | |
const int | CH_PER_SAMPLE = 2 |
サンプルあたりチャンネル数の宣言 | |
const int | SAMPLE_PER_INTR = 8 |
割り込みあたりのサンプル数 | |
const int | CODEC_RESET_PULS_WIDTH = 0x10000 |
オーディオ・コーデックのリセット時間 | |
const int | SPORT0_SLEN_32 = 31 |
SPORT0のワード長 | |
volatile int | txBuffer [INTR_PER_BUFFER][SAMPLE_PER_INTR][CH_PER_SAMPLE] |
SPORT0 DMA 送信バッファ | |
volatile int | rxBuffer [INTR_PER_BUFFER][SAMPLE_PER_INTR][CH_PER_SAMPLE] |
SPORT0 DMA 受信バッファ | |
short | lchIn [SAMPLE_PER_INTR] |
左チャンネル入力バッファ | |
short | lchOut [SAMPLE_PER_INTR] |
左チャンネル出力バッファ | |
short | rchIn [SAMPLE_PER_INTR] |
右チャンネル入力バッファ | |
short | rchOut [SAMPLE_PER_INTR] |
右チャンネル出力バッファ |
void afw::init | ( | void | ) |
afwの初期化
オーディオ・フレームワークの初期化。初期化関数はこれひとつよべば、残りの関数を まとめて呼んでくれる。ただし、 afw::start は呼ばないので、プログラマが明示的に 呼ばなければならない。また、afwISR()を割込みハンドラとして登録するのも プログラマの責任で行う
参照先 initDMA()・initGPIO()・initInterrupt()・initProcessData()・initSPORT()・resetCODEC()・SAMPLE_PER_INTR.
参照元 main().
00221 { 00222 initGPIO(); 00223 resetCODEC(); 00224 initSPORT(); 00225 initDMA(); 00226 initInterrupt(); 00227 00228 initProcessData(SAMPLE_PER_INTR); 00229 }
void afw::initDMA | ( | void | ) |
SPORT DMAの初期化
SPORT0に接続されているDMAを設定する。DMA3が受信、DMA4が送信である。 オーディオ信号は16ビット以上の長さがあるのでワードサイズは32bit, 連続送受信のためにオートバッファ、モードを使う。また、トリプル・バッファを 実装するために、DMA転送は2次元で行い、3ライン分のバッファを確保して各ラインの 転送を終えるたびに割り込みを発生させる。 afw::init()が自動的に呼び出すので、プログラマがこの関数を明示的に呼ぶ必要はない。
参照先 CH_PER_SAMPLE・INTR_PER_BUFFER・rxBuffer・SAMPLE_PER_INTR・txBuffer.
参照元 init().
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 }
void afw::initGPIO | ( | void | ) |
GPIOの初期化
PORT Fに割り当てられているGPIO(フラグピン)の初期化を行う。 PORT Fのピン割り当ては以下のとおり(カッコ内はマスク)
afw::init()が自動的に呼び出すので、プログラマがこの関数を明示的に呼ぶ必要はない。
参照元 init().
00115 { 00116 *pPORTF_FER &= ~PF12; // ポート Fのプログラマブル・フラグを利用できるようにする。 00117 *pPORTFIO_DIR |= PF12; // ポートFの方向設定。LEDとコーデックのRESET制御を出力に 00118 }
void afw::initInterrupt | ( | void | ) |
void afw::initProcessData | ( | int | count | ) |
コールバック関数の処理化
count | afw::processDataが呼ばれる際、各バッファに格納されているオーディオデータの数 |
processdata.cpp の 17 行で定義されています。
参照元 init().
void afw::initSPORT | ( | void | ) |
SPORT0の初期化
オーディオコーデックに接続されているSPORT0を初期化する。シリアル回線の フォーマットはI2Sで、クロックおよびLR信号は外部生成。この関数を読んだ段階 では、ポートはディセーブルのままにしておく。
設定は送受信とも以下のとおり
詳細はADSP-BF537 Hardware Referenceの "Stereo Serial Operation" を参照のこと。 afw::init()が自動的に呼び出すので、プログラマがこの関数を明示的に呼ぶ必要はない。
注意:EZ-KIT Lite BF537 Rev 1.0のユーザーはSPORTのクロックおよびフレーム同期 信号を自分で生成する設定に変更しなければならない。
参照先 SPORT0_SLEN_32.
参照元 init().
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 }
bool afw::ISR | ( | void | ) |
SPORT0受信DMA割り込みサービス・ルーチン
DMA3_CURR_Y_COUNTレジスタは、転送の最初に当たってDMA3_CURR_Y_COUNTレジスタの値に設定され、 ラインの転送が終わるごとにデクリメントされる。しかし、最後のラインの 転送後は、デクリメントされずに1のままに留まる。その結果、各ラインの転送終了 では、割込み発生ごとに以下のようにDMA3_CURR_Y_COUNTレジスタの値が変化する
このことから、ソフトウェアとの同期に使ってよいのはDMAx_CURR_Y_COUNTレジスタが2の場合 のみであり、あとは決めうちでバッファの添え字をインクリメントしなければならない事がわかる。 プログラム中では、この添え字としてbufferIdxをあてている。
トリプルバッファの管理が終わったら、受信DMAバッファからデータを取り出し、並べ なおしてから afw::processData を呼ぶ。
参照先 lchIn・lchOut・LEFT_CH・processData()・rchIn・rchOut・RIGHT_CH・rxBuffer・SAMPLE_PER_INTR・txBuffer.
参照元 cec::ivg9().
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 }
void afw::processData | ( | const shortfract | leftIn[], | |
const shortfract | rightIn[], | |||
shortfract | leftOut[], | |||
shortfract | rightOut[], | |||
int | count | |||
) |
オーディオ・コールバック関数
leftIn | 左チャンネルの入力データバッファ | |
rightIn | 右チャンネルの入力データバッファ | |
leftOut | 左チャンネルの出力データバッファ | |
rightOut | 右チャンネルの出力データバッファ | |
count | 各バッファに格納されているオーディオデータの数 |
配列はshortfract型である。この16bit固定小数点型はshortと同じ大きさを 持つが、四則は固定小数点領域で定義されている。
for文は常に必要なので、改造する場合はfor文の内側だけを書き換える。引数 である配列の各要素は、オーディオのサンプルデータが順番に格納されたもの である。したがって、これらを順番に処理することで、オーディオ処理を実装 できる。
割り込みソースのクリアなどは、この関数の呼び出し側で行うので、関数内で 処理する必要はない。
processdata.cpp の 48 行で定義されています。
参照先 ad7998::getValue()・ad7998::Vin1.
参照元 ISR().
00055 { 00056 shortfract gain; 00057 00058 gain = ad7998::getValue(ad7998::Vin1); // ボリュームの値を読み取る 00059 00060 for ( int i=0; i<count; i++ ){ // 引数配列のすべてのデータを処理する。 00061 leftOut[i] = leftIn[i] * gain; // ボリュームの値を信号にかける 00062 rightOut[i]= rightIn[i] * gain; 00063 } 00064 00065 } // processData
void afw::resetCODEC | ( | void | ) |
オーディオ・コーデックのリセット
PORT Fに割り当てられているコーデック・リセット信号(PF12)をトグルする。 afw::init()が自動的に呼び出すので、プログラマがこの関数を明示的に呼ぶ必要はない。
参照元 init().
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 }
void afw::start | ( | void | ) |
SPORTとDMAのイネーブル
設定が終わったSPORTとDMAの両方をイネーブルし、オーディオ処理を開始する。 必ず afw::init()の後に呼ぶ。
参照元 main().
00233 { 00234 // DMA開始 00235 *pDMA4_CONFIG |= DMAEN; // 送信 00236 *pDMA3_CONFIG |= DMAEN; // 受信 00237 00238 // SPORT開始 00239 *pSPORT0_TCR1 |= TSPEN; 00240 *pSPORT0_RCR1 |= RSPEN; 00241 }
const int afw::CH_PER_SAMPLE = 2 |
const int afw::CODEC_RESET_PULS_WIDTH = 0x10000 |
オーディオ・コーデックのリセット時間
EZ-KIT Lite BF537では、オーディオ・コーデックのリセット信号がADSP-BF537のPF12に 接続されている。コーデックの使用に先立って、この信号をアサートしなければならない。
このマクロは、リセット信号をアサートする時間を与える。時間はループの繰り返し 回数なので、あまり精度は高くない。注意深い値が必要である。
参照元 resetCODEC().
const int afw::INTR_PER_BUFFER = 3 |
バッファ数宣言定数
DMA用のバッファ領域を afw::txBufferおよび afw::rxBufferとして 確保する際に、割り込みいくつ分のバッファを用意するかを宣言する。 具体的にいえば、トリプルバッファなので3を宣言する。過去3回の割り込み分のデータをバッファに 格納できるということである。
参照元 initDMA().
short afw::lchIn[SAMPLE_PER_INTR] |
左チャンネル入力バッファ
afw::processDataに引数として渡すための一時バッファ。 afw::rxBufferのデータは L,R,L,Rになっているので、左チャンネルだけ取り出してこのバッファに格納する。
参照元 ISR().
short afw::lchOut[SAMPLE_PER_INTR] |
左チャンネル出力バッファ
afw::processDataに引数として渡すための一時バッファ。 afw::txBufferのデータは L,R,L,Rになっているので、 afw::processDataが返してきた値の左チャンネルデータを このバッファから読み出して afw::txBufferに格納する。
参照元 ISR().
const int afw::LEFT_CH = 0 |
short afw::rchIn[SAMPLE_PER_INTR] |
右チャンネル入力バッファ
afw::processDataに引数として渡すための一時バッファ。 afw::rxBufferのデータは L,R,L,Rになっているので、右チャンネルだけ取り出してこのバッファに格納する。
参照元 ISR().
short afw::rchOut[SAMPLE_PER_INTR] |
右チャンネル出力バッファ
afw::processDataに引数として渡すための一時バッファ。 afw::txBufferのデータは L,R,L,Rになっているので、 afw::processDataが返してきた値の右チャンネルデータを このバッファから読み出して afw::txBufferに格納する。
参照元 ISR().
const int afw::RIGHT_CH = 1 |
volatile int afw::rxBuffer[INTR_PER_BUFFER][SAMPLE_PER_INTR][CH_PER_SAMPLE] |
SPORT0 DMA 受信バッファ
受信DMAがアクセスし、SPORT RXチャンネルからデータを受け取るのバッファ
最下位の次元はL, Rチャンネル用に2つの要素を格納する。下から2番目の次元は、 割込み1回ごとに送信されるサンプル数を指定する。1回の割り込みの間にDMA転送 されるデータの量は、 afw::SAMPLE_PER_INTR * afw::CH_PER_SAMPLE で決まる。
afw::INTR_PER_BUFFER だけ用意される次元は、このバッファが割込み何回分のデータを 格納するかを表す。
const int afw::SAMPLE_PER_INTR = 8 |
const int afw::SPORT0_SLEN_32 = 31 |
SPORT0のワード長
SPORT0設定時に使うワード長である。EZ-KIT BF537に搭載されているコーデックは 32bit長のI2S回線を使うので、ワード長が32になるよう指定する。 32bit長にする場合は、31と設定することに注意。
参照元 initSPORT().
volatile int afw::txBuffer[INTR_PER_BUFFER][SAMPLE_PER_INTR][CH_PER_SAMPLE] |
SPORT0 DMA 送信バッファ
送信DMAがアクセスし、SPORT TXチャンネルにデータを送り込むためのバッファ
最下位の次元はL, Rチャンネル用に2つの要素を格納する。下から2番目の次元は、 割込み1回ごとに送信されるサンプル数を指定する。1回の割り込みの間にDMA転送 されるデータの量は、 afw::SAMPLE_PER_INTR * afw::CH_PER_SAMPLE で決まる。
最上位の次元は、このバッファが割込み何回分のデータを 格納するかを表す。