Skip to main content
Visitor II
January 5, 2025
Solved

STM32H7A3ZI-Q getting random values from ADC

  • January 5, 2025
  • 1 reply
  • 852 views

Hello, I'm currently trying to develop a bare-metal ADC driver for my Nucleo STM32H7A3ZI-Q Board. I have done all the necessary steps in order to setup the ADC, however I still get random values from the data register, even though I have my PF11 (or A5) connected to the GND.

Here is my current code:

#define ADC1EN					(1U<<5)
#define GPIOFEN					(1U<<5)
#define ADC_CH2					(1U<<7)
#define ADC_SEQ_LEN_1			 (0x00)

#define ADC_DEEPPWDEN			 (1U<<29)
#define ADC_REGEN				(1U<<28)
#define ADC_LDORDY				(1U<<12)
#define ADC_PRESC_2				(1U<<18)
#define ADC_CKMODE_SCLK_1		 (2U<<16)
#define ADC_ADCALDIF			 (1U<<30)
#define ADC_ADCALLIN			 (1U<<16)
#define ADC_ADCAL				(1U<<31)
#define ADC_ADEN				(1U<<0)
#define ADC_ADSTART				(1U<<2)
#define ADC_ADRDY				(1U<<0)

#define ADC_EOC					(1U<<2)

void pf11_adc_init(void) {

	// Configure the ADC GPIO pin

	RCC->AHB4ENR |= GPIOFEN; 				// Enable clock access to GPIOF
	GPIOF->MODER |= (1U<<23) | (1U<<22); 	// Set mode of PF11 to analog

	// Configure the ADC module

	RCC->AHB1ENR |= ADC1EN; // Enable clock access to ADC1

	// Conversion sequence start
	ADC1->SQR1 = ADC_CH2;

	// Conversion sequence length
	ADC1->SQR1 |= ADC_SEQ_LEN_1;

	// Disable ADC deep-power-down mode
	ADC1->CR &=~ ADC_DEEPPWDEN;

	// Start the voltage regulator
	ADC1->CR |= ADC_REGEN;

	// Wait for the regulator to start up
	while (!(ADC1->ISR & ADC_LDORDY)) {}

	// Select prescaler -> 2
//	ADC12_COMMON->CCR |= ADC_PRESC_2;

	// Select kernel clock (derive from AHB clock)
	ADC12_COMMON->CCR |= ADC_CKMODE_SCLK_1;

	// Set single-ended calibration mode
	ADC1->CR &=~ ADC_ADCALDIF;

	// Enable linearity calibration
	ADC1->CR |= ADC_ADCALLIN;

	// Start ADC calibration
	ADC1->CR |= ADC_ADCAL;

	// Wait for calibration to finish
	while (ADC1->CR & ADC_ADCAL) {}

	// Enable the ADC module
	ADC1->ISR |= ADC_ADRDY; // clear ready state
	ADC1->CR |= ADC_ADEN;

	// Wait for the ADC to be ready
	while (!(ADC1->ISR & ADC_ADRDY)) {}
}

void start_conversion(void) {

	// Start the ADC conversion
	ADC1->CR |= ADC_ADSTART;
}

uint32_t adc_read(void) {
	// Wait for conversion to be complete
	while (!(ADC1->ISR & ADC_EOC)) {}

	// Read converted result
	return ADC1->DR;
}

 

    This topic has been closed for replies.
    Best answer by ikok07

    I looked again in the reference manual and it turned out that I didn't preselect the channel. After I set the ADC_PCSEL register the ADC worked as expected. Thank you!

    1 reply

    Technical Moderator
    January 8, 2025

    Hello @ikok07 ,

    What values/range are you getting?

    Make sure that the ADC clock is running at the correct frequency. Check if the ADC channels are properly enabled and configured.

    I advise you to test and run the ready-to-use ADC example, this helps isolate the issue and ensures that the problem seems related to the hardware or software : STM32CubeH7/Projects/NUCLEO-H7A3ZI-Q/Examples/ADC at master · STMicroelectronics/STM32CubeH7 · GitHub

    Also, refer to the errata sheet for your product and check whether you have an ADC limitation that is described in the documentation.

    ikok07AuthorAnswer
    Visitor II
    January 8, 2025

    I looked again in the reference manual and it turned out that I didn't preselect the channel. After I set the ADC_PCSEL register the ADC worked as expected. Thank you!