Last Updated: April 16, 2026
STM32 ADC Multiple Channels with DMA Normal Mode: CubeMX Setup & HAL Code
In this part of the STM32 ADC tutorial series, we will learn how to read data from multiple channels using DMA Normal Mode. Unlike circular DMA, Normal Mode transfers the converted values once and then stops, giving you full control over when the next conversion should happen. This method is useful when you want to collect a batch of analog data at specific intervals. We will configure the ADC in CubeMX, write the code, and test the results on STM32 boards.
This tutorial is a continuation of the previous one, so the configuration remains the same. This is the continuation of PART1 and PART2, so you must read them first.
This is the 3rd tutorial in the STM32 ADC series. You can go through the other parts of this series, here are the links:
- Multiple Channels using Circular DMA Mode
- Multiple Channels Without DMA | Full Control
- STM32 ADC Conversion Time & Frequency Explained
- ADC External Trigger Source Selection
- ADC Injected Conversion Mode

- STM32 ADC Multi-Channel Potentiometer Wiring & Pin Connections
- How STM32 ADC Multi-Channel DMA Normal Mode Works
- How STM32 ADC Normal DMA Differs from Circular DMA and Interrupt
- STM32 ADC Multi-Channel DMA Normal Mode CubeMX Setup
- STM32 ADC Multi-Channel DMA Normal Mode HAL Code Explained
- STM32 ADC Multi-Channel DMA Output: Potentiometer Test Results
- STM32 ADC Multi-Channel DMA Normal Mode — Video Tutorial
- Download STM32 ADC Multi-Channel DMA Normal Mode Code
- STM32 ADC Multi-Channel DMA Normal Mode FAQs
STM32 ADC Multi-Channel Potentiometer Wiring & Pin Connections
The image below shows the connection between STM32H750 and the multiple Potentiometers.
As shown in the image above, four potentiometers are connected to four pins of the MCU. All potentiometers share the same 3.3V supply and GND from the MCU. Only the wiper (signal pin) of each potentiometer is connected to a unique ADC-capable pin on the STM32.
The pin connection is described in the table below.
| Potentiometer | Pin 1 (VCC) | Pin 2 (Signal / Wiper) | Pin 3 (GND) | MCU Pin (ADC Channel) |
|---|---|---|---|---|
| Potentiometer 1 | 3.3V | Middle Pin → Pink Wire | GND | PC5 (ADC Channel 15) |
| Potentiometer 2 | 3.3V | Middle Pin → Orange Wire | GND | PC4 (ADC Channel 14) |
| Potentiometer 3 | 3.3V | Middle Pin → Blue Wire | GND | PA6 (ADC Channel 6) |
| Potentiometer 4 | 3.3V | Middle Pin → Green Wire | GND | PA6 (ADC Channel 6) |
How STM32 ADC Multi-Channel DMA Normal Mode Works
In STM32, the ADC (Analog-to-Digital Converter) can sample multiple channels (e.g., multiple potentiometers or sensors). To efficiently move the conversion results from the ADC peripheral to memory, we can use DMA (Direct Memory Access).
- In Multi-Channel DMA Normal Mode, the ADC samples several channels in sequence, and the DMA transfers each conversion result into memory (usually an array).
- Once the DMA converts and transfers all the configured channels, it stops automatically.
- At this point, the CPU processes the results, and if more conversions are needed, you must restart the DMA manually.
DMA Normal Mode vs Circular Mode vs Interrupt: When to Use Each
- Normal Mode is straightforward and efficient for one-time or periodic data captures. It prevents continuous overwriting of the buffer, giving the CPU a clear dataset to work with.
- Circular Mode, on the other hand, continuously refreshes the buffer with new ADC data. It’s useful when you need constant, real-time sampling without manually restarting DMA.
- Interrupt Mode doesn’t use DMA; instead, it relies on the CPU to handle each conversion. While simple, it adds CPU load and is less efficient for multiple channels.
Advantages of Using DMA Normal Mode for STM32 ADC
- Easy to implement.
- Suitable for periodic or triggered sampling.
- Prevents accidental data overwrite.
Limitations of DMA Normal Mode to Know Before Using It
- DMA stops automatically after one sequence of conversions.
- Requires the CPU (or software trigger) to restart the DMA if continuous sampling is the need.
- Not suitable for applications that require uninterrupted, high-speed, real-time data streams.
When to Use DMA Normal Mode in Your STM32 ADC Project
- When you only need a snapshot of multiple ADC channels (e.g., reading several sensors once per second).
- Applications where data changes slowly, and continuous sampling is unnecessary.
- Situations where you want to control exactly when conversions happen (e.g., triggered measurements instead of constant monitoring).
How STM32 ADC Normal DMA Differs from Circular DMA and Interrupt
When reading multiple ADC channels, the transfer mode you pick shapes how your entire application behaves. Here is how the three common approaches differ in practice.
DMA Normal Mode converts all configured channels once, transfers the results to memory, and stops. The CPU then processes the data and restarts the DMA when the next reading is needed. This gives you precise control over when conversions happen, which is exactly what this tutorial covers.
DMA Circular Mode never stops on its own. The DMA continuously overwrites the buffer with fresh ADC data, making it the right choice for real-time monitoring where you always want the latest value available — audio sampling, sensor streaming, and closed-loop control being common examples. We cover this in Part 4.
Interrupt Mode skips DMA entirely. The CPU gets notified after each individual conversion and reads the result itself. It is the simplest approach to set up, but it becomes inefficient quickly when reading multiple channels at any meaningful speed — each conversion fires a separate interrupt, adding overhead that scales poorly.
For this tutorial, Normal Mode is the right fit: we want a clean snapshot of four channels on demand, with no risk of the buffer being overwritten mid-read.
STM32 ADC Multi-Channel DMA Normal Mode CubeMX Setup
We will connect 4 potentiometers to the 4 channels of the same ADC. As I mentioned, we will setup the DMA in Normal mode, so it will only transfer the data once.
We will see the available configuration for all three MCUs, F103C8, F446RE and H750VB.
STM32F103C8 ADC DMA Configuration
The image below shows the configuration for STM32F103C8 ADC multiple channels using DMA Normal Mode.
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 convert.
The Continuous Conversion Mode should be disabled. Doing so will make sure the ADC does not start another conversion for all the channels automatically. This way the ADC will only convert the data when we want it to do.
In the DMA section, add the DMA request for the ADC1. Also make sure to configure the DMA in the Normal Mode. In this mode the DMA will not transfer the data continuously, rather it will transfer once and then stop.
The STM32F103C8 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).
STM32F446 ADC DMA Configuration
The image below shows the configuration for STM32F446RE ADC multiple channels using DMA Normal Mode.
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. This way the ADC will only convert the data when we want it to do.
The DMA Continuous Request must also be disabled. This is to make sure that the DMA does not request the data continuously from the ADC. This mode should be kept disabled while using the DMA in Normal mode.
You should set the End of Conversion Selection at the end of all conversions. This ensures that the Conversion Complete interrupt triggers only after all four 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 Normal Mode. In this mode the DMA will not transfer the data continuously, rather it will transfer once and then stop. 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).
STM32H7 ADC DMA Configuration
The image below shows the configuration for STM32F446RE ADC multiple channels using DMA Normal Mode.
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. This way the ADC will only convert the data when we want it to do.
The Conversion Data Management Mode should be set to DMA One Shot. This is to make sure that the DMA does not request the data continuously from the ADC. This mode should be used while using the DMA in Normal 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 Normal Mode. In this mode the DMA will not transfer the data continuously, rather it will transfer once and then stop. Set the data width as per the ADC Resolution. I have configured the ADC resolution of 16bits, therefore the data width is set to Half-Word (16bits).
Fixing DMA Cache Coherency on STM32H7 Cortex-M7 with MPU
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.
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. Here I am relocating the ADC_VAL array to the section “.adcarray“.
__attribute__((section(".adcarray"))) uint16_t ADC_VAL[4];The section (.adcarray) will be defined in the flash script file as shown below.
.mysection (NOLOAD):
{
. = ABSOLUTE(0x30000000);
*(.adcarray)
} >RAM_D2As 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.
STM32 ADC Multi-Channel DMA Normal Mode HAL Code Explained
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
int isADCFinished = 0;
int count = 0;ADC_VAL is a 4-element array, with each element 16 bits in size. We use this array to store the converted ADC values. Even when using 10-bit, 12-bit, or 14-bit resolution, ADC_VAL remains defined as a 16-bit variable.
The variable isADCFinished will determine whether the ADC conversion is finished.
The count variable will keep track if the rest of the while loop is working fine.
The main function
Below is the main function.
int main ()
{
....
....
HAL_ADC_Start_DMA(&hadc1, ADC_VAL, 4);
while (1)
{
count++;
HAL_Delay(500);
if (isADCFinished == 1)
{
//process data
isADCFinished = 0;
HAL_ADC_Start_DMA(&hadc1, ADC_VAL, 4);
}
}
}Inside the main function, we will start the ADC in the 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 DMA finishes transferring the converted data from all channels, it triggers an interrupt, which calls the Conversion Complete callback.
ADC Conversion Complete Callback
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
isADCFinished = 1;
}Inside the callback we will set the variable isADCFinished. This will indicate that the DMA has finished the transfer and we can now process the data anywhere in the code.
The DMA will stop after transferring the data for all the channel once. Therefore we need to start the ADC in DMA mode whenever we want to convert the ADC data.
Inside the while loop we will check the state of the variable isADCFinished. If this variable is set, we will process the converted data and then start the ADC in DMA mode again. Here I am starting the ADC again, just to show the working for the sake of the tutorial. You can start the ADC when you want to fetch the converted data from the ADC.
STM32 ADC Multi-Channel DMA Output: Potentiometer Test Results
The video below shows the ADC values obtained by rotating the potentiometers, in the STM32CubeIDE debugger.
As you can see in the video, the element of the ADC_VAL buffer is changing with the rotation of the respective potentiometer. The data is not updating every 500ms.
The DMA transfers the data when the while loop calls it (every 500 ms), and it works fine even with the cache enabled. There is no issue of the cache coherency, otherwise the data in the ADC_VAL array would not update at all.
STM32 ADC Multi-Channel DMA Normal Mode — Video Tutorial
Watch the complete guide on reading multiple ADC channels using DMA Normal Mode in STM32. Learn CubeMX configuration, HAL implementation, DMA transfer flow, and how to process multi-channel ADC data efficiently.
Download STM32 ADC Multi-Channel DMA Normal Mode Code
Download complete STM32 ADC multi-channel DMA Normal Mode project files, including CubeMX setup and HAL source code. Tested on real hardware and ready to use.
STM32 ADC Multi-Channel DMA Normal Mode FAQs
DMA Normal Mode allows the ADC to transfer a fixed set of converted data from multiple channels to memory. Once the transfer completes, the DMA stops automatically and must be restarted manually.
Use Normal Mode when you only need a single set of ADC data (e.g., at system startup or for one-time calibration). For continuous data acquisition, Circular Mode is more efficient.
Yes, you can enable an interrupt to notify when the DMA transfer is complete. This helps trigger further processing of the captured data.
The number of channels depends on the MCU series, but typically you can read multiple channels (e.g., 4, 8, or more) in one conversion sequence.
It stops after one round of data transfer.
You must manually restart it for new conversions.
Not suitable for continuous monitoring tasks.
Conclusion
In this tutorial, we explored how to use the STM32 ADC with multiple channels configured in DMA Normal Mode. This approach is effective for capturing a fixed set of samples from several analog inputs in a single operation. However, since DMA Normal Mode stops automatically after completing the transfer, the DMA must be manually restarted if continuous or repeated sampling is required.
In the next part of the series (Part 4), we will focus on ADC with multiple channels using DMA Circular Mode. This mode enables uninterrupted, continuous data acquisition without the need to restart the DMA, making it far more efficient for real-time applications such as sensor monitoring, data logging, and closed-loop control systems.
Browse More STM32 ADC Tutorials
STM32 ADC Single Channel: Interrupt & DMA Mode with HAL Code
STM32 ADC Multiple Channels with Circular DMA: CubeMX Setup & HAL Code
STM32 ADC Multiple Channels Without DMA: CubeMX Setup & HAL Code
STM32 ADC Conversion Time: Formula, Calculation & Frequency Explained
STM32 ADC External Trigger with Timer: CubeMX & HAL Guide
STM32 ADC Injected Conversion Mode: Triggered & Auto Injection
STM32 ADC Hardware Oversampling: Improve Resolution & Reduce Noise
Arun is an embedded systems engineer with 10+ years of experience in STM32, ESP32, and AVR microcontrollers. He created ControllersTech to share practical tutorials on embedded software, HAL drivers, RTOS, and hardware design — grounded in real industrial automation experience.
Recommended Tools
Essential dev tools
Categories
Browse by platform





