cancel
Showing results for 
Search instead for 
Did you mean: 

Couldn't get any ADC value with STM32H573 ADC

B.Redmoon
Associate II

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");
	}

}

 

2 REPLIES 2
B.Redmoon
Associate II

anybody?

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.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.