STM32 ADC Multi-Channel Scan Continuous Mode DMA Example

In this tutorial, we’ll discuss the STM32 ADC Multi-Channel Scan Continuous Conversion Mode with DMA for reading the ADC conversion results of a regular group of channels. 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 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 continuous-conversion mode using the DMA. Without further ado, let’s get right into it!

Table of Contents

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

STM32 ADC Multi-Channel Scan (Continuous-Conversion)

In this tutorial, we’ll explore the STM32 ADC Multi-Channel Scan Mode in continuous-conversion 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 conversion process.

The ADC will then “automatically” restart/re-trigger itself to start converting the regular group channels one by one again and keep repeating forever. This is unlike the Multi-Channel Scan Single-Conversion Mode that we’ve discussed in a previous tutorial. Where the ADC stops at the end of the regular group conversion and it needs to be “manually” started again.

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

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

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

Can we use Polling with STM32 ADC Multi-Channel Scan in Continuous-Conversion Mode? The answer is NO. The polling can only be used with the ADC Multi-Channel Scan in Discontinuous Mode, Refer to this tutorial & example project for more details.

Therefore, it’s impractical and near impossible to implement a polling-based software or state machine to read the ADC scan (regular group) conversions in the continuous-conversion mode.

2. STM32 ADC Multi-Channel Interrupt (Continuous 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. Whether it’s a single-conversion or continuous-conversion mode, it won’t work.

In other words, 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 (Continuous 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 (Continuous-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 no matter how hard you try to build a perfect state machine to capture the readings at the right time.


STM32 ADC Multi-Channel Continuous 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 continuous-conversion mode using DMA.

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

STM32 ADC Multi-Channel Scan Continuous Mode DMA Example

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 continuous mode. You’ll find that the analog channel has these default configurations which happens to be ok for us in this example project.

STM32-ADC-Multi-Channel-Scan-Continuous-Mode-Example-CubeMX

Step #3

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

Step #4

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

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

Step #5

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

STM32 RCC External Clock Selection CubeMX

Step #6

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 #7

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

STM32 ADC Multi-Channel Scan Continuous-Conversion (DMA) Example Code

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

ADC Multi-Channel DMA Code Explanation

We only trigger the ADC once to start conversion in DMA mode. As it’s running in the continuous-conversion mode, it’ll keep triggering itself after the completion of the regular group conversion and we don’t need to “manually” start/trigger the ADC again.

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

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 Continuous-Conversion DMA Example Testing

❕ Note

In this example demo, I’ve enabled the DMA interrupt to give you a hint of how it can be incorporated into the final application. However, I’d advise against using it in this application as it, unnecessarily, adds so much CPU load. You’d be better off disabling the DMA interrupt and using the global  AD_RES_BUFFER buffer to read the last ADC result and map that to the PWM duty cycle. Which can be done in the main while(1) loop, in a periodic timer-based interrupt, or anywhere else.

To enable the DMA interrupt, you need to have a sufficiently large buffer so the DMA interrupts are less frequent to keep the system as efficient as possible. As long as the data is not urgently needed for real-time processing, things can be asynchronously accessed in a periodic way to keep the system’s dynamic behavior as predictable as possible.


STM32 ADC Multi-Channel Scan (Continuous-Conversion) Polling

This application is almost impossible to build and even if we did, it’ll still be impractical as the CPU will most probably miss reading the ADC channel before it’s overwritten by the next conversion. This could have been done if we were working in the Multi-Channel Scan Disontinuous-Mode, however, in the continuous conversion mode we’re not able to activate the discontinuous conversion and we won’t be able to implement such a thing.


STM32 ADC Multi-Channel Scan (Continuous-Conversion) Interrupt

This application is also 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.


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 how to read the STM32 ADC multiple-channel in continuous-conversion mode using the DMA. Be advised that you can’t use the interrupt or polling methods with the ADC in multi-channel scan continuous-conversion mode. The DMA is the only viable 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