Skip to main content
ikok07
Associate
January 5, 2025
Solved

STM32H7A3ZI-Q getting random values from ADC

  • January 5, 2025
  • 2 replies
  • 895 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!

2 replies

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

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Thanks
ikok07
ikok07AuthorBest answer
Associate
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!