Skip to main content
Pavel A.
February 14, 2023
Solved

ADC example for several channels polling?

Can anybody point me to example of two or more ADC channels polling?

​

I'm trying to measure two channels of one ADC but it looks like it reads one channel twice

​

Initialization:

static void MX_ADC1_Init(void)
{
 ADC_MultiModeTypeDef multimode = {0};
 ADC_ChannelConfTypeDef sConfig = {0};
 
 hadc1.Instance = ADC1;
 hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
 hadc1.Init.Resolution = ADC_RESOLUTION_12B;
 hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE; // scan all channels?
 hadc1.Init.ContinuousConvMode = DISABLE;
 hadc1.Init.DiscontinuousConvMode = DISABLE;
 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 hadc1.Init.NbrOfConversion = 2;
 hadc1.Init.DMAContinuousRequests = DISABLE;
 hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV; //<<<<
 hadc1.Init.LowPowerAutoWait = DISABLE;
 hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
 if (HAL_ADC_Init(&hadc1) != HAL_OK)
 {
 Error_Handler();
 }
 
 multimode.Mode = ADC_MODE_INDEPENDENT;
 if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
 {
 Error_Handler();
 }
 
 sConfig.Channel = ADC_CHANNEL_2;
 sConfig.Rank = ADC_REGULAR_RANK_1;
 sConfig.SingleDiff = ADC_SINGLE_ENDED;
 sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
 sConfig.OffsetNumber = ADC_OFFSET_NONE;
 sConfig.Offset = 0;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
 sConfig.Channel = ADC_CHANNEL_3;
 sConfig.Rank = ADC_REGULAR_RANK_2;
 sConfig.SingleDiff = ADC_SINGLE_ENDED;
 sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
 sConfig.OffsetNumber = ADC_OFFSET_NONE;
 sConfig.Offset = 0;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
}

​Reading;

​

 
void ADC_read2meas(ADC_HandleTypeDef *hADC_NAC, uint16_t *p1, uint16_t *p2)
{
 HAL_StatusTypeDef st = HAL_ADC_Start(hADC_NAC);
 if (st != HAL_OK) {
 Error_Handler();
 }
 
 st = HAL_ADC_PollForConversion(hADC_NAC, 3 /*ms*/);
 if (st != HAL_OK) {
 Error_Handler();
 }
 
 //1
 uint32_t v = HAL_ADC_GetValue(hADC_NAC);
 if (v & 0xFFFFF000) {
 Error_Handler(); // does not fit in 12 bits
 }
 *p1 = v & 0xFFF;
 
 v = HAL_ADC_GetValue(hADC_NAC);
 if (v & 0xFFFFF000) {
 Error_Handler(); // does not fit in 12 bits
 }
 *p2 = v & 0xFFF;
}

 Need to call start twice or call HAL_ADC_PollForConversion twice?

This topic has been closed for replies.
KnarfB
KnarfBBest answer
Super User
February 15, 2023

attached my L4 project, Drivers omitted for space reasons.

hth

KnarfB

14 replies

KnarfB
Super User
February 14, 2023

HAL_ADC_PollForConversion twice should do the trick.

Pavel A.
Pavel A.Author
February 14, 2023

> HAL_ADC_PollForConversion twice 

The 2nd HAL_ADC_PollForConversion (added in line 20) fails.

Do I need to change EOCSelection? hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

KnarfB
Super User
February 14, 2023

ADC_EOC_SINGLE_CONV

here is more on that https://community.st.com/s/question/0D53W00000trJxJSAU/reading-multiple-adc-channel

[Edit]

my init (STM32L432KC):

hadc1.Instance = ADC1;
 hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
 hadc1.Init.Resolution = ADC_RESOLUTION_12B;
 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
 hadc1.Init.LowPowerAutoWait = DISABLE;
 hadc1.Init.ContinuousConvMode = DISABLE;
 hadc1.Init.NbrOfConversion = 6;
 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.OversamplingMode = DISABLE;

my loop:

while (1)
 {
 HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
 
 status = HAL_ADC_Start(&hadc1);
 if (status != HAL_OK) {
 Error_Handler();
 }
 
 for( int i=0; i<sizeof(adc_raw)/sizeof(adc_raw[0]); ++i) {
 
 status = HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
 if (status != HAL_OK) {
 Error_Handler();
 }
 adc_raw[i] = HAL_ADC_GetValue(&hadc1);
 }
 
 HAL_Delay(1);
 
 /* USER CODE END WHILE */
 
 /* USER CODE BEGIN 3 */
 }

but HAL_ADC_Start_DMA works nicer?!

hth

KnarfB

S.Ma
Principal
February 15, 2023

There are many variations of ADC among the STM32 portfolio.

Some have injected channels, some don't

Some have differential inputs, some don't

Some have sigma delta ADC, some don't

For STM32C0, check the basic Analog.c source file. It has the basic to scan manually PA4/PA5 and Vref/Vtemp channels.

KnarfB
Super User
February 15, 2023

Yeah, but that demonstrates the per-channel config-start-poll loop, not the configall-start-poll-poll-poll... scenario.

KnarfB

KnarfB
KnarfBBest answer
Super User
February 15, 2023

attached my L4 project, Drivers omitted for space reasons.

hth

KnarfB

Pavel A.
Pavel A.Author
February 15, 2023

Thank you @KnarfB​ Sampling time in your project is much longer than mine, this can explain why it works with polling.

KnarfB
Super User
February 15, 2023

Ohh, that really makes a difference. Have reduced that time to the minimum and it stopped working. Saw the overrun flag set in ADC ISR.

As a remedy, I enabled Discontinuous Conversion Mode (1), and moved HAL_ADC_Start into the inner loop. That works for me.

hth

KnarfB

Associate II
October 15, 2023

In the Configuration part , don't we need two instances of sConfig for 2 different channel or only one instance will work no matter the number of channel?

 

Pavel A.
Pavel A.Author
October 15, 2023

@Tushar_4  The sConfig struct can be reused after HAL_ADC_ConfigChannel call. One instance will do. But this is not obvious in C code, you're right.