drivers: adc: stm32: Fix race condition with internal channels

When using one of the internal channels (die_temp, vbat, vref) the
channels are enabled in the individual drivers and disabled again
whenever an adc conversion is complete.

This creates a race condition if the ADC is used from multiple threads.

This commit moves the disabling of the channels to the individual
drivers.

Signed-off-by: Brian Juel Folkmann <bju@trackunit.com>
This commit is contained in:
Brian Juel Folkmann 2024-01-05 09:10:31 +01:00 committed by Carles Cufí
parent 768ed26010
commit 06b57926a2
4 changed files with 24 additions and 7 deletions

View file

@ -1087,10 +1087,6 @@ static void adc_context_on_complete(struct adc_context *ctx, int status)
/* Reset acquisition time used for the sequence */
data->acq_time_index = -1;
/* Reset internal channels */
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(adc),
LL_ADC_PATH_INTERNAL_NONE);
#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32U5X)
/* Reset channel preselection register */
LL_ADC_SetChannelPreselection(adc, 0);

View file

@ -67,6 +67,7 @@ static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel
struct stm32_temp_data *data = dev->data;
struct adc_sequence *sp = &data->adc_seq;
int rc;
uint32_t path;
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) {
return -ENOTSUP;
@ -80,8 +81,10 @@ static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel
goto unlock;
}
path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base));
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base),
LL_ADC_PATH_INTERNAL_TEMPSENSOR);
LL_ADC_PATH_INTERNAL_TEMPSENSOR | path);
k_usleep(LL_ADC_DELAY_TEMPSENSOR_STAB_US);
rc = adc_read(data->adc, sp);
@ -89,6 +92,10 @@ static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel
data->raw = data->sample_buffer;
}
path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base));
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base),
path &= ~LL_ADC_PATH_INTERNAL_TEMPSENSOR);
unlock:
k_mutex_unlock(&data->mutex);

View file

@ -38,6 +38,7 @@ static int stm32_vbat_sample_fetch(const struct device *dev, enum sensor_channel
struct stm32_vbat_data *data = dev->data;
struct adc_sequence *sp = &data->adc_seq;
int rc;
uint32_t path;
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE) {
return -ENOTSUP;
@ -52,14 +53,19 @@ static int stm32_vbat_sample_fetch(const struct device *dev, enum sensor_channel
goto unlock;
}
path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base));
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base),
LL_ADC_PATH_INTERNAL_VBAT);
LL_ADC_PATH_INTERNAL_VBAT | path);
rc = adc_read(data->adc, sp);
if (rc == 0) {
data->raw = data->sample_buffer;
}
path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base));
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base),
path &= ~LL_ADC_PATH_INTERNAL_VBAT);
unlock:
k_mutex_unlock(&data->mutex);

View file

@ -38,6 +38,7 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel
struct stm32_vref_data *data = dev->data;
struct adc_sequence *sp = &data->adc_seq;
int rc;
uint32_t path;
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE) {
return -ENOTSUP;
@ -51,8 +52,10 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel
goto unlock;
}
path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base));
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base),
LL_ADC_PATH_INTERNAL_VREFINT);
LL_ADC_PATH_INTERNAL_VREFINT | path);
#ifdef LL_ADC_DELAY_VREFINT_STAB_US
k_usleep(LL_ADC_DELAY_VREFINT_STAB_US);
#endif
@ -62,6 +65,11 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel
data->raw = data->sample_buffer;
}
path = LL_ADC_GetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base));
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(data->adc_base),
path &= ~LL_ADC_PATH_INTERNAL_VREFINT);
unlock:
k_mutex_unlock(&data->mutex);