AnsweredAssumed Answered

Audio stream STM32F4 disco

Question asked by jasonas.matas on Aug 24, 2015
Latest reply on Aug 24, 2015 by jasonas.matas
I've been stuck on this for weeks. I just can't correctly stream audio from on board MEMS mic to on board audio DAC cs43l22. Although DAC alone works (tried it with a sine array). If I retrieve 0x2E from audio DAC it keeps jumping beatween 0x00 (OK) and 0xC0 (Invalid MCLK/LRCK ratio).  Here is my code and it should work quite simply:

*If MEMS mic buffer is not empy
*Jumps to interrupt, starts filling the array
*If array full, start converting to PCM and set the Dataset flag to 1
*(In the main program) If Dataset flag is set, switch the microphone ouput pointer to array number 2, so the Mems mic could start filling up the next array and would'nt change the current values.
*(In the main program) Start sending values to the Audio DAC one by one, after each cheking if the TXE flag is ready.
*Process repeats..

The DAC settings are set after full initialization sequence:
*Frequency is set to AUTO DETECT
*The speakers always disabled and headphones always enabled
*DAC interface I2S up to 24-bit
*Analog inputs all disabled
*HP/Speaker De-Emphasis enabled
*Maximum threshold below full scale 0dB (Not lowered)
*Tone control is 0dB for treble and bass.

And I can't use analog passthrough, because I will later build up on this program to modify the incoming values.
  
  #include "stdint.h"
  #include "stdlib.h"
  #include "stm32f4xx.h"
  #include "stm32f4xx_rcc.h"
  #include "stm32f4xx_gpio.h"
  #include "stm32f4xx_spi.h"
  #include "pdm_filter.h"
  #include <stdbool.h>




/* DEFINES -------------------------------------------------------------------*/


  //sampling frequency
  #define FS 16000


  //PDM decimation factor
  #define DECIMATION 64


  //NUMBER OF MICROPHONE CHANNELS 
  #define MIC_CHANNELS 1


  //clock for mic
  #define I2S_CLK ((FS*DECIMATION)/(16*2))


  //uint8_t array length for filter input buffer
  #define MIC_IN_BUF_SIZE (((FS/1000)*DECIMATION)*MIC_CHANNELS/8/2)


  //uint16_t array length for filter output buffer
  #define MIC_OUT_BUF_SIZE ((FS/1000)*MIC_CHANNELS)


  // I2C1 for DAC  
  #define CODEC_I2C I2C1


/* STRUCTURES ----------------------------------------------------------------*/


  PDMFilter_InitStruct PDM_InitStruct;
  GPIO_InitTypeDef GPIO_InitStruct; 
  NVIC_InitTypeDef NVIC_InitStruct;
  I2S_InitTypeDef I2S_InitStruct;
  I2C_InitTypeDef I2C_InitStruct;
  DMA_InitTypeDef DMA_InitStructure; 
  
/* VARIABLES -----------------------------------------------------------------*/
  bool set = true;
  uint8_t DataSet = 0;
  uint8_t switcher = 0;
  uint8_t mic_buf_index = 0;
  uint8_t mic_in_buf[MIC_IN_BUF_SIZE];
  uint16_t* recBuffer;
  uint16_t* DacBuffer;
  uint16_t mic_out_buf1[MIC_OUT_BUF_SIZE];
  uint16_t mic_out_buf2[MIC_OUT_BUF_SIZE];
  uint16_t DAC_in_buf[MIC_OUT_BUF_SIZE];
  int16_t DAC_in_buf_converted[MIC_OUT_BUF_SIZE];
  uint32_t sample = 0;
  int counter = 0;
  uint16_t bufcntr = 0;
  uint8_t regValue = 0xFF;


  RCC_ClocksTypeDef RCC_Clocks;
/* FUNCTIONS -----------------------------------------------------------------*/
  
  void MemsInterruptStart();
  void TurnOnDAC();
  void TurnOffDAC();
  void Init_NVIC();
  void delayCycles(int i);
  void sendDac(uint8_t controlBytes[], uint8_t numBytes);
  void Init_GPIO();
  void laodCodecSettings();
  void Init_PDMFilter();
  void Init_I2C();
  void Init_I2S();
  uint8_t read_codec_register(uint8_t mapbyte);
  void InitRCC();
  
    
