STM32 ADC Multi Channel (Scan) + DMA (Single-Conversion)

In this tutorial, we’ll discuss the STM32 ADC Multi-Channel Scan Mode with DMA & Polling techniques for reading the ADC conversion results. You’ll learn how STM32 ADC Multi-Channel Scan mode works and how to use it to read a regular group of multiple ADC channels and get the conversion data using Polling and DMA with the STM32 HAL API functions.

The practical example we’ll implement in this tutorial is an STM32 LED dimmer using multiple potentiometers on multiple analog input pins and multiple PWM outputs to control the brightness of some LEDs. We’ll read the multiple analog input channels (regular group) in single-conversion mode using the DMA and Polling methods. Without further ado, let’s get right into it!

Table of Contents

  1. STM32 ADC Multi-Channel Scan (Single-Conversion)
  2. STM32 ADC Multi-Channel Discontinuous Mode Example
  3. STM32 STM32 ADC Multi-Channel Scan Mode Polling (Single-Conversion)
  4. STM32 ADC Multi-Channel Scan Interrupt Example (Single-Conversion)
  5. STM32 ADC Multi-Channel Scan DMA Example (Single-Conversion)
  6. Wrap Up

STM32 ADC Multi-Channel Scan (Single-Conversion)

In this tutorial, we’ll explore the STM32 ADC Multi-Channel Scan Mode in single-conversion (one-shot) mode. In this mode, the ADC will start converting the configured regular group of channels one by one according to the channel ranks (from low to high) till the end of the group where it stops and generates an interrupt signal indicating the end of the regular group’s single-conversion process.

The STM32 ADC Multi-Channel Scan Mode can also be used with Polling or DMA to get the ADC reading results as soon as the conversion is completed. And that’s what we’ll do in the practical example project hereafter in this tutorial.

STM32-ADC-Multi-Channel-Scan-Single-Conversion-Mode-DMA-Interrupt-Polling

1. STM32 ADC Multi-Channel Polling (Discontinuous Conversion)

In the polling method, the ADC is started in software at least once. We’ll poll for the conversion completion for the regular group of channels one by one until we get all the channels’ readings into the corresponding buffer variables. This is obviously a blocking way to read the ADC as the CPU will be busy waiting for the completion of all the conversions.

However, there is no guarantee that we can reliably get the correct channel reading at the right time. The CPU may be executing some higher-priority interrupt handler when the ADC EOC flag is triggered, therefore it can miss reading the channel before the buffer is overwritten by the next ADC channel conversion in the regular group. This will cause your system to mix all the subsequent ADC readings unless you reset everything at the end of the regular group conversion.

2. STM32 ADC Multi-Channel Interrupt (Discontinuous Conversion)

Using interrupts with ADC Multi-Channel scan mode is just impossible as stated in the documentation of the STM32 microcontroller’s datasheet. Because the interrupt signal is fired at the end of the regular group conversion.

This means the ADC result buffer will keep getting overwritten by the regular group channels one by one from the lowest rank to the highest. At the time of interrupt firing, you’ll only find the last group’s channel reading in the ADC buffer and all the previous channels are gone forever.

3. STM32 ADC Multi-Channel DMA (Discontinuous Conversion)

And here comes the third method which is using the DMA unit that can directly transfer the ADC result from the peripheral to the memory in the manner that you want and program it to. All that is done without any CPU intervention and upon DMA transfer completion, it can notify the CPU to process the data or whatever.

❕ Note

To sum things up, the STM32 ADC in Multi-Channel Scan Mode (Single-Conversion) can only be reliably used with DMA. The interrupt-based reading is impossible to implement and the polling method can potentially cause your system to fail (halt forever) or get the channels’ readings mixed up in more serious applications.


STM32 ADC Multi-Channel Discontinuous Mode Example

In this example project, we’ll create an STM32 LED Dimmer using ADC & PWM to read multiple analog inputs from 4x potentiometers to control the brightness of 4x PWM outputs going to 4x LEDs. This demo will run the STM32 ADC in multi-channel single-conversion mode using 3 different ADC reading techniques (DMA, Interrupt, and Polling).

  • Set up a new project as usual with system clock @ 72MHz
  • Set up 4x Analog Input Pins (Channel 6, 7, 8, and 9) In Discontinuous-Conversion Mode (The 4x Pot. Pin)
  • Set up Timer2 in PWM mode with output on channels 1-4 (The 4x LED Pins) 

