cancel
Showing results for 
Search instead for 
Did you mean: 

ADC example for several channels polling?

Pavel A.
Evangelist III

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?

1 ACCEPTED SOLUTION

Accepted Solutions
KnarfB
Principal III

attached my L4 project, Drivers omitted for space reasons.

hth

KnarfB

View solution in original post

14 REPLIES 14
KnarfB
Principal III

HAL_ADC_PollForConversion twice should do the trick.

> 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;

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

> but HAL_ADC_Start_DMA works nicer?!

Maybe. But I thought polling with multiple channels was possible too.

Changed Init.EOCSelection = ADC_EOC_SINGLE_CONV.

Repeated HAL_ADC_PollForConversion always fails for me.

failes how, timeout?

Debugging seems to interfere by reading the data register which clears EOC.

S.Ma
Principal

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.

Yes, timeout on the 2nd HAL_ADC_PollForConversion.

I run thru all this at full speed.

It seems that the ADC data register in STM32F30 does not have a buffer or FIFO, so it must be read very quickly, preferably by DMA? Or increase sampling time?

KnarfB
Principal III

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

KnarfB

Pavel A.
Evangelist III

> For STM32C0, check the basic Analog.c source file

Thank you but there you poll all channels one by one, on the same position. For each conversion, call HAL_ADC_ConfigChannel then HAL_ADC_Start. This way, it works for me on STM32F3 too. The question is, how to do conversion of several channels at once without DMA?

I've tried to use injected conversions instead of normal, same behavior.