/* MAIN PROGRAM --------------------------------------------------------------*/    
int main(){
  
  SystemInit();
  InitRCC();
  Init_PDMFilter();
  Init_GPIO();
  
  TurnOffDAC(); // KEEP DAC OFF (Parameters not yet set)
  delayCycles(20479);
  TurnOnDAC();
  
  Init_I2C();
  laodCodecSettings();
  
  Init_I2S();
  I2S_Cmd(SPI3, ENABLE);
  Init_NVIC();
 // I2C_Cmd(I2C1, DISABLE);
  
  
  MemsInterruptStart();
  while(1){
    if(DataSet == 1){
      
      if(switcher == 1){
      
        recBuffer = mic_out_buf1;
        DacBuffer = &mic_out_buf2[0];
        switcher = 0;
      }else{
      
        recBuffer = mic_out_buf2;
        DacBuffer = &mic_out_buf1[0];
        switcher = 1;
      }
      DataSet = 0;
      for(counter = 0; counter < 16; counter++){
        DAC_in_buf_converted[counter] = (int16_t)(*(DacBuffer + counter) - 32767);
          
        SPI_I2S_SendData(SPI3,  DAC_in_buf_converted[counter]);
        while (SPI_I2S_GetFlagStatus(SPI3, SPI_FLAG_TXE) == RESET);
        SPI_I2S_SendData(SPI3,  DAC_in_buf_converted[counter]);
        while (SPI_I2S_GetFlagStatus(SPI3, SPI_FLAG_TXE) == RESET);
      }
     regValue = read_codec_register(0x2E);
    }
      
  }
  
}


/* MEMS DIGITAL MICROPHONE ---------------------------------------------------*/
void InitRCC(){
  RCC_DeInit();
   
  ErrorStatus ErrorSt;
  RCC_HSEConfig(RCC_HSE_ON);
  ErrorSt = RCC_WaitForHSEStartUp();
  
  if(ErrorSt){
    
    RCC_PLLConfig(RCC_PLLSource_HSE, 8, 336, 2, 7);
    RCC_PLLCmd(ENABLE);
    RCC_GetFlagStatus(RCC_FLAG_PLLRDY == RESET);
    
    // Set flash latency
    FLASH_SetLatency(FLASH_Latency_5);
    
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
    RCC_PCLK1Config(RCC_HCLK_Div4);
    RCC_PCLK2Config(RCC_HCLK_Div2);
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    
    RCC_PLLI2SCmd(DISABLE);
    RCC_I2SCLKConfig(RCC_I2S2CLKSource_PLLI2S);
    RCC_PLLI2SConfig(258, 3);  
    RCC_PLLI2SCmd(ENABLE);
    RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY == RESET);
    RCC_GetClocksFreq(&RCC_Clocks);
  }else{
    return(ErrorSt);
  }
  
}
 
void Init_NVIC(){
  
    // NVIC CONFIGURATION
  // MEMS
  NVIC_InitStruct.NVIC_IRQChannel = SPI2_IRQn;
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStruct);
 
}

void Init_PDMFilter(){

    // CONFIGURE FILTER PARAMETERS
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
  
  PDM_InitStruct.LP_HZ=FS/2;
  PDM_InitStruct.HP_HZ=10;
  PDM_InitStruct.Fs=FS;
  PDM_InitStruct.Out_MicChannels=1;
  PDM_InitStruct.In_MicChannels=1;
  PDM_Filter_Init(&PDM_InitStruct);


}


void Init_I2S(){
      
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2 | RCC_APB1Periph_SPI3, ENABLE);
   
    //I2S3 config for DAC
  SPI_I2S_DeInit(SPI3);
  I2S_InitStruct.I2S_AudioFreq = 8000; /* 32kHz */
  I2S_InitStruct.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
  I2S_InitStruct.I2S_Mode = I2S_Mode_MasterTx;
  I2S_InitStruct.I2S_DataFormat = I2S_DataFormat_16b;
  I2S_InitStruct.I2S_Standard = I2S_Standard_Phillips;
  I2S_InitStruct.I2S_CPOL = I2S_CPOL_Low;
   
  I2S_Init(SPI3, &I2S_InitStruct); //initialize the I2S peripheral ...


   // I2S2 config for MEMS Mic
  SPI_I2S_DeInit(SPI2);
  I2S_InitStruct.I2S_AudioFreq = I2S_CLK;  /* 32kHz */
  I2S_InitStruct.I2S_Standard=I2S_Standard_LSB;
  I2S_InitStruct.I2S_DataFormat=I2S_DataFormat_16b;
  I2S_InitStruct.I2S_CPOL=I2S_CPOL_High;
  I2S_InitStruct.I2S_Mode=I2S_Mode_MasterRx;
  I2S_InitStruct.I2S_MCLKOutput=I2S_MCLKOutput_Disable;
  I2S_Init(SPI2, &I2S_InitStruct);
  
  I2S_Cmd(SPI2, ENABLE);




}


