AnsweredAssumed Answered

STM32F446 Configured SAI module plays noise instead of proper sound

Question asked by woloszyn.rafal.001 on Nov 2, 2016
Latest reply on Nov 3, 2016 by waclawek.jan
Hi all,
I have system which reads file from SD card using SDIO and sends it via SAI interface SA1 channel A to DSP processor ADAU1442. The problem is that when I read file data and try to send it to DSP processor I get noise. ADAU is configured (programmer properly) since I tested it's configuration with different SAI module. 
I belive I have some wrong configuration.

Required audio sampling frequency: 192kHz,

Is there any good way to verify that SAI is working correclty, and correct data is send throught it ? I tested with osciloscope and it seems that BCLK and MCLK clock looks correctly. Also on GPIO pin with SD (SAI data) ther are some pulses generated.


Here is SAI and SAI GPIO config

void Initalize_SAI(uint32_t AudioFreq)
{
  uint32_t tmpdiv;
   
  SAI_InitTypeDef       SAI_InitStructure;
  SAI_FrameInitTypeDef  SAI_FrameInitStructure;
  SAI_SlotInitTypeDef   SAI_SlotInitStructure;
    GPIO_InitTypeDef      GPIO_InitStructure;
  
     
     
    /*CODEC_SAI SD MCLK SCK and FS pins configuration --------------------------------*/
   
      /* Enable SAI and I2C GPIO clocks */
  RCC_AHB1PeriphClockCmd(CODEC_SAI_GPIO_CLOCK, ENABLE);
     
  /* SAI1_Block_A Pins configuration  *****************************************/
//     /* Configure pins as AF pushpull */
//   GPIO_InitStructure.GPIO_Pin = CODEC_SAI_MCK_PIN;
//   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
//   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
//   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
//   GPIO_Init(CODEC_SAI_GPIO, &GPIO_InitStructure);
   
  /* Configure pins as AF pushpull */
    /*FS*/
  GPIO_InitStructure.GPIO_Pin = CODEC_SAI_FS_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(CODEC_SAI_GPIO_FS, &GPIO_InitStructure);
     
        /*SD*/
  GPIO_InitStructure.GPIO_Pin = CODEC_SAI_SD_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(CODEC_SAI_GPIO_SD, &GPIO_InitStructure);
     
        /*SCK*/
  GPIO_InitStructure.GPIO_Pin = CODEC_SAI_SCK_PIN ;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(CODEC_SAI_GPIO_SCK, &GPIO_InitStructure);
     
     /* Connect pin to Periph */
    /* Configuration SAI1_BLockA_SD Alternate */
    GPIO_PinAFConfig(CODEC_SAI_GPIO_SD, CODEC_SAI_SD_PINSRC, GPIO_AF_SAI1);
    //   /* Configuration SAI1_BLockA_MCLK Alternate */
    //   GPIO_PinAFConfig(CODEC_SAI_GPIO_MCK, CODEC_SAI_MCK_PINSRC, GPIO_AF_SAI1); 
    /* Configuration SAI1_BLockB_SCK Alternate */ 
    GPIO_PinAFConfig(CODEC_SAI_GPIO_SCK, CODEC_SAI_SCK_PINSRC, GPIO_AF_SAI1);
    /* Configuration SAI1_BLockB_FS Alternate */ 
    GPIO_PinAFConfig(CODEC_SAI_GPIO_FS, CODEC_SAI_FS_PINSRC, GPIO_AF_SAI1);
     
     
  /* Enable the CODEC_SAI peripheral clock */
  RCC_APB2PeriphClockCmd(CODEC_SAI_CLK, ENABLE);
    
  /* Configure Master Clock using the following formula :
  MCLK_x = SAI_CK_x / (MCKDIV[3:0] * 2) with MCLK_x = 256 * FS
  FS = SAI_CK_x / (MCKDIV[3:0] * 2) * 256
  MCKDIV[3:0] = SAI_CK_x / FS * 512 */ 
  tmpdiv = SAI_CLOCK_SOURCE / (AudioFreq );
    
  SAI_InitStructure.SAI_NoDivider = SAI_MasterDivider_Enabled;
  SAI_InitStructure.SAI_MasterDivider = tmpdiv;
   
  /* Configure SAI_Block_x
  LSBFirst : Disabled
  DataSize : 16 */
  SAI_InitStructure.SAI_AudioMode = SAI_Mode_MasterTx;
  SAI_InitStructure.SAI_Protocol = SAI_Free_Protocol;
  SAI_InitStructure.SAI_DataSize = SAI_DataSize_24b;
  SAI_InitStructure.SAI_FirstBit = SAI_FirstBit_MSB;
  SAI_InitStructure.SAI_ClockStrobing = SAI_ClockStrobing_FallingEdge;
  SAI_InitStructure.SAI_Synchro = SAI_Asynchronous;
  SAI_InitStructure.SAI_OUTDRIV = SAI_OutputDrive_Disabled;
  SAI_InitStructure.SAI_FIFOThreshold = SAI_FIFOThreshold_Full;
  SAI_Init(CODEC_SAI, &SAI_InitStructure);
   
  /* Configure SAI_Block_x Frame
  Frame Length : 32
  Frame active Length: 16
  FS Definition : Start frame + Channel Side identification
  FS Polarity: FS active Low
  FS Offset: FS asserted one bit before the first bit of slot 0 */
  SAI_FrameInitStructure.SAI_FrameLength = 64;
  SAI_FrameInitStructure.SAI_ActiveFrameLength = 32; 
  SAI_FrameInitStructure.SAI_FSDefinition = SAI_FS_StartFrame;
  SAI_FrameInitStructure.SAI_FSPolarity = SAI_FS_ActiveLow; 
  SAI_FrameInitStructure.SAI_FSOffset = SAI_FS_BeforeFirstBit;
  SAI_FrameInit(CODEC_SAI, &SAI_FrameInitStructure);
   
  /* Configure SAI Block_x Slot */
  SAI_SlotInitStructure.SAI_FirstBitOffset = 0;
  SAI_SlotInitStructure.SAI_SlotSize = SAI_SlotSize_DataSize;
  SAI_SlotInitStructure.SAI_SlotNumber = 1;
  SAI_SlotInitStructure.SAI_SlotActive = USR_SAI_SlotActive;
  SAI_SlotInit(CODEC_SAI, &SAI_SlotInitStructure);
   
  SAI_FlushFIFO(CODEC_SAI);
   
  /* Mono Mode Config */
 #ifdef MONO_MODE
    SAI_MonoModeConfig(CODEC_SAI, SAI_MonoMode);
 #endif /* MONO_MODE */
}

