| 
							- // Copyright 2014 Olivier Gillet.
 - //
 - // Author: Olivier Gillet (ol.gillet@gmail.com)
 - //
 - // Permission is hereby granted, free of charge, to any person obtaining a copy
 - // of this software and associated documentation files (the "Software"), to deal
 - // in the Software without restriction, including without limitation the rights
 - // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 - // copies of the Software, and to permit persons to whom the Software is
 - // furnished to do so, subject to the following conditions:
 - // 
 - // The above copyright notice and this permission notice shall be included in
 - // all copies or substantial portions of the Software.
 - // 
 - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 - // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 - // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 - // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 - // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 - // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 - // THE SOFTWARE.
 - // 
 - // See http://creativecommons.org/licenses/MIT/ for more information.
 - //
 - // -----------------------------------------------------------------------------
 - //
 - // WM8371 Codec support.
 - 
 - #include "elements/drivers/codec.h"
 - 
 - #include <string.h>
 - 
 - #define CODEC_I2C                      I2C2
 - #define CODEC_I2C_CLK                  RCC_APB1Periph_I2C2
 - #define CODEC_I2C_GPIO_CLOCK           RCC_AHB1Periph_GPIOB
 - #define CODEC_I2C_GPIO_AF              GPIO_AF_I2C2
 - #define CODEC_I2C_GPIO                 GPIOB
 - #define CODEC_I2C_SCL_PIN              GPIO_Pin_10
 - #define CODEC_I2C_SDA_PIN              GPIO_Pin_11
 - #define CODEC_I2C_SCL_PINSRC           GPIO_PinSource10
 - #define CODEC_I2C_SDA_PINSRC           GPIO_PinSource11
 - #define CODEC_TIMEOUT                  ((uint32_t)0x1000)
 - #define CODEC_LONG_TIMEOUT             ((uint32_t)(300 * CODEC_TIMEOUT))
 - #define CODEC_I2C_SPEED                100000
 - 
 - #define CODEC_I2S                      SPI2
 - #define CODEC_I2S_EXT                  I2S2ext
 - #define CODEC_I2S_CLK                  RCC_APB1Periph_SPI2
 - #define CODEC_I2S_ADDRESS              0x4000380C
 - #define CODEC_I2S_EXT_ADDRESS          0x4000340C
 - #define CODEC_I2S_GPIO_AF              GPIO_AF_SPI2
 - #define CODEC_I2S_IRQ                  SPI2_IRQn
 - #define CODEC_I2S_EXT_IRQ              SPI2_IRQn
 - #define CODEC_I2S_GPIO_CLOCK           (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB)
 - #define CODEC_I2S_WS_PIN               GPIO_Pin_12
 - #define CODEC_I2S_SCK_PIN              GPIO_Pin_13
 - #define CODEC_I2S_SDI_PIN              GPIO_Pin_14
 - #define CODEC_I2S_SDO_PIN              GPIO_Pin_15
 - #define CODEC_I2S_MCK_PIN              GPIO_Pin_6
 - #define CODEC_I2S_WS_PINSRC            GPIO_PinSource12
 - #define CODEC_I2S_SCK_PINSRC           GPIO_PinSource13
 - #define CODEC_I2S_SDI_PINSRC           GPIO_PinSource14
 - #define CODEC_I2S_SDO_PINSRC           GPIO_PinSource15
 - #define CODEC_I2S_MCK_PINSRC           GPIO_PinSource6
 - #define CODEC_I2S_GPIO                 GPIOB
 - #define CODEC_I2S_MCK_GPIO             GPIOC
 - #define AUDIO_I2S_IRQHandler           SPI2_IRQHandler
 - 
 - #define AUDIO_DMA_PERIPH_DATA_SIZE     DMA_PeripheralDataSize_HalfWord
 - #define AUDIO_DMA_MEM_DATA_SIZE        DMA_MemoryDataSize_HalfWord
 - #define AUDIO_I2S_DMA_CLOCK            RCC_AHB1Periph_DMA1
 - #define AUDIO_I2S_DMA_STREAM           DMA1_Stream4
 - #define AUDIO_I2S_DMA_DREG             CODEC_I2S_ADDRESS
 - #define AUDIO_I2S_DMA_CHANNEL          DMA_Channel_0
 - #define AUDIO_I2S_DMA_IRQ              DMA1_Stream4_IRQn
 - #define AUDIO_I2S_DMA_FLAG_TC          DMA_FLAG_TCIF4
 - #define AUDIO_I2S_DMA_FLAG_HT          DMA_FLAG_HTIF4
 - #define AUDIO_I2S_DMA_FLAG_FE          DMA_FLAG_FEIF4
 - #define AUDIO_I2S_DMA_FLAG_TE          DMA_FLAG_TEIF4
 - #define AUDIO_I2S_DMA_FLAG_DME         DMA_FLAG_DMEIF4
 - #define AUDIO_I2S_EXT_DMA_STREAM       DMA1_Stream3
 - #define AUDIO_I2S_EXT_DMA_DREG         CODEC_I2S_EXT_ADDRESS
 - #define AUDIO_I2S_EXT_DMA_CHANNEL      DMA_Channel_3
 - #define AUDIO_I2S_EXT_DMA_IRQ          DMA1_Stream3_IRQn
 - #define AUDIO_I2S_EXT_DMA_FLAG_TC      DMA_FLAG_TCIF3
 - #define AUDIO_I2S_EXT_DMA_FLAG_HT      DMA_FLAG_HTIF3
 - #define AUDIO_I2S_EXT_DMA_FLAG_FE      DMA_FLAG_FEIF3
 - #define AUDIO_I2S_EXT_DMA_FLAG_TE      DMA_FLAG_TEIF3
 - #define AUDIO_I2S_EXT_DMA_FLAG_DME     DMA_FLAG_DMEIF3
 - #define AUDIO_I2S_EXT_DMA_REG          DMA1
 - #define AUDIO_I2S_EXT_DMA_ISR          LISR
 - #define AUDIO_I2S_EXT_DMA_IFCR         LIFCR
 - 
 - #define W8731_ADDR_0 0x1A
 - #define W8731_ADDR_1 0x1B
 - #define W8731_NUM_REGS 10
 - #define CODEC_ADDRESS           (W8731_ADDR_0 << 1)
 - 
 - #define WAIT_LONG(x) { \
 -   uint32_t timeout = CODEC_LONG_TIMEOUT; \
 -   while (x) { if ((timeout--) == 0) return false; } \
 - }
 - 
 - #define WAIT(x) { \
 -   uint32_t timeout = CODEC_TIMEOUT; \
 -   while (x) { if ((timeout--) == 0) return false; } \
 - }
 - 
 - namespace elements {
 - 
 - /* static */
 - Codec* Codec::instance_;
 - 
 - enum CodecRegister {
 -   CODEC_REG_LEFT_LINE_IN = 0x00,
 -   CODEC_REG_RIGHT_LINE_IN = 0x01,
 -   CODEC_REG_LEFT_HEADPHONES_OUT = 0x02,
 -   CODEC_REG_RIGHT_HEADPHONES_OUT = 0x03,
 -   CODEC_REG_ANALOGUE_ROUTING = 0x04,
 -   CODEC_REG_DIGITAL_ROUTING = 0x05,
 -   CODEC_REG_POWER_MANAGEMENT = 0x06,
 -   CODEC_REG_DIGITAL_FORMAT = 0x07,
 -   CODEC_REG_SAMPLE_RATE = 0x08,
 -   CODEC_REG_ACTIVE = 0x09,
 -   CODEC_REG_RESET = 0x0f,
 - };
 - 
 - bool Codec::InitializeGPIO() {
 -   GPIO_InitTypeDef gpio_init;
 - 
 -   // Start GPIO peripheral clocks.
 -   RCC_AHB1PeriphClockCmd(CODEC_I2C_GPIO_CLOCK | CODEC_I2S_GPIO_CLOCK, ENABLE);
 - 
 -   // Initialize I2C pins
 -   gpio_init.GPIO_Pin = CODEC_I2C_SCL_PIN | CODEC_I2C_SDA_PIN; 
 -   gpio_init.GPIO_Mode = GPIO_Mode_AF;
 -   gpio_init.GPIO_Speed = GPIO_Speed_25MHz;
 -   gpio_init.GPIO_OType = GPIO_OType_OD;
 -   gpio_init.GPIO_PuPd  = GPIO_PuPd_NOPULL;
 -   GPIO_Init(CODEC_I2C_GPIO, &gpio_init);
 - 
 -   // Connect pins to I2C peripheral
 -   GPIO_PinAFConfig(CODEC_I2C_GPIO, CODEC_I2C_SCL_PINSRC, CODEC_I2C_GPIO_AF);
 -   GPIO_PinAFConfig(CODEC_I2C_GPIO, CODEC_I2C_SDA_PINSRC, CODEC_I2C_GPIO_AF);
 -   
 -   // Initialize I2S pins
 -   gpio_init.GPIO_Pin = CODEC_I2S_SCK_PIN | CODEC_I2S_SDO_PIN | \
 -       CODEC_I2S_SDI_PIN | CODEC_I2S_WS_PIN; 
 -   gpio_init.GPIO_Mode = GPIO_Mode_AF;
 -   gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
 -   gpio_init.GPIO_OType = GPIO_OType_PP;
 -   gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
 -   GPIO_Init(CODEC_I2S_GPIO, &gpio_init);
 -   
 -   gpio_init.GPIO_Pin = CODEC_I2S_MCK_PIN; 
 -   GPIO_Init(CODEC_I2S_MCK_GPIO, &gpio_init);
 -   
 -   // Connect pins to I2S peripheral.
 -   GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_WS_PINSRC, CODEC_I2S_GPIO_AF);  
 -   GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SCK_PINSRC, CODEC_I2S_GPIO_AF);
 -   GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SDO_PINSRC, CODEC_I2S_GPIO_AF);
 -   GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SDI_PINSRC, CODEC_I2S_GPIO_AF);
 -   GPIO_PinAFConfig(CODEC_I2S_MCK_GPIO, CODEC_I2S_MCK_PINSRC, CODEC_I2S_GPIO_AF); 
 -   return true;
 - }
 - 
 - bool Codec::InitializeControlInterface() {
 -   I2C_InitTypeDef i2c_init;
 - 
 -   // Initialize I2C
 -   RCC_APB1PeriphClockCmd(CODEC_I2C_CLK, ENABLE);
 - 
 -   I2C_DeInit(CODEC_I2C);
 -   i2c_init.I2C_Mode = I2C_Mode_I2C;
 -   i2c_init.I2C_DutyCycle = I2C_DutyCycle_2;
 -   i2c_init.I2C_OwnAddress1 = 0x33;
 -   i2c_init.I2C_Ack = I2C_Ack_Enable;
 -   i2c_init.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
 -   i2c_init.I2C_ClockSpeed = CODEC_I2C_SPEED;
 -   
 -   I2C_Init(CODEC_I2C, &i2c_init);
 -   I2C_Cmd(CODEC_I2C, ENABLE);  
 -   
 -   return true;
 - }
 - 
 - bool Codec::InitializeAudioInterface(
 -     uint32_t sample_rate,
 -     CodecProtocol protocol,
 -     CodecFormat format) {
 - 
 -   // Configure PLL and I2S master clock.
 -   RCC_I2SCLKConfig(RCC_I2S2CLKSource_PLLI2S);
 -   
 -   // The following values have been computed for a 8Mhz external crystal!
 -   RCC_PLLI2SCmd(DISABLE);
 -   if (sample_rate == 48000) {
 -     // 47.992kHz
 -     RCC_PLLI2SConfig(258, 3);
 -   } else if (sample_rate == 44100) {
 -     // 44.11kHz
 -     RCC_PLLI2SConfig(271, 6);
 -   } else if (sample_rate == 32000) {
 -     // 32.003kHz
 -     RCC_PLLI2SConfig(426, 4);
 -   } else if (sample_rate == 96000) {
 -     // 95.95 kHz
 -     RCC_PLLI2SConfig(393, 4);
 -   } else {
 -     // Unsupported sample rate!
 -     return false;
 -   }
 -   RCC_PLLI2SCmd(ENABLE);
 -   WAIT(RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY) == RESET);
 - 
 -   RCC_APB1PeriphClockCmd(CODEC_I2S_CLK, ENABLE);
 - 
 -   // Initialize I2S
 -   I2S_InitTypeDef i2s_init;
 -   
 -   SPI_I2S_DeInit(CODEC_I2S);
 -   i2s_init.I2S_AudioFreq = sample_rate;
 -   i2s_init.I2S_Standard = protocol;
 -   i2s_init.I2S_DataFormat = format;
 -   i2s_init.I2S_CPOL = I2S_CPOL_Low;
 -   i2s_init.I2S_Mode = I2S_Mode_MasterTx;
 -   i2s_init.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
 - 
 -   // Initialize the I2S main channel for TX
 -   I2S_Init(CODEC_I2S, &i2s_init);
 -   
 -   // Initialize the I2S extended channel for RX
 -   I2S_FullDuplexConfig(CODEC_I2S_EXT, &i2s_init);
 -   
 -   return true;
 - }
 - 
 - bool Codec::WriteControlRegister(uint8_t address, uint16_t data) {
 -   uint8_t byte_1 = ((address << 1) & 0xfe) | ((data >> 8) & 0x01);
 -   uint8_t byte_2 = data & 0xff;
 -   
 -   WAIT_LONG(I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BUSY));
 -   
 -   I2C_GenerateSTART(CODEC_I2C, ENABLE);
 -   WAIT(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_MODE_SELECT));
 - 
 -   I2C_Send7bitAddress(CODEC_I2C, CODEC_ADDRESS, I2C_Direction_Transmitter);
 -   WAIT(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
 - 
 -   I2C_SendData(CODEC_I2C, byte_1);
 -   WAIT(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
 - 
 -   I2C_SendData(CODEC_I2C, byte_2);
 -   WAIT(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
 - 
 -   WAIT_LONG(!I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BTF));
 - 
 -   I2C_GenerateSTOP(CODEC_I2C, ENABLE);  
 - 
 -   return true;  
 - }
 - 
 - bool Codec::InitializeCodec(
 -     uint32_t sample_rate,
 -     CodecProtocol protocol,
 -     CodecFormat format) {
 -   bool s = true;  // success;
 -   s = s && WriteControlRegister(CODEC_REG_RESET, 0);
 -   // Configure L&R inputs
 -   s = s && WriteControlRegister(CODEC_REG_LEFT_LINE_IN, CODEC_INPUT_0_DB);
 -   s = s && WriteControlRegister(CODEC_REG_RIGHT_LINE_IN, CODEC_INPUT_0_DB);
 -   
 -   // Configure L&R headphone outputs
 -   s = s && WriteControlRegister(CODEC_REG_LEFT_HEADPHONES_OUT, CODEC_HEADPHONES_MUTE);
 -   s = s && WriteControlRegister(CODEC_REG_RIGHT_HEADPHONES_OUT, CODEC_HEADPHONES_MUTE);
 - 
 -   // Configure analog routing
 -   s = s && WriteControlRegister(
 -       CODEC_REG_ANALOGUE_ROUTING,
 -       CODEC_MIC_MUTE | CODEC_ADC_LINE | CODEC_OUTPUT_DAC_ENABLE);
 - 
 -   // Configure digital routing
 -   s = s && WriteControlRegister(CODEC_REG_DIGITAL_ROUTING, CODEC_DEEMPHASIS_NONE);
 - 
 -   // Configure power management
 -   s = s && WriteControlRegister(
 -       CODEC_REG_POWER_MANAGEMENT,
 -       CODEC_POWER_DOWN_OSCILLATOR | \
 -         CODEC_POWER_DOWN_CLOCK_OUTPUT | \
 -         CODEC_POWER_DOWN_MIC);
 -   
 -   uint8_t format_byte = CODEC_FORMAT_SLAVE;
 -   if (protocol == CODEC_PROTOCOL_PHILIPS) {
 -     format_byte |= CODEC_PROTOCOL_MASK_PHILIPS;
 -   } else if (protocol == CODEC_PROTOCOL_MSB_FIRST) {
 -     format_byte |= CODEC_PROTOCOL_MASK_MSB_FIRST;
 -   } else if (protocol == CODEC_PROTOCOL_LSB_FIRST) {
 -     format_byte |= CODEC_PROTOCOL_MASK_LSB_FIRST;
 -   }
 -   
 -   if (format == CODEC_FORMAT_16_BIT) {
 -     format_byte |= CODEC_FORMAT_MASK_16_BIT;
 -   } else if (format == CODEC_FORMAT_24_BIT) {
 -     format_byte |= CODEC_FORMAT_MASK_24_BIT;
 -   } else if (format == CODEC_FORMAT_32_BIT) {
 -     format_byte |= CODEC_FORMAT_MASK_32_BIT;
 -   }
 -   s = s && WriteControlRegister(CODEC_REG_DIGITAL_FORMAT, format_byte);
 -   
 -   uint8_t rate_byte = 0;
 -   // According to the WM8731 datasheet, the 32kHz and 96kHz modes require the
 -   // master clock to be at 12.288 MHz (384 fs / 128 fs). The STM32F4 I2S clock
 -   // is always at 256 fs. So the 32kHz and 96kHz modes are achieved by
 -   // pretending that we are doing 48kHz, but with a slower or faster master
 -   // clock.
 -   rate_byte = sample_rate == 44100 ? CODEC_RATE_44K_44K : CODEC_RATE_48K_48K;
 -   s = s && WriteControlRegister(CODEC_REG_SAMPLE_RATE, rate_byte);
 - 
 -   // For now codec is not active.
 -   s = s && WriteControlRegister(CODEC_REG_ACTIVE, 0x00);
 -   
 -   return s;
 - }
 - 
 - bool Codec::InitializeDMA() {
 -   RCC_AHB1PeriphClockCmd(AUDIO_I2S_DMA_CLOCK, ENABLE);
 - 
 -   // DMA setup for TX.
 -   DMA_Cmd(AUDIO_I2S_DMA_STREAM, DISABLE);
 -   DMA_DeInit(AUDIO_I2S_DMA_STREAM);
 - 
 -   dma_init_tx_.DMA_Channel = AUDIO_I2S_DMA_CHANNEL;
 -   dma_init_tx_.DMA_PeripheralBaseAddr = AUDIO_I2S_DMA_DREG;
 -   dma_init_tx_.DMA_Memory0BaseAddr = (uint32_t)0;
 -   dma_init_tx_.DMA_DIR = DMA_DIR_MemoryToPeripheral;
 -   dma_init_tx_.DMA_BufferSize = (uint32_t)0xFFFE;
 -   dma_init_tx_.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
 -   dma_init_tx_.DMA_MemoryInc = DMA_MemoryInc_Enable;
 -   dma_init_tx_.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
 -   dma_init_tx_.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
 -   dma_init_tx_.DMA_Mode = DMA_Mode_Circular;
 -   dma_init_tx_.DMA_Priority = DMA_Priority_High;
 -   dma_init_tx_.DMA_FIFOMode = DMA_FIFOMode_Disable;
 -   dma_init_tx_.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
 -   dma_init_tx_.DMA_MemoryBurst = DMA_MemoryBurst_Single;
 -   dma_init_tx_.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
 -   DMA_Init(AUDIO_I2S_DMA_STREAM, &dma_init_tx_);
 - 
 -   // DMA setup for RX.
 -   DMA_Cmd(AUDIO_I2S_EXT_DMA_STREAM, DISABLE);
 -   DMA_DeInit(AUDIO_I2S_EXT_DMA_STREAM);
 - 
 -   dma_init_rx_.DMA_Channel = AUDIO_I2S_EXT_DMA_CHANNEL;  
 -   dma_init_rx_.DMA_PeripheralBaseAddr = AUDIO_I2S_EXT_DMA_DREG;
 -   dma_init_rx_.DMA_Memory0BaseAddr = (uint32_t)0;
 -   dma_init_rx_.DMA_DIR = DMA_DIR_PeripheralToMemory;
 -   dma_init_rx_.DMA_BufferSize = (uint32_t)0xFFFE;
 -   dma_init_rx_.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
 -   dma_init_rx_.DMA_MemoryInc = DMA_MemoryInc_Enable;
 -   dma_init_rx_.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
 -   dma_init_rx_.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 
 -   dma_init_rx_.DMA_Mode = DMA_Mode_Circular;
 -   dma_init_rx_.DMA_Priority = DMA_Priority_High;
 -   dma_init_rx_.DMA_FIFOMode = DMA_FIFOMode_Disable;         
 -   dma_init_rx_.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
 -   dma_init_rx_.DMA_MemoryBurst = DMA_MemoryBurst_Single;
 -   dma_init_rx_.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;  
 -   DMA_Init(AUDIO_I2S_EXT_DMA_STREAM, &dma_init_rx_);  
 - 
 -   // Enable the interrupts.
 -   DMA_ITConfig(AUDIO_I2S_EXT_DMA_STREAM, DMA_IT_TC | DMA_IT_HT, ENABLE);
 -     
 -   // Enable the IRQ.
 -   NVIC_EnableIRQ(AUDIO_I2S_EXT_DMA_IRQ);
 - 
 -   // Start DMA from/to codec.
 -   SPI_I2S_DMACmd(CODEC_I2S, SPI_I2S_DMAReq_Tx, ENABLE);
 -   SPI_I2S_DMACmd(CODEC_I2S_EXT, SPI_I2S_DMAReq_Rx, ENABLE);
 -   
 -   return true;
 - }
 - 
 - bool Codec::Init(
 -     uint32_t sample_rate,
 -     CodecProtocol protocol,
 -     CodecFormat format) {
 -   rx_buffer_.Init();
 -   tx_buffer_.Init();
 - 
 -   Frame s;
 -   s.l = s.r = 0;
 - 
 -   for (size_t i = 0; i < rx_buffer_.capacity() >> 1; ++i) {
 -     rx_buffer_.Overwrite(s);
 -     tx_buffer_.Overwrite(s);
 -   }
 - 
 -   instance_ = this;
 -   callback_ = NULL;
 - 
 -   return InitializeGPIO() && \
 -       InitializeControlInterface() && \
 -       InitializeAudioInterface(sample_rate, protocol, format) && \
 -       InitializeCodec(sample_rate, protocol, format) && \
 -       InitializeDMA();
 - }
 - 
 - bool Codec::Start(FillBufferCallback callback) {
 -   // Start the codec.
 -   if (!WriteControlRegister(CODEC_REG_ACTIVE, 0x01)) {
 -     return false;
 -   }
 -   callback_ = callback;
 -   client_tx_ = NULL;
 -   client_rx_ = NULL;
 -   transmitted_ = 0;
 -   processed_ = 0;
 -   
 -   // Enable the I2S TX and RX peripherals.
 -   if ((CODEC_I2S->I2SCFGR & 0x0400) == 0){
 -     I2S_Cmd(CODEC_I2S, ENABLE);
 -   }
 -   if ((CODEC_I2S_EXT->I2SCFGR & 0x0400) == 0){
 -     I2S_Cmd(CODEC_I2S_EXT, ENABLE);
 -   }
 -   
 -   dma_init_tx_.DMA_Memory0BaseAddr = (uint32_t)(tx_dma_buffer_);
 -   dma_init_rx_.DMA_Memory0BaseAddr = (uint32_t)(rx_dma_buffer_);
 - 
 -   dma_init_tx_.DMA_BufferSize = kAudioChunkSize * 2 * 2;
 -   dma_init_rx_.DMA_BufferSize = kAudioChunkSize * 2 * 2;
 -   
 -   DMA_Init(AUDIO_I2S_DMA_STREAM, &dma_init_tx_);
 -   DMA_Init(AUDIO_I2S_EXT_DMA_STREAM, &dma_init_rx_);
 -   DMA_Cmd(AUDIO_I2S_DMA_STREAM, ENABLE);
 -   DMA_Cmd(AUDIO_I2S_EXT_DMA_STREAM, ENABLE);
 -   
 -   return true;
 - }
 - 
 - void Codec::Stop() {
 -   DMA_Cmd(AUDIO_I2S_DMA_STREAM, DISABLE);
 -   DMA_Cmd(AUDIO_I2S_EXT_DMA_STREAM, DISABLE);
 - }
 - 
 - void Codec::Fill(size_t offset) {
 -   if (kNumFIFOChunks) {
 -     // Write input samples to FIFO, Read output samples from FIFO
 -     rx_buffer_.Overwrite(&rx_dma_buffer_[offset], kAudioChunkSize);
 -     tx_buffer_.ImmediateRead(&tx_dma_buffer_[offset], kAudioChunkSize);
 -   } else if (callback_) {
 -     (*callback_)(
 -         &rx_dma_buffer_[offset],
 -         &tx_dma_buffer_[offset],
 -         kAudioChunkSize);
 -   } else {
 -     // Inform the client that some data is ready, and store pointers to the
 -     // valid section of the ring buffer.
 -     ++transmitted_;
 -     client_rx_ = &rx_dma_buffer_[offset];
 -     client_tx_ = &tx_dma_buffer_[offset];
 -   }
 - }
 - 
 - }  // namespace elements
 - 
 - extern "C" {
 - // Do not call into the firmware library to save on calls/jumps.
 - // if (DMA_GetFlagStatus(AUDIO_I2S_EXT_DMA_STREAM, AUDIO_I2S_EXT_DMA_FLAG_TC) != RESET) {
 - //  DMA_ClearFlag(AUDIO_I2S_EXT_DMA_STREAM, AUDIO_I2S_EXT_DMA_FLAG_TC);  
 - 
 - void DMA1_Stream3_IRQHandler(void) {
 -   if (AUDIO_I2S_EXT_DMA_REG->AUDIO_I2S_EXT_DMA_ISR & AUDIO_I2S_EXT_DMA_FLAG_TC) {
 -     AUDIO_I2S_EXT_DMA_REG->AUDIO_I2S_EXT_DMA_IFCR = AUDIO_I2S_EXT_DMA_FLAG_TC;
 -     elements::Codec::GetInstance()->Fill(elements::kAudioChunkSize);
 -   }
 -   if (AUDIO_I2S_EXT_DMA_REG->AUDIO_I2S_EXT_DMA_ISR & AUDIO_I2S_EXT_DMA_FLAG_HT) {
 -     AUDIO_I2S_EXT_DMA_REG->AUDIO_I2S_EXT_DMA_IFCR = AUDIO_I2S_EXT_DMA_FLAG_HT;
 -     elements::Codec::GetInstance()->Fill(0);
 -   }
 - }
 -   
 - }
 
 
  |