Skip to main content
Super User
February 14, 2023
Solved

ADC example for several channels polling?

  • February 14, 2023
  • 4 replies
  • 17392 views

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.
    Best answer by KnarfB

    attached my L4 project, Drivers omitted for space reasons.

    hth

    KnarfB

    4 replies

    Super User
    February 14, 2023

    HAL_ADC_PollForConversion twice should do the trick.

    Pavel A.Author
    Super User
    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;

    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

    Visitor II
    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.

    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

    KnarfBAnswer
    Super User
    February 15, 2023

    attached my L4 project, Drivers omitted for space reasons.

    hth

    KnarfB

    Pavel A.Author
    Super User
    February 15, 2023

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

    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

    Graduate
    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.Author
    Super User
    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.