HomeSTM32 TutorialsSTM32 ADC SeriesSTM32 ADC PART 7 – ADC External Trigger Source Selection

External Trigger Source Selection in STM32 ADC

In this tutorial, we’ll explore how to use external triggers to start ADC conversions on STM32 microcontrollers. Instead of relying on software to initiate each conversion, a hardware trigger, usually from a timer, can control exactly when the ADC samples the input. You’ll learn how to configure timers, select the right trigger source, and synchronize multiple channels for precise, consistent data acquisition.

Recommended Resources:

This is the 7th tutorial in the STM32 ADC series. In the previous tutorials we covered how to configure the ADC in STM32 F1, F4 and H7 series and how to use it in the single channel polling, interrupt and DMA modes to read the potentiometer data. We have also covered the Multiple channels in DMA Normal Mode, Circular Mode and Multiple Channels with DMA.

You Do not need to go through the previous tutorials in order to understand this one. But a basic knowledge of ADC configuration is needed.

External Trigger Source Selection in STM32 ADC

Why Do We Need an External Trigger for ADC?

In most STM32 ADC tutorials, conversions are often started by software. While this works for simple applications, it has limitations in terms of timing precision and CPU load. Using an external trigger — typically generated by a hardware timer, PWM, or another peripheral — allows the ADC to start sampling and converting automatically at precise, consistent intervals. This is especially important in real-time applications, such as motor control, sensor fusion, or signal processing, where consistent timing and synchronization are critical.

External triggers ensure that ADC conversions are not affected by software delays, interrupt routines, or varying CPU load. When combined with DMA, this approach allows high-speed, continuous data acquisition without occupying the processor, freeing it for other tasks.

For Precise and Consistent Sampling Intervals

Software-triggered conversions depend on the CPU executing instructions, which may vary slightly due to interrupts, background tasks, or code execution delays. In contrast, hardware-triggered ADCs use a dedicated timer or peripheral signal, ensuring that each conversion starts exactly at the programmed interval. This guarantees uniform sampling, which is critical for applications like waveform analysis, audio data capture, or any measurement requiring accurate timing.

To Synchronize ADC with Other Peripherals

When ADC sampling needs to be coordinated with other peripherals, such as PWM outputs for motor control or timer events in a control loop, an external trigger ensures perfect synchronization. For example, you can configure a timer to generate a trigger signal at the exact moment a PWM pulse occurs, ensuring that the ADC captures the signal at a consistent point in the cycle.

To Reduce CPU Overhead

With software-triggered ADC, the CPU must explicitly start each conversion. This adds overhead and may limit the maximum achievable sampling rate. Using an external trigger in combination with DMA in circular mode offloads the CPU completely: conversions and data transfers occur automatically, allowing the processor to focus on other critical tasks.

To Improve Multi-Channel ADC Timing

When scanning multiple ADC channels in sequence, external triggers ensure that each set of channel conversions starts at the same instant every cycle. This guarantees consistent timing across channels and reduces timing jitter, which is essential for synchronized sensor readings or real-time signal processing.

The table below summarises the differences between Software Start and External trigger source.

FeatureSoftware StartExternal Trigger
Timing PrecisionVaries depending on CPU execution and interruptsFixed and precise, controlled by hardware (timers or peripherals)
CPU LoadHigh, CPU must start each conversionLow, CPU can remain free during conversions
Synchronization with PeripheralsDifficult to achieveEasy, perfect alignment with timers, PWM, or external events
Multi-Channel ConsistencyMay vary if software delays occurConsistent timing for all channels
Use CaseSimple testing, occasional ADC readsReal-time control, waveform sampling, multi-channel synchronized measurements

How External Trigger Works: Timing Diagram

Below is an image illustrating the sequence of events when using an external trigger with the STM32 ADC:

STM32 ADC external trigger timing diagram showing ADC waiting for an external trigger, sampling phase, conversion phase, and end-of-conversion (EOC) signal, illustrating precise hardware-controlled ADC operation.
  • EXT Trigger: A timer or external event triggers the ADC conversion.
  • Sampling: The ADC samples the input signal.
  • Conversion: The sampled signal is converted to a digital value.
  • EOC (End of Conversion): Data becomes available, optionally transferred via DMA.

STM32F103C8 CubeMX Configuration

In this section, we will configure the STM32F103C8 ADC using CubeMX. You’ll learn how to select ADC channels, set sampling times, configure external triggers, and enable DMA or continuous conversion modes.

