{"id":4728,"date":"2026-09-10T11:48:15","date_gmt":"2026-09-10T11:48:15","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=4728"},"modified":"2026-09-10T11:48:17","modified_gmt":"2026-09-10T11:48:17","slug":"getting-started-with-stm32-low-layer-ll-analog-to-digital-converter-multi-channel-continuous-conversion-with-dma","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=4728","title":{"rendered":"Getting Started with STM32 Low Layer (LL): Analog to Digital Converter Multi Channel Continuous Conversion with DMA"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"585\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/image-1024x585.png\" alt=\"\" class=\"wp-image-4729\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/image-1024x585.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/image-300x171.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/image-768x439.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/image-1150x657.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/image-750x429.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/image-400x229.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/image-250x143.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/image.png 1344w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Expanding upon our single-channel DMA foundation, this guide scales the STM32F4&#8217;s ADC to simultaneously sample multiple analog channels. By enabling the ADC&#8217;s scan mode and linking it to the DMA controller via LL drivers, the system autonomously routes multi-channel conversion data directly into a structured memory array with zero CPU intervention.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In this guide, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Introduction.<\/li>\n\n\n\n<li>STM32CubeMX configuration.<\/li>\n\n\n\n<li>Firmware development.<\/li>\n\n\n\n<li>Results.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. Introduction:<\/h2>\n\n\n\n<p>As we scale up our embedded applications, monitoring a single analog channel is rarely sufficient. Real-world control systems\u2014such as motor controllers, industrial sensor arrays, or battery management systems\u2014demand the simultaneous monitoring of multiple analog inputs. For instance, a 3-phase motor controller must continuously and synchronously read multiple current sensors and temperature probes to maintain safe, closed-loop operation. Transitioning from a single-channel setup to a multi-channel acquisition on the STM32F4 introduces new hardware mechanics, primarily the ADC&#8217;s <strong>Scan Mode<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Mechanics of Multi-Channel Acquisition: Scan Mode<\/h3>\n\n\n\n<p>When dealing with multiple channels, the ADC can no longer simply look at one pin. The STM32F4\u2019s ADC features a multi-channel Sequencer, governed by Scan Mode. When Scan Mode is enabled, the ADC does not just perform a single conversion; it sweeps through a predefined list of channels\u2014configured in the Sequence Registers (ADC_SQRx)\u2014converting them one by one in a continuous sequence.<\/p>\n\n\n\n<p>For example, if you configure the sequence to read Channel 1, Channel 2, and Channel 3, the ADC will convert Channel 1, immediately switch multiplexers to Channel 2, convert it, and finally switch to Channel 3. Crucially, because the ADC operates sequentially, the converted data for all these channels is pushed out through the exact same single Data Register (ADC_DR) at different points in time.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Multi-Channel DMA Synergy<\/h3>\n\n\n\n<p>If you were to use interrupts for this multi-channel scan, you would face a severe architectural problem. Every single channel&#8217;s completion would fire an End-of-Conversion (EOC) interrupt. For a 3-channel sequence, that is three separate interrupt context switches per sweep, forcing the CPU to constantly rescue data from the single data register before it gets overwritten by the next channel&#8217;s conversion. At high frequencies, this will instantly overwhelm the Cortex-M4 core.<\/p>\n\n\n\n<p>This is where the combination of DMA and Scan Mode becomes an absolute necessity. By linking the ADC to a DMA stream, we can enable the <strong>End of Regular Conversion (EOC) DMA request<\/strong>. As the ADC sweeps through the channels in Scan Mode, the DMA controller acts as a high-speed relay catcher. Every time a channel finishes converting, the DMA controller automatically pulls the data from the ADC_DR and places it into a memory array.<\/p>\n\n\n\n<p>Because the data arrives sequentially (Channel 1&#8217;s data goes to <code>buffer[0]<\/code>, Channel 2&#8217;s data goes to <code>buffer[1]<\/code>, and Channel 3&#8217;s data goes to <code>buffer[2]<\/code>), the DMA seamlessly constructs a perfectly organized, multi-dimensional array of your analog environment in the background.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The LL Driver Advantage in Complex Routing<\/h3>\n\n\n\n<p>Configuring multi-channel ADC with DMA is one of the most complex routing tasks on the STM32F4. You must configure the ADC Sequence Registers (SQR1, SQR2, SQR3), manage the individual channel sampling times, and meticulously map the ADC&#8217;s DMA request to the correct DMA controller stream and channel.<\/p>\n\n\n\n<p>Using the HAL library for this level of hardware routing often results in hidden state errors, obscure callback chains, and significant setup latency. By utilizing the <strong>LL Drivers<\/strong>, we retain absolute, transparent control over this complex silicon routing. We will manually define the sequence length, write the channel numbers directly into the sequence registers, and hardcode the DMA stream&#8217;s peripheral-to-memory configuration. This bare-metal approach ensures our multi-channel data pipeline remains incredibly lean, highly deterministic, and perfectly synchronized, providing a rock-solid foundation for any complex, multi-sensor embedded project.<\/p>\n\n\n\n<p>In the following sections, we will dive into the exact LL register configurations required to enable Scan Mode, structure the ADC sequence, and configure the DMA to autonomously build our multi-channel memory buffer.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. STM32CubeMX Configuration:<\/h2>\n\n\n\n<p>We shall continue from the previous guide from <a href=\"https:\/\/blog.embeddedexpert.io\/?p=4721\" data-type=\"link\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=4721\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p>First, before we configure any extra pins, we need to find which pins are connected to the ADC, since this guide uses STM32F446RE Nucleo-64, Arduino pins from A0 to A5 are ADC channels:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"809\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-25-10-1024x809.jpg\" alt=\"\" class=\"wp-image-4730\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-25-10-1024x809.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-25-10-300x237.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-25-10-768x606.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-25-10-1536x1213.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-25-10-2048x1617.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-25-10-1150x908.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-25-10-750x592.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-25-10-400x316.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-25-10-250x197.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Since we shall use Arduino pins from A0 to A3 thats means we shall configure PA0, PA1, PA4 and PB0 as analog input.<\/p>\n\n\n\n<p>Hence, open the project .ioc file and configure the pins to ADC as follows:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>PA0 as ADC1_IN0<\/li>\n\n\n\n<li>PA1 as ADC1_IN1<\/li>\n\n\n\n<li>PA4 as ADC1_IN4<\/li>\n\n\n\n<li>PB0 as ADC1_IN8 <\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"662\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-29-18-1024x662.jpg\" alt=\"\" class=\"wp-image-4731\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-29-18-1024x662.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-29-18-300x194.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-29-18-768x497.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-29-18-1536x993.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-29-18-2048x1324.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-29-18-1150x744.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-29-18-750x485.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-29-18-400x259.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-29-18-250x162.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Next, from Parameters Settings:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Set Scan Conversion Mode to Enable<\/li>\n\n\n\n<li>Set Number of Conversion to 4 or how many channels you enabled.<\/li>\n<\/ul>\n\n\n\n<p>Next, from Rank, set the Rank as follows:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Rank 1 to CH0<\/li>\n\n\n\n<li>Rank 2 to CH1<\/li>\n\n\n\n<li>Rank 3 to CH4<\/li>\n\n\n\n<li>Rank 4 to CH8<\/li>\n<\/ul>\n\n\n\n<p>In short, it is how the ADC push the data and in which order, this means the ADC will convert CH0 then CH1 then CH2 and finally CH8 and go back to convert CH0. The DMA will store the data as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"280\" height=\"60\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/Drawing-9.jpg\" alt=\"\" class=\"wp-image-4732\" style=\"width:840px;height:auto\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/Drawing-9.jpg 280w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/Drawing-9-250x54.jpg 250w\" sizes=\"(max-width: 280px) 100vw, 280px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"662\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-33-15-1024x662.jpg\" alt=\"\" class=\"wp-image-4733\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-33-15-1024x662.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-33-15-300x194.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-33-15-768x497.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-33-15-1536x993.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-33-15-2048x1324.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-33-15-1150x744.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-33-15-750x485.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-33-15-400x259.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-10_14-33-15-250x162.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Thats all for the STM32CubeMX configuration.<\/p>\n\n\n\n<p>Click on Generate Code.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Firmware Development:<\/h2>\n\n\n\n<p>Open the project in STM32CubeIDE.<\/p>\n\n\n\n<p>Open the adc.h header file<\/p>\n\n\n\n<p>In user code begin Prototytpes, declare the following function:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void ADC_Start_DMA_MultiChannnel(uint16_t *adcBuff, uint16_t len);<\/pre><\/div>\n\n\n\n<p>This function shall start the ADC in DMA mode for multiple channels.<\/p>\n\n\n\n<p>Thats all for the header file.<\/p>\n\n\n\n<p>Open adc.c source file.<\/p>\n\n\n\n<p>In user code begin 1,<\/p>\n\n\n\n<p>Declare the function:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void ADC_Start_DMA_MultiChannnel(uint16_t *adcBuff, uint16_t len)<\/pre><\/div>\n\n\n\n<p>Within the function:<\/p>\n\n\n\n<p>Disable the stream and make sure it is disabled:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_0);\nwhile (LL_DMA_IsEnabledStream(DMA2, LL_DMA_STREAM_0));<\/pre><\/div>\n\n\n\n<p>Next, set the peripheral address to ADC data register:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">LL_DMA_SetPeriphAddress(DMA2, LL_DMA_STREAM_0, LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA));<\/pre><\/div>\n\n\n\n<p>Next, set the memory address which is passed by the user:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">LL_DMA_SetMemoryAddress(DMA2, LL_DMA_STREAM_0, (uint32_t)adcBuff);<\/pre><\/div>\n\n\n\n<p>Set the length to the length passed by the user:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_0, len);<\/pre><\/div>\n\n\n\n<p>Next, enable the DMA stream:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_0);<\/pre><\/div>\n\n\n\n<p>Finally, enable the ADC and start the conversion:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">LL_ADC_Enable(ADC1);\nLL_ADC_REG_StartConversionSWStart(ADC1);<\/pre><\/div>\n\n\n\n<p>Hence, the function as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void ADC_Start_DMA_MultiChannnel(uint16_t *adcBuff, uint16_t len)\n{\n    LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_0);\n    while (LL_DMA_IsEnabledStream(DMA2, LL_DMA_STREAM_0));\n\n    LL_DMA_SetPeriphAddress(DMA2, LL_DMA_STREAM_0, LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA));\n    LL_DMA_SetMemoryAddress(DMA2, LL_DMA_STREAM_0, (uint32_t)adcBuff);\n    LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_0, len);\n\n    LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_0);\n\n    LL_ADC_Enable(ADC1);\n    LL_ADC_REG_StartConversionSWStart(ADC1);\n}<\/pre><\/div>\n\n\n\n<p>Next, open main.c<\/p>\n\n\n\n<p>In user code begin PV, update the adc_value to be array of 4 as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">uint16_t adc_value[4];<\/pre><\/div>\n\n\n\n<p>In user code begin 2 in main function, start the multichannel adc as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">ADC_Start_DMA_MultiChannnel(adc_value,4);<\/pre><\/div>\n\n\n\n<p>Thats all for the guide.<\/p>\n\n\n\n<p>Save, build the project and run it as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"34\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-1024x34.png\" alt=\"\" class=\"wp-image-4349\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-1024x34.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-300x10.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-768x26.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-1536x51.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-1150x38.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-750x25.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-400x13.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1-250x8.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/image-1.png 1986w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>You may download the project from our github repository from&nbsp;<a href=\"https:\/\/github.com\/hussamaldean\/Embedded-Expert-Post-Projects\/tree\/main\/Projects\/ADC_LL\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Results:<\/h2>\n\n\n\n<p>Open a debugging session, add adc_value to live expression, you should get something like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"373\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-09_09-28-30-1024x373.jpg\" alt=\"\" class=\"wp-image-4734\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-09_09-28-30-1024x373.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-09_09-28-30-300x109.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-09_09-28-30-768x279.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-09_09-28-30-1150x418.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-09_09-28-30-750x273.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-09_09-28-30-400x146.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-09_09-28-30-250x91.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/09\/2026-09-09_09-28-30.jpg 1314w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Thats all for this guide.<\/p>\n\n\n\n<p>Next, we shall use timer to trigger the ADC conversion at fixed rate.<\/p>\n\n\n\n<p>Stay tuned.<\/p>\n\n\n\n<p>Happy coding  \ud83d\ude09 <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Expanding upon our single-channel DMA foundation, this guide scales the STM32F4&#8217;s ADC to simultaneously sample multiple analog channels. By enabling the ADC&#8217;s scan mode and linking it to the DMA controller via LL drivers, the system autonomously routes multi-channel conversion data directly into a structured memory array with zero CPU intervention. In this guide, we [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,11,12],"tags":[],"class_list":["post-4728","post","type-post","status-publish","format-standard","hentry","category-embedded-systems","category-peripheral-drivers","category-stm32"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4728"}],"collection":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4728"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4728\/revisions"}],"predecessor-version":[{"id":4735,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4728\/revisions\/4735"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4728"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4728"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4728"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}