void Init_I2C(){
   
  // I2C config
  I2C_DeInit(I2C1);
  I2C_InitStruct.I2C_ClockSpeed = 100000;
  I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
  I2C_InitStruct.I2C_OwnAddress1 = 0x33;
  I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
  I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
  
  I2C_Cmd(I2C1, ENABLE); 
  I2C_Init(I2C1, &I2C_InitStruct);   //initialize the I2C peripheral ...
    
}


void Init_GPIO(){
  //RCC_ClocksTypeDef RCC_Clocks;
  GPIO_StructInit(&GPIO_InitStruct);
    
    // MP45DT02 CLK-PB10


  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
  GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStruct);
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_SPI2);


  // MP45DT02 DOUT-PC3
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
  
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_3;
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
  GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_Init(GPIOC, &GPIO_InitStruct);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource3, GPIO_AF_SPI2);
  
  
  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1 | RCC_APB1Periph_SPI3, ENABLE);
    
   // CONFIGURE GPIO FOR DAC CS43L22 (TO GET THE SAME CLOCK)
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
 
  //RESET
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; 
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; 
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; 
  GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_NOPULL;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 
   
  GPIO_Init(GPIOD, &GPIO_InitStruct); 
  
  //I2C-------------------------------------------------------------------------
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOA| RCC_AHB1Periph_GPIOB, ENABLE);
  
 


  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_9; //I2C SCL and SDA pins
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; 
  GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; 
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; 
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 
  
  GPIO_Init(GPIOB, &GPIO_InitStruct);
  
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);
  
  
  
  // I2S PC10- IS3_CK; PC7- I2S3_MCK; PC12- I2S3_SD
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);


  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_7 | GPIO_Pin_12; 
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
  GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_100MHz;
  GPIO_Init(GPIOC, &GPIO_InitStruct);
   
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_SPI3);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SPI3);
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SPI3);
  
  // I2S PA4- IS3_WS
  
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; 
  GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI3);
   
}


/* START MEMS MIC ------------------------------------------------------------*/

void MemsInterruptStart(){
        /* Enable the Rx buffer not empty interrupt */
      SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);
}

/* MEMS INTERRUPT ------------------------------------------------------------*/


void SPI2_IRQHandler(){     
  uint16_t sample;
 if( SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)  != RESET){
  
    sample = SPI_I2S_ReceiveData(SPI2);
    mic_in_buf[mic_buf_index++] = HTONS(sample);



    if(mic_buf_index >= MIC_IN_BUF_SIZE){

      DataSet = 1;
      
      mic_buf_index=0;
      
      PDM_Filter_64_LSB((uint8_t *)mic_in_buf, (uint16_t *)recBuffer, 50, (PDMFilter_InitStruct *)&PDM_InitStruct);     
    
    }
    
  }
        
}


/* DAC ON/ DAC OFF FUNCTIONS -------------------------------------------------*/


void TurnOnDAC(){


  GPIO_SetBits(GPIOD, GPIO_Pin_4);
  
}


void TurnOffDAC(){


  GPIO_ResetBits(GPIOD, GPIO_Pin_4);


}


/* DAC CONTROL SETTINGS ------------------------------------------------------*/




