From b495b7b95c4d2d5ed909068fbf2a74b94e78895f Mon Sep 17 00:00:00 2001 From: Randy Rossi Date: Sat, 18 Oct 2025 10:20:58 -0400 Subject: [PATCH] arch/arm/stm32h5: Fix hanging ADC enable call. Posix open() calls to /dev/adc# were hanging often due to the ready loop check at the end of adc_enable() never returning. According to ES0565 document, at least 4 ADC clock cycles must pass between the time we waited for calibration to end and before we can set ADEN. This will depend on what clock is set for ADC. So to ensure enough time passes, we are adding a short delay (so that even a slow clock will work). Also, we are clearing the ADRDY flag before hand to ensure we are detecting a fresh event. The delay to wait for the voltage regulator is also increased to account for extra time required in non-ideal conditions. Signed-off-by: Liam Howatt --- arch/arm/src/stm32h5/stm32_adc.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/arch/arm/src/stm32h5/stm32_adc.c b/arch/arm/src/stm32h5/stm32_adc.c index e38f34e8a70..8e7d31113dd 100644 --- a/arch/arm/src/stm32h5/stm32_adc.c +++ b/arch/arm/src/stm32h5/stm32_adc.c @@ -649,7 +649,12 @@ static void adc_enable(struct stm32_dev_s *priv) /* Wait for voltage regulator to power up */ - up_udelay(20); + /* Datasheet recommends a _minimum_ of 20ms but it will depend + * on temperature, supply ramp and whether we've recently + * powered up ADC. So give a larger delay for safety. + */ + + up_udelay(50); /* Perform single-ended and/or differential calibration if necessary */ @@ -680,6 +685,17 @@ static void adc_enable(struct stm32_dev_s *priv) * ARM instructions. */ + /* ES0565 document (STM32H562/563/573 series) : As noted above, we + * can't set ADEN until 4 ADC clock cycles from now. This will depend + * on what we use for ADC clock. To ensure we give enough guard time + * we are delaying ADEN by at least 1 microsecond. This will ensure + * even a slow clock will have enough time before we try to set ADEN. + * Also, clear ADRDY to ensure we are waiting for a fresh event. + */ + + adc_modifyreg(priv, STM32_ADC_ISR_OFFSET, 0, ADC_INT_ADRDY); + up_udelay(1); + regval = adc_getreg(priv, STM32_ADC_CR_OFFSET); regval |= ADC_CR_ADEN; adc_putreg(priv, STM32_ADC_CR_OFFSET, regval);