STM32 ADC | PART 7 External Trigger Source Selection

Learn to configure STM32 ADC external trigger using timers for precise sampling control. This tutorial includes CubeMX setup and HAL code for F1, F4, and H7 series. The project is available to download at the end of the post.

STM32 ADC External Trigger Source Selection

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

Introducing STM32 ADC Peripheral

The Analog-to-Digital Converter (ADC) in STM32 microcontrollers is a powerful peripheral that allows the conversion of analog input signals into digital values. This capability enables STM32 devices to interface seamlessly with real-world sensors and analog inputs, such as temperature sensors, light sensors, potentiometers, and more. The ADC module is highly configurable and supports a range of resolutions and modes, making it suitable for both basic and advanced embedded applications.

Whether you’re developing a battery-powered IoT device or a high-speed data acquisition system, the STM32 ADC provides flexible configuration options, precision control, and efficient performance.

Here are some important features of STM32 ADC:

  • Multi-Channel Support – Capable of reading from multiple analog inputs using internal channel scanning, reducing the need for external hardware.
  • High Resolution Options – Offers selectable resolutions (6-, 8-, 10-, or 12-bit), allowing a balance between accuracy and conversion speed.
  • Multiple Conversion Modes – Supports single, continuous, scan, and discontinuous modes to suit different application needs.
  • Flexible Triggering – Conversion can be started via software or automatically triggered by hardware events like timers or external interrupts.
  • Low Power Consumption – Designed with power-saving features, ideal for energy-efficient and battery-operated systems.

STM32F103C8 CONFIGURATION

We will cover both, ADC and Timer configuration for all the microcontrollers.

ADC Configuration

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

STM32F103 ADC Configuration

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 are using 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

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

We will first enable the internal clock as the clock source for the TIM3. The TIM3 is currently running at a clock of 72MHz.

We will use the prescaler of 7200 to reduce the TIM3 clock to 10KHz, 72000000/7200 = 10000. We will further use the ARR value of 1000 to reduce the clock down to 10Hz, 10000/1000 = 10.

Choose the Update Event in the Trigger Event Selection.

Basically the timer’s counter starts counting up from 0. When the counter overflows, an event will be triggered. This event will then be used by the ADC to start the conversion.

F446 CONFIGURATION

We will start with the ADC configuration first.

ADC Configuration

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

STM32F446 ADC Configuration

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

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

We will first enable the internal clock as the clock source for the TIM2. The TIM2 is currently running at a clock of 90MHz.

We will use the prescaler of 9000 to reduce the TIM2 clock to 10KHz, 90000000/9000 = 10000. We will further use the ARR value of 1000 to reduce the clock down to 10Hz, 10000/1000 = 10.

Choose the Update Event in the Trigger Event Selection.

Basically the timer’s counter starts counting up from 0. When the counter overflows, an event will be triggered. This event will then be used by the ADC to start the conversion.

H750 CONFIGURATION

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

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

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

We will first enable the internal clock as the clock source for the TIM1. The TIM1 is currently running at a clock of 240MHz.

We will use the prescaler of 24000 to reduce the TIM2 clock to 10KHz, 240000000/24000 = 10000. We will further use the ARR value of 1000 to reduce the clock down to 10Hz, 10000/1000 = 10.

Choose the Update Event in the Trigger Event Selection.

Basically the timer’s counter starts counting up from 0. When the counter overflows, an event will be triggered. This event will then be used by the ADC to start the conversion.

Cortex M7 Related

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

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

Potentiometers connected to STM32

As you can see in the image above, the 4 potentiometers are connected to the 4 pins of the MCU. These 4 pins represents 4 channels of the ADC. The potentiometers are connected to the 3.3V from the MCU.

THE CODE

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

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

ADC working STM32

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.

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

You can check the video to see the complete explanation and working of this project.

Check out the Video Below

PROJECT DOWNLOAD

Info

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

You May Also Like..

Subscribe
Notify of

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

Download button downloads PART4 not PART7

🛈 Advertising Disclosure

This website relies on advertisements as its main source of revenue to support the creation of free, high-quality content.
If you enjoy our work and would like to help us continue, please consider disabling your ad blocker while browsing here.

Your support truly makes a difference — thank you!

Share this Article

Recent Posts

Join Our Community

Weekly Newsletter

Subscribe to our newsletter to get our news