The Application will have 3 versions each does the same thing which is to read the ADC result and move it to the timer CCR register which decides the PWM duty cycle percentage on the output LED pin.

Example 1, ADC Multi-Channel Discontinuous-Conversion is used in blocking mode (polling)

Example 2, ADC Multi-Channel Discontinuous-Conversion is used in non-blocking mode (interrupt)

Example 3, ADC Multi-Channel Discontinuous-Conversion is used in non-blocking mode (DMA)


STM32 STM32 ADC Multi-Channel Scan Mode Polling (Single-Conversion)

In this LAB, our goal is to build a system that initializes multiple ADC analog input pins (4x channels: 6-9). And also configure a timer module to operate in PWM mode with 4x outputs on channels 1-4 (4x LED pins). Therefore, we can start an ADC regular group conversion, get & map the results to the PWM duty cycle registers, and repeat the whole process over and over again.

And now, let’s build this system step-by-step

Step #1

Open STM32CubeMX, create a new project, and select the target microcontroller.

Step #2

Configure The ADC1 Peripheral, Enable the Channels: 6-9, and enable the discontinuous mode. You’ll find that the analog channel has these default configurations which happens to be ok for us in this example project.

STM32-Multiple-Channel-Scan-Single-Conversion-HAL-Example-CubeMX-Configuration

Step #3

Configure Timer2 To Operate In PWM Mode With Output On CH1-4.

STM32-Multiple-Channel-Scan-Single-Conversion-Example-CubeMX

Step #4

Go to the RCC clock configuration page and enable the HSE external crystal oscillator input.

STM32 RCC External Clock Selection CubeMX

Step #5

Go to the clock configurations page, and select the HSE as a clock source, PLL output, and type in 72MHz for the desired output system frequency. Hit the “ Enter” key, and let the application solve for the required PLL dividers/multipliers to achieve the desired clock rate.

STM32-Blue-Pill-Proteus-Library-Simulation-Clock-Configuration

Step #6

Name & Generate The Project Initialization Code For CubeIDE or The IDE You’re Using.

STM32 ADC Multi-Channel Scan Single-Conversion (Polling) Example Code

Here is The Application Code For This LAB (main.c)

Wiring

I know it looks messy, but there isn’t too much about it. These are only 4x LEDs and 4x potentiometers connected to the corresponding GPIO pins on the STM32 blue pill board.

STM32-ADC-Multiple-Channel-Scan-Example

STM32 ADC Multi-Channel Single-Conversion Example Testing


STM32 ADC Multi-Channel Scan Interrupt Example (Single-Conversion)

This application is impossible to build as stated in the STM32 ADC documentation (reference manual). We used to build this interrupt-based application for all the previous STM32 ADC tutorial parts, however, we won’t be doing it this time.

For ADC Multi-Channel regular group scan, reading the conversion can either be achieved by Polling ( HAL_ADC_Start() with Discontinuous mode and NbrOfDiscConversion=1) or by DMA ( HAL_ADC_Start_DMA()), but not by interruption ( HAL_ADC_Start_IT()).

In the STM32 ADC multi-channel scan mode, interruption is triggered only on the last conversion of the sequence. All previous conversions will be overwritten by the last one. The injected group used with scan mode doesn’t have this limitation. Each rank has its own result buffer register, no data is overwritten in injected mode as we’ll test it in a later tutorial in this multi-part STM32 ADC series.

❕ Note

To sum things up, we just can’t use the interrupt with the STM32 ADC in scan mode (multi-channel) conversion. The interrupt is fired only on the last conversion of the sequence (regular group of channels). All previous conversions will be overwritten by the last one.


STM32 ADC Multi-Channel Scan DMA Example (Single-Conversion)

Also The Exact Same Steps As The First Example Except For Step 2. The ADC Configuration Will Be As Follows:

