Switching Between Internal and External Audio Clock Sources and back again
I’m implementing an audio clock source switching mechanism where the system runs on the internal audio clock if no external clock is detected. As soon as an external clock becomes available, it switches to use that external clock source.
This works initially, but when the external clock is lost for any reason and the system switches back to the internal clock — then later detects the external clock again and switches back — I notice that data is still being received through the SAIs, but the clock is no longer synchronized with the external clock source. It seems to continue running from the internal clock instead.
Is what I’m trying to do here actually possible?
void SwitchAudioMode(eAudioClockSelection::Enum ClockSelection)
{
if (gAudioMode == ClockSelection)
{
return;
}
else
{
gAudioMode = ClockSelection;
}
HAL_SAI_Abort(&hsai_BlockA1);
HAL_SAI_Abort(&hsai_BlockA3);
HAL_SAI_Abort(&hsai_BlockB3);
HAL_SAI_DMAStop(&hsai_BlockA1);
HAL_SAI_DMAStop(&hsai_BlockA3);
HAL_SAI_DMAStop(&hsai_BlockB3);
HAL_SAI_DeInit(&hsai_BlockA1);
HAL_SAI_DeInit(&hsai_BlockA3);
HAL_SAI_DeInit(&hsai_BlockB3);
__HAL_RCC_SAI3_FORCE_RESET();
__HAL_RCC_SAI3_RELEASE_RESET();
__HAL_RCC_SAI1_FORCE_RESET();
__HAL_RCC_SAI1_RELEASE_RESET();
// Use Clock from A2B
if (ClockSelection == eAudioClockSelection::External)
{
__HAL_RCC_SAI23_CONFIG(RCC_SAI23CLKSOURCE_PIN);
}
else
{
while (__HAL_RCC_GET_FLAG(RCC_FLAG_PLL3RDY) == RESET);
__HAL_RCC_SAI23_CONFIG(RCC_SAI23CLKSOURCE_PLL3);
}
HAL_SAI_Init(&hsai_BlockB3);
HAL_SAI_Init(&hsai_BlockA3);
HAL_SAI_Init(&hsai_BlockA1);
// Start DMA for SAI1_A (RX from A2B_1 aka HUD)
HAL_SAI_Receive_DMA(&hsai_BlockA1, (uint8_t *)&mRxHeadUnitA2B1Buffer[0], 2 * cNoOfBlockSamples * NUMBER_OF_A2B_DOWNSTREAM_CHANNELS);
// Start DMA for SAI3_A (TX to AMP)
HAL_SAI_Transmit_DMA(&hsai_BlockA3, (uint8_t *)&mTxTDM1Buffer[0], 2 * cNoOfBlockSamples * NUMBER_OF_TDM_CHANNELS);
// Start DMA for SAI3_B (TX to AMP)
HAL_SAI_Transmit_DMA(&hsai_BlockB3, (uint8_t *)&mTxTDM2Buffer[0], 2 * cNoOfBlockSamples * NUMBER_OF_TDM_CHANNELS);
}