{"id":4384,"date":"2026-04-23T12:39:02","date_gmt":"2026-04-23T12:39:02","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=4384"},"modified":"2026-04-23T12:44:03","modified_gmt":"2026-04-23T12:44:03","slug":"getting-started-with-stm32-low-layer-ll-blinking-an-led","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=4384","title":{"rendered":"Getting Started with STM32 Low Layer (LL): Blinking an LED"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"559\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_e9bewqe9bewqe9be-1024x559.png\" alt=\"\" class=\"wp-image-4385\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_e9bewqe9bewqe9be-1024x559.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_e9bewqe9bewqe9be-300x164.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_e9bewqe9bewqe9be-768x419.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_e9bewqe9bewqe9be-1150x627.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_e9bewqe9bewqe9be-750x409.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_e9bewqe9bewqe9be-400x218.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_e9bewqe9bewqe9be-250x136.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/Gemini_Generated_Image_e9bewqe9bewqe9be.png 1408w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Master the balance between hardware control and code efficiency by leveraging the STM32F4\u2019s Low Layer (LL) drivers for direct register access. This introductory guide walks you through a lean project setup and GPIO configuration to execute a high-performance LED blink with minimal overhead.<\/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 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>Embarking on the development of firmware for the&nbsp;<strong>STM32F4<\/strong>&nbsp;series often presents a choice between high-level abstraction and low-level control. While many developers begin their journey with the Hardware Abstraction Layer (HAL), those seeking to extract maximum performance and efficiency from their silicon eventually turn to the&nbsp;<strong>Low Layer (LL)<\/strong>&nbsp;drivers. The LL drivers provide a hardware-proximate set of inline functions that map directly to the microcontroller&#8217;s registers. Unlike HAL, which manages state and handles complex error checking behind the scenes, LL acts as a thin wrapper over the hardware, offering a &#8220;what you see is what you get&#8221; approach to firmware engineering.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Why LL is Important<\/h5>\n\n\n\n<p>In the world of embedded systems, resources like execution time and memory are often at a premium. The LL drivers are vital for several key reasons:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Zero-Overhead Performance:<\/strong>&nbsp;Because LL functions are often defined as&nbsp;<code>inline<\/code>, they frequently compile down to a single assembly instruction. This eliminates the function-call overhead associated with HAL, making it ideal for high-speed interrupts and time-critical loops.<\/li>\n\n\n\n<li><strong>Minimal Footprint:<\/strong>&nbsp;LL drivers do not maintain internal state variables or large configuration structures. This significantly reduces the Flash and RAM footprint of your application, which is crucial when working on memory-constrained projects.<\/li>\n\n\n\n<li><strong>Predictability:<\/strong>&nbsp;For engineers who need to know exactly when a bit is toggled or a peripheral is enabled, LL provides transparent access. There are no hidden side effects or background processes, giving the developer total sovereignty over the CPU.<\/li>\n<\/ul>\n\n\n\n<h5 class=\"wp-block-heading\">LL vs. HAL: A Comparison<\/h5>\n\n\n\n<p>Choosing between HAL and LL is generally a trade-off between&nbsp;<strong>development speed<\/strong>&nbsp;and&nbsp;<strong>runtime efficiency<\/strong>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Feature<\/strong><\/td><td><strong>HAL (Hardware Abstraction Layer)<\/strong><\/td><td><strong>LL (Low Layer)<\/strong><\/td><\/tr><\/thead><tbody><tr><td><strong>Abstraction Level<\/strong><\/td><td>High; hides register complexity.<\/td><td>Low; direct register mapping.<\/td><\/tr><tr><td><strong>Code Size<\/strong><\/td><td>Larger due to generic state handling.<\/td><td>Minimal; very small footprint.<\/td><\/tr><tr><td><strong>Execution Speed<\/strong><\/td><td>Slower; involves multiple function calls.<\/td><td>Optimized; often zero-overhead.<\/td><\/tr><tr><td><strong>Ease of Use<\/strong><\/td><td>User-friendly; handles peripheral dependencies.<\/td><td>Requires deep datasheet knowledge.<\/td><\/tr><tr><td><strong>Portability<\/strong><\/td><td>Highly portable across STM32 families.<\/td><td>Less portable; register-specific.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>While HAL is excellent for rapid prototyping and complex middleware integration (like USB or TCP\/IP stacks), LL is the preferred choice for drivers where every clock cycle counts. By mastering LL, you gain the ability to write professional-grade, lean firmware that utilizes the STM32F4 hardware to its absolute limit. In this guide, we will leverage this efficiency to set up our environment and execute a precise LED blink.<\/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>From the user manual of STM32F411 Nucleo-64, we can find that the LD2 is connected to PA5:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"493\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-20-54-1024x493.png\" alt=\"\" class=\"wp-image-4386\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-20-54-1024x493.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-20-54-300x144.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-20-54-768x370.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-20-54-1536x739.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-20-54-2048x985.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-20-54-1150x553.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-20-54-750x361.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-20-54-400x192.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-20-54-250x120.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Next, set PA5 as output 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\/04\/2026-04-23_15-23-46-1024x662.png\" alt=\"\" class=\"wp-image-4387\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-23-46-1024x662.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-23-46-300x194.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-23-46-768x497.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-23-46-1536x993.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-23-46-2048x1324.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-23-46-1150x744.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-23-46-750x485.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-23-46-400x259.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-23-46-250x162.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Next, from Project Manager, head to Advanced Settings, set both RCC and GPIO to LL 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\/04\/2026-04-23_15-24-42-1024x662.png\" alt=\"\" class=\"wp-image-4388\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-24-42-1024x662.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-24-42-300x194.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-24-42-768x497.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-24-42-1536x993.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-24-42-2048x1324.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-24-42-1150x744.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-24-42-750x485.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-24-42-400x259.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-24-42-250x162.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, from Project, give the project a name and set toolchain\/IDE to STM32CubeIDE and click on 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\/04\/2026-04-23_15-25-50-1024x662.png\" alt=\"\" class=\"wp-image-4389\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-25-50-1024x662.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-25-50-300x194.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-25-50-768x497.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-25-50-1536x993.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-25-50-2048x1324.png 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-25-50-1150x744.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-25-50-750x485.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-25-50-400x259.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2026\/04\/2026-04-23_15-25-50-250x162.png 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Thats all for STM32CubeMX setup.<\/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<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Firmware Development:<\/h2>\n\n\n\n<p>Before we develop the firmware, let us explain the generated function.<\/p>\n\n\n\n<p>This function,&nbsp;<code>SystemClock_Config<\/code>, is the heartbeat of your firmware. Using&nbsp;<strong>Low Layer (LL)<\/strong>&nbsp;calls, it manually configures the STM32F4 to run using its internal oscillator. In the world of registers, this is where you define how fast your CPU &#8220;thinks&#8221; and how it handles memory access.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h5 class=\"wp-block-heading\">Phase 1: Flash Memory Latency<\/h5>\n\n\n\n<p><\/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_FLASH_SetLatency(LL_FLASH_LATENCY_0);\nwhile(LL_FLASH_GetLatency()!= LL_FLASH_LATENCY_0) { }\n<\/pre><\/div>\n\n\n\n<p>Flash memory is significantly slower than the CPU. If the CPU clock is high, we must add&nbsp;<strong>Wait States<\/strong>&nbsp;(latency) so the Flash can keep up. Since you are configuring a relatively slow clock (16 MHz),&nbsp;<code>LATENCY_0<\/code>&nbsp;is used, meaning the CPU can read from Flash instantly without waiting. The&nbsp;<code>while<\/code>&nbsp;loop is a hardware barrier ensuring the setting is applied before moving on.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Phase 2: Power and Internal Oscillator (HSI)<\/h5>\n\n\n\n<p><\/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_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);\nLL_RCC_HSI_SetCalibTrimming(16);\nLL_RCC_HSI_Enable();\nwhile(LL_RCC_HSI_IsReady() != 1) { }\n<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Voltage Scaling:<\/strong>&nbsp;This adjusts the internal main voltage regulator to balance power consumption versus performance.&nbsp;<code>SCALE1<\/code>&nbsp;is the highest performance mode.<\/li>\n\n\n\n<li><strong>HSI (High-Speed Internal):<\/strong>&nbsp;This enables the internal 16 MHz RC oscillator. You don&#8217;t need an external crystal for this. The code trims the factory calibration and waits for the&nbsp;<code>HSI_IsReady<\/code>&nbsp;flag to ensure the clock signal is stable.<\/li>\n<\/ul>\n\n\n\n<h5 class=\"wp-block-heading\">Phase 3: Bus Prescalers<\/h5>\n\n\n\n<p><\/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_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);\nLL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);\nLL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);\n<\/pre><\/div>\n\n\n\n<p>The STM32 doesn&#8217;t just have one clock; it has a hierarchy of buses:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>AHB (Advanced High-performance Bus):<\/strong>&nbsp;Connects the Core to high-speed peripherals (like GPIO).<\/li>\n\n\n\n<li><strong>APB1\/APB2 (Advanced Peripheral Buses):<\/strong>&nbsp;Connects slower peripherals (like UART or I2C).By setting these to&nbsp;<code>DIV_1<\/code>, you are running all these buses at the full 16 MHz speed.<\/li>\n<\/ul>\n\n\n\n<h5 class=\"wp-block-heading\">Phase 4: System Clock Selection<\/h5>\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_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);\nwhile(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI) { }\n<\/pre><\/div>\n\n\n\n<p>This is the &#8220;switch-over&#8221; moment. You tell the MCU to stop using its default startup clock and start using the&nbsp;<strong>HSI<\/strong>&nbsp;as the main&nbsp;<code>SYSCLK<\/code>. The loop confirms the hardware has successfully made the transition.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Phase 5: Timekeeping and Core Updates<\/h5>\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_Init1msTick(16000000);\nLL_SetSystemCoreClock(16000000);\n<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>LL_Init1msTick:<\/strong>&nbsp;Configures the SysTick timer to generate an interrupt every 1ms based on the 16 MHz frequency. This is vital for functions like&nbsp;<code>LL_mDelay<\/code>.<\/li>\n\n\n\n<li><strong>LL_SetSystemCoreClock:<\/strong>&nbsp;Updates the global&nbsp;<code>SystemCoreClock<\/code>&nbsp;variable. This doesn&#8217;t change hardware speed, but it tells the CMSIS software layers exactly how fast the hardware is running so timing calculations remain accurate.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p>The&nbsp;<code>MX_GPIO_Init<\/code>&nbsp;function handles the fundamental setup of the microcontroller&#8217;s hardware pins. Using the&nbsp;<strong>Low Layer (LL)<\/strong>&nbsp;library, it takes a structured approach to transform a generic silicon pin into a functional digital output.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h5 class=\"wp-block-heading\">1. Enabling the Peripheral Clock<\/h5>\n\n\n\n<p><\/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_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);\n<\/pre><\/div>\n\n\n\n<p>On the STM32F4, peripherals are disabled by default to save power. Before you can modify any registers in&nbsp;<strong>Port A<\/strong>, you must enable its clock on the&nbsp;<strong>AHB1<\/strong>&nbsp;(Advanced High-performance Bus). Without this line, any subsequent commands to&nbsp;<code>GPIOA<\/code>&nbsp;will be ignored by the hardware.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">2. Ensuring a Safe Initial State<\/h5>\n\n\n\n<p><\/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_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_5);\n<\/pre><\/div>\n\n\n\n<p>It is a professional &#8220;best practice&#8221; to define the pin state&nbsp;<em>before<\/em>&nbsp;it becomes an output. By resetting&nbsp;<strong>Pin 5<\/strong>, you ensure that as soon as the pin is initialized, it starts at&nbsp;<strong>0V (Logic Low)<\/strong>, preventing any accidental &#8220;glitches&#8221; or brief power-on pulses to whatever hardware is connected.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">3. Configuring the GPIO Structure<\/h5>\n\n\n\n<p>The function uses the&nbsp;<code>LL_GPIO_InitTypeDef<\/code>&nbsp;structure to define the physical characteristics of the pin. This is essentially a template that gets translated into register values by the&nbsp;<code>LL_GPIO_Init<\/code>&nbsp;function.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><td><strong>Parameter<\/strong><\/td><td><strong>Value<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><\/thead><tbody><tr><td><strong>Pin<\/strong><\/td><td><code>LL_GPIO_PIN_5<\/code><\/td><td>Targets the specific physical pin (PA5).<\/td><\/tr><tr><td><strong>Mode<\/strong><\/td><td><code>OUTPUT<\/code><\/td><td>Sets the pin to drive a signal out (rather than reading one in).<\/td><\/tr><tr><td><strong>Speed<\/strong><\/td><td><code>FREQ_LOW<\/code><\/td><td>Reduces the &#8220;slew rate&#8221; (how fast the voltage rises\/falls). Low frequency reduces EMI (Electromagnetic Interference) and is perfect for an LED.<\/td><\/tr><tr><td><strong>OutputType<\/strong><\/td><td><code>PUSHPULL<\/code><\/td><td>The pin can actively drive the signal to both VCC (High) and Ground (Low).<\/td><\/tr><tr><td><strong>Pull<\/strong><\/td><td><code>PULL_NO<\/code><\/td><td>Disables internal resistors. Since the pin is in Push-Pull mode, it doesn&#8217;t need internal help to stay at a logic level.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h5 class=\"wp-block-heading\">4. Hardware Application<\/h5>\n\n\n\n<p><\/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_GPIO_Init(GPIOA, &amp;GPIO_InitStruct);\n<\/pre><\/div>\n\n\n\n<p>This final call is where the magic happens. It takes all the settings defined in your&nbsp;<code>GPIO_InitStruct<\/code>&nbsp;and writes them into the&nbsp;<strong>MODER<\/strong>,&nbsp;<strong>OSPEEDR<\/strong>,&nbsp;<strong>OTYPER<\/strong>, and&nbsp;<strong>PUPDR<\/strong>&nbsp;registers of Port A. Once this line executes, PA5 is officially ready to drive your LED.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, in while 1 loop, in user code begin 3, toggle the LED state 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;}\">LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);<\/pre><\/div>\n\n\n\n<p>Delay by 1 second:<\/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_mDelay(1000);<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Alternatively, you can use the following to toggle the state of the LED as follows:<\/p>\n\n\n\n<p>To set the pin to high:<\/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_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_5);<\/pre><\/div>\n\n\n\n<p>To set the pin low:<\/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_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_5);<\/pre><\/div>\n\n\n\n<p>Note that set and reset function are separated. This will improve the performance of the MUC.<\/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 <a href=\"https:\/\/github.com\/hussamaldean\/Embedded-Expert-Post-Projects\/tree\/main\/Projects\/LL_Blinking%20LED\" data-type=\"link\" data-id=\"https:\/\/github.com\/hussamaldean\/Embedded-Expert-Post-Projects\/tree\/main\/Projects\/LL_Blinking%20LED\" 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>You should get something similar to this:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"LED toggle using DMA and timer\" width=\"1170\" height=\"658\" src=\"https:\/\/www.youtube.com\/embed\/xFh9q-DyUX4?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>Happy coding \ud83d\ude09<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Master the balance between hardware control and code efficiency by leveraging the STM32F4\u2019s Low Layer (LL) drivers for direct register access. This introductory guide walks you through a lean project setup and GPIO configuration to execute a high-performance LED blink with minimal overhead. In this guide, we shall cover the following: 1. Introduction: Embarking on [&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-4384","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\/4384"}],"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=4384"}],"version-history":[{"count":3,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4384\/revisions"}],"predecessor-version":[{"id":4393,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/4384\/revisions\/4393"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4384"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4384"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4384"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}