void laodCodecSettings()
{
     uint8_t CodecCommandBuffer[5];


     
     


     delayCycles(5000000);
        
     //keep codec OFF
     CodecCommandBuffer[0] = 0x02;
     CodecCommandBuffer[1] = 0x01;
     sendDac(CodecCommandBuffer, 2);


        
        
        CodecCommandBuffer[1] = 0x99;
     sendDac(CodecCommandBuffer, 2);


     CodecCommandBuffer[0] = 0x47;
     CodecCommandBuffer[1] = 0x80;
     sendDac(CodecCommandBuffer, 2);


     regValue = read_codec_register(0x32);


     CodecCommandBuffer[0] = 0x32;
     CodecCommandBuffer[1] = regValue | 0x80;
     sendDac(CodecCommandBuffer, 2);


     regValue = read_codec_register(0x32);


     CodecCommandBuffer[0] = 0x32;
     CodecCommandBuffer[1] = regValue & (~0x80);
     sendDac(CodecCommandBuffer, 2);


     CodecCommandBuffer[0] = 0x00;
     CodecCommandBuffer[1] = 0x00;
     sendDac(CodecCommandBuffer, 2);
     //end of initialization sequence
        
        
        
        CodecCommandBuffer[0] = 0x04;
     CodecCommandBuffer[1] = 0xAF;
     sendDac(CodecCommandBuffer, 2);
        
        CodecCommandBuffer[0] = 0x05;
     CodecCommandBuffer[1] = 0x80; //auto detect clock//
     sendDac(CodecCommandBuffer, 2);
        
        CodecCommandBuffer[0] = 0x06;
     CodecCommandBuffer[1] = 0x04;
     sendDac(CodecCommandBuffer, 2);


        
        CodecCommandBuffer[0] = 0x09;
     CodecCommandBuffer[1] = 0x00;
     sendDac(CodecCommandBuffer, 2);
        
        CodecCommandBuffer[0] = 0x08;
     CodecCommandBuffer[1] = 0x00;
     sendDac(CodecCommandBuffer, 2);
                                  
        CodecCommandBuffer[0] = 0x0A;
     CodecCommandBuffer[1] = 0x00;
     sendDac(CodecCommandBuffer, 2);
        
        
        CodecCommandBuffer[0] = 0x0E;
     CodecCommandBuffer[1] = 0x04;
     sendDac(CodecCommandBuffer, 2);
        


        
        CodecCommandBuffer[0] = 0x27;
     CodecCommandBuffer[1] = 0x00;
     sendDac(CodecCommandBuffer, 2);


        CodecCommandBuffer[0] = 0x1F;
     CodecCommandBuffer[1] = 0x0F;
     sendDac(CodecCommandBuffer, 2);
        


        
        
        CodecCommandBuffer[0] = 0x1A;
     CodecCommandBuffer[1] = 0x02;
     sendDac(CodecCommandBuffer, 2);
        
        CodecCommandBuffer[0] = 0x1B;
     CodecCommandBuffer[1] = 0x02;
     sendDac(CodecCommandBuffer, 2);
        


        CodecCommandBuffer[0] = 0x02;
     CodecCommandBuffer[1] = 0x9E;
     sendDac(CodecCommandBuffer, 2);
     
      
        /* Enable the PassThrough on AIN1A and AIN1B */
       




}








/* I2C SEND TO DAC -----------------------------------------------------------*/


void sendDac(uint8_t controlBytes[], uint8_t numBytes){
  
  uint8_t bytesSent = 0;
  
  // check if busy
  while (I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BUSY)); 
  
  // send START signal
  I2C_GenerateSTART(CODEC_I2C, ENABLE);
  while (!I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_SB)); 
  
  // set as transmitter
  I2C_Send7bitAddress(CODEC_I2C, 0x94, I2C_Direction_Transmitter);
  while (!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
  
  for(bytesSent = 0; bytesSent < numBytes; bytesSent++){
    
    I2C_SendData(CODEC_I2C, controlBytes[bytesSent]);
    while (!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
    
  }
  
  // Check if last byte is sent
  while(!I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BTF));
  
  // send STOP signal
  I2C_GenerateSTOP(CODEC_I2C, ENABLE);
  
  // check if STOP signal has been sent
  while(I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF));
  
}


void delayCycles(int delay){
  int i = 0;
  for(i = 0; i < delay; i++);
}










uint8_t read_codec_register(uint8_t mapbyte)
{
     uint8_t receivedByte = 0;


     while (I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BUSY))
     {
          //just wait until no longer busy
     }


     I2C_GenerateSTART(CODEC_I2C, ENABLE);
     while (!I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_SB))
     {
          //wait for generation of start condition
     }


     I2C_Send7bitAddress(CODEC_I2C, 0x94, I2C_Direction_Transmitter);
     while (!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
     {
          //wait for end of address transmission
     }


     I2C_SendData(CODEC_I2C, mapbyte); //sets the transmitter address
     while (!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
     {
          //wait for transmission of byte
     }


     I2C_GenerateSTOP(CODEC_I2C, ENABLE);


     while (I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BUSY))
     {
          //just wait until no longer busy
     }


     I2C_AcknowledgeConfig(CODEC_I2C, DISABLE);


     I2C_GenerateSTART(CODEC_I2C, ENABLE);
     while (!I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_SB))
     {
          //wait for generation of start condition
     }


     I2C_Send7bitAddress(CODEC_I2C, 0x94, I2C_Direction_Receiver);
     while (!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
     {
          //wait for end of address transmission
     }


     while (!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_BYTE_RECEIVED))
     {
          //wait until byte arrived
     }
     receivedByte = I2C_ReceiveData(CODEC_I2C);


     I2C_GenerateSTOP(CODEC_I2C, ENABLE);


     return receivedByte;
}






Outcomes