I am working on a project wherein, I need to read the Analog outputs from 4 sources and convert them to a digital value using a single ADC module on the STM32F407 microcontroller. I want to sample the ADC values every 50ms and therefore have decided to use it in polling mode and have a timer Interrupt every 50ms to trigger the ADC reading. I am using the STM32 CubeMX software to generate initializations for me.

Here are the ADC initializations:

hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.NbrOfDiscConversion = 0;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = DISABLE;

And in my main function:

while (1)
g_ADCValue = HAL_ADC_GetValue(&hadc1);

Now this works when I have one ADC channel enabled, but how do I read from more than 1 channel at the same time? How does the GetValue() function return the ADC value of a certain channel? Also I know I do not want to use ADC interrupts for this as I want to sample the ADC at particular intervals of time (every 50 ms), but should I be using DMA? If so, how would I do that?

Thank you very much for all your help!

  • \$\begingroup\$ at the same time is not possible.. the ADC Channels should be read sequentially isn't it? i believe the channels are many but ADC is one unit in STM32407, and in other MCUs too \$\endgroup\$ – User323693 Mar 16 '17 at 7:19
  • 1
    \$\begingroup\$ Your MCU has three ADCs, each with an input mux to take the input voltage from a larger set of pins. By reading them at the same time, you mean 'on the same 50 ms interval but very quickly, one after the other' I take it? You can read three by triggering your ADCs from a repeating timer set to 50 ms and skewing a second pollable/interrupting repeating timer to expire every 50 ms but once the ADCs have converted. But you want 4 in on 3 ADCs so would have to wait while 4th in is selected and converted by one ADC. I'd look at e.g. 1 ms interrupt that reads all inputs in sequence and stores them. \$\endgroup\$ – TonyM Mar 16 '17 at 8:58
  • \$\begingroup\$ When I do HAL_ADC_GetValue() does it give me the digital value from one channel? Which channel does it give it from? I'm confused how that works. \$\endgroup\$ – Shubham Rastogi Mar 16 '17 at 17:09
  • \$\begingroup\$ Read their reference manual on how to read ADC in 12 Bits sequentially. It works for me \$\endgroup\$ – don Feb 5 '18 at 22:43
  • \$\begingroup\$ As is, this doesn't really help. It may be true, but is there a specific suggestion you are making? \$\endgroup\$ – Brian Carlton Feb 6 '18 at 3:32
hadc1.Init.ScanConvMode = DISABLE;

the sequencer is disabled so you cant read or even convert data coming from the other channel.
Also you have to define the rank of every channel.
for exemple :

sConfig.Rank      = 1;
     sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5 ;
     sConfig.Channel = REF_1_5_Volt_Pin;
     HAL_ADC_ConfigChannel(&hadc, &sConfig);
 sConfig.Rank = 2;
 sConfig.Channel = L1_voltage_Pin;
 HAL_ADC_ConfigChannel(&hadc, &sConfig);

 sConfig.Rank = 3;
 sConfig.Channel = L2_voltage_Pin;
 HAL_ADC_ConfigChannel(&hadc, &sConfig);

 sConfig.Rank = 4;
 sConfig.Channel = L3_voltage_Pin;
 HAL_ADC_ConfigChannel(&hadc, &sConfig);

 sConfig.Rank = 5;
 sConfig.Channel = L1_curent_Pin;
 HAL_ADC_ConfigChannel(&hadc, &sConfig);

 sConfig.Rank = 6;
 sConfig.Channel = L2_curent_Pin;
 HAL_ADC_ConfigChannel(&hadc, &sConfig);

 sConfig.Rank = 7
 sConfig.Channel = L3_curent_Pin;
 HAL_ADC_ConfigChannel(&hadc, &sConfig)
|improve this answer|||||

I want to sample the ADC values every 50ms

hadc1.Init.ContinuousConvMode = ENABLE;

I guess you need to convert all channels only once in 50ms, it means you should disable continuous conversion because it will restart conversion automatically without waiting for 50ms trigger.

hadc1.Init.DMAContinuousRequests = ENABLE;

This will allow DMA channel to collect converted data from ADC's data register and will transfer to any RAM location.

As suggested by @Aymen Lachkhem you need to configure rank for each channel, this will add desired channels to sequencer for conversion otherwise that particular channel will not be scanned.

Suggestion: You can start ADC conversion using DMA, provide RAM location and number of data to be transferred. You can collect converted data when DMA transfer complete callback invokes. HAL library provides APIs to start ADC conversion using DMA and a weak implementation of callback.

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.