2
\$\begingroup\$

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

\$\endgroup\$
3
  • 2
    \$\begingroup\$ 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. \$\endgroup\$
    – Klas-Kenny
    Feb 14 at 20:17
  • \$\begingroup\$ @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! :) \$\endgroup\$ Feb 15 at 14:02
  • \$\begingroup\$ @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. \$\endgroup\$
    – SamGibson
    Feb 16 at 15:31

1 Answer 1

2
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ Solved in comments, added this answer instead as per moderators request, \$\endgroup\$
    – Klas-Kenny
    Feb 16 at 6:32
  • \$\begingroup\$ 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. \$\endgroup\$ Apr 27 at 14:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.