AnsweredAssumed Answered

Strange problem with SAI full-duplex slave in I2S mode

Question asked by tomasz radomski on Nov 21, 2017
Latest reply on Nov 23, 2017 by Simon V.

Hi, 

i have  a strange problem in using SAI in I2S mode.

I hava DA7212 codec connected to STM32F479NI, SAI is configured in slave rx tx mode.

When i use DSP mode it works perfect, i can make a loop - receive data from microphone (SAIA) and send it back to codec (SAIB) using simple:

HAL_SAI_Receive_DMA(&hsai_BlockA1, (uint8_t *)(audio_GSM_buffer1),AUDIO_BUFFER_SIZE);//DMA circular
HAL_SAI_Transmit_DMA(&hsai_BlockB1, (uint8_t *)(audio_GSM_buffer1),AUDIO_BUFFER_SIZE));//DMA circular

 

But when i use I2S mode i can also hear voice in a loop but is is very disturbed, i can hardly hear words and so on.

 

Something is wrong with  I2S mode at the microcontroller side. I connect codec in I2S mode to GSM DVI interface in I2S mode and it works ok, so i assume something is wrong with my SAI configuration. I try everything with si init, frame init and so on. Nothing is changing. I am quite sure that codec data is correct. I also checked waveforms using logic analyzer, and tx data from uP is different than RX data. So SAI module is working correct.

 

Please help me with this problem, it took me a copule of days.

 

This is my code:

 

