2024-02-11 11:06 AM
Hi,
I am trying to do multi-channel single conversion in polling mode in a scan sequence on an Nucleo-STM32G070 board, there is a multi-channel ADC example with this board, but it needs a trigger for every channel. What I need is:
start the conversion for all channels successively, one by one, and after one second,
collect the result in an array and start the conversion again.
So the questions are:
1. how to configure so that the multi-channels could be converted one by one with just one trigger?
2. how to retrieve the conversion data for all channels?
I checked the HAL driver stm32g0xx_hal_adc.c, it provides only one function to get the result:
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
It returns the DR register value. I did not find a similar function that returns a pointer which points to an array of the conversion values for the multi-channels.
The following is my MX_ADC1_Init:
static void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
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_ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.LowPowerAutoPowerOff = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.NbrOfConversion = 3;
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_1CYCLE_5;
hadc1.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_1CYCLE_5;
hadc1.Init.OversamplingMode = DISABLE;
hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_VREFINT;
sConfig.Rank = ADC_REGULAR_RANK_3;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
Please help!
Regards
Chao
Solved! Go to Solution.
2024-02-13 10:31 AM
SystemCoreClock as 56MHz -> cpu at this clk. right.
+
cycles of adc : = adc clk cycles ; you set the adc clk in Cube - so you should know (look, what you set..)
if ADC_CLOCK_SYNC_PCLK_DIV2 : 56M /2 = 28M (adc clk)
x 79 cyc = about 2,8 us , so set more sampling cycles, to fulfill 5us .
set : 160.5 cyc -> about 5,9us , seems good.
2024-02-11 12:04 PM
Hi,
ADC works on a sequence of conversions - you set it . (in >Cube)
>1. how to configure so that the multi-channels could be converted one by one with just one trigger?
Then start sequence...doing exactly this.
>2. how to retrieve the conversion data for all channels?
You set/start sequence with "INT" , so you get an interrupt after each conversion, and you store result ...in array or what you like. So you see: ADC is no magic , you have to store results, or you use a DMA , to do this for you.
(But little bit more complex,to set up. Trigger->ADC sequence ->DMA writes to array. )
2024-02-13 06:57 AM
Thank you so much, now I use DMA to do it. But the mcu internal temperature calculation using predefined macro __LL_ADC_CALC_TEMPERATURE in stm32g0xx_ll_adc.h gives result from -42 to -72 for a Nucleo-STM32G070 board, while room temperature is about +18°C.
The following is the macro:
and this is the use of the macro:
uint32_t vrefAnalogVoltage = __HAL_ADC_CALC_VREFANALOG_VOLTAGE(convertedData[2], ADC_RESOLUTION_12B);
int32_t McuTemp = __HAL_ADC_CALC_TEMPERATURE(vrefAnalogVoltage, convertedData[1], ADC_RESOLUTION_12B);
where convertedData[2] is the measured value for VrefInt, and convertedData[1] is the measured value of the internal TempSensor.
Where is wrong in my calculation ?
Regards
Chao
2024-02-13 07:23 AM - edited 2024-02-13 07:26 AM
Did you set the adc for temp measuring ? (Needs special setup...slow...and wait time; read rm !! )
->
2024-02-13 09:45 AM
Thank you. It helps.
It's the sampling time issue, the default 1.5cycle is not enough, after I have chosen 79.5 cycles as the sampling time I could see the measured temperature would not fall any more. Referring to the datasheet of STM32G070, the minimal ts_temp is 5us, I am not sure on comparison between 5us and 79.5 cycles.
I set the SystemCoreClock as 56MHz for the Timer3, does that mean the Mcu is running with that clock, and how many microseconds for one cycle?
Regards
Chao
2024-02-13 10:08 AM
56MHz => period of 0.018us
79.5 periods = 1.42 us
2024-02-13 10:31 AM
SystemCoreClock as 56MHz -> cpu at this clk. right.
+
cycles of adc : = adc clk cycles ; you set the adc clk in Cube - so you should know (look, what you set..)
if ADC_CLOCK_SYNC_PCLK_DIV2 : 56M /2 = 28M (adc clk)
x 79 cyc = about 2,8 us , so set more sampling cycles, to fulfill 5us .
set : 160.5 cyc -> about 5,9us , seems good.
2024-02-13 10:47 AM
Thank you very much!