SAI DMA config:
void Audio_MAL_Init(void
{  
#if defined(AUDIO_MAL_DMA_IT_TC_EN) || defined(AUDIO_MAL_DMA_IT_HT_EN) || defined(AUDIO_MAL_DMA_IT_TE_EN)
  NVIC_InitTypeDef NVIC_InitStructure;
#endif
  /* Enable the SAI  */
  SAI_Cmd(CODEC_SAI, DISABLE);
   
  /* Enable the DMA clock */
  RCC_AHB1PeriphClockCmd(AUDIO_MAL_DMA_CLOCK, ENABLE);
   
  /* Configure the DMA Stream */
  DMA_Cmd(AUDIO_MAL_DMA_STREAM, DISABLE);
  DMA_DeInit(AUDIO_MAL_DMA_STREAM);
  /* Set the parameters to be configured */
  DMA_SAI_InitStructure.DMA_Channel = AUDIO_MAL_DMA_CHANNEL; 
  DMA_SAI_InitStructure.DMA_PeripheralBaseAddr = CODEC_SAI_ADDRESS;
  DMA_SAI_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0;      /* This field will be configured in play function */
  DMA_SAI_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
  DMA_SAI_InitStructure.DMA_BufferSize = (uint32_t)0xFFFF;      /* This field will be configured in play function */
  DMA_SAI_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_SAI_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_SAI_InitStructure.DMA_PeripheralDataSize = AUDIO_MAL_DMA_PERIPH_DATA_SIZE;
  DMA_SAI_InitStructure.DMA_MemoryDataSize = AUDIO_MAL_DMA_MEM_DATA_SIZE;
#ifdef AUDIO_MAL_MODE_NORMAL
  DMA_SAI_InitStructure.DMA_Mode = DMA_Mode_Normal;
#elif defined(AUDIO_MAL_MODE_CIRCULAR)
  DMA_SAI_InitStructure.DMA_Mode = DMA_Mode_Circular;
#else
  #error "AUDIO_MAL_MODE_NORMAL or AUDIO_MAL_MODE_CIRCULAR should be selected !!"
#endif /* AUDIO_MAL_MODE_NORMAL */ 
  DMA_SAI_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_SAI_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;        
  DMA_SAI_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  DMA_SAI_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_SAI_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 
  DMA_Init(AUDIO_MAL_DMA_STREAM, &DMA_SAI_InitStructure); 
 
  /* Enable the selected DMA interrupts */
#ifdef AUDIO_MAL_DMA_IT_TC_EN
  DMA_ITConfig(AUDIO_MAL_DMA_STREAM, DMA_IT_TC, ENABLE);
#endif /* AUDIO_MAL_DMA_IT_TC_EN */
#ifdef AUDIO_MAL_DMA_IT_HT_EN
  DMA_ITConfig(AUDIO_MAL_DMA_STREAM, DMA_IT_HT, ENABLE);
#endif /* AUDIO_MAL_DMA_IT_HT_EN */
#ifdef AUDIO_MAL_DMA_IT_TE_EN
  DMA_ITConfig(AUDIO_MAL_DMA_STREAM, DMA_IT_TE | DMA_IT_FE | DMA_IT_DME, ENABLE);
#endif /* AUDIO_MAL_DMA_IT_TE_EN */
   
  /* Enable the SAI DMA request */
  SAI_DMACmd(CODEC_SAI, ENABLE);
   
#if defined(AUDIO_MAL_DMA_IT_TC_EN) || defined(AUDIO_MAL_DMA_IT_HT_EN) || defined(AUDIO_MAL_DMA_IT_TE_EN)
  /* SAI DMA IRQ Channel configuration */
  NVIC_InitStructure.NVIC_IRQChannel = AUDIO_MAL_DMA_IRQ;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = EVAL_AUDIO_IRQ_PREPRIO;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = EVAL_AUDIO_IRQ_SUBRIO;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
#endif
}



SAI Pll config:

void PLLSAI_Config(void)
{
  /* Configure PLLSAI prescalers */
  /* PLLSAI_VCO : VCO_429M */
  /* SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 429/2 = 214.5 Mhz */
  RCC_PLLSAIConfig(16, 344, 2, 7);
   
  /* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 214.5/19 = 11.289 Mhz */ 
  RCC_SAIPLLSAIClkDivConfig(1); //98mhz
   
  /* Configure PLLI2S prescalers */
  /* PLLI2S_VCO : VCO_344M */
  /* SAI_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 344/7 = 49.142 Mhz */
  RCC_PLLI2SConfig(16, 344, 2, 7, 2);
   
  /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ = 49.142/1 = 49.142 Mhz */ 
  RCC_SAIPLLI2SClkDivConfig(1);
   
  /* Configure Clock source for SAI Block A */
    RCC_SAICLKConfig(RCC_SAIInstance_SAI1,RCC_SAICLKSource_PLLI2S);
   
  /* Enable PLLSAI Clock */
  RCC_PLLSAICmd(ENABLE);
   
  /* Wait till PLLSAI is ready */
  while(RCC_GetFlagStatus(RCC_FLAG_PLLSAIRDY) == RESET)
  {
  }
   
  /* Enable PLLI2S Clock */
  RCC_PLLI2SCmd(ENABLE);
   
  /* Wait till PLLI2S is ready */
  while(RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY) == RESET)
  {
  }
}

ADAU requires 24bit TDM or I2S data stream.

Most of the code is copied from examples, so there are some similiarites. 

Anyway. Is there any simple way to test 

Outcomes