in Drivers/STM32U5xx_HAL/Src/stm32u5xx_hal_adc.c [2883:3335]
HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef *hadc, ADC_ChannelConfTypeDef *pConfig)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
uint32_t tmp_offset_shifted;
uint32_t tmp_config_internal_channel;
__IO uint32_t wait_loop_index = 0;
uint32_t tmp_adc_is_conversion_on_going_regular;
uint32_t tmp_adc_is_conversion_on_going_injected;
uint32_t tmp_channel;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
if (hadc->Instance != ADC4) /* ADC1 or ADC2 */
{
assert_param(IS_ADC_REGULAR_RANK(pConfig->Rank));
assert_param(IS_ADC_SAMPLE_TIME(pConfig->SamplingTime));
assert_param(IS_ADC_SINGLE_DIFFERENTIAL(pConfig->SingleDiff));
assert_param(IS_ADC_OFFSET_NUMBER(pConfig->OffsetNumber));
assert_param(IS_ADC_RANGE(hadc->Instance, ADC_GET_RESOLUTION(hadc), pConfig->Offset));
/* if ROVSE is set, the value of the OFFSETy_EN bit in ADCx_OFRy register is
ignored (considered as reset) */
assert_param(!((pConfig->OffsetNumber != ADC_OFFSET_NONE) && (hadc->Init.OversamplingMode == ENABLE)));
/* Verification of channel number */
if (pConfig->SingleDiff != ADC_DIFFERENTIAL_ENDED)
{
assert_param(IS_ADC_CHANNEL(pConfig->Channel));
}
else
{
assert_param(IS_ADC1_DIFF_CHANNEL(pConfig->Channel));
}
}
else
{
assert_param(IS_ADC4_SAMPLE_TIME(pConfig->SamplingTime));
if ((hadc->Init.ScanConvMode == ADC_SCAN_SEQ_FIXED) ||
(hadc->Init.ScanConvMode == ADC_SCAN_SEQ_FIXED_BACKWARD))
{
assert_param(IS_ADC4_REGULAR_RANK_SEQ_FIXED(pConfig->Rank));
}
else
{
assert_param(IS_ADC4_REGULAR_NB_CONV(hadc->Init.NbrOfConversion));
assert_param(IS_ADC4_REGULAR_RANK(pConfig->Rank));
}
}
__HAL_LOCK(hadc);
/* Parameters update conditioned to ADC state: */
/* Parameters that can be updated when ADC is disabled or enabled without */
/* conversion on going on regular group: */
/* - Channel number */
/* - Channel rank */
if (LL_ADC_REG_IsConversionOngoing(hadc->Instance) == 0UL)
{
if (hadc->Instance != ADC4) /* ADC1 or ADC2 */
{
/* ADC channels preselection */
hadc->Instance->PCSEL |= (1UL << (__LL_ADC_CHANNEL_TO_DECIMAL_NB((uint32_t)pConfig->Channel) & 0x1FUL));
/* Set ADC group regular sequence: channel on the selected scan sequence rank */
LL_ADC_REG_SetSequencerRanks(hadc->Instance, pConfig->Rank, pConfig->Channel);
/* Parameters update conditioned to ADC state: */
/* Parameters that can be updated when ADC is disabled or enabled without */
/* conversion on going on regular group: */
/* - Channel sampling time */
/* - Channel offset */
tmp_adc_is_conversion_on_going_regular = LL_ADC_REG_IsConversionOngoing(hadc->Instance);
tmp_adc_is_conversion_on_going_injected = LL_ADC_INJ_IsConversionOngoing(hadc->Instance);
if ((tmp_adc_is_conversion_on_going_regular == 0UL)
&& (tmp_adc_is_conversion_on_going_injected == 0UL)
)
{
/* Set sampling time of the selected ADC channel */
LL_ADC_SetChannelSamplingTime(hadc->Instance, pConfig->Channel, pConfig->SamplingTime);
/* Configure the offset: offset enable/disable, channel, offset value */
/* Shift the offset with respect to the selected ADC resolution. */
/* Offset has to be left-aligned on bit 11, the LSB (right bits) are set to 0 */
tmp_offset_shifted = ADC_OFFSET_SHIFT_RESOLUTION(hadc, (uint32_t)pConfig->Offset);
if (pConfig->OffsetNumber != ADC_OFFSET_NONE)
{
/* Set ADC selected offset number */
LL_ADC_SetOffset(hadc->Instance, pConfig->OffsetNumber, pConfig->Channel, tmp_offset_shifted);
assert_param(IS_ADC_OFFSET_SIGN(pConfig->OffsetSign));
assert_param(IS_FUNCTIONAL_STATE(pConfig->OffsetSignedSaturation));
/* Set ADC selected offset sign */
LL_ADC_SetOffsetSign(hadc->Instance, pConfig->OffsetNumber, pConfig->OffsetSign);
/* Set ADC selected offset signed saturation */
LL_ADC_SetOffsetSignedSaturation(hadc->Instance, pConfig->OffsetNumber, \
(pConfig->OffsetSignedSaturation == ENABLE) \
? LL_ADC_OFFSET_SIGNED_SATURATION_ENABLE \
: LL_ADC_OFFSET_SIGNED_SATURATION_DISABLE);
}
else
{
/* Scan OFR1, OFR2, OFR3, OFR4 to check if the selected channel is enabled.
If this is the case, offset OFRx is disabled since
pConfig->OffsetNumber = ADC_OFFSET_NONE. */
if (((hadc->Instance->OFR1) & ADC_OFR1_OFFSET1_CH) == ADC_OFR_CHANNEL(pConfig->Channel))
{
CLEAR_BIT(hadc->Instance->OFR1, ADC_OFR1_SSAT);
}
if (((hadc->Instance->OFR2) & ADC_OFR2_OFFSET2_CH) == ADC_OFR_CHANNEL(pConfig->Channel))
{
CLEAR_BIT(hadc->Instance->OFR2, ADC_OFR2_SSAT);
}
if (((hadc->Instance->OFR3) & ADC_OFR3_OFFSET3_CH) == ADC_OFR_CHANNEL(pConfig->Channel))
{
CLEAR_BIT(hadc->Instance->OFR3, ADC_OFR3_SSAT);
}
if (((hadc->Instance->OFR4) & ADC_OFR4_OFFSET4_CH) == ADC_OFR_CHANNEL(pConfig->Channel))
{
CLEAR_BIT(hadc->Instance->OFR4, ADC_OFR4_SSAT);
}
}
}
/* Parameters update conditioned to ADC state: */
/* Parameters that can be updated only when ADC is disabled: */
/* - Single or differential mode */
/* - Internal measurement channels: Vbat/VrefInt/TempSensor */
if (LL_ADC_IsEnabled(hadc->Instance) == 0UL)
{
/* Set mode single-ended or differential input of the selected ADC channel */
LL_ADC_SetChannelSingleDiff(hadc->Instance, pConfig->Channel, pConfig->SingleDiff);
/* Configuration of differential mode */
if (pConfig->SingleDiff == ADC_DIFFERENTIAL_ENDED)
{
/* Set sampling time of the selected ADC channel */
/* Note: ADC channel number masked with value "0x1F" to ensure shift value within 32 bits range */
tmp_channel = __LL_ADC_DECIMAL_NB_TO_CHANNEL((__LL_ADC_CHANNEL_TO_DECIMAL_NB(pConfig->Channel) \
+ 1UL) & 0x1FUL);
LL_ADC_SetChannelSamplingTime(hadc->Instance, tmp_channel, pConfig->SamplingTime);
}
/* Management of internal measurement channels: Vbat/VrefInt/TempSensor. */
/* If internal channel selected, enable dedicated internal buffers and */
/* paths. */
/* Note: these internal measurement paths can be disabled using */
/* HAL_ADC_DeInit(). */
if (__LL_ADC_IS_CHANNEL_INTERNAL(pConfig->Channel))
{
/* Configuration of common ADC parameters */
tmp_config_internal_channel = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance));
/* Software is allowed to change common parameters only when all ADCs */
/* of the common group are disabled. */
if (__LL_ADC_IS_ENABLED_ALL_COMMON_INSTANCE(__LL_ADC_COMMON_INSTANCE(hadc->Instance)) == 0UL)
{
/* If the requested internal measurement path has already been enabled, */
/* bypass the configuration processing. */
if ((pConfig->Channel == ADC_CHANNEL_TEMPSENSOR)
&& ((tmp_config_internal_channel & LL_ADC_PATH_INTERNAL_TEMPSENSOR) == 0UL))
{
if (ADC_TEMPERATURE_SENSOR_INSTANCE(hadc))
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance),
LL_ADC_PATH_INTERNAL_TEMPSENSOR | tmp_config_internal_channel);
/* Delay for temperature sensor stabilization time */
/* Wait loop initialization and execution */
/* Note: Variable divided by 2 to compensate partially */
/* CPU processing cycles, scaling in us split to not */
/* exceed 32 bits register capacity and handle low frequency. */
wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US / 10UL) \
* ((SystemCoreClock / (100000UL * 2UL)) + 1UL));
while (wait_loop_index != 0UL)
{
wait_loop_index--;
}
}
}
else if ((pConfig->Channel == ADC_CHANNEL_VBAT) && ((tmp_config_internal_channel \
& LL_ADC_PATH_INTERNAL_VBAT) == 0UL))
{
if (ADC_BATTERY_VOLTAGE_INSTANCE(hadc))
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance),
LL_ADC_PATH_INTERNAL_VBAT | tmp_config_internal_channel);
}
}
else if ((pConfig->Channel == ADC_CHANNEL_VREFINT)
&& ((tmp_config_internal_channel & LL_ADC_PATH_INTERNAL_VREFINT) == 0UL))
{
if (ADC_VREFINT_INSTANCE(hadc))
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance),
LL_ADC_PATH_INTERNAL_VREFINT | tmp_config_internal_channel);
}
}
else
{
/* nothing to do */
}
}
/* If the requested internal measurement path has already been */
/* enabled and other ADC of the common group are enabled, internal */
/* measurement paths cannot be enabled. */
else
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
tmp_hal_status = HAL_ERROR;
}
}
}
}
else
{
/* Remap Internal Channels for Cut1 vs Cut2 */
tmp_channel = pConfig->Channel;
if (HAL_GetREVID() == REV_ID_A) /* STM32U5 silicon Rev.A */
{
if (pConfig->Channel == ADC4_CHANNEL_TEMPSENSOR)
{
tmp_channel = (LL_ADC_CHANNEL_22 | ADC_CHANNEL_ID_INTERNAL_CH);
}
else if (pConfig->Channel == ADC4_CHANNEL_VBAT)
{
tmp_channel = (LL_ADC_CHANNEL_23 | ADC_CHANNEL_ID_INTERNAL_CH);
}
else if (pConfig->Channel == ADC_CHANNEL_VCORE)
{
tmp_channel = (LL_ADC_CHANNEL_VREFINT | LL_ADC_CHANNEL_DIFFERENCIATION_VREFINT_VCORE);
}
else if (pConfig->Channel == ADC_CHANNEL_DAC1CH1_ADC4)
{
tmp_channel = (LL_ADC_CHANNEL_20 | ADC_CHANNEL_ID_INTERNAL_CH);
}
else if (pConfig->Channel == ADC_CHANNEL_DAC1CH2_ADC4)
{
tmp_channel = (LL_ADC_CHANNEL_21 | ADC_CHANNEL_ID_INTERNAL_CH);
}
else
{
tmp_channel = pConfig->Channel;
}
}
/* Configure channel: depending on rank setting, add it or remove it from */
/* ADC sequencer. */
/* If sequencer set to not fully configurable with channel rank set to */
/* none, remove the channel from the sequencer. */
/* Otherwise (sequencer set to fully configurable or to to not fully */
/* configurable with channel rank to be set), configure the selected */
/* channel. */
if (pConfig->Rank != ADC4_RANK_NONE)
{
/* Regular sequence configuration */
/* Note: ADC channel configuration requires few ADC clock cycles */
/* to be ready. Processing of ADC settings in this function */
/* induce that a specific wait time is not necessary. */
/* For more details on ADC channel configuration ready, */
/* refer to function "LL_ADC_IsActiveFlag_CCRDY()". */
if ((hadc->Init.ScanConvMode == ADC_SCAN_SEQ_FIXED) ||
(hadc->Init.ScanConvMode == ADC_SCAN_SEQ_FIXED_BACKWARD))
{
/* Sequencer set to not fully configurable: */
/* Set the channel by enabling the corresponding bitfield. */
LL_ADC_REG_SetSequencerChAdd(hadc->Instance, tmp_channel);
}
else
{
/* Sequencer set to fully configurable: */
/* Set the channel by entering it into the selected rank. */
/* Memorize the channel set into variable in HAL ADC handle */
MODIFY_REG(hadc->ADCGroupRegularSequencerRanks,
ADC_CHSELR_SQ1 << (pConfig->Rank & 0x1FUL),
__LL_ADC_CHANNEL_TO_DECIMAL_NB(tmp_channel) << (pConfig->Rank & 0x1FUL));
/* If the selected rank is below ADC group regular sequencer length, */
/* apply the configuration in ADC register. */
/* Note: Otherwise, configuration is not applied. */
/* To apply it, parameter'NbrOfConversion' must be increased. */
if (((pConfig->Rank >> 2UL) + 1UL) <= hadc->Init.NbrOfConversion)
{
if (HAL_GetREVID() <= REV_ID_A) /* STM32U5 silicon Rev.A */
{
if (__LL_ADC_CHANNEL_TO_DECIMAL_NB(tmp_channel) >= 20UL)
{
tmp_channel = (1UL << (__LL_ADC_CHANNEL_TO_DECIMAL_NB(tmp_channel) - 9UL));
}
}
LL_ADC_REG_SetSequencerRanks(hadc->Instance, pConfig->Rank, tmp_channel);
}
}
/* Set sampling time of the selected ADC channel */
LL_ADC_SetChannelSamplingTime(hadc->Instance, tmp_channel, pConfig->SamplingTime);
/* Management of internal measurement channels: VrefInt/TempSensor/Vbat */
/* internal measurement paths enable: If internal channel selected, */
/* enable dedicated internal buffers and path. */
/* Note: these internal measurement paths can be disabled using */
/* HAL_ADC_DeInit() or removing the channel from sequencer with */
/* channel configuration parameter "Rank". */
if (__LL_ADC_IS_CHANNEL_INTERNAL(pConfig->Channel))
{
tmp_config_internal_channel = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance));
/* If the requested internal measurement path has already been enabled, */
/* bypass the configuration processing. */
if ((pConfig->Channel == ADC4_CHANNEL_TEMPSENSOR) \
&& ((tmp_config_internal_channel & LL_ADC_PATH_INTERNAL_TEMPSENSOR) == 0UL))
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance),
LL_ADC_PATH_INTERNAL_TEMPSENSOR | tmp_config_internal_channel);
/* Delay for temperature sensor stabilization time */
/* Wait loop initialization and execution */
/* Note: Variable divided by 2 to compensate partially */
/* CPU processing cycles, scaling in us split to not */
/* exceed 32 bits register capacity and handle low frequency. */
wait_loop_index = ((LL_ADC_DELAY_TEMPSENSOR_STAB_US / 10UL) * (SystemCoreClock / (100000UL * 2UL)));
while (wait_loop_index != 0UL)
{
wait_loop_index--;
}
}
else if ((pConfig->Channel == ADC4_CHANNEL_VBAT) && ((tmp_config_internal_channel \
& LL_ADC_PATH_INTERNAL_VBAT) == 0UL))
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance),
LL_ADC_PATH_INTERNAL_VBAT | tmp_config_internal_channel);
}
else if ((pConfig->Channel == ADC_CHANNEL_VREFINT) \
&& ((tmp_config_internal_channel & LL_ADC_PATH_INTERNAL_VREFINT) == 0UL))
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance),
LL_ADC_PATH_INTERNAL_VREFINT | tmp_config_internal_channel);
}
else if ((pConfig->Channel == ADC_CHANNEL_VCORE) \
&& ((tmp_config_internal_channel & LL_ADC_PATH_INTERNAL_VREFINT) == 0UL))
{
if (ADC_VCORE_INSTANCE(hadc))
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance),
LL_ADC_PATH_INTERNAL_VREFINT | tmp_config_internal_channel);
if (HAL_GetREVID() <= REV_ID_A) /* STM32U5 silicon Rev.A */
{
SET_BIT((hadc->Instance->OR), ADC_OR_CHN0SEL);
}
}
}
else
{
/* nothing to do */
}
/* If STM32U5 silicon Rev.B, ADC_CHANNEL_DAC1CH1 and ADC_CHANNEL_DAC1CH2 are both on Channel 21
and selection is done via ADC_OR[0] register */
if (HAL_GetREVID() == REV_ID_B) /* STM32U5 silicon Rev.B */
{
if ((pConfig->Channel == ADC_CHANNEL_DAC1CH2_ADC4) \
&& ((tmp_config_internal_channel & LL_ADC_PATH_INTERNAL_VREFINT) == 0UL))
{
SET_BIT((hadc->Instance->OR), ADC_OR_CHN0SEL);
}
}
}
}
else
{
/* Regular sequencer configuration */
/* Note: Case of sequencer set to fully configurable: */
/* Sequencer rank cannot be disabled, only affected to */
/* another channel. */
/* To remove a rank, use parameter 'NbrOfConversion". */
if ((hadc->Init.ScanConvMode == ADC_SCAN_SEQ_FIXED) ||
(hadc->Init.ScanConvMode == ADC_SCAN_SEQ_FIXED_BACKWARD))
{
/* Sequencer set to not fully configurable: */
/* Reset the channel by disabling the corresponding bitfield. */
LL_ADC_REG_SetSequencerChRem(hadc->Instance, tmp_channel);
}
/* Management of internal measurement channels: Vbat/VrefInt/TempSensor. */
/* If internal channel selected, enable dedicated internal buffers and */
/* paths. */
if (__LL_ADC_IS_CHANNEL_INTERNAL(pConfig->Channel))
{
tmp_config_internal_channel = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance));
if (pConfig->Channel == ADC_CHANNEL_TEMPSENSOR)
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance),
~LL_ADC_PATH_INTERNAL_TEMPSENSOR & tmp_config_internal_channel);
}
else if (pConfig->Channel == ADC_CHANNEL_VBAT)
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance),
~LL_ADC_PATH_INTERNAL_VBAT & tmp_config_internal_channel);
}
else if (pConfig->Channel == ADC_CHANNEL_VREFINT)
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance),
~LL_ADC_PATH_INTERNAL_VREFINT & tmp_config_internal_channel);
}
else if (pConfig->Channel == ADC_CHANNEL_VCORE)
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(hadc->Instance),
~LL_ADC_PATH_INTERNAL_VREFINT & tmp_config_internal_channel);
if (HAL_GetREVID() <= REV_ID_A) /* STM32U5 silicon Rev.A */
{
SET_BIT((hadc->Instance->OR), ADC_OR_CHN0SEL);
}
}
else
{
/* nothing to do */
}
/* If STM32U5 silicon Rev.B, ADC_CHANNEL_DAC1CH1 and ADC_CHANNEL_DAC1CH2 are both on Channel 21
and selection is done via ADC_OR[0] register */
if (HAL_GetREVID() == REV_ID_B) /* STM32U5 silicon Rev.B */
{
if ((pConfig->Channel == ADC_CHANNEL_DAC1CH2_ADC4) \
&& ((tmp_config_internal_channel & LL_ADC_PATH_INTERNAL_VREFINT) == 0UL))
{
SET_BIT((hadc->Instance->OR), ADC_OR_CHN0SEL);
}
}
}
}
}
}
/* If a conversion is on going on regular group, no update on regular */
/* channel could be done on neither of the channel configuration structure */
/* parameters. */
else
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
tmp_hal_status = HAL_ERROR;
}
__HAL_UNLOCK(hadc);
return tmp_hal_status;
}