AnsweredAssumed Answered

STM32F4 Discovery with onboard CS43L22 MP45DT02 problem

Question asked by jasonas.matas on Jul 15, 2015
Hey everybody, it has been a while i've been working on it. The idea is to take the sound from the MEMS mic and play it through the DAC. I've been looking at all the examples I could find, but still not working. It is just ouputing a ~926Hz pulses (which match the Master clock of DAC don't know why.) The full program is here:

  
  #include <stdint.h>
  #include "stm32f4xx.h"
  #include "stm32f4xx_rcc.h"
  #include "stm32f4xx_gpio.h"
  #include "stm32f4xx_spi.h"
  #include "pdm_filter.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;
  
/* VARIABLES -----------------------------------------------------------------*/


  uint8_t mic_in_buf[MIC_IN_BUF_SIZE];
  uint16_t mic_out_buf[MIC_OUT_BUF_SIZE];
  uint32_t mic_buf_index = 0;


  int16_t sample = 0;
  int counter = 0;




/* FUNCTIONS -----------------------------------------------------------------*/
  
  void mp45dt02_start();
  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);
    
/* MAIN PROGRAM --------------------------------------------------------------*/    
int main()
{
  SystemInit();
  Init_PDMFilter();
  Init_GPIO();
  Init_NVIC();
  Init_I2S();
  Init_I2C();
  laodCodecSettings();
  I2S_Cmd(SPI3, ENABLE);
  mp45dt02_start();
  
  while(1);
}


/* MEMS DIGITAL MICROPHONE ---------------------------------------------------*/


// a very crude FIR lowpass filter




void Init_NVIC(){
  
    // NVIC CONFIGURATION
  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
  NVIC_InitStruct.NVIC_IRQChannel = SPI2_IRQn;
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
  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=8000;
  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(){
        
  // I2S2 config for MEMS Mic
  SPI_I2S_DeInit(SPI2);
  I2S_InitStruct.I2S_AudioFreq=I2S_CLK;
  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);


   
  //I2S3 config for DAC
  SPI_I2S_DeInit(SPI3);
  I2S_InitStruct.I2S_AudioFreq = I2S_CLK;
  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 ...
    
}


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(){
  
  GPIO_StructInit(&GPIO_InitStruct);
   
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2 | RCC_APB1Periph_I2C1 | RCC_APB1Periph_SPI3, ENABLE);
  RCC_PLLI2SCmd(ENABLE);
  while(!RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY));
  
  
  
  // 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);
  
  
   // 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_DOWN; 
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 
   
  GPIO_Init(GPIOD, &GPIO_InitStruct);


  
  TurnOffDAC(); // KEEP DAC OFF (Parameters not yet set)


  //I2C-------------------------------------------------------------------------
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOA| RCC_AHB1Periph_GPIOB, ENABLE);
  
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);


  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);
  
  
  
  
  // 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_50MHz;
  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
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; 
  GPIO_Init(GPIOA, &GPIO_InitStruct);
  
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI3);
 
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
  
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
  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);
  
}


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


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


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


void SPI2_IRQHandler(){
        
        if((SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE)) && (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE))){
            
           sample=SPI_I2S_ReceiveData(SPI2);


            
            
            mic_in_buf[mic_buf_index++]=HTONS(sample);
            
            if(mic_buf_index >= MIC_IN_BUF_SIZE){
                    mic_buf_index=0;
                    
                    PDM_Filter_64_LSB((uint8_t *)mic_in_buf, mic_out_buf, 50, &PDM_InitStruct);
                     
                    uint32_t i;
                    for(i=0; i<MIC_OUT_BUF_SIZE; i++){
                      SPI_I2S_SendData(SPI3, mic_out_buf[i]);
                    }
            }
                
          counter++;
          if(counter == 64000){
            
            GPIO_ResetBits(GPIOD, GPIO_Pin_15);
            counter = 0;
            
          }else if(counter == 32000){
          
            GPIO_SetBits(GPIOD, GPIO_Pin_15);
          
          }
          
            SPI_I2S_ClearITPendingBit(SPI2, SPI_I2S_IT_RXNE);
            SPI_I2S_ClearITPendingBit(SPI3, SPI_I2S_IT_TXE);
  
          }
        
}


/* 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];


     uint8_t regValue = 0xFF;


     GPIO_SetBits(GPIOD, GPIO_Pin_4);


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


     //begin initialization sequence (p. 32)
     CodecCommandBuffer[0] = 0x00;
     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
      
        /* Enable the PassThrough on AIN1A and AIN1B */
       
        CodecCommandBuffer[0] = 0x08;
     CodecCommandBuffer[1] = 0x01;
     sendDac(CodecCommandBuffer, 2);
        
        CodecCommandBuffer[0] = 0x09;
     CodecCommandBuffer[1] = 0x01;
     sendDac(CodecCommandBuffer, 2);        
        
        /* Set the Passthough volume */
    
        CodecCommandBuffer[0] = 0x14;
     CodecCommandBuffer[1] = 0x00;
     sendDac(CodecCommandBuffer, 2);
        
        CodecCommandBuffer[0] = 0x15;
     CodecCommandBuffer[1] = 0x00;
     sendDac(CodecCommandBuffer, 2);
        
        
     CodecCommandBuffer[0] = 0x04;
     CodecCommandBuffer[1] = 0xAF;
     sendDac(CodecCommandBuffer, 2);


     /*CodecCommandBuffer[0] = 0x0D;
     CodecCommandBuffer[1] = 0x70;
     sendDac(CodecCommandBuffer, 2);*/


     CodecCommandBuffer[0] = 0x05;
     CodecCommandBuffer[1] = 0x81; //auto detect clock
     sendDac(CodecCommandBuffer, 2);


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


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


     CodecCommandBuffer[0] = 0x1A | 0x1B;
     CodecCommandBuffer[1] = 0x0A;
     CodecCommandBuffer[2] = 0x0A;
     sendDac(CodecCommandBuffer, 3);


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


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


}








/* 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;
}



It should work as this:
*configure MIC and DAC (I2S2 and I2S3)
*run interrupt of I2S2 RXNE (as soon the buffer gets the data)
*filter it with PDM filter and output it to the DAC.

If you have any info you are welcome to post it :)

Outcomes