in Drivers/STM32U5xx_HAL/Src/stm32u5xx_hal_adc_ex.c [1694:2130]
HAL_StatusTypeDef HAL_ADCEx_InjectedConfigChannel(ADC_HandleTypeDef *hadc, ADC_InjectionConfTypeDef *pConfigInjected)
{
HAL_StatusTypeDef tmp_hal_status = HAL_OK;
uint32_t tmp_offset_shifted;
uint32_t tmp_config_internal_channel;
uint32_t tmp_adc_is_conversion_on_going_regular;
uint32_t tmp_adc_is_conversion_on_going_injected;
__IO uint32_t wait_loop_index;
uint32_t tmp_jsqr_context_queue_being_built = 0U;
uint32_t tmp_channel;
/* Check the parameters */
assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));
assert_param(IS_ADC_SAMPLE_TIME(pConfigInjected->InjectedSamplingTime));
assert_param(IS_ADC_SINGLE_DIFFERENTIAL(pConfigInjected->InjectedSingleDiff));
assert_param(IS_FUNCTIONAL_STATE(pConfigInjected->AutoInjectedConv));
assert_param(IS_ADC_EXTTRIGINJEC_EDGE(pConfigInjected->ExternalTrigInjecConvEdge));
assert_param(IS_ADC_EXTTRIGINJEC(pConfigInjected->ExternalTrigInjecConv));
assert_param(IS_ADC_OFFSET_NUMBER(pConfigInjected->InjectedOffsetNumber));
assert_param(IS_ADC_OFFSET_SIGN(pConfigInjected->InjectedOffsetSign));
assert_param(IS_ADC_RANGE(hadc->Instance, ADC_GET_RESOLUTION(hadc), pConfigInjected->InjectedOffset));
assert_param(IS_FUNCTIONAL_STATE(pConfigInjected->InjecOversamplingMode));
if (hadc->Init.ScanConvMode != ADC_SCAN_DISABLE)
{
assert_param(IS_ADC_INJECTED_RANK(pConfigInjected->InjectedRank));
assert_param(IS_ADC_INJECTED_NB_CONV(pConfigInjected->InjectedNbrOfConversion));
assert_param(IS_FUNCTIONAL_STATE(pConfigInjected->InjectedDiscontinuousConvMode));
}
/* Check offset range according to oversampling setting */
if (hadc->Init.OversamplingMode == ENABLE)
{
assert_param(IS_ADC_RANGE(hadc->Instance, ADC_GET_RESOLUTION(hadc),
pConfigInjected->InjectedOffset / (hadc->Init.Oversampling.Ratio + 1U)));
}
else
{
assert_param(IS_ADC_RANGE(hadc->Instance, ADC_GET_RESOLUTION(hadc), pConfigInjected->InjectedOffset));
}
/* JDISCEN and JAUTO bits can't be set at the same time */
assert_param(!((pConfigInjected->InjectedDiscontinuousConvMode == ENABLE) \
&& (pConfigInjected->AutoInjectedConv == ENABLE)));
/* DISCEN and JAUTO bits can't be set at the same time */
assert_param(!((hadc->Init.DiscontinuousConvMode == ENABLE) && (pConfigInjected->AutoInjectedConv == ENABLE)));
/* Verification of channel number */
if (pConfigInjected->InjectedSingleDiff != ADC_DIFFERENTIAL_ENDED)
{
assert_param(IS_ADC_CHANNEL(pConfigInjected->InjectedChannel));
}
else
{
if (hadc->Instance != ADC4) /* ADC1 or ADC2 */
{
assert_param(IS_ADC1_DIFF_CHANNEL(pConfigInjected->InjectedChannel));
}
}
__HAL_LOCK(hadc);
/* Configuration of injected group sequencer: */
/* Hardware constraint: Must fully define injected context register JSQR */
/* before make it entering into injected sequencer queue. */
/* */
/* - if scan mode is disabled: */
/* * Injected channels sequence length is set to 0x00: 1 channel */
/* converted (channel on injected rank 1) */
/* Parameter "InjectedNbrOfConversion" is discarded. */
/* * Injected context register JSQR setting is simple: register is fully */
/* defined on one call of this function (for injected rank 1) and can */
/* be entered into queue directly. */
/* - if scan mode is enabled: */
/* * Injected channels sequence length is set to parameter */
/* "InjectedNbrOfConversion". */
/* * Injected context register JSQR setting more complex: register is */
/* fully defined over successive calls of this function, for each */
/* injected channel rank. It is entered into queue only when all */
/* injected ranks have been set. */
/* Note: Scan mode is not present by hardware on this device, but used */
/* by software for alignment over all STM32 devices. */
if ((hadc->Init.ScanConvMode == ADC_SCAN_DISABLE) ||
(pConfigInjected->InjectedNbrOfConversion == 1U))
{
/* Configuration of context register JSQR: */
/* - number of ranks in injected group sequencer: fixed to 1st rank */
/* (scan mode disabled, only rank 1 used) */
/* - external trigger to start conversion */
/* - external trigger polarity */
/* - channel set to rank 1 (scan mode disabled, only rank 1 can be used) */
if (pConfigInjected->InjectedRank == ADC_INJECTED_RANK_1)
{
/* Enable external trigger if trigger selection is different of */
/* software start. */
/* Note: This configuration keeps the hardware feature of parameter */
/* ExternalTrigInjecConvEdge "trigger edge none" equivalent to */
/* software start. */
if (pConfigInjected->ExternalTrigInjecConv != ADC_INJECTED_SOFTWARE_START)
{
tmp_jsqr_context_queue_being_built = (ADC_JSQR_RK(pConfigInjected->InjectedChannel, ADC_INJECTED_RANK_1)
| (pConfigInjected->ExternalTrigInjecConv & ADC_JSQR_JEXTSEL)
| pConfigInjected->ExternalTrigInjecConvEdge
);
}
else
{
tmp_jsqr_context_queue_being_built = (ADC_JSQR_RK(pConfigInjected->InjectedChannel, ADC_INJECTED_RANK_1));
}
MODIFY_REG(hadc->Instance->JSQR, ADC_JSQR_FIELDS, tmp_jsqr_context_queue_being_built);
/* For debug and informative reasons, hadc handle saves JSQR setting */
hadc->InjectionConfig.ContextQueue = tmp_jsqr_context_queue_being_built;
}
}
else
{
/* Case of scan mode enabled, several channels to set into injected group */
/* sequencer. */
/* */
/* Procedure to define injected context register JSQR over successive */
/* calls of this function, for each injected channel rank: */
/* 1. Start new context and set parameters related to all injected */
/* channels: injected sequence length and trigger. */
/* if hadc->InjectionConfig.ChannelCount is equal to 0, this is the first */
/* call of the context under setting */
if (hadc->InjectionConfig.ChannelCount == 0U)
{
/* Initialize number of channels that will be configured on the context */
/* being built */
hadc->InjectionConfig.ChannelCount = pConfigInjected->InjectedNbrOfConversion;
/* Handle hadc saves the context under build up over each HAL_ADCEx_InjectedConfigChannel()
call, this context will be written in JSQR register at the last call.
At this point, the context is merely reset */
hadc->InjectionConfig.ContextQueue = 0x00000000U;
/* Configuration of context register JSQR: */
/* - number of ranks in injected group sequencer */
/* - external trigger to start conversion */
/* - external trigger polarity */
/* Enable external trigger if trigger selection is different of */
/* software start. */
/* Note: This configuration keeps the hardware feature of parameter */
/* ExternalTrigInjecConvEdge "trigger edge none" equivalent to */
/* software start. */
if (pConfigInjected->ExternalTrigInjecConv != ADC_INJECTED_SOFTWARE_START)
{
tmp_jsqr_context_queue_being_built = ((pConfigInjected->InjectedNbrOfConversion - 1U)
| (pConfigInjected->ExternalTrigInjecConv & ADC_JSQR_JEXTSEL)
| pConfigInjected->ExternalTrigInjecConvEdge
);
}
else
{
tmp_jsqr_context_queue_being_built = ((pConfigInjected->InjectedNbrOfConversion - 1U));
}
}
/* 2. Continue setting of context under definition with parameter */
/* related to each channel: channel rank sequence */
/* Clear the old JSQx bits for the selected rank */
tmp_jsqr_context_queue_being_built &= ~ADC_JSQR_RK(ADC_SQR3_SQ10, pConfigInjected->InjectedRank);
/* Set the JSQx bits for the selected rank */
tmp_jsqr_context_queue_being_built |= ADC_JSQR_RK(pConfigInjected->InjectedChannel, pConfigInjected->InjectedRank);
/* Decrease channel count */
hadc->InjectionConfig.ChannelCount--;
/* 3. tmp_jsqr_context_queue_being_built is fully built for this HAL_ADCEx_InjectedConfigChannel()
call, aggregate the setting to those already built during the previous
HAL_ADCEx_InjectedConfigChannel() calls (for the same context of course) */
hadc->InjectionConfig.ContextQueue |= tmp_jsqr_context_queue_being_built;
/* 4. End of context setting: if this is the last channel set, then write context
into register JSQR and make it enter into queue */
if (hadc->InjectionConfig.ChannelCount == 0U)
{
MODIFY_REG(hadc->Instance->JSQR, ADC_JSQR_FIELDS, hadc->InjectionConfig.ContextQueue);
}
}
/* Parameters update conditioned to ADC state: */
/* Parameters that can be updated when ADC is disabled or enabled without */
/* conversion on going on injected group: */
/* - Injected context queue: Queue disable (active context is kept) or */
/* enable (context decremented, up to 2 contexts queued) */
/* - Injected discontinuous mode: can be enabled only if auto-injected */
/* mode is disabled. */
if (LL_ADC_INJ_IsConversionOngoing(hadc->Instance) == 0UL)
{
/* ADC channels preselection */
hadc->Instance->PCSEL |= (1UL << (__LL_ADC_CHANNEL_TO_DECIMAL_NB(pConfigInjected->InjectedChannel) & 0x1FUL));
/* If auto-injected mode is disabled: no constraint */
if (pConfigInjected->AutoInjectedConv == DISABLE)
{
MODIFY_REG(hadc->Instance->CFGR1,
ADC_CFGR1_JDISCEN,
ADC_CFGR_INJECT_DISCCONTINUOUS((uint32_t)pConfigInjected->InjectedDiscontinuousConvMode));
}
/* If auto-injected mode is enabled: Injected discontinuous setting is */
/* discarded. */
else
{
MODIFY_REG(hadc->Instance->CFGR1,
ADC_CFGR1_JDISCEN,
ADC_CFGR_INJECT_DISCCONTINUOUS((uint32_t)pConfigInjected->InjectedDiscontinuousConvMode));
}
}
/* Parameters update conditioned to ADC state: */
/* Parameters that can be updated when ADC is disabled or enabled without */
/* conversion on going on regular and injected groups: */
/* - Automatic injected conversion: can be enabled if injected group */
/* external triggers are disabled. */
/* - 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)
)
{
/* If injected group external triggers are disabled (set to injected */
/* software start): no constraint */
if ((pConfigInjected->ExternalTrigInjecConv == ADC_INJECTED_SOFTWARE_START)
|| (pConfigInjected->ExternalTrigInjecConvEdge == ADC_EXTERNALTRIGINJECCONV_EDGE_NONE))
{
if (pConfigInjected->AutoInjectedConv == ENABLE)
{
SET_BIT(hadc->Instance->CFGR1, ADC_CFGR1_JAUTO);
}
else
{
CLEAR_BIT(hadc->Instance->CFGR1, ADC_CFGR1_JAUTO);
}
}
/* If Automatic injected conversion was intended to be set and could not */
/* due to injected group external triggers enabled, error is reported. */
else
{
if (pConfigInjected->AutoInjectedConv == ENABLE)
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_CONFIG);
tmp_hal_status = HAL_ERROR;
}
else
{
CLEAR_BIT(hadc->Instance->CFGR1, ADC_CFGR1_JAUTO);
}
}
if (pConfigInjected->InjecOversamplingMode == ENABLE)
{
assert_param(IS_ADC_OVERSAMPLING_RATIO(pConfigInjected->InjecOversampling.Ratio));
assert_param(IS_ADC_RIGHT_BIT_SHIFT(pConfigInjected->InjecOversampling.RightBitShift));
/* JOVSE must be reset in case of triggered regular mode */
assert_param(!(READ_BIT(hadc->Instance->CFGR2, ADC_CFGR2_ROVSE | ADC_CFGR2_TROVS) ==
(ADC_CFGR2_ROVSE | ADC_CFGR2_TROVS)));
/* Configuration of Injected Oversampler: */
/* - Oversampling Ratio */
/* - Right bit shift */
/* Enable OverSampling mode */
MODIFY_REG(hadc->Instance->CFGR2,
ADC_CFGR2_JOVSE | ADC_CFGR2_OVSR | ADC_CFGR2_OVSS,
ADC_CFGR2_JOVSE | pConfigInjected->InjecOversampling.Ratio |
pConfigInjected->InjecOversampling.RightBitShift
);
}
else
{
/* Disable Regular OverSampling */
CLEAR_BIT(hadc->Instance->CFGR2, ADC_CFGR2_JOVSE);
}
/* Set sampling time of the selected ADC channel */
LL_ADC_SetChannelSamplingTime(hadc->Instance, pConfigInjected->InjectedChannel,
pConfigInjected->InjectedSamplingTime);
/* 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, pConfigInjected->InjectedOffset);
if (pConfigInjected->InjectedOffsetNumber != ADC_OFFSET_NONE)
{
/* Set ADC selected offset number */
LL_ADC_SetOffset(hadc->Instance, pConfigInjected->InjectedOffsetNumber, pConfigInjected->InjectedChannel,
tmp_offset_shifted);
/* Set ADC selected offset sign */
LL_ADC_SetOffsetSign(hadc->Instance, pConfigInjected->InjectedOffsetNumber, pConfigInjected->InjectedOffsetSign);
/* Set ADC selected offset signed saturation */
LL_ADC_SetOffsetSignedSaturation(hadc->Instance, pConfigInjected->InjectedOffsetNumber,
(pConfigInjected->InjectedOffsetSignedSaturation == ENABLE)
? LL_ADC_OFFSET_SIGNED_SATURATION_ENABLE \
: LL_ADC_OFFSET_SIGNED_SATURATION_DISABLE);
}
else
{
/* Scan each offset register to check if the selected channel is targeted. */
/* If this is the case, the corresponding offset number is disabled. */
if (__LL_ADC_CHANNEL_TO_DECIMAL_NB(LL_ADC_GetOffsetChannel(hadc->Instance, LL_ADC_OFFSET_1)) ==
__LL_ADC_CHANNEL_TO_DECIMAL_NB(pConfigInjected->InjectedChannel))
{
LL_ADC_SetOffset(hadc->Instance, LL_ADC_OFFSET_1, pConfigInjected->InjectedChannel,
LL_ADC_OFFSET_SIGNED_SATURATION_DISABLE);
}
if (__LL_ADC_CHANNEL_TO_DECIMAL_NB(LL_ADC_GetOffsetChannel(hadc->Instance, LL_ADC_OFFSET_2)) ==
__LL_ADC_CHANNEL_TO_DECIMAL_NB(pConfigInjected->InjectedChannel))
{
LL_ADC_SetOffset(hadc->Instance, LL_ADC_OFFSET_2, pConfigInjected->InjectedChannel,
LL_ADC_OFFSET_SIGNED_SATURATION_DISABLE);
}
if (__LL_ADC_CHANNEL_TO_DECIMAL_NB(LL_ADC_GetOffsetChannel(hadc->Instance, LL_ADC_OFFSET_3)) ==
__LL_ADC_CHANNEL_TO_DECIMAL_NB(pConfigInjected->InjectedChannel))
{
LL_ADC_SetOffset(hadc->Instance, LL_ADC_OFFSET_4, pConfigInjected->InjectedChannel,
LL_ADC_OFFSET_SIGNED_SATURATION_DISABLE);
}
if (__LL_ADC_CHANNEL_TO_DECIMAL_NB(LL_ADC_GetOffsetChannel(hadc->Instance, LL_ADC_OFFSET_4)) ==
__LL_ADC_CHANNEL_TO_DECIMAL_NB(pConfigInjected->InjectedChannel))
{
LL_ADC_SetOffset(hadc->Instance, LL_ADC_OFFSET_4, pConfigInjected->InjectedChannel,
LL_ADC_OFFSET_SIGNED_SATURATION_DISABLE);
}
}
}
/* 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, pConfigInjected->InjectedChannel, pConfigInjected->InjectedSingleDiff);
/* Configuration of differential mode */
/* Note: ADC channel number masked with value "0x1F" to ensure shift value within 32 bits range */
if (pConfigInjected->InjectedSingleDiff == ADC_DIFFERENTIAL_ENDED)
{
/* Set sampling time of the selected ADC channel */
tmp_channel = __LL_ADC_DECIMAL_NB_TO_CHANNEL((__LL_ADC_CHANNEL_TO_DECIMAL_NB(pConfigInjected->InjectedChannel) \
+ 1UL) & 0x1FUL);
LL_ADC_SetChannelSamplingTime(hadc->Instance, tmp_channel, pConfigInjected->InjectedSamplingTime);
}
/* Management of internal measurement channels: Vbat/VrefInt/TempSensor */
/* 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(). */
if (__LL_ADC_IS_CHANNEL_INTERNAL(pConfigInjected->InjectedChannel))
{
/* Configuration of common ADC parameters (continuation) */
/* 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)
{
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 ((pConfigInjected->InjectedChannel == 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_TEMPSENSOR_STAB_US / 10UL) * (SystemCoreClock / (100000UL * 2UL)));
while (wait_loop_index != 0UL)
{
wait_loop_index--;
}
}
}
else if ((pConfigInjected->InjectedChannel == 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 ((pConfigInjected->InjectedChannel == 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;
}
}
}
__HAL_UNLOCK(hadc);
return tmp_hal_status;
}