in Drivers/STM32U5xx_HAL/Src/stm32u5xx_hal_sai.c [368:651]
HAL_StatusTypeDef HAL_SAI_Init(SAI_HandleTypeDef *hsai)
{
uint32_t tmpregisterGCR;
uint32_t ckstr_bits;
uint32_t syncen_bits;
/* Check the SAI handle allocation */
if (hsai == NULL)
{
return HAL_ERROR;
}
/* check the instance */
assert_param(IS_SAI_ALL_INSTANCE(hsai->Instance));
/* Check the SAI Block parameters */
assert_param(IS_SAI_AUDIO_FREQUENCY(hsai->Init.AudioFrequency));
assert_param(IS_SAI_BLOCK_PROTOCOL(hsai->Init.Protocol));
assert_param(IS_SAI_BLOCK_MODE(hsai->Init.AudioMode));
assert_param(IS_SAI_BLOCK_DATASIZE(hsai->Init.DataSize));
assert_param(IS_SAI_BLOCK_FIRST_BIT(hsai->Init.FirstBit));
assert_param(IS_SAI_BLOCK_CLOCK_STROBING(hsai->Init.ClockStrobing));
assert_param(IS_SAI_BLOCK_SYNCHRO(hsai->Init.Synchro));
assert_param(IS_SAI_BLOCK_MCK_OUTPUT(hsai->Init.MckOutput));
assert_param(IS_SAI_BLOCK_OUTPUT_DRIVE(hsai->Init.OutputDrive));
assert_param(IS_SAI_BLOCK_NODIVIDER(hsai->Init.NoDivider));
assert_param(IS_SAI_BLOCK_FIFO_THRESHOLD(hsai->Init.FIFOThreshold));
assert_param(IS_SAI_MONO_STEREO_MODE(hsai->Init.MonoStereoMode));
assert_param(IS_SAI_BLOCK_COMPANDING_MODE(hsai->Init.CompandingMode));
assert_param(IS_SAI_BLOCK_TRISTATE_MANAGEMENT(hsai->Init.TriState));
assert_param(IS_SAI_BLOCK_SYNCEXT(hsai->Init.SynchroExt));
assert_param(IS_SAI_BLOCK_MCK_OVERSAMPLING(hsai->Init.MckOverSampling));
/* Check the SAI Block Frame parameters */
assert_param(IS_SAI_BLOCK_FRAME_LENGTH(hsai->FrameInit.FrameLength));
assert_param(IS_SAI_BLOCK_ACTIVE_FRAME(hsai->FrameInit.ActiveFrameLength));
assert_param(IS_SAI_BLOCK_FS_DEFINITION(hsai->FrameInit.FSDefinition));
assert_param(IS_SAI_BLOCK_FS_POLARITY(hsai->FrameInit.FSPolarity));
assert_param(IS_SAI_BLOCK_FS_OFFSET(hsai->FrameInit.FSOffset));
/* Check the SAI Block Slot parameters */
assert_param(IS_SAI_BLOCK_FIRSTBIT_OFFSET(hsai->SlotInit.FirstBitOffset));
assert_param(IS_SAI_BLOCK_SLOT_SIZE(hsai->SlotInit.SlotSize));
assert_param(IS_SAI_BLOCK_SLOT_NUMBER(hsai->SlotInit.SlotNumber));
assert_param(IS_SAI_SLOT_ACTIVE(hsai->SlotInit.SlotActive));
/* Check the SAI PDM parameters */
assert_param(IS_FUNCTIONAL_STATE(hsai->Init.PdmInit.Activation));
if (hsai->Init.PdmInit.Activation == ENABLE)
{
assert_param(IS_SAI_PDM_MIC_PAIRS_NUMBER(hsai->Init.PdmInit.MicPairsNbr));
assert_param(IS_SAI_PDM_CLOCK_ENABLE(hsai->Init.PdmInit.ClockEnable));
/* Check that SAI sub-block is SAI1 sub-block A, in master RX mode with free protocol */
if ((hsai->Instance != SAI1_Block_A) ||
(hsai->Init.AudioMode != SAI_MODEMASTER_RX) ||
(hsai->Init.Protocol != SAI_FREE_PROTOCOL))
{
return HAL_ERROR;
}
}
if (hsai->State == HAL_SAI_STATE_RESET)
{
/* Allocate lock resource and initialize it */
hsai->Lock = HAL_UNLOCKED;
#if (USE_HAL_SAI_REGISTER_CALLBACKS == 1)
/* Reset callback pointers to the weak predefined callbacks */
hsai->RxCpltCallback = HAL_SAI_RxCpltCallback;
hsai->RxHalfCpltCallback = HAL_SAI_RxHalfCpltCallback;
hsai->TxCpltCallback = HAL_SAI_TxCpltCallback;
hsai->TxHalfCpltCallback = HAL_SAI_TxHalfCpltCallback;
hsai->ErrorCallback = HAL_SAI_ErrorCallback;
/* Init the low level hardware : GPIO, CLOCK, NVIC and DMA */
if (hsai->MspInitCallback == NULL)
{
hsai->MspInitCallback = HAL_SAI_MspInit;
}
hsai->MspInitCallback(hsai);
#else
/* Init the low level hardware : GPIO, CLOCK, NVIC and DMA */
HAL_SAI_MspInit(hsai);
#endif /* USE_HAL_SAI_REGISTER_CALLBACKS */
}
/* Disable the selected SAI peripheral */
if (SAI_Disable(hsai) != HAL_OK)
{
return HAL_ERROR;
}
hsai->State = HAL_SAI_STATE_BUSY;
/* SAI Block Synchro Configuration -----------------------------------------*/
/* This setting must be done with both audio block (A & B) disabled */
switch (hsai->Init.SynchroExt)
{
case SAI_SYNCEXT_DISABLE :
tmpregisterGCR = 0;
break;
case SAI_SYNCEXT_OUTBLOCKA_ENABLE :
tmpregisterGCR = SAI_GCR_SYNCOUT_0;
break;
case SAI_SYNCEXT_OUTBLOCKB_ENABLE :
tmpregisterGCR = SAI_GCR_SYNCOUT_1;
break;
default :
tmpregisterGCR = 0;
break;
}
switch (hsai->Init.Synchro)
{
case SAI_ASYNCHRONOUS :
syncen_bits = 0;
break;
case SAI_SYNCHRONOUS :
syncen_bits = SAI_xCR1_SYNCEN_0;
break;
case SAI_SYNCHRONOUS_EXT_SAI1 :
syncen_bits = SAI_xCR1_SYNCEN_1;
break;
case SAI_SYNCHRONOUS_EXT_SAI2 :
syncen_bits = SAI_xCR1_SYNCEN_1;
tmpregisterGCR |= SAI_GCR_SYNCIN_0;
break;
default :
syncen_bits = 0;
break;
}
if ((hsai->Instance == SAI1_Block_A) || (hsai->Instance == SAI1_Block_B))
{
SAI1->GCR = tmpregisterGCR;
}
else
{
SAI2->GCR = tmpregisterGCR;
}
if (hsai->Init.AudioFrequency != SAI_AUDIO_FREQUENCY_MCKDIV)
{
uint32_t freq = 0;
uint32_t tmpval;
/* In this case, the MCKDIV value is calculated to get AudioFrequency */
if ((hsai->Instance == SAI1_Block_A) || (hsai->Instance == SAI1_Block_B))
{
freq = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SAI1);
}
if ((hsai->Instance == SAI2_Block_A) || (hsai->Instance == SAI2_Block_B))
{
freq = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SAI2);
}
/* Configure Master Clock Divider using the following formula :
- If NODIV = 1 :
MCKDIV[5:0] = SAI_CK_x / (FS * (FRL + 1))
- If NODIV = 0 :
MCKDIV[5:0] = SAI_CK_x / (FS * (OSR + 1) * 256) */
if (hsai->Init.NoDivider == SAI_MASTERDIVIDER_DISABLE)
{
/* NODIV = 1 */
uint32_t tmpframelength;
if (hsai->Init.Protocol == SAI_SPDIF_PROTOCOL)
{
/* For SPDIF protocol, frame length is set by hardware to 64 */
tmpframelength = 64U;
}
else if (hsai->Init.Protocol == SAI_AC97_PROTOCOL)
{
/* For AC97 protocol, frame length is set by hardware to 256 */
tmpframelength = 256U;
}
else
{
/* For free protocol, frame length is set by user */
tmpframelength = hsai->FrameInit.FrameLength;
}
/* (freq x 10) to keep Significant digits */
tmpval = (freq * 10U) / (hsai->Init.AudioFrequency * tmpframelength);
}
else
{
/* NODIV = 0 */
uint32_t tmposr;
tmposr = (hsai->Init.MckOverSampling == SAI_MCK_OVERSAMPLING_ENABLE) ? 2U : 1U;
/* (freq x 10) to keep Significant digits */
tmpval = (freq * 10U) / (hsai->Init.AudioFrequency * tmposr * 256U);
}
hsai->Init.Mckdiv = tmpval / 10U;
/* Round result to the nearest integer */
if ((tmpval % 10U) > 8U)
{
hsai->Init.Mckdiv += 1U;
}
/* For SPDIF protocol, SAI shall provide a bit clock twice faster the symbol-rate */
if (hsai->Init.Protocol == SAI_SPDIF_PROTOCOL)
{
hsai->Init.Mckdiv = hsai->Init.Mckdiv >> 1;
}
}
/* Check the SAI Block master clock divider parameter */
assert_param(IS_SAI_BLOCK_MASTER_DIVIDER(hsai->Init.Mckdiv));
/* Compute CKSTR bits of SAI CR1 according ClockStrobing and AudioMode */
if ((hsai->Init.AudioMode == SAI_MODEMASTER_TX) || (hsai->Init.AudioMode == SAI_MODESLAVE_TX))
{
/* Transmit */
ckstr_bits = (hsai->Init.ClockStrobing == SAI_CLOCKSTROBING_RISINGEDGE) ? 0U : SAI_xCR1_CKSTR;
}
else
{
/* Receive */
ckstr_bits = (hsai->Init.ClockStrobing == SAI_CLOCKSTROBING_RISINGEDGE) ? SAI_xCR1_CKSTR : 0U;
}
/* SAI Block Configuration -------------------------------------------------*/
/* SAI CR1 Configuration */
hsai->Instance->CR1 &= ~(SAI_xCR1_MODE | SAI_xCR1_PRTCFG | SAI_xCR1_DS | \
SAI_xCR1_LSBFIRST | SAI_xCR1_CKSTR | SAI_xCR1_SYNCEN | \
SAI_xCR1_MONO | SAI_xCR1_OUTDRIV | SAI_xCR1_DMAEN | \
SAI_xCR1_NODIV | SAI_xCR1_MCKDIV | SAI_xCR1_OSR | \
SAI_xCR1_MCKEN);
hsai->Instance->CR1 |= (hsai->Init.AudioMode | hsai->Init.Protocol | \
hsai->Init.DataSize | hsai->Init.FirstBit | \
ckstr_bits | syncen_bits | \
hsai->Init.MonoStereoMode | hsai->Init.OutputDrive | \
hsai->Init.NoDivider | (hsai->Init.Mckdiv << 20) | \
hsai->Init.MckOverSampling | hsai->Init.MckOutput);
/* SAI CR2 Configuration */
hsai->Instance->CR2 &= ~(SAI_xCR2_FTH | SAI_xCR2_FFLUSH | SAI_xCR2_COMP | SAI_xCR2_CPL);
hsai->Instance->CR2 |= (hsai->Init.FIFOThreshold | hsai->Init.CompandingMode | hsai->Init.TriState);
/* SAI Frame Configuration -----------------------------------------*/
hsai->Instance->FRCR &= (~(SAI_xFRCR_FRL | SAI_xFRCR_FSALL | SAI_xFRCR_FSDEF | \
SAI_xFRCR_FSPOL | SAI_xFRCR_FSOFF));
hsai->Instance->FRCR |= ((hsai->FrameInit.FrameLength - 1U) |
hsai->FrameInit.FSOffset |
hsai->FrameInit.FSDefinition |
hsai->FrameInit.FSPolarity |
((hsai->FrameInit.ActiveFrameLength - 1U) << 8));
/* SAI Block_x SLOT Configuration ------------------------------------------*/
/* This register has no meaning in AC 97 and SPDIF audio protocol */
hsai->Instance->SLOTR &= (~(SAI_xSLOTR_FBOFF | SAI_xSLOTR_SLOTSZ | \
SAI_xSLOTR_NBSLOT | SAI_xSLOTR_SLOTEN));
hsai->Instance->SLOTR |= hsai->SlotInit.FirstBitOffset | hsai->SlotInit.SlotSize | \
(hsai->SlotInit.SlotActive << 16) | ((hsai->SlotInit.SlotNumber - 1U) << 8);
/* SAI PDM Configuration ---------------------------------------------------*/
if (hsai->Instance == SAI1_Block_A)
{
/* Disable PDM interface */
SAI1->PDMCR &= ~(SAI_PDMCR_PDMEN);
if (hsai->Init.PdmInit.Activation == ENABLE)
{
/* Configure and enable PDM interface */
SAI1->PDMCR = (hsai->Init.PdmInit.ClockEnable |
((hsai->Init.PdmInit.MicPairsNbr - 1U) << SAI_PDMCR_MICNBR_Pos));
SAI1->PDMCR |= SAI_PDMCR_PDMEN;
}
}
/* Initialize the error code */
hsai->ErrorCode = HAL_SAI_ERROR_NONE;
/* Initialize the SAI state */
hsai->State = HAL_SAI_STATE_READY;
/* Release Lock */
__HAL_UNLOCK(hsai);
return HAL_OK;
}