cancel
Showing results for 
Search instead for 
Did you mean: 

Help Needed: STM32H750 ADC1 PA0 Not Reading Continuously

electrohighlow
Visitor

Issue Description:
I am trying to configure ADC1 on PA0 (Channel 16) in continuous mode on the STM32H750 microcontroller. However, the code gets stuck at:

while (!(ADC1->ISR & ISR_EOC) && --timeout); // :white_heavy_check_mark: Wait for End-of-Conversion
This suggests that EOC (End-of-Conversion) is never set, meaning the ADC is not completing a conversion.

*What I Have Done:
-Enabled clocks for GPIOA and ADC1 (RCC->AHB4ENR and RCC->AHB1ENR)
-Configured PA0 as Analog Mode (GPIOA->MODER |= (3U << 0);)
-Set the correct ADC clock source in CCR
-Exited deep power-down mode and enabled the ADC voltage regulator
-Performed ADC calibration and waited for completion
-Enabled ADC and waited for ISR_ADRDY (ADC Ready flag)
-Enabled PA0 in PCSEL
-Set CFGR_CONT for continuous mode
-Configured SQR1 for a single-channel sequence (Channel 16, Rank 1)
-Set maximum sampling time for PA0 (SMPR1)
-Started ADC conversion (CR_ADSTART)
-Full Code:
#include "stm32h7xx.h"
#include <stdint.h>

// Define Register Bit Masks
#define GPIOAEN (1U << 0) // Enable GPIOA Clock
#define ADC1EN (1U << 5) // Enable ADC1 Clock
#define CR_ADVREGEN (1U << 28) // Voltage Regulator Enable
#define CR_DEEPPWD (1U << 29) // Deep Power-Down Disable
#define ADC_CALIBRATION (1U << 31) // ADC Calibration
#define CFGR_CONT (1U << 13) // Continuous Mode Enable

// Define ADC Control Register Bits
#define CR_ADEN (1U << 0) // ADC Enable Bit
#define CR_ADSTART (1U << 2) // ADC Start Conversion
#define CR_ADDIS (1U << 1) // ADC Disable Bit

// Define ADC Status Register Bits
#define ISR_EOC (1U << 2) // End of Conversion Flag
#define ISR_ADRDY (1U << 0) // ADC Ready Flag
#define ISR_LDORDY (1U << 12) // ADC LDO Ready Flag

// Define ADC Channel Configuration
#define CH16_RANK1 (16U << 6) // Channel 16 (PA0) as Rank 1

volatile uint32_t adc_value; // Store ADC result

// Function to Initialize ADC for PA0 (Channel 16) in Continuous Mode
void adc1_init(void) {
// 1-Enable Clocks for GPIOA and ADC1
RCC->AHB4ENR |= GPIOAEN; // Enable GPIOA Clock
RCC->AHB1ENR |= ADC1EN; // Enable ADC1 Clock

// :white_heavy_check_mark: Ensure ADC is using the correct clock
ADC12_COMMON->CCR &= ~(0b11 << 16); // Clear clock source
ADC12_COMMON->CCR |= (0b01 << 16); // Select AHB clock for ADC

//2-Configure PA0 as Analog Mode
GPIOA->MODER |= (3U << 0); // Set PA0 to Analog Mode
GPIOA->PUPDR &= ~(3U << 0); // No Pull-up, No Pull-down

// 3-Exit Deep Power Down & Enable Voltage Regulator
ADC1->CR &= ~CR_DEEPPWD; // Exit deep power-down
ADC1->CR |= CR_ADVREGEN; // Enable voltage regulator
while (!(ADC1->ISR & ISR_LDORDY)); // :white_heavy_check_mark: Wait for LDO Ready

// 4-Ensure ADC is Disabled Before Calibration
if (ADC1->CR & CR_ADEN) {
ADC1->CR |= CR_ADDIS; // ADC Disable
while (ADC1->CR & CR_ADEN);
}

// 5-Start Calibration
ADC1->CR |= ADC_CALIBRATION;
while (ADC1->CR & ADC_CALIBRATION); // :white_heavy_check_mark: Wait for calibration

// 6-Enable ADC
ADC1->CR |= CR_ADEN;
while (!(ADC1->ISR & ISR_ADRDY)); // :white_heavy_check_mark: Wait for ADC Ready

// 7-Enable Channel 16 (PA0) in PCSEL
ADC1->PCSEL |= (1U << 16); // :white_heavy_check_mark: Must enable the channel in PCSEL

// 8-Configure ADC for Continuous Mode
ADC1->CFGR |= CFGR_CONT; // :white_heavy_check_mark: Enable Continuous Mode
ADC1->SQR1 &= ~(0xF << 0); // Clear sequence length
ADC1->SQR1 |= CH16_RANK1; // Set Channel 16 (PA0) as Rank 1

// 9-Set Correct Sampling Time for Channel 16
ADC1->SMPR1 |= (0b111 << 18); // Max sampling time for PA0

// 10-Start ADC Conversion (Only if ADC is Ready)
ADC1->ISR |= ISR_EOC; // :white_heavy_check_mark: Clear any previous EOC flag
ADC1->CR |= CR_ADSTART;
}

// Function to Read ADC Value
uint32_t adc_read(void) {
uint32_t timeout = 1000000; // Prevent infinite loop

while (!(ADC1->ISR & ISR_EOC) && --timeout); // :white_heavy_check_mark: Wait for End-of-Conversion
if (timeout == 0) {
return 0xFFFFFFFF; // Error: Timeout occurred
}

ADC1->ISR |= ISR_EOC; // :white_heavy_check_mark: Clear EOC flag to allow next conversion
return ADC1->DR; // Read ADC value
}

int main(void) {
adc1_init(); // Initialize ADC1 for Continuous Conversion on PA0

while (1) {
adc_value = adc_read(); // Continuously Read ADC
}
}
*****What I Need Help With***
Why does the ADC get stuck at while (!(ADC1->ISR & ISR_EOC));?

Is ADSTART getting cleared automatically after the first conversion?
Should I manually restart ADSTART?
Is PCSEL being set correctly before conversion starts?

I am enabling PCSEL (ADC1->PCSEL |= (1U << 16);) before configuring the sequence.
Are there any additional settings required in CCR, CFGR, or SMPR?

Should I explicitly configure DIFSEL or LTR registers?
Are there better debugging methods to check if the ADC is running?

Should I use an oscilloscope to check PA0 input?
Are there any status bits I should read to confirm ADC is running?
******System Information*****
Microcontroller: STM32H750
IDE: STM32CubeIDE
Debugger: ST-LINK V2

0 REPLIES 0