# STM32H7 ADC Baremetal - ADC not ready - ADC no conversion

I am trying to make baremetal ADC driver for following development board STM32H723ZG Nucleo (144 pins).

To simplify, lets assume (for example) to use PA3. According to Datasheet, PA3 corresponds to Channel 15. In order to use ADC module and proper pins, I perform following actions:

1. Enable Clk access to GPIOA
2. Set PA3 as Analog Mode
3. Enable Clk access to ADC1 module
4. Set conversion mode of ADC1 to continuous
5. Set sequence length to 1 (since only channel 15 is converted)
6. Set ADC channel to be converted in SQR1 (channel 15)
7. Disable deep powered mode by clearing DEEPPWD in Control Register
8. Enable regulator voltage VREGEN in Control Register
9. Wait for LDO to be supplied (LDORDY in ADC_ISR)
10. Enable the ADC by setting ADEN in Control Register
11. Start conversion with ADSTART in Control Register

Now the crazy thing is. All steps succeed. I can see the results in SFRs. But conversion is still not happening. Observing ADC_ISR bit ADRDY, it looks like ADC is not ready at all.

I dug through documentation forwards and backwards.

No errors triggered as well. Board is directly from the ST themselves.

Anyone has any helpful tips? :)

Thanks!

code:

#define ADC_1_CONV          (0U << 4U)
#define ADC_ISR_LDO_RDY     (1U << 12U)
#define PA3_ADC_CHN15           (15U << 6U)

void ADC_Init(void){
/**Configure the ADC pin**/
// Enable Clock Access to pins
RCC_SetAHB4_PeriphClock(RCC_AHB4ENR_GPIOAEN);
// Configure ADC pin to Analog mode
GPIO_SetPinMode(GPIOA,PA3_PIN,GPIO_ANALOG_MODE);

/* Configure the ADC module */
// Enable clock to ADC
RCC_SetAHB1_PeriphClock(RCC_AHB1ENR_ADC12EN);

// Set the conversion mode (continuous)
SET_BIT(ADC1->CFGR,ADC_CFGR_CONT);

// Set sequencer length
MODIFY_REG(ADC1->SQR1,ADC_SQR1_L,ADC_1_CONV);

// Set ADC channel
MODIFY_REG(ADC1->SQR1,ADC_SQR1_SQ1,PA3_ADC_CHN15);
//SET_BIT(ADC1->PCSEL_RES0,ADC_PCSEL_PCSEL_3);
//ADC_ISR_ADRDY

// Enable ADC module
CLEAR_BIT(ADC1->CR,ADC_CR_DEEPPWD);
SET_BIT(ADC1->CR,ADC_CR_ADVREGEN);
while (!(ADC1->ISR & ADC_ISR_LDO_RDY));

//SET_BIT(ADC1->ISR,ADC_ISR_ADRDY);
SET_BIT(ADC1->CR,ADC_CR_ADEN);
//while (!(ADC1->ISR & ADC_ISR_ADRDY));
for (int i = 0; i<10000; i++){};

// Start conversion
SET_BIT(ADC1->CR,ADC_CR_ADSTART);
}


Please note, helper functions like

GPIO_SetPinMode


and

RCC_SetAHB1_PeriphClock


work with 100% certainty :)

• I'd try setting the CKMODE bits to 0b11, to use the system clock (or some other divisor, depending on your clock frequency). The clock route through RCC is non-trivial, and you don't include any specific setup for that (other than enabling the ADC clock) so it may not be set up correctly by default. Feb 14 at 20:17
• @Klas-Kenny You were correct. The Clock source was not provided correctly. Meaning that ADC Kernel had no clock. Interesting, because I thought that without proper clock, registers cannot be configure. So I automatically assumed that clock was correct. However I totally forgot about dual clock domain. Thanks! :) Feb 15 at 14:02
• @AljazJelen - Hi, Now that Klas-Kenny has kindly written an answer containing the solution which you commented was successful, please consider "accepting" the answer (i.e. click the "tick mark" next to that answer, to turn it green). Although accepting an answer isn't mandatory, it is encouraged as your question is then shown as having an accepted answer in various lists, it makes it clear that you aren't waiting for more answers, it rewards both the answer-writer and you, and we don't get nagged for it being a question without an accepted answer. Thanks. Feb 16 at 15:31

## 1 Answer

You have not set the CKMODE bits of the ADC1_CCR register, so they are at their reset state of 0b00, selecting the kernel clock from RCC.

Although, you have not included any setup of RCC, other than enabling the ADC1/2 clock. Since the clock route through RCC is non-trivial, it is likely that the default state of RCC won't provide a functioning clock to the ADC.

I'd try setting CKMODE bits to 0b11 to use the system clock instead (or 0b01/0b10 for some other clock divider, depending on system clock frequency) to see if the ADC works then.
If it does, you know that clock is the issue and you can go ahead and try setting up RCC properly if you don't want to use the system clock.

• Solved in comments, added this answer instead as per moderators request, Feb 16 at 6:32
• Yes, I've solved my same problem with adding hadc2.Init.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4; line to code, but why? Why the path you called not trivial is not trivial, it mentioned on the reference manual and must work. Apr 27 at 14:53