6 #include "t_services.h"
7 #include "s_services.h"
8 #include "cdefBF592-A.h"
10 #include "kernel_id.h"
11 #include <i2c_subsystem.h>
13 * \brief コーデック初期化データ列の長さ
15 * TLV320AIC23に与える初期化データの長さである。長さはレジスタアドレスとデータの組が
18 #define CODECINITDATALEN 11 /* TLV320AIC23B初期化データ長 */
21 #define CODEC_ADDRESS 0x1A
26 * TLV320AIC23Bを初期化するためのデータ列である。
28 static unsigned char tlv320aic23init[CODECINITDATALEN][2] =
30 { 30 | 0x00, 0x00 }, /* RESET. */
31 { 0 | 0x01, 0x17 }, /* L_in vol : LR simul-update, unmute, 0dB */
32 { 2 | 0x01, 0x17 }, /* R_in vol : LR simul-update, unmute, 0dB */
33 { 4 | 0x01, 0xF9 }, /* L_HP vol : LR simul-update, zero-cross, 0dB */
34 { 6 | 0x01, 0xF9 }, /* R_HP vol : LR simul-update, zero-cross, 0dB */
35 { 8 | 0x00, 0x12 }, /* Analog Audio Path : No Sidetone, No bypass, DAC for Out, Line out for ADC, Mic Mute */
36 { 10 | 0x00, 0x00 }, /* Digital Path: DAC unmute, De-emphasis 48k, ADC HPF enable */
37 { 12 | 0x00, 0x02 }, /* Power Down : Only Mic is down*/
38 { 14 | 0x00, 0x4E }, /* Digital Audio Format : Master, 32bit, I2S */
39 { 16 | 0x00, 0x01 }, /* Sanmpling Rate, 48kHz, USB mode*/
40 // { 16 | 0x00, 0x00 }, /* Sanmpling Rate, 48kHz, NORMAL mode*/
41 { 18 | 0x00, 0x01 } /* Activateion : Active. */
49 * ADSP-BF533のDMA用デスクリプタ型。 avairablebufメンバーはDMAが使わないフィールドで、
50 * これは@ref task_CODEC()が利用できるバッファを特定するためのIDとして使う。
52 struct DMA_DESCRIPTOR{
53 struct DMA_DESCRIPTOR * next; ///< 次のデスクリプタへのポインタ
54 void * start; ///< DMAバッファの開始アドレス
55 unsigned short config; ///< DMAコンフィグレーションレジスタへのロード値
56 unsigned short x_count; ///< DMAのX方向への転送数[個]
57 short x_modify; ///< DMAのX方向へのインクリメント値[BYTE]
61 * 初期化時に定数を設定しておく。@ref task_CODEC()はDMAが使用中のデスクリプタの
62 * このフィールドを読み、有効なバッファにアクセスするためのインデックスとして使う。
72 * DMAがSPORT経由でCODECにデータを送り出すためのバッファ。配列要素が3つあるのはトリプルバッファであるため。
74 static struct CODEC_BUFFER TxBuffer[3];
79 * DMAがSPORT経由でCODECにデータを受信するためのバッファ。配列要素が3つあるのはトリプルバッファであるため。
81 static struct CODEC_BUFFER RxBuffer[3];
84 * @brief 送信DMAデスクリプタ変数
87 * トリプルバッファなのでデスクリプタを3個使用する。
89 static struct DMA_DESCRIPTOR txDesc[3];
91 * @brief 受信DMAデスクリプタ変数
94 * トリプルバッファなのでデスクリプタを3個使用する。
96 static struct DMA_DESCRIPTOR rxDesc[3];
102 * @ref codec_callback()関数に入力オーディオデータを渡すための引数。
103 * 左右チャンネルそれぞれに配列を与える。配列内部にはサンプル順にデータが並ぶ。
104 * ステレオは2系統あるので左チャンネルも2系統分のデータがある。
106 static int leftIn[AUDIOBUFSIZE];
111 * @ref codec_callback()関数に入力オーディオデータを渡すための引数。
112 * 左右チャンネルそれぞれに配列を与える。配列内部にはサンプル順にデータが並ぶ。
113 * ステレオは2系統あるので右チャンネルも2系統分のデータがある。
115 static int rightIn[AUDIOBUFSIZE];
120 * @ref codec_callback()関数から出力オーディオデータをうけとるための引数。
121 * 左右チャンネルそれぞれに配列を与える。配列内部にはサンプル順にデータが並ぶ。
123 static int leftOut[AUDIOBUFSIZE];
128 * @ref codec_callback()関数から出力オーディオデータをうけとるための引数。
129 * 左右チャンネルそれぞれに配列を与える。配列内部にはサンプル順にデータが並ぶ。
131 static int rightOut[AUDIOBUFSIZE];
136 * TLV32AIC23Bに初期化数値列をI2C経由で送り込む。タスクコンテキストで呼び出さなければならない。
137 * 初期化後、TLV32AIC23Bはクロック信号を生成して動作を開始する。
144 /* TLV320AIC23Bに初期化データを送信する */
145 for ( i=0; i< CODECINITDATALEN; i++){
146 i2c_master_write( I2C_PORT, CODEC_ADDRESS, tlv320aic23init[i], 2 );
153 * @brief CODEC用SPORTを設定する
156 * SPORT0をCODEC用に設定する。EZ-KIT BF533の結線はTDM仕様になっているので
157 * この設定もI2SではなくTDMである。RCRx, TCRxの設定はBF533のマニュアルを参照されたい。
159 static void setup_sport0(void)
161 // ADSP-BF592 PORTG設定
162 // DR0PRI, RSCK0, RFS0, TD0PRI, TSCK0, TSF0をMUXで0 ( Primary func )にする
163 *pPORTG_MUX &= ~0x00ee;
165 // ADSP-BF592 PORTG設定
166 // DR0PRI, RSCK0, RFS0, TD0PRI, TSCK0, TSF0をFERでイネーブルにする
167 *pPORTG_FER = 0x00ee;
173 *pSPORT0_RCR1 = RFSR | RCKFE;
174 *pSPORT0_RCR2 = 31 | RSFSE; // データ長 32
179 *pSPORT0_TCR1 = TFSR | TCKFE;
180 *pSPORT0_TCR2 = 31 | TSFSE; // データ長 32
182 // MTCS/MRCSはI2Sには関係ない
183 *pSPORT0_MTCS0 = 0x00000000;
184 *pSPORT0_MRCS0 = 0x00000000;
187 *pSPORT0_MCMC1 = 0x0000; // オフセット = 0, ウインドウサイズ = 8
188 *pSPORT0_MCMC2 = 0x0000; // マルチチャンネル・ディセーブル;
192 * @brief CODEC用にSPORT0 DMAを設定する
195 * CODEC用のオーディオDMAを設定する。DMAはデスクリプタのリンクからなる。トリプルバッファを
196 * 使うため、デスクリプタは送受それぞれに3つ用意する。
198 * デスクリプタ変数のavairableBufフィールドはDMAハードウェア用ではなく、管理ソフトウェア
199 * 用である。DMAエンジンが次にフェッチするDMAデスクリプタのアドレスは、DMA_NEXT_PTRレジスタ
200 * からしることができる。そこで、DMA_NEXT_PTRレジスタが示すデスクリプタのavairableBuf
201 * メンバーを読めば、CPUが「現在」データを読み書きしてもよいバッファのインデックスがわかるよう
202 * になっている。このインデックスはトリプルバッファのうちどれを使うかを指す。つまり0から2の値をとる。
205 static void setup_sport0_dma(void)
207 rxDesc[0].next = &rxDesc[1];
208 rxDesc[0].start = RxBuffer[0].data;
209 rxDesc[0].config = 0x7700 | WNR | WDSIZE_32 | DI_EN | DMAEN; // Large List, 7 short word.
210 rxDesc[0].x_count = SLOT_PER_SAMPLE * AUDIOBUFSIZE;
211 rxDesc[0].x_modify = 4;
212 rxDesc[0].avairableBuf = 1; // DMA_NEXT_PTRがデスクリプタ[0]なら、バッファ1を使える。
214 rxDesc[1].next = &rxDesc[2];
215 rxDesc[1].start = RxBuffer[1].data;
216 rxDesc[1].config = 0x7700 | WNR | WDSIZE_32 | DI_EN | DMAEN; // Large List, 7 short word.
217 rxDesc[1].x_count = SLOT_PER_SAMPLE * AUDIOBUFSIZE;
218 rxDesc[1].x_modify = 4;
219 rxDesc[1].avairableBuf = 2; // DMA_NEXT_PTRがデスクリプタ[1]なら、バッファ2を使える。
221 rxDesc[2].next = &rxDesc[0];
222 rxDesc[2].start = RxBuffer[2].data;
223 rxDesc[2].config = 0x7700 | WNR | WDSIZE_32 | DI_EN | DMAEN; // Large List, 7 short word.
224 rxDesc[2].x_count = SLOT_PER_SAMPLE * AUDIOBUFSIZE;
225 rxDesc[2].x_modify = 4;
226 rxDesc[2].avairableBuf = 0; // DMA_NEXT_PTRがデスクリプタ[2]なら、バッファ0を使える。
228 // DMA2設定 (SPORT0 TX)
229 txDesc[0].next = &txDesc[1];
230 txDesc[0].start = TxBuffer[0].data;
231 txDesc[0].config = 0x7700 | WDSIZE_32 | DMAEN; // Large List, 7 short word.
232 txDesc[0].x_count = SLOT_PER_SAMPLE * AUDIOBUFSIZE;
233 txDesc[0].x_modify = 4;
234 txDesc[0].avairableBuf = 1; // DMA_NEXT_PTRがデスクリプタ[0]なら、バッファ1を使える。
236 txDesc[1].next = &txDesc[2];
237 txDesc[1].start = TxBuffer[1].data;
238 txDesc[1].config = 0x7700 | WDSIZE_32 | DMAEN; // Large List, 7 short word.
239 txDesc[1].x_count = SLOT_PER_SAMPLE * AUDIOBUFSIZE;
240 txDesc[1].x_modify = 4;
241 txDesc[1].avairableBuf = 2; // DMA_NEXT_PTRがデスクリプタ[1]なら、バッファ2を使える。
243 txDesc[2].next = &txDesc[0];
244 txDesc[2].start = TxBuffer[2].data;
245 txDesc[2].config = 0x7700 | WDSIZE_32 | DMAEN; // Large List, 7 short word.
246 txDesc[2].x_count = SLOT_PER_SAMPLE * AUDIOBUFSIZE;
247 txDesc[2].x_modify = 4;
248 txDesc[2].avairableBuf = 0; // DMA_NEXT_PTRがデスクリプタ[2]なら、バッファ1を使える。
251 *pDMA2_NEXT_DESC_PTR = &txDesc[0]; // 送信設定
252 *pDMA1_NEXT_DESC_PTR = &rxDesc[0]; // 受信DMA設定
253 *pDMA2_CONFIG = 0x7700 | WDSIZE_32; // 32bit転送、デスクリプタ・リンク、デスクリプタ・サイズ=7word
254 *pDMA1_CONFIG = 0x7700 | WNR | WDSIZE_32;
258 * @brief SPORTをイネーブルにしてオーディオ処理をはじめる
261 * DMA送受信を開始してオーディオ送受信を開始する。この関数はCPUアンロック状態で呼ばなければならない。
263 static void start_audio(void)
266 *pDMA2_CONFIG |= DMAEN;
267 *pDMA1_CONFIG |= DMAEN;
270 // SPORT0 開始 なるべくアトミックに近い状態になるよう、CPUロック状態で開始する。
272 *pSPORT0_TCR1 |= TSPEN;
273 *pSPORT0_RCR1 |= RSPEN;
278 * @brief オーディオ処理の開始とコールバック呼び出し
279 * @param extinf ITRONのタスク引数。このタスクはタスク引数を利用しない。
282 * オーディオ・ペリフェラルの初期化と処理の実行を行う。
284 * 最初にSPIとSPORT0の割り込み禁止を解除する。SPORT0はオーディオ受信DMA割り込み
285 * であるため問題はないが、SPIに関しては他のペリフェラルと共用するならば何らかの検討が必要である。
288 * SPORT DMAは送受信いずれもDMAチェーンを用いている。そのための設計をする際、
289 * デスクリプタ変数に有効なバッファのインデックスを書き込んでおくことで後の処理を簡略化
292 * 割り込み待ちのループ内部ではsport0_semを使ってSPORT RX割り込みハンドらである
293 * @ref inh_codec_sport()からの割り込み通知を待つ。通知を受けたらCODECの構造に依存した
294 * バッファを解いてフラットな入力配列をL/R両方に用意する。これは @ref codec_callback()に
297 * @ref codec_callback()から戻ったら、今度は先ほどと逆にフラットな出力配列からCODECの
301 void task_audiocodec(VP_INT extinf)
304 ena_int( INTNO_SPORT0_RX ); // SPORT0 DMA割り込みマスクをはずす
308 init_audio( AUDIOBUFSIZE ); // コールバックの初期化
310 setup_sport0(); // SPORT0 設定
311 setup_sport0_dma(); // SPORT DMA 設定
312 start_audio(); // SPORT0 開始
317 int sample; // どのサンプルを処理するかを示すループ・インデックス
318 int bufTx, bufRx; // 利用する送受信バッファのインデックス
322 wai_sem( SPORT0_SEM);
324 // プロセッサが使ってよいバッファを割り出す
325 bufTx = (( struct DMA_DESCRIPTOR * ) *pDMA2_NEXT_DESC_PTR )->avairableBuf;
326 bufRx = (( struct DMA_DESCRIPTOR * ) *pDMA1_NEXT_DESC_PTR )->avairableBuf;
328 // CODECの受信データを引数バッファにコピー
329 for ( sample = 0; sample < AUDIOBUFSIZE; sample++ ){
330 leftIn[sample] = RxBuffer[bufRx].data[sample][ADC_L0];
331 rightIn[sample] = RxBuffer[bufRx].data[sample][ADC_R0];
342 // 引数データをCODEC用送信バッファにコピー
343 for ( sample = 0; sample < AUDIOBUFSIZE; sample++ ){
344 TxBuffer[bufRx].data[sample][DAC_L0] = leftOut[sample];
345 TxBuffer[bufRx].data[sample][DAC_R0] = rightOut[sample];
354 * @brief SPORT RX割り込み
357 * SPORT0 RX DMA割り込みを検出してタスクに通知する。このハンドラでは
358 * 通知後割り込みをクリアするだけで割り込みの原因となった事象(DMA完了)の
361 * このハンドラの登録はコンフィグレーターが行う。したがってプログラム中で
364 void inh_codec_sport(void)
366 *pDMA1_IRQ_STATUS = DMA_DONE; // SPORT0 RX DMA割り込みをクリア
367 asm("ssync;"); // クリアが終了するのを待つ
368 isig_sem( SPORT0_SEM ); // タスクに通知