ADC Configuration

Below is the image showing the ADC configuration for multiple channels.

STM32F103 ADC Configuration for external trigger source

I have enabled 4 channels of the ADC1. This is where the 4 potentiometers will be connected to.

Since we are using 4 different Channels of ADC1, set the Number of Conversions (under ADC_Regular_ConversionMode) to 4. This will automatically enable the Scan Conversion Mode, which is necessary in case of Multiple Channels.

You can configure the Rank and Sampling Time for each channel. The Rank determines the sequence in which the channels will be converted.

The Continuous Conversion Mode should be Disabled. Doing so will make sure the ADC does not start another conversion for all the channels automatically. Instead we will use the timer’s event to start the conversion. This way we can control the sampling rate of the ADC channels.

The External Trigger Conversion Source is set to Timer3 Trigger out Event. So whenever the Timer3 will generate an event, it will start the conversion in the ADC1.

In the DMA section, add the DMA request for the ADC1. Also make sure that the DMA is configured in the Circular Mode. In this mode the DMA will transfer the data continuously.

The F103C8 has 12 bit ADC resolution by default and we don’t have the option to configure it. Therefore the data width for the DMA must be set to Half-Word (16 bits).


Timer Configuration

We will use Timer3’s event to trigger the ADC conversion. Before we configure the timer, we must find more details about where this timer is connected to. Below is the image showing some details about it.

STM32F103 Timer Clock for ADC trigger

The second half of the image above is taken from the F103C8 Datasheet. It shows that the TIM3 is connected to the APB1 Bus. The first Half of the image is showing the clock configuration for this project. The APB1 Timer clock is running at 72MHz clock, so this will be the TIM3 clock as well.

We will now configure the TIM3’s Prescaler and ARR to reduce this clock to the desired ADC sampling rate we need.

STM32F103 Timer Configuration for ADC trigger

We will first use the internal clock as the clock source for TIM3, which is running at 72 MHz. To generate a suitable trigger for the ADC, we configure the prescaler and auto-reload register (ARR) as follows.

Step 1: Apply the Prescaler

The prescaler divides the timer clock:

fTIM3_PSC=fTIM3Prescalerf_{\text{TIM3\_PSC}} = \frac{f_{\text{TIM3}}}{\text{Prescaler}}

fTIM3_PSC=720000007200=10000 Hzf_{\text{TIM3\_PSC}} = \frac{72\,000\,000}{7200} = 10\,000\ \text{Hz}

After the prescaler, the timer counts at 10 kHz.

Step 2: Apply the Auto-Reload Register (ARR)

The ARR determines how many timer ticks occur before an update event (overflow) is generated:

fUpdate Event=fTIM3_PSCARRf_{\text{Update Event}} = \frac{f_{\text{TIM3\_PSC}}}{\text{ARR}}

fUpdate Event=100001000=10 Hzf_{\text{Update Event}} = \frac{10\,000}{1000} = 10\ \text{Hz}

This means the timer will generate an update event every 0.1 s, which we can use to trigger the ADC conversion.

Step 3: Select the Trigger Event

In CubeMX, choose “Update Event” in the ADC Trigger Event selection. This configures the ADC to start a conversion each time the TIM3 counter overflows.

How it Works

  • Using this method ensures precise, hardware-controlled ADC sampling at 10 Hz.
  • TIM3 counter starts from 0 and counts up.
  • When the counter reaches the ARR value, it overflows.
  • This overflow generates an update event, which is then used as the external trigger for the ADC.

STM32F446 CubeMX Configuration

Similar to the STM32F103C8 configuration, here we will see how to configure the STM32F446RE. We will start with the ADC configuration first.

ADC Configuration

Below is the image showing the ADC configuration for multiple channels.

STM32F446 ADC Configuration for external trigger

I have enabled 4 channels of the ADC1. This is where the 4 potentiometers will be connected to.

Since we are using 4 different Channels of ADC1, set the Number of Conversions (under ADC_Regular_ConversionMode) to 4. This will automatically enable the Scan Conversion Mode, which is necessary in case of Multiple Channels.

You can configure the Rank and Sampling Time for each channel. The Rank determines the sequence in which the channels will be converted.

The Continuous Conversion Mode should be Disabled. Doing so will make sure the ADC does not start another conversion for all the channels automatically. Instead we will use the timer’s event to start the conversion. This way we can control the sampling rate of the ADC channels.

