2026-05-18 6:15 PM
Hello all,
I've been having trouble with the ADC system on the STM32G071G8U6. I'm using the STM32CubeMX to generate initialization code. I have 5 external A/D inputs and it appears I am not getting readings anywhere near the real values, so I have switched to trying to just read the internal reference. I hope that if I can get the internal reference or the temperature to read correctly, I'll be able to solve the problems with the external inputs.
My VDD is provided from a 2.5 volt LDO. Looking at it with a DVOM, that looks accurate.
I am running the A/D at 12 bit resolution and my clcok prescaler is Synchronous clock mode divided by 2. I have the sampling time set to the maximum available in Cube, 160.5 cycles.
I have a polling routine running every 1 second that reads all 5 external and all 3 internal channels.
I set the VREFEN and TSEN bits in the ADC CCR register at the end of init and leave them enabled.
I realize there may be board related problems with the external inputs. However, even when I just try to read the internal inputs, the internal reference or the temperature, I see 0, 1, or 2 A/D counts.
My periodic readings look like this, with some expected noise in the readings. The value on the left is a timestamp, followed by the channel name, followed by the channel value in square braces, followed by the raw A/D value:
[ 1.007] ADC polling:
[ 1.014] Internal Temp Raw ADC[B0001000] =0
[ 1.016] Internal Vref Raw ADC[B4002000] =2
[ 1.017] Internal Vbat Raw ADC[B8004000] =1983
I would expect the internal temperature channel and the internal Vref channel to be the easiest to debug. I assume there's some step I am missing...
The Cube generated ADC1 init routine is as follows:
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.LowPowerAutoPowerOff = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_160CYCLES_5;
hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_1CYCLE_5;
hadc1.Init.OversamplingMode = DISABLE;
hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_VREFINT;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
After all HAL initializations are completed, I run my ADC init routine:
void ADC_Init(void)
{
SET_BIT(ADC->CCR, ADC_CCR_VREFEN);
SET_BIT(ADC->CCR, ADC_CCR_TSEN);
HAL_ADCEx_Calibration_Start(&hadc1);
last_polling_tick = HAL_GetTick();
}
And then my actual readings are taken with this code:
uint32_t ADC_ReadChannel (uint32_t channel)
{
ADC_ChannelConfTypeDef sConfig = {0};
HAL_StatusTypeDef status;
uint32_t raw_adc = 4096;
// Configure the desired channel
sConfig.Channel = channel;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1; // Adjust as needed
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// Do the reading
status = HAL_ADC_Start(&hadc1);
if (status == HAL_OK)
{
status = HAL_ADC_PollForConversion(&hadc1, ADC_TIMEOUT_mS);
}
if (status == HAL_OK)
{
raw_adc = HAL_ADC_GetValue(&hadc1);
}
HAL_ADC_Stop(&hadc1);
PRINT_APP_DBG_NO_TIME(" Raw ADC[%08lX] =%i\r", channel, raw_adc);
return (raw_adc);
}
I can't see what I'm missing that's causing the ADC_CHANNEL_VREFINT and ADC_CHANNEL_TEMPSENSOR values to always be near 0...