Skip to main content
Explorer
October 9, 2023
Question

Unable to reinitialize SAI peripheral

  • October 9, 2023
  • 3 replies
  • 1858 views

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.
 
 

 

    This topic has been closed for replies.

    3 replies

    Graduate II
    October 9, 2023

    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.

    Graduate II
    October 9, 2023

    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

    pbortoAuthor
    Explorer
    October 9, 2023

    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.

     

     

    Graduate II
    October 10, 2023

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