2025-01-05 12:07 PM
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;
}
Solved! Go to Solution.
2025-01-08 11:40 AM
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!
2025-01-08 12:23 AM
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.
2025-01-08 11:40 AM
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!