The External Trigger Conversion Source is set to Timer2 Trigger out Event. So whenever the Timer2 will generate an event, it will start the conversion in the ADC1.

The DMA Continuous Request must also be Enabled. This is to make sure that the DMA requests the data continuously from the ADC. This mode should be kept Enabled while using the DMA in Circular mode.

The End of Conversion Selection should be set at the end of all the conversions. Doing this will make sure that the Conversion complete interrupt in only triggered when all the 4 channels (one complete sequence) have been converted.

In the DMA section, add the DMA request for the ADC1. Also make sure that the DMA is configured in the Circular Mode. In this mode the DMA will transfer the data continuously. Set the data width as per the ADC Resolution. I have configured the ADC with 12bits resolution, therefore the data width is set to half word (16bits).


Timer Configuration

We are using Timer2’s event to trigger the ADC conversion. Before we configure the timer, we must find more details about where this timer is connected to. Below is the image showing some details about it.

STM32F446 Timer Clock for ADC trigger

The First half of the image above is taken from the F446RE Datasheet. It shows that the TIM2 is connected to the APB1 Bus. The Second Half of the image is showing the clock configuration for this project. The APB1 Timer clock is running at 90MHz clock, so this will be the TIM2 clock as well.

We will now configure the TIM2’s Prescaler and ARR to reduce this clock to the desired ADC sampling rate we need.

STM32F446 Timer Configuration for ADC trigger

We will first enable the internal clock as the clock source for TIM2, which is running at 90 MHz. To generate a trigger suitable for the ADC, we configure the prescaler and auto-reload register (ARR) as follows.

Step 1: Apply the Prescaler

The prescaler divides the timer clock to slow it down:

fTIM2_PSC=fTIM2Prescalerf_{\text{TIM2\_PSC}} = \frac{f_{\text{TIM2}}}{\text{Prescaler}}

fTIM2_PSC=900000009000=10000 Hzf_{\text{TIM2\_PSC}} = \frac{90\,000\,000}{9000} = 10\,000\ \text{Hz}

After applying the prescaler, TIM2 counts at 10 kHz.

Step 2: Apply the Auto-Reload Register (ARR)

The ARR determines how many timer ticks occur before an update event (overflow) is generated:

fUpdate Event=fTIM2_PSCARRf_{\text{Update Event}} = \frac{f_{\text{TIM2\_PSC}}}{\text{ARR}}

fUpdate Event=100001000=10 Hzf_{\text{Update Event}} = \frac{10\,000}{1000} = 10\ \text{Hz}

This means TIM2 will generate an update event every 0.1 s, which will serve as the ADC trigger.

Step 3: Configure ADC Trigger Event

In CubeMX, select “Update Event” as the ADC trigger source. This ensures that each time TIM2 overflows, it triggers an ADC conversion automatically.

How It Works

  1. TIM2 counter starts at 0 and increments with each tick of the prescaled clock.
  2. When the counter reaches the ARR value (1000), it overflows.
  3. The overflow generates an update event, which is then used by the ADC as an external trigger.
  4. This setup ensures precise, hardware-timed ADC sampling at 10 Hz without CPU intervention.

STM32H750 CubeMX Configuration

Let’s configure the STM32H750 Microcontroller now. We will again start with the ADC configuration first.

ADC Configuration

Below is the image showing the ADC configuration for multiple channels.

STM32H7 ADC Configuration for external trigger

I have enabled 4 channels of the ADC1. This is where the 4 potentiometers will be connected to.

Since we are using 4 different Channels of ADC1, set the Number of Conversions (under ADC_Regular_ConversionMode) to 4. This will automatically enable the Scan Conversion Mode, which is necessary in case of Multiple Channels.

You can configure the Rank and Sampling Time for each channel. The Rank determines the sequence in which the channels will be converted.

The Continuous Conversion Mode should be Disabled. Doing so will make sure the ADC does not start another conversion for all the channels automatically. Instead we will use the timer’s event to start the conversion. This way we can control the sampling rate of the ADC channels.

The External Trigger Conversion Source is set to Timer1 Trigger out Event. So whenever the Timer1 will generate an event, it will start the conversion in the ADC1.

The Conversion Data Management Mode should be set to DMA Circular. This is to make sure that the DMA does requests the data continuously from the ADC. This mode should be used while using the DMA in Circular mode.

