cancel
Showing results for 
Search instead for 
Did you mean: 

Help Needed on A/D Conversion

Chao
Senior

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

1 ACCEPTED SOLUTION

Accepted Solutions

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.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

7 REPLIES 7
AScha.3
Chief III

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. )

If you feel a post has answered your question, please click "Accept as Solution".

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.

Chao_0-1707835654074.png

The following is the macro:

Chao_1-1707835759807.png

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

Did you set the adc for temp measuring ? (Needs special setup...slow...and wait time; read rm !! )

->

AScha3_0-1707837985775.png

 

If you feel a post has answered your question, please click "Accept as Solution".

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

Chao_0-1707847399201.png

56MHz => period of 0.018us

79.5 periods = 1.42 us

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.

If you feel a post has answered your question, please click "Accept as Solution".

Thank you very much!