void MX_SAI1_Init_I2S(void)//nadawanie i odbiór - kodek audio DA7212,
{//I2S
/* Initialize SAI */
__HAL_SAI_RESET_HANDLE_STATE(&hsai_BlockA1);
__HAL_SAI_RESET_HANDLE_STATE(&hsai_BlockB1);

hsai_BlockA1.Instance = SAI1_Block_A;

//; __HAL_SAI_DISABLE(&hsai_BlockA1);

hsai_BlockA1.Init.Protocol = SAI_FREE_PROTOCOL;
hsai_BlockA1.Init.AudioMode = SAI_MODESLAVE_RX;
hsai_BlockA1.Init.DataSize = SAI_DATASIZE_16;
hsai_BlockA1.Init.FirstBit = SAI_FIRSTBIT_MSB;
hsai_BlockA1.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE;//SAI_CLOCKSTROBING_RISINGEDGE;
hsai_BlockA1.Init.Synchro = SAI_ASYNCHRONOUS;
hsai_BlockA1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
hsai_BlockA1.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;//SAI_MASTERDIVIDER_DISABLE;
hsai_BlockA1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_HF;//SAI_FIFOTHRESHOLD_1QF
hsai_BlockA1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_8K;
hsai_BlockA1.Init.SynchroExt = SAI_SYNCEXT_DISABLE;//SAI_SYNCEXT_OUTBLOCKB_ENABLE;
hsai_BlockA1.Init.MonoStereoMode = SAI_MONOMODE;
hsai_BlockA1.Init.CompandingMode = SAI_NOCOMPANDING;
hsai_BlockA1.Init.TriState = SAI_OUTPUT_NOTRELEASED;

hsai_BlockA1.FrameInit.FrameLength = 64;
hsai_BlockA1.FrameInit.ActiveFrameLength = 32;
hsai_BlockA1.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
hsai_BlockA1.FrameInit.FSPolarity = SAI_FS_ACTIVE_HIGH;//SAI_FS_ACTIVE_LOW;
hsai_BlockA1.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;//SAI_FS_FIRSTBIT;

hsai_BlockA1.SlotInit.FirstBitOffset = 0;
hsai_BlockA1.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
hsai_BlockA1.SlotInit.SlotNumber = 4;
hsai_BlockA1.SlotInit.SlotActive = SAI_SLOTACTIVE_0;

if (HAL_SAI_Init(&hsai_BlockA1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}

hsai_BlockB1.Instance = SAI1_Block_B;

hsai_BlockB1.Init.Protocol = SAI_FREE_PROTOCOL;
hsai_BlockB1.Init.AudioMode = SAI_MODESLAVE_TX;
hsai_BlockB1.Init.DataSize = SAI_DATASIZE_16;
hsai_BlockB1.Init.FirstBit = SAI_FIRSTBIT_MSB;
hsai_BlockB1.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE;//SAI_CLOCKSTROBING_RISINGEDGE;
hsai_BlockB1.Init.Synchro = SAI_SYNCHRONOUS;
hsai_BlockB1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
hsai_BlockB1.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
hsai_BlockB1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_HF;
hsai_BlockB1.Init.SynchroExt = SAI_SYNCEXT_DISABLE;//SAI_SYNCEXT_OUTBLOCKA_ENABLE;//SAI_SYNCEXT_DISABLE;
hsai_BlockB1.Init.MonoStereoMode = SAI_MONOMODE;
hsai_BlockB1.Init.CompandingMode = SAI_NOCOMPANDING;
hsai_BlockB1.Init.TriState = SAI_OUTPUT_NOTRELEASED;

hsai_BlockB1.FrameInit.FrameLength = 64;
hsai_BlockB1.FrameInit.ActiveFrameLength = 32;
hsai_BlockB1.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
hsai_BlockB1.FrameInit.FSPolarity = SAI_FS_ACTIVE_HIGH;
hsai_BlockB1.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;//SAI_FS_FIRSTBIT;

hsai_BlockB1.SlotInit.FirstBitOffset = 0;
hsai_BlockB1.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
hsai_BlockB1.SlotInit.SlotNumber = 4;
hsai_BlockB1.SlotInit.SlotActive = SAI_SLOTACTIVE_0;
if (HAL_SAI_Init(&hsai_BlockB1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}

 

void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s)
{

GPIO_InitTypeDef GPIO_InitStruct;
if(hi2s->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspInit 0 */

/* USER CODE END SPI2_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SPI2_CLK_ENABLE();

/**I2S2 GPIO Configuration
PD3 ------> I2S2_CK
PB12 ------> I2S2_WS
PC1 ------> I2S2_SD
PC2 ------> I2S2_ext_SD
*/
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_I2S2ext;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

/* USER CODE BEGIN SPI2_MspInit 1 */

/* USER CODE END SPI2_MspInit 1 */
}

/* Enable the DMA clock */
__HAL_RCC_DMA1_CLK_ENABLE();

/* SPI2_TX Init */
hdma_spi2_tx.Instance = DMA1_Stream4;
hdma_spi2_tx.Init.Channel = DMA_CHANNEL_0;
hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_spi2_tx.Init.Mode = DMA_CIRCULAR;
hdma_spi2_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;//DMA_FIFOMODE_DISABLE;
hdma_spi2_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_spi2_tx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_spi2_tx.Init.PeriphBurst = DMA_MBURST_SINGLE;

if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}

__HAL_LINKDMA(hi2s,hdmatx,hdma_spi2_tx);


/* Configure the hdma_i2s_rx handle parameters */
hdma_i2s2_ext_rx.Instance = DMA1_Stream3;
hdma_i2s2_ext_rx.Init.Channel = DMA_CHANNEL_3;
hdma_i2s2_ext_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_i2s2_ext_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2s2_ext_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2s2_ext_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_i2s2_ext_rx.Init.MemDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_i2s2_ext_rx.Init.Mode = DMA_CIRCULAR;
hdma_i2s2_ext_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_i2s2_ext_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;//DMA_FIFOMODE_DISABLE;
hdma_i2s2_ext_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_i2s2_ext_rx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_i2s2_ext_rx.Init.PeriphBurst = DMA_MBURST_SINGLE;

if (HAL_DMA_Init(&hdma_i2s2_ext_rx) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}

/* Associate the DMA handle */
__HAL_LINKDMA(hi2s, hdmarx, hdma_i2s2_ext_rx);

/* Deinitialize the Stream for new transfer */
// HAL_DMA_DeInit(&hdma_i2s2_ext_rx);

/* Configure the DMA Stream */
// HAL_DMA_Init(&hdma_i2s2_ext_rx);

/* I2S DMA IRQ Channel configuration */
HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 3, 0);//0x0F /* Select the preemption priority level(0 is the highest) */
HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);

/* DMA1_Stream4_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);

}

 

BR 

Tom

Outcomes