OSDN Git Service

AD7999によるボリューム読み取りのAPIを実装した
[uzume/uzume_bfin.git] / uzume_prototype / uzume.c
1
2 /**
3  * @file uzume.c
4  * @brief CODECの初期化と制御
5  */
6 #include "t_services.h"
7 #include "s_services.h"
8 #include "cdefBF592-A.h"
9 #include "uzume.h"
10 #include "kernel_id.h"
11 #include <i2c_subsystem.h>
12 /**
13  * \brief コーデック初期化データ列の長さ
14  * \details
15  * TLV320AIC23に与える初期化データの長さである。長さはレジスタアドレスとデータの組が
16  * 何組であるかを示す。
17  */
18 #define     CODECINITDATALEN        11      /* TLV320AIC23B初期化データ長 */
19
20 #define     I2C_PORT        0
21 #define     CODEC_ADDRESS   0x1A
22
23 /**
24  * \brief CODEC初期化データ列
25  * \details
26  * TLV320AIC23Bを初期化するためのデータ列である。
27  */
28 static unsigned char tlv320aic23init[CODECINITDATALEN][2] =
29 {
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. */
42
43 };
44
45
46 /**
47  * @brief DMAデスクリプタ型
48  * 
49  * ADSP-BF533のDMA用デスクリプタ型。 avairablebufメンバーはDMAが使わないフィールドで、
50  * これは@ref task_CODEC()が利用できるバッファを特定するためのIDとして使う。
51  */
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]
58         /**
59          * @brief バッファ特定用フィールド
60          * 
61          * 初期化時に定数を設定しておく。@ref task_CODEC()はDMAが使用中のデスクリプタの
62          * このフィールドを読み、有効なバッファにアクセスするためのインデックスとして使う。
63          */
64         short avairableBuf;     
65 };
66
67
68
69 /**
70  * @brief 送信CODECバッファ
71  * 
72  * DMAがSPORT経由でCODECにデータを送り出すためのバッファ。配列要素が3つあるのはトリプルバッファであるため。
73  */
74 static struct CODEC_BUFFER TxBuffer[3];
75 /**
76  * @brief 受信CODECバッファ
77  * 
78  * 
79  * DMAがSPORT経由でCODECにデータを受信するためのバッファ。配列要素が3つあるのはトリプルバッファであるため。
80  */
81 static struct CODEC_BUFFER RxBuffer[3];
82
83 /**
84  * @brief 送信DMAデスクリプタ変数
85  * 
86  * 
87  * トリプルバッファなのでデスクリプタを3個使用する。
88  */
89 static struct DMA_DESCRIPTOR txDesc[3];
90 /**
91  * @brief 受信DMAデスクリプタ変数
92  * 
93  * 
94  * トリプルバッファなのでデスクリプタを3個使用する。
95  */
96 static struct DMA_DESCRIPTOR rxDesc[3];
97
98 /**
99  * @brief 左入力データ引渡し変数
100  * 
101  * 
102  * @ref codec_callback()関数に入力オーディオデータを渡すための引数。
103  * 左右チャンネルそれぞれに配列を与える。配列内部にはサンプル順にデータが並ぶ。
104  * ステレオは2系統あるので左チャンネルも2系統分のデータがある。
105  */
106 static int leftIn[UZUME_BLOCKSIZE];
107 /**
108  * @brief 右入力データ引渡し変数
109  * 
110  * 
111  * @ref codec_callback()関数に入力オーディオデータを渡すための引数。
112  * 左右チャンネルそれぞれに配列を与える。配列内部にはサンプル順にデータが並ぶ。
113  * ステレオは2系統あるので右チャンネルも2系統分のデータがある。
114  */
115 static int rightIn[UZUME_BLOCKSIZE];
116 /**
117  * @brief 左出力データ引渡し変数
118  * 
119  * 
120  * @ref codec_callback()関数から出力オーディオデータをうけとるための引数。
121  * 左右チャンネルそれぞれに配列を与える。配列内部にはサンプル順にデータが並ぶ。
122  */
123 static int leftOut[UZUME_BLOCKSIZE];
124 /**
125  * @brief 右出力データ引渡し変数
126  * 
127  * 
128  * @ref codec_callback()関数から出力オーディオデータをうけとるための引数。
129  * 左右チャンネルそれぞれに配列を与える。配列内部にはサンプル順にデータが並ぶ。
130  */
131 static int rightOut[UZUME_BLOCKSIZE];
132
133 /**
134  * @brief コーデックの初期化
135  * @details
136  * TLV32AIC23Bに初期化数値列をI2C経由で送り込む。タスクコンテキストで呼び出さなければならない。
137  * 初期化後、TLV32AIC23Bはクロック信号を生成して動作を開始する。
138  */
139 void init_codec()
140 {
141         int i;
142
143
144                 /* TLV320AIC23Bに初期化データを送信する */
145         for ( i=0; i< CODECINITDATALEN; i++){
146                 i2c_master_write( I2C_PORT, CODEC_ADDRESS, tlv320aic23init[i], 2 );
147         }
148 }
149
150
151
152 /**
153  * @brief CODEC用SPORTを設定する
154  * 
155  * 
156  * SPORT0をCODEC用に設定する。EZ-KIT BF533の結線はTDM仕様になっているので
157  * この設定もI2SではなくTDMである。RCRx, TCRxの設定はBF533のマニュアルを参照されたい。
158  */
159 static void setup_sport0(void)
160 {
161     // ADSP-BF592 PORTG設定
162     // DR0PRI, RSCK0, RFS0, TD0PRI, TSCK0, TSF0をMUXで0 ( Primary func )にする
163     *pPORTG_MUX &= ~0x00ee;
164
165     // ADSP-BF592 PORTG設定
166     // DR0PRI, RSCK0, RFS0, TD0PRI, TSCK0, TSF0をFERでイネーブルにする
167     *pPORTG_FER = 0x00ee;
168
169         // I2S設定
170         // Sport0 受信設定 
171         // 外部クロック, 外部同期信号,
172         // 32-bit データ 
173         *pSPORT0_RCR1 = RFSR | RCKFE;
174         *pSPORT0_RCR2 = 31 | RSFSE;             // データ長 32
175         
176         // Sport0 送信設定
177         // 外部クロック, 外部同期信号
178         // 32ビットデータ 
179         *pSPORT0_TCR1 = TFSR | TCKFE;
180         *pSPORT0_TCR2 = 31 | TSFSE;             // データ長 32
181         
182         // MTCS/MRCSはI2Sには関係ない
183         *pSPORT0_MTCS0 = 0x00000000;
184         *pSPORT0_MRCS0 = 0x00000000;
185         
186         // マルチチャンネル設定
187         *pSPORT0_MCMC1 = 0x0000; // オフセット = 0, ウインドウサイズ = 8
188         *pSPORT0_MCMC2 = 0x0000; // マルチチャンネル・ディセーブル;
189 }
190
191 /**
192  * @brief CODEC用にSPORT0 DMAを設定する
193  * 
194  * 
195  * CODEC用のオーディオDMAを設定する。DMAはデスクリプタのリンクからなる。トリプルバッファを
196  * 使うため、デスクリプタは送受それぞれに3つ用意する。
197  * 
198  * デスクリプタ変数のavairableBufフィールドはDMAハードウェア用ではなく、管理ソフトウェア
199  * 用である。DMAエンジンが次にフェッチするDMAデスクリプタのアドレスは、DMA_NEXT_PTRレジスタ
200  * からしることができる。そこで、DMA_NEXT_PTRレジスタが示すデスクリプタのavairableBuf
201  * メンバーを読めば、CPUが「現在」データを読み書きしてもよいバッファのインデックスがわかるよう
202  * になっている。このインデックスはトリプルバッファのうちどれを使うかを指す。つまり0から2の値をとる。
203  * 
204  */
205 static void setup_sport0_dma(void)
206 {
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 * UZUME_BLOCKSIZE;
211         rxDesc[0].x_modify = 4;
212         rxDesc[0].avairableBuf = 1;     // DMA_NEXT_PTRがデスクリプタ[0]なら、バッファ1を使える。
213         
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 * UZUME_BLOCKSIZE;
218         rxDesc[1].x_modify = 4;
219         rxDesc[1].avairableBuf = 2;     // DMA_NEXT_PTRがデスクリプタ[1]なら、バッファ2を使える。
220         
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 * UZUME_BLOCKSIZE;
225         rxDesc[2].x_modify = 4;
226         rxDesc[2].avairableBuf = 0;     // DMA_NEXT_PTRがデスクリプタ[2]なら、バッファ0を使える。
227         
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 * UZUME_BLOCKSIZE;
233         txDesc[0].x_modify = 4;
234         txDesc[0].avairableBuf = 1;     // DMA_NEXT_PTRがデスクリプタ[0]なら、バッファ1を使える。
235         
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 * UZUME_BLOCKSIZE;
240         txDesc[1].x_modify = 4;
241         txDesc[1].avairableBuf = 2;     // DMA_NEXT_PTRがデスクリプタ[1]なら、バッファ2を使える。
242
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 * UZUME_BLOCKSIZE;
247         txDesc[2].x_modify = 4;
248         txDesc[2].avairableBuf = 0;     // DMA_NEXT_PTRがデスクリプタ[2]なら、バッファ1を使える。
249
250
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;
255 }
256
257 /**
258  * @brief SPORTをイネーブルにしてオーディオ処理をはじめる
259  * 
260  * 
261  * DMA送受信を開始してオーディオ送受信を開始する。この関数はCPUアンロック状態で呼ばなければならない。
262  */
263 static void start_audio(void)
264 {
265         // DMA 開始 
266         *pDMA2_CONFIG |= DMAEN;
267         *pDMA1_CONFIG |= DMAEN;
268         asm("ssync;");
269
270         // SPORT0 開始 なるべくアトミックに近い状態になるよう、CPUロック状態で開始する。
271         loc_cpu();
272         *pSPORT0_TCR1 |= TSPEN;
273         *pSPORT0_RCR1 |= RSPEN;
274         unl_cpu();
275 }
276
277 /**
278  * @brief オーディオ処理の開始とコールバック呼び出し
279  * @param extinf ITRONのタスク引数。このタスクはタスク引数を利用しない。
280  * @ingroup TOPPERS
281  * 
282  * オーディオ・ペリフェラルの初期化と処理の実行を行う。
283  * 
284  * 最初にSPIとSPORT0の割り込み禁止を解除する。SPORT0はオーディオ受信DMA割り込み
285  * であるため問題はないが、SPIに関しては他のペリフェラルと共用するならば何らかの検討が必要である。
286  * 
287  * 
288  * SPORT DMAは送受信いずれもDMAチェーンを用いている。そのための設計をする際、
289  * デスクリプタ変数に有効なバッファのインデックスを書き込んでおくことで後の処理を簡略化
290  * できるようにしている。
291  * 
292  * 割り込み待ちのループ内部ではsport0_semを使ってSPORT RX割り込みハンドらである
293  * @ref inh_codec_sport()からの割り込み通知を待つ。通知を受けたらCODECの構造に依存した
294  * バッファを解いてフラットな入力配列をL/R両方に用意する。これは @ref codec_callback()に
295  * 渡すためのものである。
296  * 
297  * @ref codec_callback()から戻ったら、今度は先ほどと逆にフラットな出力配列からCODECの
298  * 構造に応じたバッファを組み立てる。
299  * 
300  */
301 void task_audiocodec(VP_INT extinf)
302 {
303         
304         ena_int( INTNO_SPORT0_RX );             // SPORT0 DMA割り込みマスクをはずす 
305         
306         init_codec();
307
308         init_audio( UZUME_BLOCKSIZE );  // コールバックの初期化
309
310         setup_sport0();         //                      SPORT0 設定 
311         setup_sport0_dma();     //                      SPORT DMA 設定 
312         start_audio();          //                       SPORT0 開始
313         
314
315                 // 割り込み待ちループ
316         while( 1 ){
317                 int sample;             // どのサンプルを処理するかを示すループ・インデックス
318                 int bufTx, bufRx;       // 利用する送受信バッファのインデックス
319
320                 
321                                 // 受信DMA終了割り込みと同期
322                 wai_sem( SPORT0_SEM);
323                         
324                                 // プロセッサが使ってよいバッファを割り出す 
325                 bufTx = (( struct DMA_DESCRIPTOR * ) *pDMA2_NEXT_DESC_PTR )->avairableBuf;
326                 bufRx = (( struct DMA_DESCRIPTOR * ) *pDMA1_NEXT_DESC_PTR )->avairableBuf;
327                 
328                                 // CODECの受信データを引数バッファにコピー
329                 for ( sample = 0; sample < UZUME_BLOCKSIZE; sample++ ){
330                         leftIn[sample]  = RxBuffer[bufRx].data[sample][ADC_L0] >> UZUME_INT_BITS;
331                         rightIn[sample] = RxBuffer[bufRx].data[sample][ADC_R0] >> UZUME_INT_BITS;
332                 }
333                 
334                                 // 信号処理
335                 process_audio( 
336                                 leftIn,
337                                 rightIn,
338                                 leftOut,
339                                 rightOut
340                                 );
341                 
342                                 // 引数データをCODEC用送信バッファにコピー
343                 for ( sample = 0; sample < UZUME_BLOCKSIZE; sample++ ){
344                         TxBuffer[bufRx].data[sample][DAC_L0] = leftOut[sample]  << UZUME_INT_BITS;
345                         TxBuffer[bufRx].data[sample][DAC_R0] = rightOut[sample] << UZUME_INT_BITS;
346                 }                               
347
348         }
349
350 }
351
352
353 /**
354  * @brief SPORT RX割り込み
355  * @ingroup TOPPERS
356  * 
357  * SPORT0 RX DMA割り込みを検出してタスクに通知する。このハンドラでは
358  * 通知後割り込みをクリアするだけで割り込みの原因となった事象(DMA完了)の
359  * 処理は行わない。
360  * 
361  * このハンドラの登録はコンフィグレーターが行う。したがってプログラム中で
362  * 明示的に登録する必要はない。
363  */
364 void inh_codec_sport(void)
365 {
366         *pDMA1_IRQ_STATUS = DMA_DONE;           // SPORT0 RX DMA割り込みをクリア
367         asm("ssync;");                                          // クリアが終了するのを待つ
368         isig_sem( SPORT0_SEM );                         // タスクに通知
369 }
370
371