cancel
Showing results for 
Search instead for 
Did you mean: 

I believe there is a bug in HAL_ADC_ConfigChannel(). Using the STM32g071, with ADC_SCAN_SEQ_FIXED, ADC_EOC_SINGLE_CONV, and NbrOfConversion == 1, when HAL_ADC_ConfigChannel() is called, it OR's in the new channel number, which is incorrect.

CSmit.4
Associate II

   hadc1.Instance = ADC1;

   hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;

   hadc1.Init.Resolution = ADC_RESOLUTION_12B;

   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

    hadc1.Init.ScanConvMode = ADC_SCAN_SEQ_FIXED;

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

   hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

   hadc1.Init.DMAContinuousRequests = DISABLE;

   hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

   hadc1.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_19CYCLES_5;

   hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_79CYCLES_5;

   hadc1.Init.OversamplingMode = DISABLE;

   hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;

after initialization, when HAL_ADC_ConfigChannel() is called to switch (single) channels, it OR's the new channel number into ADC_CHSELR, instead of just writing the new channel number in. The workaround is to call LL_ADC_REG_SetSequencerChannels() after every HAL_ADC_ConfigChannel() call.

1 ACCEPTED SOLUTION

Accepted Solutions
Imen.D
ST Employee

Hi @CSmit.4​ ,

In fact this is the expected behavior with ADC_SCAN_SEQ_FIXED.

In case you want to configure a sequence with several channels, you have to call "HAL_ADC_ConfigChannel()" successively for each channel.

=> there is accumulation of channels, it is needed

 /* Configure Regular Channel: add channel to sequence */
 sConfig.Channel = ADC_CHANNEL_4;
 sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
 sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;
 HAL_ADC_ConfigChannel(&hadc1, &sConfig);
 
 /* Configure Regular Channel: add channel to sequence */
 sConfig.Channel = ADC_CHANNEL_VREFINT;
 HAL_ADC_ConfigChannel(&hadc1, &sConfig);

In case you want to change a channel into the sequence, you have to call "HAL_ADC_ConfigChannel()" twice: to remove channel from sequence (using sConfig.Rank = ADC_RANK_NONE) and add another one.

For example switch from channel 4 to channel VrefInt:

/* Configure Regular Channel: add channel to sequence */
 sConfig.Channel = ADC_CHANNEL_4;
 sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
 sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_2;
 HAL_ADC_ConfigChannel(&hadc1, &sConfig);
...
...
 /* Configure Regular Channel: remove channel from sequence */
 sConfig.Channel = ADC_CHANNEL_4;
 sConfig.Rank = ADC_RANK_NONE;
 HAL_ADC_ConfigChannel(&hadc1, &sConfig);
 
 /* Configure Regular Channel: add channel to sequence */
 sConfig.Channel = ADC_CHANNEL_VREFINT;
 sConfig.Rank = ADC_REGULAR_RANK_3;
 HAL_ADC_ConfigChannel(&hadc1, &sConfig);

Hope this answer your question.

 Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen

View solution in original post

6 REPLIES 6
Imen.D
ST Employee

Hello @CSmit.4​ ,

Welcome to the STM32 Community :smiling_face_with_smiling_eyes:

Which release of CubeMx and STM32G0 MCU package are you using ?

Did you reproduced this issue only when generated your project by CubeMx ? If possible to share your ioc file for more check and review.

Have you checked with the ADC working examples availabe under STM32CubeG0 MCU package:

STM32Cube_FW_G0_V1.4.0\Projects\NUCLEO-G071RB\Examples_LL\ADC\

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
CSmit.4
Associate II

STM32G0 MCU package 1.30...I will update to 1.40 and re-test.

The ADC configuration was originally created using CubeMX, but the actual application (polling one channel then the next, then the next), is where the problem occurs.

None of the ADC examples appear to poll for conversion complete on one channel, then change to a different (single) channel and poll it, which is what we are doing.

CSmit.4
Associate II

Verified the problem still occurs with 1.4.0

Imen.D
ST Employee

Hi @CSmit.4​ ,

In fact this is the expected behavior with ADC_SCAN_SEQ_FIXED.

In case you want to configure a sequence with several channels, you have to call "HAL_ADC_ConfigChannel()" successively for each channel.

=> there is accumulation of channels, it is needed

 /* Configure Regular Channel: add channel to sequence */
 sConfig.Channel = ADC_CHANNEL_4;
 sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
 sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;
 HAL_ADC_ConfigChannel(&hadc1, &sConfig);
 
 /* Configure Regular Channel: add channel to sequence */
 sConfig.Channel = ADC_CHANNEL_VREFINT;
 HAL_ADC_ConfigChannel(&hadc1, &sConfig);