The End of Conversion Selection should be set at the end of sequence of conversion. Doing this will make sure that the Conversion complete interrupt in only triggered when all the 4 channels (one complete sequence) have been converted.

In the DMA section, add the DMA request for the ADC1. Also make sure that the DMA is configured in the Circular Mode. In this mode the DMA will transfer the data continuously. I have configured the ADC resolution of 16bits, therefore the data width is set to Half-Word (16bits).


Timer Configuration

We are using Timer2’s event to trigger the ADC conversion. Before we configure the timer, we must find more details about where this timer is connected to. Below is the image showing some details about it.

STM32H7 Timer Clock for ADC trigger

The First half of the image above is taken from the H750 Datasheet. It shows that the TIM1 is connected to the APB2 Bus. The Second Half of the image is showing the clock configuration for this project. The APB2 Timer clock is running at 240MHz clock, so this will be the TIM1 clock as well.

We will now configure the TIM1’s Prescaler and ARR to reduce this clock to the desired ADC sampling rate we need.

STM32H7 Timer Configuration or ADC trigger

We will first enable the internal clock as the clock source for TIM1, which is running at 240 MHz. To generate a trigger suitable for the ADC, we configure the prescaler and auto-reload register (ARR) as follows.

Step 1: Apply the Prescaler

The prescaler reduces the timer clock to a lower frequency:

fTIM1_PSC=fTIM1Prescalerf_{\text{TIM1\_PSC}} = \frac{f_{\text{TIM1}}}{\text{Prescaler}}

fTIM1_PSC=24000000024000=10000 Hzf_{\text{TIM1\_PSC}} = \frac{240\,000\,000}{24\,000} = 10\,000\ \text{Hz}

After applying the prescaler, TIM1 counts at 10 kHz.

Step 2: Apply the Auto-Reload Register (ARR)

The ARR determines how many timer ticks occur before an update event (overflow) is generated:

fUpdate Event=fTIM1_PSCARRf_{\text{Update Event}} = \frac{f_{\text{TIM1\_PSC}}}{\text{ARR}}

fUpdate Event=100001000=10 Hzf_{\text{Update Event}} = \frac{10\,000}{1\,000} = 10\ \text{Hz}

This means TIM1 will generate an update event every 0.1 s, which will serve as the ADC trigger.

Step 3: Configure ADC Trigger Event

In CubeMX, select “Update Event” as the ADC trigger source. This ensures that each time TIM1 overflows, it triggers an ADC conversion automatically.

How It Works

  1. TIM1 counter starts at 0 and increments with each tick of the prescaled clock.
  2. When the counter reaches the ARR value (1000), it overflows.
  3. The overflow generates an update event, which is used by the ADC as an external trigger.
  4. This setup ensures precise, hardware-timed ADC sampling at 10 Hz without CPU intervention.

Cortex M7 Related Changes

In this section we will cover the configuration and code exclusively needed for the cortex M7 devices.

We know that as per ST’s recommendation, we should use the Instruction and Data cache to improve the system performance. But if the cache are enabled, the DMA will always have the cache coherency issue. This is why we will use the Memory Processing Unit (MPU) of the cortex M7 to deal with the cache coherency.

Below is the image showing the MPU configuration in the cortex M7 Devices.

CortexM7 ADC DMA MPU Configuration

As you can see in the image above, I have enabled both Instruction and Data Cache (ICache & DCache).

We also need to enable the MPU in the MPU_PRIVILEGED_DEFAULT mode. Here I am choosing the Base Address region 0x30000000, this is the region for the RAM_D2 and we will relocate our buffer in this region.

  • Here I have selected the 32 Bytes region, since it’s the least size available. The ADC Buffer is going to be 20 bytes in size.
  • The rest of the configuration is to set the region as non-cacheable region. This would prevent the cache coherency issue between the CPU and the DMA.

In the main file, we need to relocate the ADC_VAL array to the RAM_D2 Region, 0x30000000. We can do this by using the section attribute as shown below.

__attribute__((section(".adcarray"))) uint16_t ADC_VAL[4];

Here I am relocating the ADC_VAL array to the section “.adcarray“. The section (.adcarray) will be defined in the flash script file as shown below.

  .mysection (NOLOAD):
  {
    . = ABSOLUTE(0x30000000);
    *(.adcarray)
  } >RAM_D2

As you can see above, the section (.adcarray) is linked to the region RAM_D2 (0x30000000).

