Getting Started with STM32H5 ARM Cortex M33: ADC Multi Channel Continuous Conversion with DMA and Timer Trigger

In the previous guide (here), we took a look at why we should use DMA to acquire data from ADC in multichannel and let the ADC trigger itself each time the conversion is completed. In this guide, we shall use timer to trigger the ADC to start the conversion which will allow the ADC to sample at fixed interval depending on the requirement of your application.

In this guide, we shall cover the following:

  • Continuous conversion vs timer triggered.
  • STM32CubeMX setup.
  • Firmware development.
  • Results.

1. Continuous Conversion vs Timer Triggered:

The difference between timer-triggered ADC and continuous conversion ADC in STM32H5 lies in how and when ADC conversions are initiated, and their respective use cases. Here’s a detailed comparison:

1. Continuous Conversion Mode

In continuous conversion mode, the ADC keeps converting data continuously without any external trigger after a single start command.

How It Works:

• The ADC is started, and it automatically begins a new conversion as soon as the previous one finishes.

• No external trigger or timer is needed.

• Conversion is governed by the ADC clock and internal settings like sampling time.

Advantages:

Simple implementation: Easy to configure and use.

Real-time updates: Ideal for monitoring analog signals that change continuously, like temperature or voltage.

Low latency: Results are updated as fast as the ADC can operate.

Disadvantages:

Uncontrolled timing: The sampling rate is constant but not synchronized to external events.

High power consumption: Continuous operation may consume more power, especially if results are not always needed.

Use Cases:

• Applications that require high-speed, continuous signal sampling, such as waveform monitoring.

• Systems where precise timing of conversions is not critical.

2. Timer-Triggered Conversion Mode

In timer-triggered mode, an external timer or other peripheral triggers the ADC to start a conversion at specific intervals.

How It Works:

• A timer (e.g., TIMx) generates a trigger signal at a fixed frequency.

• The ADC conversion starts only when the trigger signal occurs.

• The timer determines the sampling frequency, ensuring synchronization.

Advantages:

Precise timing: Conversions are synchronized with the timer, providing deterministic sampling intervals.

Event-driven operation: ADC only converts data when triggered, saving power compared to continuous mode.

Flexibility: Can synchronize ADC with other peripherals or external events.

Disadvantages:

Slightly complex setup: Requires configuration of both the timer and the ADC trigger.

Latency: ADC waits for a timer trigger, which could introduce latency in systems requiring immediate conversion.

Use Cases:

• Applications requiring regular sampling at precise intervals, such as data acquisition systems.

• Synchronizing ADC sampling with events like PWM signals or communication protocols.

2. STM32CubeMX Setup:

Open adc_single.ioc file as following:

Next from the ADC1 parameters setting, disable continuous conversion mode as following:

Next, In External Trigger conversion source:

  • Set the source to be TIM8 Trigger out even.
  • Edge is set to rising edge.

This will allow the ADC to be triggered using timer8 of STM32H5.

Next from clock configuration, we need to find the frequencies of the timers:

By default, STM32H563Zi is running at 32MHz. Hence, the timers are 32MHz in speed.

After we got the frequency, from pinout and configuration, select timers and tim8 as following:

Enable the timer by setting clock source to be internal as following:

Configure the timer with the following:

  • Prescaller value of 32000-1 which will reduce the speed to 1KHz.
  • The counter period to 1000-1 which will give us 1 second.
  • Trigger event selection to update event.

Also, from System Core NVIC, make sure that ADC1 and GPDMA1 Channel 0 interrupts are enabled.

Thats all for the STM32CubeMX setup.

Save the project and this will generate the code.

3. Firmware Development:

In main.c file, in user code begin PV (Private variable), declare the following variable as volatile:

volatile uint8_t adc_done;

In STM32H5xx_hal_adc.c source file, there is a function that can be called each time the ADC generate interrupt as following:

The function called:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)

This function shall be called each time when the ADC finish conversion.

In user code begin 4 (at the end of main.c), we shall declare the function as following:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
	adc_done=1;

}

This function shall only set the adc_done to 1 to indicate that the ADC finished conversion.

In user code begin 2 in the main function:

Start timer8 in base mode to generate the timing event only as following:

HAL_TIM_Base_Start(&htim8);

Launch the ADC in DMA mode similar to the previous guide:

HAL_ADC_Start_DMA(&hadc1, (uint32_t)&adc_value, 2);

In user code begin 3 in while 1 loop, we can print the result when the ADC finishes conversion as following:

if(adc_done==1)
{
  for (uint16_t i=0;i<2;i++)
  {
    printf("ADC Value[%d] =%d\r\n",i,adc_value[i]);
  }
  adc_done=0;
}

Check if the adc_done is set to 1 which means there is new data, if there is, print the new data and set the variable to 0. This will print the results only when the ADC has finished conversion of all channels.

Thats all for the firmware.

Save, build and run the project on your board as following:

4. Results:

Open your favourite serial terminal application and set the baudrate to be 115200 and you should get the following to be printed each 1 second:

Happy coding 😉

Add Comment

Your email address will not be published. Required fields are marked *