In case you want to change a channel into the sequence, you have to call "HAL_ADC_ConfigChannel()" twice: to remove channel from sequence (using sConfig.Rank = ADC_RANK_NONE) and add another one.

For example switch from channel 4 to channel VrefInt:

/* Configure Regular Channel: add channel to sequence */
 sConfig.Channel = ADC_CHANNEL_4;
 sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
 sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_2;
 HAL_ADC_ConfigChannel(&hadc1, &sConfig);
...
...
 /* Configure Regular Channel: remove channel from sequence */
 sConfig.Channel = ADC_CHANNEL_4;
 sConfig.Rank = ADC_RANK_NONE;
 HAL_ADC_ConfigChannel(&hadc1, &sConfig);
 
 /* Configure Regular Channel: add channel to sequence */
 sConfig.Channel = ADC_CHANNEL_VREFINT;
 sConfig.Rank = ADC_REGULAR_RANK_3;
 HAL_ADC_ConfigChannel(&hadc1, &sConfig);

Hope this answer your question.

 Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
CSmit.4
Associate II

Hi Imen,,

Thank you for that insight. That makes sense. It does seem a little awkward to keep removing a channel after each conversion, but it is good to know that is how it works. I feel like the workaround we are using, calling LL_ADC_REG_SetSequencerChannels(), after each HAL_ADC_ConfigChannel() call is more concise. In general, it would be nice to have a way to say "I am converting channel X", "now I am converting Channel Y", more succinctly than the above solution, but at least what we have works.

Thank you again!

Chuck

JD3
Associate II

STM32G0B1CBT6

 

#define ADC0_OBJ_COUNT 9

const uint8_t ch_remap[ADC0_OBJ_COUNT] = {ADC_CHANNEL_0, ADC_CHANNEL_1, ADC_CHANNEL_2, ADC_CHANNEL_3, ADC_CHANNEL_4, ADC_CHANNEL_5, ADC_CHANNEL_6, ADC_CHANNEL_7, ADC_CHANNEL_10};

//const uint8_t ch_remap[ADC0_OBJ_COUNT] = {0 , 1, 2, 3, 4, 5, 6, 7, 10};

uint32_t adc1_value[ADC0_OBJ_COUNT];

 

 

static void MX_ADC1_Init(void) {

ADC_ChannelConfTypeDef sConfig = {0};

 

hadc1.Instance = ADC1;

hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;

hadc1.Init.Resolution = ADC_RESOLUTION_12B;

hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;

hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;

hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

hadc1.Init.LowPowerAutoWait = DISABLE;

hadc1.Init.LowPowerAutoPowerOff = DISABLE;

hadc1.Init.ContinuousConvMode = DISABLE;

hadc1.Init.NbrOfConversion = 1; // 1 konverze najednou

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.SamplingTimeCommon1 = ADC_SAMPLETIME_160CYCLES_5;

hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_160CYCLES_5;

hadc1.Init.OversamplingMode = DISABLE;

hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_LOW;

 

if (HAL_ADC_Init(&hadc1) != HAL_OK) {

Error_Handler();

}

 

// Inicializujte první kanál jako výchozí

sConfig.Channel = ADC_CHANNEL_0;

sConfig.Rank = ADC_REGULAR_RANK_1;

sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;

if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {

Error_Handler();

}

}

 

void adc1_update(void) {

ADC_ChannelConfTypeDef sConfig = {0};

 

for (uint8_t i = 0; i < ADC0_OBJ_COUNT; i++) {

/* Configure Regular Channel: add channel to sequence */

sConfig.Channel = ch_remap[i];

sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;

//sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;

HAL_ADC_ConfigChannel(&hadc1, &sConfig);

 

// Spustíme konverzi

HAL_ADC_Start(&hadc1);

HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);

adc1_value[i] = HAL_ADC_GetValue(&hadc1);

adc_obj[i].curr = kalman_filter(&kalman_filters[i], adc1_value[i]);

 

/* Configure Regular Channel: remove channel from sequence */

sConfig.Channel = ch_remap[i];

sConfig.Rank = ADC_RANK_NONE;

HAL_ADC_ConfigChannel(&hadc1, &sConfig);

}

}

 

 

Where is mistake ? It measures only CH0 and copies to all buffer spaces 0-8.