cancel
Showing results for 
Search instead for 
Did you mean: 

Unable to reinitialize SAI peripheral

pborto
Associate II

Hi,

I'm working with self designed board (STM32F765 MCU) and currently able to initialize SAI2 peripheral to work with codec in DMA mode.

At some point in my code, I need to change the sample rate of my codec (through MCLK).

The sequence of operations is basically as follows:

//1. DeInit SAI
HAL_SAI_DeInit(&hsai_BlockB2); //Deinit SAI_MODEMASTER_TX block set at old AudioFrequency
HAL_SAI_DeInit(&hsai_BlockA2); //Deinit SAI_MODESLAVE_RX block

//2 Init SAI with new freq. SAI_AUDIO_FREQUENCY_96K
hsai_BlockA2.Instance = SAI2_Block_A;
hsai_BlockA2.Init.AudioMode = SAI_MODESLAVE_RX;
hsai_BlockA2.Init.Synchro = SAI_SYNCHRONOUS;
hsai_BlockA2.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
hsai_BlockA2.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
hsai_BlockA2.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
hsai_BlockA2.Init.MonoStereoMode = SAI_STEREOMODE;
hsai_BlockA2.Init.CompandingMode = SAI_NOCOMPANDING;
hsai_BlockA2.Init.TriState = SAI_OUTPUT_NOTRELEASED;
if (HAL_SAI_InitProtocol(&hsai_BlockA2, SAI_I2S_STANDARD, SAI_PROTOCOL_DATASIZE_16BIT, 2) != HAL_OK)
{
Error_Handler();
}

hsai_BlockB2.Instance = SAI2_Block_B;
hsai_BlockB2.Init.AudioMode = SAI_MODEMASTER_TX;
hsai_BlockB2.Init.Synchro = SAI_ASYNCHRONOUS;
hsai_BlockB2.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;
hsai_BlockB2.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
hsai_BlockB2.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
hsai_BlockB2.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_96K;
hsai_BlockB2.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
hsai_BlockB2.Init.MonoStereoMode = SAI_STEREOMODE;
hsai_BlockB2.Init.CompandingMode = SAI_NOCOMPANDING;
hsai_BlockB2.Init.TriState = SAI_OUTPUT_NOTRELEASED;
if (HAL_SAI_InitProtocol(&hsai_BlockB2, SAI_I2S_STANDARD, SAI_PROTOCOL_DATASIZE_16BIT, 2) != HAL_OK)
{
Error_Handler();
}

//3 custom function that reinit codec
Codec_Init();

//4. restart DMA tx and rx

if(HAL_OK != HAL_SAI_Transmit_DMA(&hsai_BlockB2, (uint8_t *)txAddr, Size))
{
Error_Handler();
}
 
if(HAL_OK != HAL_SAI_Receive_DMA(&hsai_BlockA2, (uint8_t *)rxAddr, Size))
{
Error_Handler();
}
 
The problem arises inside HAL_SAI_Transmit_DMA(&hsai_BlockB2, (uint8_t *)txAddr, Size), at the following :
 
if (HAL_DMA_Start_IT(hsai->hdmarx, (uint32_t)&hsai->Instance->DR, (uint32_t)hsai->pBuffPtr, hsai->XferSize) != HAL_OK)  
 
the system goes in:
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
 
The sequence of operations is the same at the start (working) and when I try to set the new frequency (not working) except for:
hsai_BlockB2.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_8K; (working case)
hsai_BlockB2.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_96K; (not working case)
 
I checked PeriphClkInitStruct settings and are ok for both cases.
I also verified that if I start directly by setting the frequency to 96k everything works; so it seems like something related to the reinitialization operation.
 
Thanks in advance for the support.
 
 

 

4 REPLIES 4
LCE
Principal

Did you stop DMA?

I'm doing that on a F767 this way:

  • stop DMA (circular mode) with HAL_SAI_DMAStop(), that includes FIFO flush and SAI disable
  • then I set the MCKDIV bits in CR1
  • then restart DMA with HAL_SAI_Receive_DMA() (modified for DBM)

So no complete init / deinit. (I'm using HAL only for start / stop DMA)

/* clear and set sampling rate */
u32MckDivNew = some define depending on sampling rate for the divider...
SAI1_Block_A->CR1 &= ~SAI_xCR1_MCKDIV;
SAI1_Block_A->CR1 |= u32MckDivNew;

PS: I just see that probably the link between DMA and SAI is gone after your De-Init.

pborto
Associate II

Hi LCE,

Thank you for your quick reply.

I tried first, as you suggested, to stop DMA with the function HAL_SAI_DMAStop(), but without success.

If I call HAL_SAI_DMAStop() at the same time as HAL_SAI_TxCpltCallback or HAL_SAI_RxCpltCallback, I get the following error: DMA_ERROR_NO_XFER.

If I make the call to HAL_SAI_DMAStop() somewhere else, I end up in the infinite loop of Default_Handler.

 

 

I'm using HAL only for start / stop DMA


And, like everything in HAL, that is also broken...

https://community.st.com/t5/stm32-mcus-embedded-software/bug-stm32-hal-sai-abort-and-dma-stop-logic-is-flawed/td-p/54339

LCE
Principal

Thanks for that hint, I'll get back to this.