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 */ /* Reset acquisition time used for the sequence */
data->acq_time_index = -1; 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) #if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32U5X)
/* Reset channel preselection register */ /* Reset channel preselection register */
LL_ADC_SetChannelPreselection(adc, 0); 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 stm32_temp_data *data = dev->data;
struct adc_sequence *sp = &data->adc_seq; struct adc_sequence *sp = &data->adc_seq;
int rc; int rc;
uint32_t path;
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) { if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_DIE_TEMP) {
return -ENOTSUP; return -ENOTSUP;
@ -80,8 +81,10 @@ static int stm32_temp_sample_fetch(const struct device *dev, enum sensor_channel
goto unlock; 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_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); k_usleep(LL_ADC_DELAY_TEMPSENSOR_STAB_US);
rc = adc_read(data->adc, sp); 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; 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: unlock:
k_mutex_unlock(&data->mutex); 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 stm32_vbat_data *data = dev->data;
struct adc_sequence *sp = &data->adc_seq; struct adc_sequence *sp = &data->adc_seq;
int rc; int rc;
uint32_t path;
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE) { if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE) {
return -ENOTSUP; return -ENOTSUP;
@ -52,14 +53,19 @@ static int stm32_vbat_sample_fetch(const struct device *dev, enum sensor_channel
goto unlock; 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_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); rc = adc_read(data->adc, sp);
if (rc == 0) { if (rc == 0) {
data->raw = data->sample_buffer; 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: unlock:
k_mutex_unlock(&data->mutex); 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 stm32_vref_data *data = dev->data;
struct adc_sequence *sp = &data->adc_seq; struct adc_sequence *sp = &data->adc_seq;
int rc; int rc;
uint32_t path;
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE) { if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_VOLTAGE) {
return -ENOTSUP; return -ENOTSUP;
@ -51,8 +52,10 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel
goto unlock; 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_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 #ifdef LL_ADC_DELAY_VREFINT_STAB_US
k_usleep(LL_ADC_DELAY_VREFINT_STAB_US); k_usleep(LL_ADC_DELAY_VREFINT_STAB_US);
#endif #endif
@ -62,6 +65,11 @@ static int stm32_vref_sample_fetch(const struct device *dev, enum sensor_channel
data->raw = data->sample_buffer; 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: unlock:
k_mutex_unlock(&data->mutex); k_mutex_unlock(&data->mutex);