cancel
Showing results for 
Search instead for 
Did you mean: 

What can keep the ADC from finishing a conversion? (STM32G474)

EThom.3
Senior II

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 finish

My 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.

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Super User

Wait until calibration is done before configuring the ADC.

You're not really following the RM procedure for how to enable the ADC.

TDK_0-1768922146453.png

 

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

2 REPLIES 2
TDK
Super User

Wait until calibration is done before configuring the ADC.

You're not really following the RM procedure for how to enable the ADC.

TDK_0-1768922146453.png

 

If you feel a post has answered your question, please click "Accept as Solution".

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! :)