The rest of the code remains the same as we used in the DMA section.

Wiring Diagram: Connect Potentiometers to STM32

Below is the image showing the connection between the potentiometers and the H750.

Potentiometers connected to STM32

As shown in the image above, four potentiometers are connected to four input pins of the MCU, each corresponding to a separate ADC channel. These pins allow the ADC to read the analog voltage from each potentiometer independently.

The potentiometers are powered from the MCU’s 3.3 V supply, and their wipers provide a variable voltage to the ADC inputs, ranging from 0 V to 3.3 V. This setup allows us to measure and monitor the voltage level of each potentiometer in real time, demonstrating multi-channel ADC operation on the STM32 microcontroller.

STM32 Code for ADC External Trigger

The code will remain the same for all the STM32 MCUs. If there are any changes, I will specify in this section itself.

Definitions

Let’s define some variables, which we will use in the main function later.

//uint16_t ADC_VAL[4];
__attribute__((section(".adcarray"))) uint16_t ADC_VAL[4];  // cortex M7 only

ADC_VAL is an array of 4 elements of 16 bit in size. We will use this array to store the converted ADC Value. Even if you are using 10bits, 12bits or 14bits resolution the ADC_VAL will still be defined as a 16 bit variable.


The main function

Below is the main function.

int main()
{
  ....
  HAL_TIM_Base_Start(&htim1);
  HAL_ADC_Start_DMA(&hadc1, ADC_VAL, 4);
  while (1)
  {
  }
}

Inside the main function we will first start the TIM1 in the base mode. This will start will Timer’s counter, which will start counting up. Once the counter overflows, an event will trigger, which will start the ADC conversions. The counter than resets back to 0 and starts counting UP again.

Next we will start the ADC in DMA Mode.The parameter ADC_VAL is the array where we want to store the converted data, and 4 is the number of conversions we want the DMA to transfer.

Once the ADC finishes all the conversions, an interrupt will trigger and the ADC Conversion Callback will be called.

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1);
}

Inside this callback we will toggle the pin PA1. This pin toggles each time the callback is called and hence it can be used to calculate the time interval of the callback function. We will measure it on the scope.

Result of STM32 ADC External Trigger

Below is the gif showing the ADC channel data on the debugger.

Multiple channels of the ADC are being read and the values are updating on the debugger.

As you can see above, the ADC data is updating every 100ms. This is because we have set the Timer’s output to 10Hz. To confirm if this is indeed 100ms, we can view the toggling time of the pin PA1 on the logic analyzer. Below is the image showing the same.

Analyzer shows the ADC Timing

As you can see above, the pin PA1 remains HIGH and LOW for 100ms. This means that the pin Toggles every 100ms. This is because the Conversion Complete Callback is called every 100ms. Which signifies that the ADC sampling frequency is set to 10Hz.

Video Tutorial

STM32 ADC External Trigger – Video Tutorial

In this tutorial, we demonstrate how to configure the ADC on STM32 microcontrollers to start conversions using an external trigger. You’ll learn how to select timers as trigger sources, configure update events, and synchronize multiple channels for precise, hardware-controlled sampling. A complete video walkthrough is included, showing CubeMX configuration, code implementation, and real hardware results step by step.

Watch the Video

Conclusion

In this tutorial, we explored how to configure the ADC on STM32 microcontrollers to start conversions using an external hardware trigger, typically generated by a timer. We covered how to select the appropriate timer, configure its prescaler and auto-reload register (ARR), and use the update event as the trigger source for the ADC. The post also explained how to synchronize multiple ADC channels, enable DMA in circular mode, and achieve precise, consistent sampling intervals without relying on software-based triggers.

Using external triggers for ADC conversions provides hardware-timed precision, reduces CPU overhead, and ensures reliable multi-channel measurements. This approach is especially useful for real-time applications such as motor control, signal processing, or sensor monitoring, where predictable timing is critical. By understanding and implementing these concepts, developers can achieve accurate, efficient, and scalable ADC-based data acquisition systems on STM32 microcontrollers.

Browse More STM32 ADC Tutorials

STM32 ADC ext trigger project Download

Info

You can help with the development by DONATING Below.
To download the project, click the DOWNLOAD button.

STM32 ADC Multiple channels FAQs

Subscribe
Notify of

2 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
DavidTLutz
10 months ago

Download button downloads PART4 not PART7

×