Skip to main content
Visitor II
March 26, 2025
Question

Couldn't get any ADC value with STM32H573 ADC

  • March 26, 2025
  • 1 reply
  • 465 views

I need help. I couldn't get any adc value whether with live expressions or UART . UART is working fine so the problem is within the ADC configuration code. have i miss or overcomplicated anything?

 

#include "stdio.h"
#include "stdint.h"
#include "stm32h573xx.h"
#include "uart.h"

//volatile uint16_t sensor_value;
__IO uint16_t sensor_value;

void PA4_PA5_ADC_Init(void) {
 //RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;					//Enable Clock for GPIOA
 GPIOA->MODER &= ~((3U << (4 * 2)) | (3U << (5 * 2)));	//Reset PA4 & PA5
 GPIOA->MODER |= ((3U << (4 * 2)) | (3U << (5 * 2)));	//Set PA4 & PA5 as analog input
 GPIOA->PUPDR &= ~((3U << (4 * 2)) | (3U << (5 * 2))); //Set no pullup or pulldown
}

void adcclk_init(void){
	// Configure ADC clock source
	//
	//hsi_ck selected as system clk in uart.c
	//
	RCC->AHB2ENR |= (1U << 10);								//Enable ADC Clock

	RCC->CCIPR5 &= ~(7U << 0); 							// Clear ADCSEL bits; rcc_hclk as clock source (default after reset)
	RCC->CCIPR5 |= (1U<<0);									//sys_ck slected as kernel clk for ADC

	ADC12_COMMON->CCR &= ~(0x1F<<0);						//Set ADC1 and ADC2 to independent mode
	ADC12_COMMON->CCR &= ~(15U<<18);						//PRESC[3:0] | ADC prescaler; Input ADC clock not divided

	ADC12_COMMON->CCR &= ~(3U<<16);							//CKMODE[1:0] | 00 ADC clock scheme: adc_ker_ck
	ADC12_COMMON->CCR |= (1U<<16);							//CKMODE[1:0] | 01 ADC clock scheme: adc_hclk/1
	//This configuration must be enabled only if the AHB clock prescaler is set to 1 (HPRE[3:0] = 0XXX in RCC_CFGR register)
	//and if the system clock has a 50% duty cycle. RCC_CFGR HPRE[3:0] wasset in uart.c
}

void adcinit(void) {
	VREFBUF->CSR &= ~(7U<<4);								//Set to VREFBUF0
 // Enable VREFBUF
	VREFBUF->CSR &= ~(1U<<1);								//Set HIZ to 0
	VREFBUF->CSR &= ~(1U<<0);
	VREFBUF->CSR |= (1U<<0);								//Set ENVR to 1
 while (!(VREFBUF->CSR & VREFBUF_CSR_VRR)) {}
 //while (!(VREFBUF->CSR & (1U<<3))) {}					//Wait until Voltage ref buffer output has stabilized.



 ADC1->SMPR2 &= ~(7U <<24);					// Set ADC CH18 sample time to 2.5ADC cycles
 ADC1->DIFSEL |= (1U << 18);				// Set ADC Channel 18 as diff. mode (PA4 is INP18 while PA5 is INN18)
 //ADC1->DIFSEL &= ~(1U << 18);				// Set ADC Channel 18 as single-ended mode (PA4 is INP18 while PA5 is INN18)


 ADC1->SQR1 &= ~(15U << 0); 			// Set Seq length to single conversion
 ADC1->SQR1 &= ~(31U << 6); 				// Clear bits 6-10
 ADC1->SQR1 |= (18U << 6); 				// Write 18 (dec) on bits 6-10 to set Channel 18 as the 1st sequence for ADC conversion

 ADC1->CFGR &= ~((1U << 11) | (1U << 10));	// Select sw trigger for ADC conversion
 ADC1->CFGR &= ~((1U << 4) | (1U << 3));		// Set 12-bit resolution (default)
 ADC1->CFGR &= ~(1U << 15); 					// Set to right alignment

 ADC1->CFGR |= ADC_CFGR_CONT;				// Set ADC to continuous mode
 ADC1->CFGR |= ADC_CFGR_OVRMOD;				// Set ADC to overwrite when register is full

 ADC1->CR &= ~ADC_CR_DEEPPWD;				// Take ADC voltage regulator out of deep power down mode
 ADC1->CR |= ADC_CR_ADVREGEN;				// Enable ADC regulator
 for (volatile int i = 0; i < 10000; i++);	// Implement delay > TADCVREG_STUP which is 10us

 ADC1->ISR &= ~(1U << 4);					// Clear OVR status
 ADC1->ISR &= ~(1U << 3);					// Clear EOS status
 ADC1->CR &= ~ADC_CR_ADDIS; 					// Clear ADC disable command

}
//
void start_conversion(void) {

	ADC1->ISR &= ~ADC_ISR_ADRDY;		 // Clear ADC ready status
	ADC1->CR |= ADC_CR_ADEN; 					// Enable ADC
	for (volatile int i = 0; i < 10000; i++); 	// Small delay
 while (!(ADC1->ISR & ADC_ISR_ADRDY)) {}
 for (volatile int i = 0; i < 10000; i++); 	// Small delay
 ADC1->CR |= ADC_CR_ADSTART;					// Start conversion
}

uint16_t ADC_Read(void) {
 int timeout = 1000000;
 while (!(ADC1->ISR & ADC_ISR_EOC)) {		//if End of Conversion is reached
 //if (--timeout == 0) {
 // printf("ADC Timeout! \n\r");
 // return 0;
 //}
 }
 return (uint16_t)ADC1->DR;
}


int main(void)

{
	RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;
	usart1_rxtx_init();
	PA4_PA5_ADC_Init();
	adcclk_init();
	adcinit();

	while(1)
	{
		start_conversion();
		sensor_value = ADC_Read();
		printf("Sensor Value: %d \n", sensor_value);
		//usart1_write('Y');
		//printf("UART is working fine........\n\r");
		for (volatile int i = 0; i < 100000; i++);
		printf("UART is working fine........\n\r");
	}

}

 

    This topic has been closed for replies.

    1 reply

    B.RedmoonAuthor
    Visitor II
    April 1, 2025

    anybody?

    Technical Moderator
    April 3, 2025

    Hello,

    Better to start by using the HAL and inspire from the examples provided in STM32CubeH5 package:
    https://github.com/STMicroelectronics/STM32CubeH5/tree/main/Projects/NUCLEO-H563ZI/Examples/ADC
    Or simply start by using CubeMX to generate the code base on your configuration.
    Then if you succeed with that you can inspire from the HAL implementation to develop your specific direct access to the registers.