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