Skip to main content
jagauthier
Associate III
April 20, 2023
Solved

STM32G0B1 ADC DMA multichannel

  • April 20, 2023
  • 3 replies
  • 1745 views

Having some trouble with reading ADC channels on this unit only when using multiple channels. I have no problem using a single channel, but as soon as I expand it to two, or more, my readings are just garbage.

Code for working single channel:

 hadc1.Instance = ADC1;
 hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV16;
 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_EXTERNALTRIG_T2_TRGO;
 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
 hadc1.Init.DMAContinuousRequests = ENABLE;
 hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
 hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_1CYCLE_5;
 hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_160CYCLES_5;
 hadc1.Init.OversamplingMode = ENABLE;
 hadc1.Init.Oversampling.Ratio = ADC_OVERSAMPLING_RATIO_16;
 hadc1.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_NONE;
 hadc1.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
 hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_LOW;
 
 sConfig.Channel = ADC_CHANNEL_9;
 sConfig.Rank = ADC_REGULAR_RANK_1;
 sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_2;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

Them my own code: [relevant snips]

#define ADC_CHANNELS 1
uint32_t dmaBuffer[ADC_CHANNELS];
HAL_ADC_Start_DMA(&hadc1, &dmaBuffer, ADC_CHANNELS);

Values I read from dmaBuffer are exactly as I expect them to be.

Now, when I extend this to a secondary channel:

 hadc1.Instance = ADC1;
 hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV16;
 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.LowPowerAutoPowerOff = DISABLE;
 hadc1.Init.ContinuousConvMode = DISABLE;
 hadc1.Init.NbrOfConversion = 2;
 hadc1.Init.DiscontinuousConvMode = DISABLE;
 hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T2_TRGO;
 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
 hadc1.Init.DMAContinuousRequests = ENABLE;
 hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
 hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_1CYCLE_5;
 hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_160CYCLES_5;
 hadc1.Init.OversamplingMode = ENABLE;
 hadc1.Init.Oversampling.Ratio = ADC_OVERSAMPLING_RATIO_16;
 hadc1.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_NONE;
 hadc1.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
 hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_LOW;
 
 sConfig.Channel = ADC_CHANNEL_9;
 sConfig.Rank = ADC_REGULAR_RANK_1;
 sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_2;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
 
 /** Configure Regular Channel
 */
 sConfig.Channel = ADC_CHANNEL_VREFINT;
 sConfig.Rank = ADC_REGULAR_RANK_2;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

My custom code:

#define ADC_CHANNELS 2
uint32_t dmaBuffer[ADC_CHANNELS];
 
HAL_ADC_Start_DMA(&hadc1, dmaBuffer, ADC_CHANNELS);
 

The value in dmaBuffer[0] is "garbage" and dmaBuffer[1] is always 0.

I am not sure what's going on with this,. Any advice?

This topic has been closed for replies.
Best answer by Kamil Duljas

You get garbage because all data fit in first 32 bits - 16 bits as first conversion, next 16 bits as second conversion.

look at your DMA settings. Data width is propably HALF_WORLD (uint16_t) but your buffer is uint32_t. Change your buffer on uint16_t like this:

#define ADC_CHANNELS 2
uint16_t dmaBuffer[ADC_CHANNELS];
 
HAL_ADC_Start_DMA(&hadc1, (uint16_t*)dmaBuffer, ADC_CHANNELS);

3 replies

Kamil DuljasBest answer
Senior III
April 21, 2023

You get garbage because all data fit in first 32 bits - 16 bits as first conversion, next 16 bits as second conversion.

look at your DMA settings. Data width is propably HALF_WORLD (uint16_t) but your buffer is uint32_t. Change your buffer on uint16_t like this:

#define ADC_CHANNELS 2
uint16_t dmaBuffer[ADC_CHANNELS];
 
HAL_ADC_Start_DMA(&hadc1, (uint16_t*)dmaBuffer, ADC_CHANNELS);

Dudo
jagauthier
Associate III
April 21, 2023

You're right. However, passing a uint16_t to HAL_ADC_Start throws an warning because it's expecting uint32_t. So there are 2 solutions.

Define the dma buffer as 16 bit, and cast is 32, or define the DMA buffer to a word.

Both worked. Thanks for the tip!

Senior III
April 21, 2023

@Community member​ please marks best answer and we are closing topic :)

Dudo