2026-01-20 7:00 AM - edited 2026-01-20 7:07 AM
I am trying to complete one – just one – ADC conversion without using DMA. This is sort of a one-off sampling after power-on, and subsquently the regular sequence conversion with DMA is to take over. But I don't get that far.
I'm trying to sample ADC1 channel 15, but never get a high EOC flag. To be absolutely certain about how the ADC is set up, I've read these register values via STM32CubeProgrammer:
ADC1_CFGR = 0x80000000
In short: Injected queue disabled; contiuous and discontinuous modes off; hardware trigger disabled; DMA disabled.
ADC1_CFGR2 = 0
In short: BULB disabled; gain compensation disabled; oversampling disabled.
ADC1_SMPR2 = 0x0003E000
In short: Channel 15 sampling time 640.5 clock cycles; channel 14 sampling time 247.5 clock cycles.
ADC1_SQR1 = 0x081C23C0
In short: First conversion channel is 15. Number of conversions is 1. All other bits should be irrelevant.
ADC1_CR = 0x10000005
In short: ADC voltage regulator is enabled; ADC is enabled: ADC is converting (apparently)
ADC1_ISR = 1
In short: ADC is ready. EOC never changes to 1.
Just to check that the ADC clock is enabled, I read the appropriate RCC register:
RCC_AHB2ENR = 0x0003607F
In short: All ADC clocks are enabled.
Has the IO pin (PB0) even be set to be an analog input?
GPIOB_MODER = 0xAAFEAA7F
Yes, the IO pin is configured as an analog input.
DMA1_CCR7 = 0x00000580
In short: The DMA channel is disabled, as I intend not to use it for this conversion.
A condensed version of the ADC code is here:
ADCHandle->Instance->CR |= ADC_CR_ADCAL; // Start calibration
ADCHandle->Instance->SMPR2 |= ADC_SMPR2_SMP15_Msk; // Set 640.5 ADC clock cycles for channel 15.
ADCHandle->Instance->SQR1 = (ADCHandle->Instance->SQR1 & ~(ADC_SQR1_SQ1_Msk | ADC_SQR1_L_Msk)) | (15 << ADC_SQR1_SQ1_Pos); // Set channel 15 and only one conversion
ADCHandle->Instance->CFGR = ADC_CFGR_JQDIS; // Disable injected queue and DMA
ADCHandle->Instance->CFGR2 = 0;
while (ADCHandle->Instance->CR & ADC_CR_ADCAL); // Wait for calibration to finish
ADCHandle->Instance->CR |= ADC_CR_ADEN; // ADC enable
ADCHandle->Instance->ISR = ADC_ISR_EOS | ADC_ISR_EOC; // Reset EOS and EOC flags
ADCHandle->Instance->CR |= ADC_CR_ADSTART; // ADC start conversion
while (!(ADCHandle->Instance->ISR & ADC_ISR_EOC)); // Wait for conversion to finishMy program gets stuck in the last while loop, as EOC never becomes 1.
ADCHandle is a pointer to hadc1, which is declared in main.c. I could have used ADC1 diectly, but I initially intended to make the function more portable. In any case, the registers get the intended values, so this shouldn't be the issue..
If I skip this piece of code, the DMA-based conversions run fine. I clearly have access to the ADC when I set it up with DMA – just not without it. I am currently considering using DMA for this just to make something work, but I would rather figure out what I am doing wrong.
Can someone see if I've missed something obvious? One of more crucial registers I haven't considered? Any help would be greatly appreciated.
Edit: Corrected name of RCC register.
Solved! Go to Solution.
2026-01-20 7:16 AM
Wait until calibration is done before configuring the ADC.
You're not really following the RM procedure for how to enable the ADC.
2026-01-20 7:16 AM
Wait until calibration is done before configuring the ADC.
You're not really following the RM procedure for how to enable the ADC.
2026-01-20 7:28 AM
Thanks! I had a hunch that I had overlooked something relatively simple.
This made a huge difference:
ADCHandle->Instance->ISR = ADC_ISR_ADRDY; // Clear ADRDY flag
ADCHandle->Instance->CR |= ADC_CR_ADEN; // ADC enable
while (!(ADCHandle->Instance->ISR & ADC_ISR_ADRDY)); // Wait for ADC ready
Much appreciated! :)