|
28 | 28 | // extmod/machine_adc.c via MICROPY_PY_MACHINE_ADC_INCLUDEFILE. |
29 | 29 |
|
30 | 30 | #include "py/mphal.h" |
| 31 | +#include "py/mperrno.h" |
31 | 32 | #include "adc.h" |
32 | 33 |
|
33 | 34 | #if defined(STM32F0) || defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32H7) || defined(STM32L0) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL) |
|
87 | 88 | #define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_247CYCLES_5 |
88 | 89 | #endif |
89 | 90 |
|
| 91 | +#define ADC_RESOLUTION (12) |
| 92 | + |
90 | 93 | // Timeout for waiting for end-of-conversion |
91 | 94 | #define ADC_EOC_TIMEOUT_MS (10) |
92 | 95 |
|
@@ -327,14 +330,31 @@ static int adc_get_bits(ADC_TypeDef *adc) { |
327 | 330 | static void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t sample_time) { |
328 | 331 | #if ADC_V2 |
329 | 332 | 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 | + } |
333 | 355 | } |
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); |
338 | 358 | } |
339 | 359 | } |
340 | 360 | #else |
@@ -445,11 +465,14 @@ static void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp |
445 | 465 |
|
446 | 466 | static uint32_t adc_read_channel(ADC_TypeDef *adc) { |
447 | 467 | 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++) |
453 | 476 | #endif |
454 | 477 | { |
455 | 478 | #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 |
596 | 619 | mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0); |
597 | 620 | } |
598 | 621 |
|
599 | | - adc_config(adc, 12); |
| 622 | + adc_config(adc, ADC_RESOLUTION); |
600 | 623 |
|
601 | 624 | machine_adc_obj_t *o = mp_obj_malloc(machine_adc_obj_t, &machine_adc_type); |
602 | 625 | o->adc = adc; |
|
0 commit comments