{"id":4684,"date":"2026-08-22T07:48:20","date_gmt":"2026-08-22T07:48:20","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=4684"},"modified":"2026-08-22T07:49:16","modified_gmt":"2026-08-22T07:49:16","slug":"getting-started-with-stm32-low-layer-ll-analog-to-digital-converter-single-channel-single-conversion","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=4684","title":{"rendered":"Getting Started with STM32 Low Layer (LL): Analog to Digital Converter Single Channel Single Conversion"},"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\/08\/stm32f4_adc_ll_holographic-1024x585.jpg\" alt=\"\" class=\"wp-image-4685\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/stm32f4_adc_ll_holographic-1024x585.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/stm32f4_adc_ll_holographic-300x171.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/stm32f4_adc_ll_holographic-768x439.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/stm32f4_adc_ll_holographic-1150x657.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/stm32f4_adc_ll_holographic-750x429.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/stm32f4_adc_ll_holographic-400x229.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/stm32f4_adc_ll_holographic-250x143.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/stm32f4_adc_ll_holographic.jpg 1344w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>This guide demonstrates how to configure the STM32F4 Analog-to-Digital Converter (ADC) using the Low Layer (LL) drivers for a straightforward single-channel, single-conversion read. By bypassing the overhead of the Hardware Abstraction Layer (HAL), this approach provides a lightweight, direct, and highly efficient method for reading analog sensor data.<\/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 setup.<\/li>\n\n\n\n<li>Importing the project to STM32CubeIDE.<\/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>In the world of embedded systems, bridging the gap between the analog physical world and the digital processing domain is a fundamental task. Whether you are reading a temperature sensor, monitoring a battery voltage, or capturing audio, the Analog-to-Digital Converter (ADC) is your gateway. The STM32F4 family of microcontrollers, renowned for its powerful Cortex-M4 core and rich peripheral set, features a highly sophisticated ADC capable of speeds up to 2.4 MSPS. However, the way you choose to software-interface with this ADC can drastically alter the performance, memory footprint, and predictability of your application.<\/p>\n\n\n\n<p>When programming STM32 microcontrollers, developers typically stand at a crossroads: choosing between the Hardware Abstraction Layer (HAL) or the Low Layer (LL) drivers. Both libraries are provided by STMicroelectronics and can be generated via STM32CubeMX, but they cater to distinctly different engineering philosophies.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">The Great Debate: HAL vs. LL Drivers<\/h4>\n\n\n\n<p><strong>The Hardware Abstraction Layer (HAL)<\/strong> is designed with portability and ease of use in mind. It provides a high-level, user-friendly API that hides the complex register manipulations beneath the surface. If you write a piece of code using HAL for the STM32F4, porting that code to an STM32L4 or STM32G4 requires minimal changes.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Pros:<\/strong> HAL significantly reduces development time. It handles edge cases, initialization states, and complex sequences (like DMA multi-channel scans) out-of-the-box. It is ideal for rapid prototyping, beginners, and applications where time-to-market is more critical than raw silicon-level efficiency.<\/li>\n\n\n\n<li><strong>Cons:<\/strong> This convenience comes at a cost. The HAL introduces significant overhead. A simple ADC read involves multiple function calls, state-checking variables, and timeout mechanisms. This overhead consumes more Flash memory, utilizes more RAM, and introduces latency, which can be detrimental in strict real-time or resource-constrained applications.<\/li>\n<\/ul>\n\n\n\n<p><strong>The Low Layer (LL) Drivers<\/strong>, on the other hand, offer a lightweight, optimized alternative. The LL drivers sit just a thin step above direct register-level programming. They provide inline functions and macros that map almost directly to the microcontroller&#8217;s hardware registers.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Pros:<\/strong> LL code is incredibly fast and highly deterministic. Because it strips away the bloated state-checking and abstract logic of the HAL, it executes in a fraction of the clock cycles. It also consumes minimal memory, making it perfect for bootloaders, interrupt service routines (ISRs), ultra-low-power applications, and high-frequency control loops.<\/li>\n\n\n\n<li><strong>Cons:<\/strong> The trade-off is portability and readability. LL code is highly specific to the exact microcontroller family you are using. An LL configuration for an STM32F4\u2019s ADC will not directly translate to an STM32F1. Furthermore, it requires the developer to have a much deeper understanding of the microcontroller&#8217;s Reference Manual, as you are dealing much closer to the bare metal.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Why LL for a Single-Channel, Single-Conversion Read?<\/h4>\n\n\n\n<p>For a task as fundamental as reading a single analog channel in a one-shot conversion, using the HAL can feel like using a sledgehammer to crack a nut. The overhead of the HAL&#8217;s <code>HAL_ADC_Start()<\/code> and <code>HAL_ADC_PollForConversion()<\/code> functions introduces unnecessary cycles that delay your execution.<\/p>\n\n\n\n<p>By utilizing the LL drivers for this task, we achieve a lean, highly efficient read. We will directly enable the ADC, trigger the conversion, poll the status register, and read the data register in a fraction of the time it takes HAL to do the same. This approach not only saves valuable program memory but teaches you exactly what is happening under the hood of the STM32F4&#8217;s ADC peripheral.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. STM32CubeMX Setup:<\/h2>\n\n\n\n<p>Open STM32CubeMX as start a new project as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"662\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-04-37-1024x662.jpg\" alt=\"\" class=\"wp-image-3990\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-04-37-1024x662.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-04-37-300x194.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-04-37-768x497.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-04-37-1536x993.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-04-37-2048x1324.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-04-37-1150x744.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-04-37-750x485.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-04-37-400x259.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-04-37-250x162.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Search for your STM32 MCU, select the MCU and click on Start New Project as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"724\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-06-08-1024x724.jpg\" alt=\"\" class=\"wp-image-3991\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-06-08-1024x724.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-06-08-300x212.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-06-08-768x543.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-06-08-1536x1087.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-06-08-2048x1449.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-06-08-1150x814.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-06-08-750x531.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-06-08-400x283.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_11-06-08-250x177.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, from Analog, ADC1, select IN0 as input:<\/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\/08\/2026-08-22_10-12-53-1024x662.jpg\" alt=\"\" class=\"wp-image-4686\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-12-53-1024x662.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-12-53-300x194.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-12-53-768x497.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-12-53-1536x993.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-12-53-2048x1324.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-12-53-1150x744.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-12-53-750x485.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-12-53-400x259.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-12-53-250x162.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>This will enable PA0 as analog input.<\/p>\n\n\n\n<p>Next, from Project Manager, Advanced Settings, set GPIO and ADC as LL, keep RCC as HAL, we shall use the delay.<\/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\/08\/2026-08-22_10-13-37-1024x662.jpg\" alt=\"\" class=\"wp-image-4687\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-37-1024x662.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-37-300x194.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-37-768x497.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-37-1536x993.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-37-2048x1324.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-37-1150x744.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-37-750x485.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-37-400x259.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-37-250x162.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Next, from Code Generation, enable generation peripheral initialization as pair of .c\/h per peripheral as follows:<\/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\/08\/2026-08-22_10-13-50-1024x662.jpg\" alt=\"\" class=\"wp-image-4688\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-50-1024x662.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-50-300x194.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-50-768x497.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-50-1536x993.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-50-2048x1324.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-50-1150x744.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-50-750x485.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-50-400x259.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-13-50-250x162.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Finally, from Project, Give the project a name, set toolchain\/IDE to STM32CubeIDE and click Generate Code as follows:<\/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\/08\/2026-08-22_10-14-30-1-1024x662.jpg\" alt=\"\" class=\"wp-image-4690\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-14-30-1-1024x662.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-14-30-1-300x194.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-14-30-1-768x497.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-14-30-1-1536x993.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-14-30-1-2048x1324.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-14-30-1-1150x744.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-14-30-1-750x485.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-14-30-1-400x259.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-14-30-1-250x162.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>That&#8217;s all for STM32CubeMX configuration.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Importing the Project to STM32CubeIDE:<\/h2>\n\n\n\n<p>Open STM32CubeIDE, select your workspace and click on Launch.<\/p>\n\n\n\n<p>From the IDE, click File and select STM32 Project Create\/Import as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"873\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_16-57-21-1024x873.jpg\" alt=\"\" class=\"wp-image-3997\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_16-57-21-1024x873.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_16-57-21-300x256.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_16-57-21-768x655.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_16-57-21-1150x981.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_16-57-21-750x640.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_16-57-21-400x341.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_16-57-21-250x213.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_16-57-21.jpg 1524w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Next, from Import STM32 Project, select STM32CubeMX\/STM32CubeIDE Project and click on Next as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"769\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_17-00-37-1024x769.jpg\" alt=\"\" class=\"wp-image-3998\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_17-00-37-1024x769.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_17-00-37-300x225.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_17-00-37-768x577.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_17-00-37-1150x863.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_17-00-37-750x563.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_17-00-37-400x300.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_17-00-37-250x188.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/11\/2025-11-26_17-00-37.jpg 1172w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Next, select the folder that contains the .ioc file and click on Finish as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"652\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-11_11-31-41-1024x652.jpg\" alt=\"\" class=\"wp-image-4360\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-11_11-31-41-1024x652.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-11_11-31-41-300x191.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-11_11-31-41-768x489.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-11_11-31-41-1536x977.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-11_11-31-41-1150x732.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-11_11-31-41-750x477.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-11_11-31-41-400x255.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-11_11-31-41-250x159.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-11_11-31-41.jpg 1760w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Note: Project name is for reference only.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Firmware Development:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>Open adc.h header file and in user code begin prototype, 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;}\">uint16_t ADCReadBlocking(void);<\/pre><\/div>\n\n\n\n<p>This function shall read the ADC in blocking mode and return the measured ADC value.<\/p>\n\n\n\n<p>Next, open adc.c and in user code begin 1, we shall populate the function.<\/p>\n\n\n\n<p>We start by declaring the ADCReadBlocking 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;}\">uint16_t ADCReadBlocking(void)<\/pre><\/div>\n\n\n\n<p>Within the function, we start by enabling the 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;}\">\/* Enable the ADC *\/\nLL_ADC_Enable(ADC1);<\/pre><\/div>\n\n\n\n<p>Next, start the conversion using software trigger:<\/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;}\">\/* Start conversion *\/\nLL_ADC_REG_StartConversionSWStart(ADC1);<\/pre><\/div>\n\n\n\n<p>Next, wait for the conversion to complete 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;}\">\/* Wait for end of conversion *\/\nwhile (!LL_ADC_IsActiveFlag_EOCS(ADC1));<\/pre><\/div>\n\n\n\n<p>Next, read the result of the conversion 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;}\">\/* Read ADC value *\/\nuint16_t val = LL_ADC_REG_ReadConversionData12(ADC1);<\/pre><\/div>\n\n\n\n<p>Disable the ADC:<\/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;}\">\/* Disable the ADC *\/\nLL_ADC_Disable(ADC1);<\/pre><\/div>\n\n\n\n<p>Finally, return the measured value 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;}\">return val;<\/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;}\">uint16_t ADCReadBlocking(void)\n{\n\t\/* Enable the ADC *\/\n\tLL_ADC_Enable(ADC1);\n\n\t\/* Start conversion *\/\n\tLL_ADC_REG_StartConversionSWStart(ADC1);\n\n\t\/* Wait for end of conversion *\/\n\twhile (!LL_ADC_IsActiveFlag_EOCS(ADC1));\n\n\t\/* Read ADC value *\/\n\tuint16_t val = LL_ADC_REG_ReadConversionData12(ADC1);\n\n\t\/* Disable the ADC *\/\n\tLL_ADC_Disable(ADC1);\n\n\treturn val;\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, in main.c file.<\/p>\n\n\n\n<p>In user code begin PV, declare the following variable:<\/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;<\/pre><\/div>\n\n\n\n<p>This will hold the measured adc value.<\/p>\n\n\n\n<p>Next, in user code begin 3 in while 1 loop, start the conversion each 200ms 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_value=ADCReadBlocking();\nHAL_Delay(200);<\/pre><\/div>\n\n\n\n<p>Thats all for the firmware.<\/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<h2 class=\"wp-block-heading\">5. 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=\"510\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-20-36-1024x510.jpg\" alt=\"\" class=\"wp-image-4691\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-20-36-1024x510.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-20-36-300x149.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-20-36-768x382.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-20-36-1150x572.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-20-36-750x373.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-20-36-400x199.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-20-36-250x124.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/08\/2026-08-22_10-20-36.jpg 1298w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Thats all for the guide.<\/p>\n\n\n\n<p>Next, we shall use continuous mode with interrupt to keep the ADC data alive.<\/p>\n\n\n\n<p>Stay tuned.<\/p>\n\n\n\n<p>Happy coding \ud83d\ude09<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This guide demonstrates how to configure the STM32F4 Analog-to-Digital Converter (ADC) using the Low Layer (LL) drivers for a straightforward single-channel, single-conversion read. By bypassing the overhead of the Hardware Abstraction Layer (HAL), this approach provides a lightweight, direct, and highly efficient method for reading analog sensor data. In this guide, we shall cover the [&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-4684","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\/4684"}],"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=4684"}],"version-history":[{"count":2,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4684\/revisions"}],"predecessor-version":[{"id":4693,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4684\/revisions\/4693"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4684"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4684"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4684"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}