2 * \file i2s_subsystem.c
8 #include "i2s_subsystem.h"
9 #include "kernel_cfg.h"
18 LPC_SC->PCONP |= 1 << 27;
19 /* I2SのPCLKを 1/4 にセット (25MHz) */
20 LPC_SC->PCLKSEL0 &= ~(0x3 << 22);
22 /** P0.4 - P0.9を I2Sに */
23 LPC_PINCON->PINSEL0 &= ~(0xFFF << 8);
24 // LPC_PINCON->PINSEL0 |= 0x555 << 8;
25 LPC_PINCON->PINSEL0 |= 0x550 << 8; // RX ws/clk disconnect
29 * I2S, 32bit, 4-wire transmitter slave mode sharing the
30 * receiver bit clock and WS Typical receiver slave mode
31 * stereo, stop & reset.
33 * TXのビット/ワードクロックはRXから供給を受け、RXの
34 * ビット/ワードクロックは外部から供給を受ける。
35 * この場合、TXはデバイダ関係の設定が不要のはずである。
36 * また、UM10360 rev 2 Fig111によるとI2SRXBITRATEは
37 * div by 1になるよう設定しなければならない。
41 * Digital Audio Output & Input
45 * UM10360には詳細がしるされていないが、NXPによるCMSISの例題を
46 * 読む限り、設定前にDAO/DAIをreset, stop状態に置き、
47 * 処理開始時にresetから解除し、stopから解除する動作になっている。
48 * reset状態でレジスタを操作する事には不安を感じるが、例題しか
51 LPC_I2S->I2SDAO = 0x0; /* Disable */
52 LPC_I2S->I2SDAI = 0x0; /* Disable */
54 LPC_I2S->I2SDAO = 3 << 0 // 32bit data
55 | 0 << 2 // mono : 1 is mono, 0 is stereo
56 | 1 << 3 // stop : 1 is stop
57 | 1 << 4 // reset : 1 is reset;
58 | 1 << 5 // ws_sel : 1 is slave, 0 is master
59 | 31 << 6 // ws_halfpeiod : half period value -1;
60 | 0 << 15; // mute : 1 is mute, 0 is unmute
62 LPC_I2S->I2SDAI = 3 << 0 // 32bit data
63 | 0 << 2 // mono : 1 is mono, 0 is stereo
64 | 1 << 3 // stop : 1 is stop
65 | 1 << 4 // reset : 1 is reset;
66 | 1 << 5 // ws_sel : 1 is slave, 0 is master
67 | 31 << 6; // ws_halfpeiod : half period value -1;
69 /* DMA Configuration. RX DMA is Enabled */
70 LPC_I2S->I2SDMA1 = 1 << 0 // RX enable
71 | 2 << 8; // FIFO depth = 2
72 /* DMA Configuration. TX DMA is enabled */
73 LPC_I2S->I2SDMA2 = 1 << 1 // TX DMA Enable
74 | 2 << 16; // FIFO depth = 2;
81 * 外部ビットクロックから内部ビットクロックを生成する分周器。1で割る。
83 LPC_I2S->I2SRXBITRATE = 0; /* RX bit clock div by 1 */
84 LPC_I2S->I2STXBITRATE = 0; /* RX bit clock div by 1 */
87 LPC_I2S->I2STXMODE = 0; /* Transmit slave typical mode */
89 LPC_I2S->I2SRXMODE = 4; /* Receive slave typical mode */
90 // LPC_I2S->I2SRXMODE = 0; /* Receive slave 4-wire mode */
96 /* TX I2S をストップから開放 */
97 LPC_I2S->I2SDAO &= ~(1 << 3);
98 /* RX I2S をストップから開放 */
99 LPC_I2S->I2SDAI &= ~(1 << 3);
100 /* TX I2S をリセットから開放 */
101 LPC_I2S->I2SDAO &= ~(1 << 4);
102 /* RX I2S をリセットから開放 */
103 LPC_I2S->I2SDAI &= ~(1 << 4);
106 void i2s_dma_init(struct I2S_AUDIO_DATA *audio_data)
111 LPC_SC->PCONP |= 1 << 29;
112 /* DMA Controler Enable */
113 LPC_GPDMA->DMACConfig = 0x01; /* Little Endian, Enable */
116 audio_data->txI2SLLI[0].SrcAddr = audio_data->txBuffer[0]; /* 送信データのバッファ */
117 audio_data->txI2SLLI[0].DstAddr = (int *) &LPC_I2S->I2STXFIFO; /* I2SのFIFOに送信する */
118 audio_data->txI2SLLI[0].nextLLI = &(audio_data->txI2SLLI[1]); /* 次のLLIへのリンク */
119 /* No interrupt, Source Incr, Src/Dest 32bit, Src/Dest Bust=1, Bufsize = AUDIOBUFSIZE */
120 audio_data->txI2SLLI[0].Control = 0 << 31 // I : Interrupt : Do not trigger interrupt
121 | 0 << 27 // DI : Destination Increment : Do not increment after transfer
122 | 1 << 26 // SI : Source increment : Increment after transfer
123 | 2 << 21 // Dwidth : Destination width : 32bit
124 | 2 << 18 // SWidth : Source width : 32bit
125 | 0 << 15 // DBSize : Destination Burst
126 | 0 << 12 // SBSize : Source burst
127 | AUDIOBUFSIZE; // Transfer size [count]
130 audio_data->txI2SLLI[1].SrcAddr = audio_data->txBuffer[1]; /* 送信データのバッファ */
131 audio_data->txI2SLLI[1].DstAddr = (int *) &LPC_I2S->I2STXFIFO; /* I2SのFIFOに送信する */
132 audio_data->txI2SLLI[1].nextLLI = &(audio_data->txI2SLLI[0]); /* 次のLLIへのリンク */
133 /* No interrupt, Source Incr, Src/Dest 32bit, Src/Dest Bust=1, Bufsize = AUDIOBUFSIZE */
134 audio_data->txI2SLLI[1].Control = 0 << 31 // I : Interrupt : Do not trigger interrupt
135 | 0 << 27 // DI : Destination Increment : Do not increment after transfer
136 | 1 << 26 // SI : Source increment : Increment after transfer
137 | 2 << 21 // Dwidth : Destination width : 32bit
138 | 2 << 18 // SWidth : Source width : 32bit
139 | 0 << 15 // DBSize : Destination Burst
140 | 0 << 12 // SBSize : Source burst
141 | AUDIOBUFSIZE; // Transfer size [count]
144 audio_data->rxI2SLLI[0].DstAddr = audio_data->rxBuffer[0]; /* 受信データのバッファ */
145 audio_data->rxI2SLLI[0].SrcAddr = (int *) &LPC_I2S->I2SRXFIFO; /* I2SのFIFOから受信する */
146 audio_data->rxI2SLLI[0].nextLLI = &(audio_data->rxI2SLLI[1]); /* 次のLLIへのリンク */
147 /* No interrupt, Source Incr, Src/Dest 32bit, Src/Dest Bust=1, Bufsize = AUDIOBUFSIZE */
148 audio_data->rxI2SLLI[0].Control = 1 << 31 // I : Interrupt : trigger interrupt
149 | 1 << 27 // DI : Destination Increment : Increment after transfer
150 | 0 << 26 // SI : Source increment : Do not increment after transfer
151 | 2 << 21 // Dwidth : Destination width : 32bit
152 | 2 << 18 // SWidth : Source width : 32bit
153 | 0 << 15 // DBSize : Destination Burst
154 | 0 << 12 // SBSize : Source burst
155 | AUDIOBUFSIZE; // Transfer size [count]
158 audio_data->rxI2SLLI[1].DstAddr = audio_data->rxBuffer[1]; /* 受信データのバッファ */
159 audio_data->rxI2SLLI[1].SrcAddr = (int *) &LPC_I2S->I2SRXFIFO; /* I2SのFIFOから受信する */
160 audio_data->rxI2SLLI[1].nextLLI = &(audio_data->rxI2SLLI[0]); /* 次のLLIへのリンク */
161 /* No interrupt, Source Incr, Src/Dest 32bit, Src/Dest Bust=1, Bufsize = AUDIOBUFSIZE */
162 audio_data->rxI2SLLI[1].Control = 1 << 31 // I : Interrupt : trigger interrupt
163 | 1 << 27 // DI : Destination Increment : Increment after transfer
164 | 0 << 26 // SI : Source increment : Do not increment after transfer
165 | 2 << 21 // Dwidth : Destination width : 32bit
166 | 2 << 18 // SWidth : Source width : 32bit
167 | 0 << 15 // DBSize : Destination Burst
168 | 0 << 12 // SBSize : Source burst
169 | AUDIOBUFSIZE; // Transfer size [count]
172 for (i = 0; i < AUDIOBUFSIZE; i++) {
173 audio_data->txBuffer[0][i] = 0x00; /* ゼロフィル */
174 audio_data->txBuffer[1][i] = 0x00;
178 for (i = 0; i < AUDIOBUFSIZE; i++) {
179 audio_data->rxBuffer[0][i] = 0x00; /* ゼロフィル */
180 audio_data->rxBuffer[1][i] = 0x00;
184 * DMAの最初の1回の動作はレジスタを直接初期化して起動する。
185 * LPC1768のDMA起動方法は洗練されているとは言い難い。
189 LPC_GPDMACH0->DMACCSrcAddr = (int) audio_data->txI2SLLI[0].SrcAddr;
190 LPC_GPDMACH0->DMACCDestAddr = (int) audio_data->txI2SLLI[0].DstAddr;
191 LPC_GPDMACH0->DMACCLLI = (int) &audio_data->txI2SLLI[1];
192 LPC_GPDMACH0->DMACCControl = audio_data->txI2SLLI[0].Control;
195 LPC_GPDMACH1->DMACCSrcAddr = (int) audio_data->rxI2SLLI[0].SrcAddr;
196 LPC_GPDMACH1->DMACCDestAddr = (int) audio_data->rxI2SLLI[0].DstAddr;
197 LPC_GPDMACH1->DMACCLLI = (int) &(audio_data->rxI2SLLI[1]);
198 LPC_GPDMACH1->DMACCControl = audio_data->rxI2SLLI[0].Control;
202 * この時点ではDMAはディセーブルである。
206 LPC_GPDMACH0->DMACCConfig = 0 // Enable : 0 is Disable
207 | 0 << 1 // Src Peripheral ( Ignored when M->P )
208 | 6 << 6 // Dst Peripheral, Dest is I2Sch1
209 | 1 << 11 // Transfer type : 1 is M->P
210 | 0 << 14 // IE : Interrupt Enable : 0 is Disable
211 | 0 << 15 // ITC : Terminal Count Intr Mask : 0 is masking out
212 | 0 << 18; // H : Halt : 0 is active, 1 is Halt
214 LPC_GPDMACH1->DMACCConfig = 0 // Enable : 0 is Disable
215 | 5 << 1 // Src Peripheral, Src is I2Sch0
216 | 0 << 6 // Dst Peripheral, ( Ignored when P->M )
217 | 2 << 11 // Transfer type : 2 is P->M
218 | 1 << 14 // IE : Interrupt Enable : 0 is Disable
219 | 1 << 15 // ITC : Terminal Count Intr Mask : 0 is masking out
220 | 0 << 18; // H : Halt : 0 is active, 1 is Halt
222 /* 最後の処理としてDMAチャンネルを有功にする */
223 LPC_GPDMACH0->DMACCConfig |= 1;
224 LPC_GPDMACH1->DMACCConfig |= 1;
228 * \brief 現在ソフトウェアが使えるI2S TXバッファをかえす。
229 * \return プログラムが書き込んでいい送信バッファの先頭アドレス
231 * DMAが使用していないバッファをかえす。
232 * DMAと同期したプログラムを書く場合には必ずこのルーチンを使用して
233 * プログラムが使ってもよいバッファを決定する。
235 * DMAチャンネルの番号は決め打ちである。
236 * 適切なDMA管理機構を使った方式への変更が必要である。
238 AUDIOSAMPLE *i2s_getTxBuf()
242 // このプログラムではDMACH0をI2S TXに使っている。
243 // 使用していないバッファとは、現在使用中のLLIの、
244 // 次のLLIが指し示すバッファである。
245 nextLLI = (struct LLI *) LPC_GPDMACH0->DMACCLLI;
246 return nextLLI->SrcAddr;
250 * \brief 現在ソフトウェアが使えるI2S RXバッファをかえす。
251 * \return プログラムが読み込んでいい受信バッファの先頭アドレス
253 * DMAが使用していないバッファをかえす。
254 * DMAと同期したプログラムを書く場合には必ずこのルーチンを使用して
255 * プログラムが使ってもよいバッファを決定する。
257 * DMAチャンネルの番号は決め打ちである。
258 * 適切なDMA管理機構を使った方式への変更が必要である。
260 AUDIOSAMPLE *i2s_getRxBuf()
264 // このプログラムではDMACH1をI2S RXに使っている。
265 // 使用していないバッファとは、現在使用中のLLIの、
266 // 次のLLIが指し示すバッファである。
267 nextLLI = (struct LLI *) LPC_GPDMACH1->DMACCLLI;
268 return nextLLI->DstAddr;
271 void i2s_dma_intr_handler()
273 if (LPC_GPDMA->DMACIntTCStat & (1 << 1))
278 // CH1 (I2S DMA)のTC割り込みをクリア
279 LPC_GPDMA->DMACIntTCClear = (1 << 1);
280 // IS2 バッファ転送割り込みが起きたことをタスクに通知する。
281 isig_sem(SEM_I2SDMA);