STM32-Multi-Channel-Scan-Single-Conversion-HAL-DMA-Example-CubeMX-Configuration

This time the STM32 ADC interrupts are not activated and the DMA is configured instead, and the DMA interrupt is enabled by default in the NVIC controller tab. The STM32 DMA configurations for the ADC will be as shown below.

STM32-Multi-Channel-Scan-DMA-Single-Conversion-HAL-Example-CubeMX-Configuration

Generate The Project & Open It In The CubeIDE

STM32 ADC Multi-Channel DMA (Single-Conversion) Example Code

Here Is The Application Code Using The DMA Method

ADC Multi-Channel DMA Code Explanation

Even though this tutorial is dedicated to the ADC Mutli-Channel Scan Mode in Single-Conversion operations, we need to keep the conversion going to smoothly control the LED brightness using the potentiometers.

Therefore, I had to “manually” trigger the ADC in DMA mode every 1ms to keep it going. But this doesn’t contradict the fact that the ADC is actually running in single-conversion (one-shot) mode as we intended to do in this tutorial.

Upon DMA transfer completion, the DMA interrupt is fired. In its ISR, we read the ADC_RES_BUFFER array to get the readings of the ADC Channels (6-9). Then we map those readings from 12-bit to 16-bit values to be written to the timer’s CCRx registers for PWM duty cycle control.

❕ Note

Using the DMA is the best way to read the STM32 ADC in multi-channel (scan) mode whether it’s a single-conversion (one-shot) or a continuous-conversion as we’ll see in the next tutorial.


Required Parts For STM32 Examples

All the example Code/LABs/Projects in this STM32 Series of Tutorials are done using the Dev boards & Electronic Parts Below:

QTY.Component NameAmazon.comAliExpresseBay
1STM32-F103 BluePill Board (ARM Cortex-M3 @ 72MHz)AmazonAliExpresseBay
1Nucleo-L432KC (ARM Cortex-M4 @ 80MHz)AmazonAliExpresseBay
1ST-Link V2 DebuggerAmazonAliExpresseBay
2BreadBoardAmazonAliExpresseBay
1LEDs KitAmazonAmazonAliExpresseBay
1Resistors KitAmazonAmazonAliExpresseBay
1Capacitors KitAmazonAmazonAliExpress & AliExpresseBay & eBay
1Jumper Wires PackAmazonAmazonAliExpress & AliExpresseBay & eBay
1Push ButtonsAmazonAmazonAliExpresseBay
1PotentiometersAmazonAliExpresseBay
1Micro USB CableAmazonAliExpresseBay

★ Check The Links Below For The Full Course Kit List & LAB Test Equipment Required For Debugging ★

Download Attachments

You can download all attachment files for this Article/Tutorial (project files, schematics, code, etc..) using the link below. Please consider supporting our work through the various support options listed in the link down below. Every small donation helps to keep this website up and running and ultimately supports the whole community.


Wrap Up

In conclusion, we’ve explored the various methods of reading the STM32 ADC multiple-channel in single-conversion mode using: (DMA & Polling). Be advised that you can’t use the interrupt method with the ADC in multi-channel scan mode. The DMA is the best option for this sort of application.

You can build on top of the examples provided in this tutorial and/or explore the other parts of the STM32 ADC tutorials series for more information about the other STM32 ADC operating modes and conversion schemes.

This Tutorial is Part of The Following Multi-Part Tutorial Series:

Share This Page With Your Network!
Join Our +25,000 Newsletter Subscribers!

Stay Updated With All New Content Releases. You Also Get Occasional FREE Coupon Codes For Courses & Other Stuff!

Photo of author
Author
Khaled Magdy
Embedded systems engineer with several years of experience in embedded software and hardware design. I work as an embedded SW engineer in the Automotive & e-Mobility industry. However, I still do Hardware design and SW development for DSP, Control Systems, Robotics, AI/ML, and other fields I'm passionate about.
I love reading, writing, creating projects, and teaching. A reader by day and a writer by night, it's my lifestyle. I believe that the combination of brilliant minds, bold ideas, and a complete disregard for what is possible, can and will change the world! I will be there when it happens, will you?

Leave a Reply