Skip to content

Commit ebfa7a9

Browse files
committed
stm32/machine_adc: Handle config failures in adc read.
Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
1 parent 5eee5a6 commit ebfa7a9

File tree

1 file changed

+36
-13
lines changed

1 file changed

+36
-13
lines changed

ports/stm32/machine_adc.c

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
// extmod/machine_adc.c via MICROPY_PY_MACHINE_ADC_INCLUDEFILE.
2929

3030
#include "py/mphal.h"
31+
#include "py/mperrno.h"
3132
#include "adc.h"
3233

3334
#if defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL)
@@ -87,6 +88,8 @@
8788
#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_247CYCLES_5
8889
#endif
8990

91+
#define ADC_RESOLUTION (12)
92+
9093
// Timeout for waiting for end-of-conversion
9194
#define ADC_EOC_TIMEOUT_MS (10)
9295

@@ -327,14 +330,31 @@ static int adc_get_bits(ADC_TypeDef *adc) {
327330
static void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t sample_time) {
328331
#if ADC_V2
329332
if (!(adc->CR & ADC_CR_ADEN)) {
330-
if (adc->CR & 0x3f) {
331-
// Cannot enable ADC with CR!=0
332-
return;
333+
for (uint8_t retry = 0; retry < 3; retry++) {
334+
if (adc->CR & 0x3f) {
335+
// Cannot enable ADC with CR!=0, reset and try again.
336+
adc_config(adc, ADC_RESOLUTION);
337+
if (adc->CR & 0x3f) {
338+
mp_raise_OSError(MP_EPERM);
339+
}
340+
}
341+
adc->ISR = ADC_ISR_ADRDY; // clear ADRDY
342+
adc->CR |= ADC_CR_ADEN;
343+
adc_stabilisation_delay_us(ADC_STAB_DELAY_US);
344+
uint32_t t0 = mp_hal_ticks_ms();
345+
while (!(adc->ISR & ADC_ISR_ADRDY)) {
346+
if (mp_hal_ticks_ms() - t0 > 10) {
347+
// The ADC hasn't enabled, reconfigure it
348+
adc_config(adc, ADC_RESOLUTION);
349+
break;
350+
}
351+
}
352+
if (adc->ISR & ADC_ISR_ADRDY) {
353+
break;
354+
}
333355
}
334-
adc->ISR = ADC_ISR_ADRDY; // clear ADRDY
335-
adc->CR |= ADC_CR_ADEN;
336-
adc_stabilisation_delay_us(ADC_STAB_DELAY_US);
337-
while (!(adc->ISR & ADC_ISR_ADRDY)) {
356+
if (!(adc->ISR & ADC_ISR_ADRDY)) {
357+
mp_raise_OSError(MP_ETIMEDOUT);
338358
}
339359
}
340360
#else
@@ -445,11 +465,14 @@ static void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp
445465

446466
static uint32_t adc_read_channel(ADC_TypeDef *adc) {
447467
uint32_t value;
448-
#if defined(STM32G4)
449-
// For STM32G4 there is errata 2.7.7, "Wrong ADC result if conversion done late after
450-
// calibration or previous conversion". According to the errata, this can be avoided
451-
// by performing two consecutive ADC conversions and keeping the second result.
452-
for (uint8_t i = 0; i < 2; i++)
468+
#if defined(STM32G4) || defined(STM32WB)
469+
// For STM32G4 errata 2.7.7 / STM32WB errata 2.7.1:
470+
// "Wrong ADC result if conversion done late after calibration or previous conversion"
471+
// states an incorrect reading is returned if more than 1ms has elapsed since the last
472+
// reading or calibration. According to the errata, this can be avoided by performing
473+
// two consecutive ADC conversions and keeping the second result.
474+
// Note: On STM32WB55 @ 64Mhz each ADC read takes ~ 3us.
475+
for (int8_t i = 0; i < 2; i++)
453476
#endif
454477
{
455478
#if ADC_V2
@@ -596,7 +619,7 @@ static mp_obj_t mp_machine_adc_make_new(const mp_obj_type_t *type, size_t n_args
596619
mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
597620
}
598621

599-
adc_config(adc, 12);
622+
adc_config(adc, ADC_RESOLUTION);
600623

601624
machine_adc_obj_t *o = mp_obj_malloc(machine_adc_obj_t, &machine_adc_type);
602625
o->adc = adc;

0 commit comments

Comments
 (0)