cancel
Showing results for 
Search instead for 
Did you mean: 

ADC conversion at specific intervals - is there a better way to do this?

Hrishikesh
Senior

While trying to figure out how to trigger multiple ADC conversions every 100ms, I came up with what is listed below. This works but I wanted to know if there is a better way to do this? Also do all selected channels get monitored for conversion at the end of each 100ms period or does each single channel conversion happen every 100ms?

Any inputs would be appreciated!

TIM2 clock is at 84MHz (APB1)

PSC = 8400 which brings it down to 10Khz

ARR = 1000 which brings it down to 10Hz

Under TRGO parameters Master/Slave is Enabled and Trigger event selection is set to Timer 2 Update Event.

Under ADC1, clock is PCLK2/4 (84Mhz/4=21Mhz). Channels 0 and 1 are enabled. Resolution is 12 bits. Sampling time is 56 cycles (15 ADC cycles + 12 cycles as per the datasheet which works out to 27/21Mhz = 1.3us per sample). Scan conversion mode is Enabled. Continous conversion, DMA continous requests and Discontinous conversion modes are Disabled. Enternal trigger conversion source is set to Timer 2 Trigger Out with trigger detection on the rising edge. 

Under DMA for ADC, the buffer is set to circular model with memory increment. 

Under main.c this is the code,

if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*) adc1_values, ADC_BUF_SIZE) != HAL_OK)
{
  Error_Handler();
}
 
if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK)
{
  Error_Handler();
}
 
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
  HAL_ADC_Stop_DMA(&hadc1);
}
 
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance == TIM2)
  {
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*) adc1_values, ADC_BUF_SIZE);
  }
}

7 REPLIES 7
TDK
Guru

What you're doing is fine, but you can also have the timer trigger the ADC directly so it doesn't require use of the CPU.

You can either convert ALL channels per trigger, or one per trigger. It is configurable.

There is no need to call HAL_ADC_Stop_DMA. After things are converted, it is already stopped (unless you have it set to convert continuously).

There's probably an example if the cube repository for your chip family. I would have found it for you, but you didn't specify your chip number.

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

The chip is STM32F407VGTx.

"...but you can also have the timer trigger the ADC directly so it doesn't require use of the CPU." - How can I do this? I thought I was doing this in the ADC configuration when I set it to start conversion with the Update event of Timer 2.

"There is no need to call HAL_ADC_Stop_DMA. After things are converted, it is already stopped (unless you have it set to convert continuously)." - Ok, good to know. I knew I was going to trigger it with the timer and hence it is not set to convert continuously.

The chip is STM32F407VGTx.

"...but you can also have the timer trigger the ADC directly so it doesn't require use of the CPU." - How can I do this? I thought I was doing this in the ADC configuration when I set it to start conversion with the Update event of Timer 2.

"There is no need to call HAL_ADC_Stop_DMA. After things are converted, it is already stopped (unless you have it set to convert continuously)." - Ok, good to know. I knew I was going to trigger it with the timer and hence it is not set to convert continuously.

"You can either convert ALL channels per trigger, or one per trigger. It is configurable." - How? The ADC settings are as shown below,

0693W000006Gu8WQAS.png

TDK
Guru

> How can I do this? I thought I was doing this in the ADC configuration when I set it to start conversion with the Update event of Timer 2.

You've connected the conversion start to the Timer 2 TRGO event, not necessarily the update event. You need to select update as the TRGO event selection within the TIM2 settings.

To convert one channel per trigger, enable discontinuous conversion mode and select 1 discontinuous conversion.

If you're trying to use circular DMA with the ADC, you need to enable DMA continuous requests.

Once all that is set up, I would process the results using the DMA half-complete and complete callbacks (HAL_ADC_ConvHalfCpltCallback/HAL_ADC_ConvCpltCallback).

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

> You've connected the conversion start to the Timer 2 TRGO event, not necessarily the update event. You need to select update as the TRGO event selection within the TIM2 settings.

Oh yes, I have set the TIM2 to update event in its settings, and then selected Timer 2 Update Event under the ADC trigger settings. I thought you were referring some other way to do it.

> To convert one channel per trigger, enable discontinuous conversion mode and select 1 discontinuous conversion.

Got it. I have 7 channels that I need to process in one go. I can setup discontinuous mode to processes all 7 in one event trigger.

> Once all that is set up, I would process the results using the DMA half-complete and complete callbacks (HAL_ADC_ConvHalfCpltCallback/HAL_ADC_ConvCpltCallback).

You mean do something with the ADC data buffer here since the HAL_ADC_Start_DMA anyway transferred the data to the defined buffer?

Thanks again though! Your answers were helpful.

TDK
Guru

> Got it. I have 7 channels that I need to process in one go. I can setup discontinuous mode to processes all 7 in one event trigger.

If you want to convert all channels on each trigger, just leave this mode disabled as that is the default behavior.

> You mean do something with the ADC data buffer here since the HAL_ADC_Start_DMA anyway transferred the data to the defined buffer?

Yes. You could also do whatever you wanted with the data in HAL_ADC_ConvCpltCallback instead.

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