cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F446 Configured SAI module plays noise instead of proper sound

rafal23
Associate II
Posted on November 02, 2016 at 01:42

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 ADAU14 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 = 5 Mhz */
RCC_PLLSAIConfig(16, 344, 2, 7);
/* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 5/19 = 289 Mhz */
RCC_SAIPLLSAIClkDivConfig(1); 
//98mhz
/* Configure PLLI2S prescalers */
/* PLLI2S_VCO : VCO_344M */
/* SAI_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 344/7 = 142 Mhz */
RCC_PLLI2SConfig(16, 344, 2, 7, 2);
/* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ = 142/1 = 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
1 REPLY 1
Posted on November 03, 2016 at 02:00

I am not expert on SAI.

> Anyway. Is there any simple way to test

As a start, I would avoid the SD card and associated libraries etc. (I would avoid any library at all, but that's me). Instead, I'd set a short buffer in RAM, fill half of it with zeros and other half with the maximum positive value (0x7FFFFF for 24-bit samples, keeping in mind the transfer size) and set DMA to run circularly from this buffer. That should produce a square waveform on the output, and also the data line (SD) should be fairly easy to check.

JW