1 // Copyright 2014 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.gillet@gmail.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 //
23 // See http://creativecommons.org/licenses/MIT/ for more information.
24 //
25 // -----------------------------------------------------------------------------
26 //
27 // WM8371 Codec support.
28
29 #include "warps/drivers/codec.h"
30
31 #define CODEC_I2C I2C2
32 #define CODEC_I2C_CLK RCC_APB1Periph_I2C2
33 #define CODEC_I2C_GPIO_CLOCK RCC_AHB1Periph_GPIOB
34 #define CODEC_I2C_GPIO_AF GPIO_AF_I2C2
35 #define CODEC_I2C_GPIO GPIOB
36 #define CODEC_I2C_SCL_PIN GPIO_Pin_10
37 #define CODEC_I2C_SDA_PIN GPIO_Pin_11
38 #define CODEC_I2C_SCL_PINSRC GPIO_PinSource10
39 #define CODEC_I2C_SDA_PINSRC GPIO_PinSource11
40 #define CODEC_TIMEOUT ((uint32_t)0x1000)
41 #define CODEC_LONG_TIMEOUT ((uint32_t)(300 * CODEC_TIMEOUT))
42 #define CODEC_I2C_SPEED 100000
43
44 #define CODEC_I2S SPI2
45 #define CODEC_I2S_EXT I2S2ext
46 #define CODEC_I2S_CLK RCC_APB1Periph_SPI2
47 #define CODEC_I2S_ADDRESS 0x4000380C
48 #define CODEC_I2S_EXT_ADDRESS 0x4000340C
49 #define CODEC_I2S_GPIO_AF GPIO_AF_SPI2
50 #define CODEC_I2S_IRQ SPI2_IRQn
51 #define CODEC_I2S_EXT_IRQ SPI2_IRQn
52 #define CODEC_I2S_GPIO_CLOCK (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB)
53 #define CODEC_I2S_WS_PIN GPIO_Pin_12
54 #define CODEC_I2S_SCK_PIN GPIO_Pin_13
55 #define CODEC_I2S_SDI_PIN GPIO_Pin_14
56 #define CODEC_I2S_SDO_PIN GPIO_Pin_15
57 #define CODEC_I2S_MCK_PIN GPIO_Pin_6
58 #define CODEC_I2S_WS_PINSRC GPIO_PinSource12
59 #define CODEC_I2S_SCK_PINSRC GPIO_PinSource13
60 #define CODEC_I2S_SDI_PINSRC GPIO_PinSource14
61 #define CODEC_I2S_SDO_PINSRC GPIO_PinSource15
62 #define CODEC_I2S_MCK_PINSRC GPIO_PinSource6
63 #define CODEC_I2S_GPIO GPIOB
64 #define CODEC_I2S_MCK_GPIO GPIOC
65 #define AUDIO_I2S_IRQHandler SPI2_IRQHandler
66
67 #define AUDIO_DMA_PERIPH_DATA_SIZE DMA_PeripheralDataSize_HalfWord
68 #define AUDIO_DMA_MEM_DATA_SIZE DMA_MemoryDataSize_HalfWord
69 #define AUDIO_I2S_DMA_CLOCK RCC_AHB1Periph_DMA1
70 #define AUDIO_I2S_DMA_STREAM DMA1_Stream4
71 #define AUDIO_I2S_DMA_DREG CODEC_I2S_ADDRESS
72 #define AUDIO_I2S_DMA_CHANNEL DMA_Channel_0
73 #define AUDIO_I2S_DMA_IRQ DMA1_Stream4_IRQn
74 #define AUDIO_I2S_DMA_FLAG_TC DMA_FLAG_TCIF4
75 #define AUDIO_I2S_DMA_FLAG_HT DMA_FLAG_HTIF4
76 #define AUDIO_I2S_DMA_FLAG_FE DMA_FLAG_FEIF4
77 #define AUDIO_I2S_DMA_FLAG_TE DMA_FLAG_TEIF4
78 #define AUDIO_I2S_DMA_FLAG_DME DMA_FLAG_DMEIF4
79 #define AUDIO_I2S_EXT_DMA_STREAM DMA1_Stream3
80 #define AUDIO_I2S_EXT_DMA_DREG CODEC_I2S_EXT_ADDRESS
81 #define AUDIO_I2S_EXT_DMA_CHANNEL DMA_Channel_3
82 #define AUDIO_I2S_EXT_DMA_IRQ DMA1_Stream3_IRQn
83 #define AUDIO_I2S_EXT_DMA_FLAG_TC DMA_FLAG_TCIF3
84 #define AUDIO_I2S_EXT_DMA_FLAG_HT DMA_FLAG_HTIF3
85 #define AUDIO_I2S_EXT_DMA_FLAG_FE DMA_FLAG_FEIF3
86 #define AUDIO_I2S_EXT_DMA_FLAG_TE DMA_FLAG_TEIF3
87 #define AUDIO_I2S_EXT_DMA_FLAG_DME DMA_FLAG_DMEIF3
88 #define AUDIO_I2S_EXT_DMA_REG DMA1
89 #define AUDIO_I2S_EXT_DMA_ISR LISR
90 #define AUDIO_I2S_EXT_DMA_IFCR LIFCR
91
92 #define W8731_ADDR_0 0x1A
93 #define W8731_ADDR_1 0x1B
94 #define W8731_NUM_REGS 10
95 #define CODEC_ADDRESS (W8731_ADDR_0 << 1)
96
97 #define WAIT_LONG(x) { \
98 uint32_t timeout = CODEC_LONG_TIMEOUT; \
99 while (x) { if ((timeout--) == 0) return false; } \
100 }
101
102 #define WAIT(x) { \
103 uint32_t timeout = CODEC_TIMEOUT; \
104 while (x) { if ((timeout--) == 0) return false; } \
105 }
106
107 namespace warps {
108
109 /* static */
110 Codec* Codec::instance_;
111
112 enum CodecRegister {
113 CODEC_REG_LEFT_LINE_IN = 0x00,
114 CODEC_REG_RIGHT_LINE_IN = 0x01,
115 CODEC_REG_LEFT_HEADPHONES_OUT = 0x02,
116 CODEC_REG_RIGHT_HEADPHONES_OUT = 0x03,
117 CODEC_REG_ANALOGUE_ROUTING = 0x04,
118 CODEC_REG_DIGITAL_ROUTING = 0x05,
119 CODEC_REG_POWER_MANAGEMENT = 0x06,
120 CODEC_REG_DIGITAL_FORMAT = 0x07,
121 CODEC_REG_SAMPLE_RATE = 0x08,
122 CODEC_REG_ACTIVE = 0x09,
123 CODEC_REG_RESET = 0x0f,
124 };
125
126 enum CodecSettings {
127 CODEC_INPUT_0_DB = 0x17,
128 CODEC_INPUT_UPDATE_BOTH = 0x40,
129 CODEC_HEADPHONES_MUTE = 0x00,
130 CODEC_MIC_BOOST = 0x1,
131 CODEC_MIC_MUTE = 0x2,
132 CODEC_ADC_MIC = 0x4,
133 CODEC_ADC_LINE = 0x0,
134 CODEC_OUTPUT_DAC_ENABLE = 0x10,
135 CODEC_OUTPUT_MONITOR = 0x20,
136 CODEC_DEEMPHASIS_NONE = 0x00,
137 CODEC_DEEMPHASIS_32K = 0x01,
138 CODEC_DEEMPHASIS_44K = 0x02,
139 CODEC_DEEMPHASIS_48K = 0x03,
140 CODEC_SOFT_MUTE = 0x01,
141 CODEC_ADC_HPF = 0x00,
142
143 CODEC_POWER_DOWN_LINE_IN = 0x01,
144 CODEC_POWER_DOWN_MIC = 0x02,
145 CODEC_POWER_DOWN_ADC = 0x04,
146 CODEC_POWER_DOWN_DAC = 0x08,
147 CODEC_POWER_DOWN_LINE_OUT = 0x10,
148 CODEC_POWER_DOWN_OSCILLATOR = 0x20,
149 CODEC_POWER_DOWN_CLOCK_OUTPUT = 0x40,
150 CODEC_POWER_DOWN_EVERYTHING = 0x80,
151
152 CODEC_PROTOCOL_MASK_MSB_FIRST = 0x00,
153 CODEC_PROTOCOL_MASK_LSB_FIRST = 0x01,
154 CODEC_PROTOCOL_MASK_PHILIPS = 0x02,
155 CODEC_PROTOCOL_MASK_DSP = 0x03,
156
157 CODEC_FORMAT_MASK_16_BIT = 0x00 << 2,
158 CODEC_FORMAT_MASK_20_BIT = 0x01 << 2,
159 CODEC_FORMAT_MASK_24_BIT = 0x02 << 2,
160 CODEC_FORMAT_MASK_32_BIT = 0x03 << 2,
161
162 CODEC_FORMAT_LR_SWAP = 0x20,
163 CODEC_FORMAT_MASTER = 0x40,
164 CODEC_FORMAT_SLAVE = 0x00,
165 CODEC_FORMAT_INVERT_CLOCK = 0x80,
166
167 CODEC_RATE_48K_48K = 0x00 << 2,
168 CODEC_RATE_8K_8K = 0x03 << 2,
169 CODEC_RATE_96K_96K = 0x07 << 2,
170 CODEC_RATE_32K_32K = 0x06 << 2,
171 CODEC_RATE_44K_44K = 0x08 << 2,
172 };
173
InitializeGPIO()174 bool Codec::InitializeGPIO() {
175 GPIO_InitTypeDef gpio_init;
176
177 // Start GPIO peripheral clocks.
178 RCC_AHB1PeriphClockCmd(CODEC_I2C_GPIO_CLOCK | CODEC_I2S_GPIO_CLOCK, ENABLE);
179
180 // Initialize I2C pins
181 gpio_init.GPIO_Pin = CODEC_I2C_SCL_PIN | CODEC_I2C_SDA_PIN;
182 gpio_init.GPIO_Mode = GPIO_Mode_AF;
183 gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
184 gpio_init.GPIO_OType = GPIO_OType_OD;
185 gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
186 GPIO_Init(CODEC_I2C_GPIO, &gpio_init);
187
188 // Connect pins to I2C peripheral
189 GPIO_PinAFConfig(CODEC_I2C_GPIO, CODEC_I2C_SCL_PINSRC, CODEC_I2C_GPIO_AF);
190 GPIO_PinAFConfig(CODEC_I2C_GPIO, CODEC_I2C_SDA_PINSRC, CODEC_I2C_GPIO_AF);
191
192 // Initialize I2S pins
193 gpio_init.GPIO_Pin = CODEC_I2S_SCK_PIN | CODEC_I2S_SDO_PIN | \
194 CODEC_I2S_SDI_PIN | CODEC_I2S_WS_PIN;
195 gpio_init.GPIO_Mode = GPIO_Mode_AF;
196 gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
197 gpio_init.GPIO_OType = GPIO_OType_PP;
198 gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
199 GPIO_Init(CODEC_I2S_GPIO, &gpio_init);
200
201 gpio_init.GPIO_Pin = CODEC_I2S_MCK_PIN;
202 GPIO_Init(CODEC_I2S_MCK_GPIO, &gpio_init);
203
204 // Connect pins to I2S peripheral.
205 GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_WS_PINSRC, CODEC_I2S_GPIO_AF);
206 GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SCK_PINSRC, CODEC_I2S_GPIO_AF);
207 GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SDO_PINSRC, CODEC_I2S_GPIO_AF);
208 GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SDI_PINSRC, CODEC_I2S_GPIO_AF);
209 GPIO_PinAFConfig(CODEC_I2S_MCK_GPIO, CODEC_I2S_MCK_PINSRC, CODEC_I2S_GPIO_AF);
210 return true;
211 }
212
InitializeControlInterface()213 bool Codec::InitializeControlInterface() {
214 I2C_InitTypeDef i2c_init;
215
216 // Initialize I2C
217 RCC_APB1PeriphClockCmd(CODEC_I2C_CLK, ENABLE);
218
219 I2C_DeInit(CODEC_I2C);
220 i2c_init.I2C_Mode = I2C_Mode_I2C;
221 i2c_init.I2C_DutyCycle = I2C_DutyCycle_2;
222 i2c_init.I2C_OwnAddress1 = 0x33;
223 i2c_init.I2C_Ack = I2C_Ack_Enable;
224 i2c_init.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
225 i2c_init.I2C_ClockSpeed = CODEC_I2C_SPEED;
226
227 I2C_Init(CODEC_I2C, &i2c_init);
228 I2C_Cmd(CODEC_I2C, ENABLE);
229
230 return true;
231 }
232
InitializeAudioInterface(bool mcu_is_master,int32_t sample_rate)233 bool Codec::InitializeAudioInterface(
234 bool mcu_is_master,
235 int32_t sample_rate) {
236 // Configure PLL and I2S master clock.
237 RCC_I2SCLKConfig(RCC_I2S2CLKSource_PLLI2S);
238
239 // The following values have been computed for a 8Mhz external crystal!
240 RCC_PLLI2SCmd(DISABLE);
241 if (sample_rate == 48000) {
242 // 47.992kHz
243 RCC_PLLI2SConfig(258, 3);
244 } else if (sample_rate == 44100) {
245 // 44.11kHz
246 RCC_PLLI2SConfig(271, 6);
247 } else if (sample_rate == 32000) {
248 // 32.003kHz
249 RCC_PLLI2SConfig(426, 4);
250 } else if (sample_rate == 96000) {
251 // 95.95 kHz
252 RCC_PLLI2SConfig(393, 4);
253 } else {
254 // Unsupported sample rate!
255 return false;
256 }
257 RCC_PLLI2SCmd(ENABLE);
258 WAIT(RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY) == RESET);
259
260 RCC_APB1PeriphClockCmd(CODEC_I2S_CLK, ENABLE);
261
262 // Initialize I2S
263 I2S_InitTypeDef i2s_init;
264
265 SPI_I2S_DeInit(CODEC_I2S);
266 i2s_init.I2S_AudioFreq = sample_rate;
267 i2s_init.I2S_Standard = I2S_Standard_Phillips;
268 i2s_init.I2S_DataFormat = I2S_DataFormat_16b;
269 i2s_init.I2S_CPOL = I2S_CPOL_Low;
270 i2s_init.I2S_Mode = mcu_is_master ? I2S_Mode_MasterTx : I2S_Mode_SlaveTx;
271 i2s_init.I2S_MCLKOutput = mcu_is_master
272 ? I2S_MCLKOutput_Enable
273 : I2S_MCLKOutput_Disable;
274
275 // Initialize the I2S main channel for TX
276 I2S_Init(CODEC_I2S, &i2s_init);
277
278 // Initialize the I2S extended channel for RX
279 I2S_FullDuplexConfig(CODEC_I2S_EXT, &i2s_init);
280
281 return true;
282 }
283
WriteControlRegister(uint8_t address,uint16_t data)284 bool Codec::WriteControlRegister(uint8_t address, uint16_t data) {
285 uint8_t byte_1 = ((address << 1) & 0xfe) | ((data >> 8) & 0x01);
286 uint8_t byte_2 = data & 0xff;
287
288 WAIT_LONG(I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BUSY));
289
290 I2C_GenerateSTART(CODEC_I2C, ENABLE);
291 WAIT(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_MODE_SELECT));
292
293 I2C_Send7bitAddress(CODEC_I2C, CODEC_ADDRESS, I2C_Direction_Transmitter);
294 WAIT(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
295
296 I2C_SendData(CODEC_I2C, byte_1);
297 WAIT(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
298
299 I2C_SendData(CODEC_I2C, byte_2);
300 WAIT(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
301
302 WAIT_LONG(!I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BTF));
303
304 I2C_GenerateSTOP(CODEC_I2C, ENABLE);
305
306 return true;
307 }
308
InitializeCodec(bool mcu_is_master,int32_t sample_rate)309 bool Codec::InitializeCodec(
310 bool mcu_is_master,
311 int32_t sample_rate) {
312 bool s = true; // success;
313 s = s && WriteControlRegister(CODEC_REG_RESET, 0);
314 // Configure L&R inputs
315 s = s && WriteControlRegister(CODEC_REG_LEFT_LINE_IN, CODEC_INPUT_0_DB);
316 s = s && WriteControlRegister(CODEC_REG_RIGHT_LINE_IN, CODEC_INPUT_0_DB);
317
318 // Configure L&R headphone outputs
319 s = s && WriteControlRegister(CODEC_REG_LEFT_HEADPHONES_OUT, CODEC_HEADPHONES_MUTE);
320 s = s && WriteControlRegister(CODEC_REG_RIGHT_HEADPHONES_OUT, CODEC_HEADPHONES_MUTE);
321
322 // Configure analog routing
323 s = s && WriteControlRegister(
324 CODEC_REG_ANALOGUE_ROUTING,
325 CODEC_MIC_MUTE | CODEC_ADC_LINE | CODEC_OUTPUT_DAC_ENABLE);
326
327 // Configure digital routing
328 s = s && WriteControlRegister(CODEC_REG_DIGITAL_ROUTING, CODEC_DEEMPHASIS_NONE);
329
330 // Configure power management
331 uint8_t power_down_reg = CODEC_POWER_DOWN_MIC | CODEC_POWER_DOWN_CLOCK_OUTPUT;
332 if (mcu_is_master) {
333 power_down_reg |= CODEC_POWER_DOWN_OSCILLATOR;
334 }
335
336 s = s && WriteControlRegister(CODEC_REG_POWER_MANAGEMENT, power_down_reg);
337
338 uint8_t format_byte = CODEC_PROTOCOL_MASK_PHILIPS | CODEC_FORMAT_MASK_16_BIT;
339 format_byte |= mcu_is_master ? CODEC_FORMAT_SLAVE : CODEC_FORMAT_MASTER;
340
341 s = s && WriteControlRegister(CODEC_REG_DIGITAL_FORMAT, format_byte);
342
343 uint8_t rate_byte = 0;
344 if (mcu_is_master) {
345 // According to the WM8731 datasheet, the 32kHz and 96kHz modes require the
346 // master clock to be at 12.288 MHz (384 fs / 128 fs). The STM32F4 I2S clock
347 // is always at 256 fs. So the 32kHz and 96kHz modes are achieved by
348 // pretending that we are doing 48kHz, but with a slower or faster master
349 // clock.
350 rate_byte = sample_rate == 44100 ? CODEC_RATE_44K_44K : CODEC_RATE_48K_48K;
351 } else {
352 switch (sample_rate) {
353 case 8000:
354 rate_byte = CODEC_RATE_8K_8K;
355 break;
356 case 32000:
357 rate_byte = CODEC_RATE_32K_32K;
358 break;
359 case 44100:
360 rate_byte = CODEC_RATE_44K_44K;
361 break;
362 case 96000:
363 rate_byte = CODEC_RATE_96K_96K;
364 break;
365 case 48000:
366 default:
367 rate_byte = CODEC_RATE_48K_48K;
368 break;
369 }
370 }
371 s = s && WriteControlRegister(CODEC_REG_SAMPLE_RATE, rate_byte);
372
373 // For now codec is not active.
374 s = s && WriteControlRegister(CODEC_REG_ACTIVE, 0x00);
375
376 return s;
377 }
378
InitializeDMA()379 bool Codec::InitializeDMA() {
380 RCC_AHB1PeriphClockCmd(AUDIO_I2S_DMA_CLOCK, ENABLE);
381
382 // DMA setup for TX.
383 DMA_Cmd(AUDIO_I2S_DMA_STREAM, DISABLE);
384 DMA_DeInit(AUDIO_I2S_DMA_STREAM);
385
386 dma_init_tx_.DMA_Channel = AUDIO_I2S_DMA_CHANNEL;
387 dma_init_tx_.DMA_PeripheralBaseAddr = AUDIO_I2S_DMA_DREG;
388 dma_init_tx_.DMA_Memory0BaseAddr = (uint32_t)0;
389 dma_init_tx_.DMA_DIR = DMA_DIR_MemoryToPeripheral;
390 dma_init_tx_.DMA_BufferSize = (uint32_t)0xFFFE;
391 dma_init_tx_.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
392 dma_init_tx_.DMA_MemoryInc = DMA_MemoryInc_Enable;
393 dma_init_tx_.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
394 dma_init_tx_.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
395 dma_init_tx_.DMA_Mode = DMA_Mode_Circular;
396 dma_init_tx_.DMA_Priority = DMA_Priority_High;
397 dma_init_tx_.DMA_FIFOMode = DMA_FIFOMode_Disable;
398 dma_init_tx_.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
399 dma_init_tx_.DMA_MemoryBurst = DMA_MemoryBurst_Single;
400 dma_init_tx_.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
401 DMA_Init(AUDIO_I2S_DMA_STREAM, &dma_init_tx_);
402
403 // DMA setup for RX.
404 DMA_Cmd(AUDIO_I2S_EXT_DMA_STREAM, DISABLE);
405 DMA_DeInit(AUDIO_I2S_EXT_DMA_STREAM);
406
407 dma_init_rx_.DMA_Channel = AUDIO_I2S_EXT_DMA_CHANNEL;
408 dma_init_rx_.DMA_PeripheralBaseAddr = AUDIO_I2S_EXT_DMA_DREG;
409 dma_init_rx_.DMA_Memory0BaseAddr = (uint32_t)0;
410 dma_init_rx_.DMA_DIR = DMA_DIR_PeripheralToMemory;
411 dma_init_rx_.DMA_BufferSize = (uint32_t)0xFFFE;
412 dma_init_rx_.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
413 dma_init_rx_.DMA_MemoryInc = DMA_MemoryInc_Enable;
414 dma_init_rx_.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
415 dma_init_rx_.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
416 dma_init_rx_.DMA_Mode = DMA_Mode_Circular;
417 dma_init_rx_.DMA_Priority = DMA_Priority_High;
418 dma_init_rx_.DMA_FIFOMode = DMA_FIFOMode_Disable;
419 dma_init_rx_.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
420 dma_init_rx_.DMA_MemoryBurst = DMA_MemoryBurst_Single;
421 dma_init_rx_.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
422 DMA_Init(AUDIO_I2S_EXT_DMA_STREAM, &dma_init_rx_);
423
424 // Enable the interrupts.
425 DMA_ITConfig(AUDIO_I2S_EXT_DMA_STREAM, DMA_IT_TC | DMA_IT_HT, ENABLE);
426
427 // Enable the IRQ.
428 NVIC_EnableIRQ(AUDIO_I2S_EXT_DMA_IRQ);
429
430 // Start DMA from/to codec.
431 SPI_I2S_DMACmd(CODEC_I2S, SPI_I2S_DMAReq_Tx, ENABLE);
432 SPI_I2S_DMACmd(CODEC_I2S_EXT, SPI_I2S_DMAReq_Rx, ENABLE);
433
434 return true;
435 }
436
Init(bool mcu_is_master,int32_t sample_rate)437 bool Codec::Init(
438 bool mcu_is_master,
439 int32_t sample_rate) {
440 instance_ = this;
441 callback_ = NULL;
442
443 sample_rate_ = sample_rate;
444 mcu_is_master_ = mcu_is_master;
445
446 return InitializeGPIO() && \
447 InitializeControlInterface() && \
448 InitializeAudioInterface(mcu_is_master, sample_rate) && \
449 InitializeCodec(mcu_is_master, sample_rate) && \
450 InitializeDMA();
451 }
452
Start(size_t block_size,FillBufferCallback callback)453 bool Codec::Start(size_t block_size, FillBufferCallback callback) {
454 // Start the codec.
455 if (!WriteControlRegister(CODEC_REG_ACTIVE, 0x01)) {
456 return false;
457 }
458 if (block_size > kMaxCodecBlockSize) {
459 return false;
460 }
461
462 if (!mcu_is_master_) {
463 while(GPIO_ReadInputDataBit(CODEC_I2S_GPIO, CODEC_I2S_WS_PIN));
464 while(!GPIO_ReadInputDataBit(CODEC_I2S_GPIO, CODEC_I2S_WS_PIN));
465 }
466
467 callback_ = callback;
468
469 // Enable the I2S TX and RX peripherals.
470 if ((CODEC_I2S->I2SCFGR & 0x0400) == 0){
471 I2S_Cmd(CODEC_I2S, ENABLE);
472 }
473 if ((CODEC_I2S_EXT->I2SCFGR & 0x0400) == 0){
474 I2S_Cmd(CODEC_I2S_EXT, ENABLE);
475 }
476
477 dma_init_tx_.DMA_Memory0BaseAddr = (uint32_t)(tx_dma_buffer_);
478 dma_init_rx_.DMA_Memory0BaseAddr = (uint32_t)(rx_dma_buffer_);
479
480 size_t stride = 1;
481 if (!mcu_is_master_) {
482 // When the WM8731 is the master, the data is sent with padding.
483 switch (sample_rate_) {
484 case 32000:
485 stride = 3;
486 break;
487 case 48000:
488 stride = 2;
489 break;
490 case 96000:
491 stride = 4;
492 break;
493 }
494 }
495
496 block_size_ = block_size;
497 stride_ = stride;
498
499 dma_init_tx_.DMA_BufferSize = 2 * stride * block_size * 2;
500 dma_init_rx_.DMA_BufferSize = 2 * stride * block_size * 2;
501
502 DMA_Init(AUDIO_I2S_DMA_STREAM, &dma_init_tx_);
503 DMA_Init(AUDIO_I2S_EXT_DMA_STREAM, &dma_init_rx_);
504 DMA_Cmd(AUDIO_I2S_DMA_STREAM, ENABLE);
505 DMA_Cmd(AUDIO_I2S_EXT_DMA_STREAM, ENABLE);
506
507 return true;
508 }
509
Stop()510 void Codec::Stop() {
511 DMA_Cmd(AUDIO_I2S_DMA_STREAM, DISABLE);
512 DMA_Cmd(AUDIO_I2S_EXT_DMA_STREAM, DISABLE);
513 }
514
set_line_input_gain(int32_t channel,int32_t gain)515 bool Codec::set_line_input_gain(int32_t channel, int32_t gain) {
516 return WriteControlRegister(CODEC_REG_LEFT_LINE_IN + channel, gain);
517 }
518
set_line_input_gain(int32_t gain)519 bool Codec::set_line_input_gain(int32_t gain) {
520 return WriteControlRegister(0, gain) && WriteControlRegister(1, gain);
521 }
522
Fill(size_t offset)523 void Codec::Fill(size_t offset) {
524 if (callback_) {
525 offset *= block_size_ * stride_ * 2;
526 short* in = &rx_dma_buffer_[offset];
527 short* out = &tx_dma_buffer_[offset];
528 if (stride_) {
529 // Undo the padding from the WM8731.
530 for (size_t i = 1; i < block_size_ * 2; ++i) {
531 in[i] = in[i * stride_];
532 }
533 }
534 (*callback_)((Frame*)(in), (Frame*)(out), block_size_);
535 if (stride_) {
536 // Pad for the WM8731.
537 for (size_t i = block_size_ * 2 - 1; i > 0; --i) {
538 out[i * stride_] = out[i];
539 }
540 }
541 }
542 }
543
544 } // namespace warps
545
546 extern "C" {
547 // Do not call into the firmware library to save on calls/jumps.
548 // if (DMA_GetFlagStatus(AUDIO_I2S_EXT_DMA_STREAM, AUDIO_I2S_EXT_DMA_FLAG_TC) != RESET) {
549 // DMA_ClearFlag(AUDIO_I2S_EXT_DMA_STREAM, AUDIO_I2S_EXT_DMA_FLAG_TC);
550
DMA1_Stream3_IRQHandler(void)551 void DMA1_Stream3_IRQHandler(void) {
552 if (AUDIO_I2S_EXT_DMA_REG->AUDIO_I2S_EXT_DMA_ISR & AUDIO_I2S_EXT_DMA_FLAG_TC) {
553 AUDIO_I2S_EXT_DMA_REG->AUDIO_I2S_EXT_DMA_IFCR = AUDIO_I2S_EXT_DMA_FLAG_TC;
554 warps::Codec::GetInstance()->Fill(1);
555 }
556 if (AUDIO_I2S_EXT_DMA_REG->AUDIO_I2S_EXT_DMA_ISR & AUDIO_I2S_EXT_DMA_FLAG_HT) {
557 AUDIO_I2S_EXT_DMA_REG->AUDIO_I2S_EXT_DMA_IFCR = AUDIO_I2S_EXT_DMA_FLAG_HT;
558 warps::Codec::GetInstance()->Fill(0);
559 }
560 }
561
562 }
563