2021-01-21 04:12 PM
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.
Solved! Go to Solution.
2021-02-05 09:06 AM
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
2021-01-26 04:53 AM
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
2021-01-26 09:12 AM
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.
2021-01-27 10:19 AM
Verified the problem still occurs with 1.4.0
2021-02-05 09:06 AM
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
2021-02-08 09:27 AM
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
2024-10-18 10:21 AM
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.