{"id":3645,"date":"2025-07-25T13:34:21","date_gmt":"2025-07-25T13:34:21","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=3645"},"modified":"2025-07-28T10:08:26","modified_gmt":"2025-07-28T10:08:26","slug":"stm32-uart-part-2-send-data-using-interrupt-and-dma","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=3645","title":{"rendered":"STM32 UART Part 2: Send Data using Interrupt and DMA"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"683\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/ChatGPT-Image-Jul-24-2025-at-03_03_50-PM-1-1024x683.png\" alt=\"\" class=\"wp-image-3646\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/ChatGPT-Image-Jul-24-2025-at-03_03_50-PM-1-1024x683.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/ChatGPT-Image-Jul-24-2025-at-03_03_50-PM-1-300x200.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/ChatGPT-Image-Jul-24-2025-at-03_03_50-PM-1-768x512.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/ChatGPT-Image-Jul-24-2025-at-03_03_50-PM-1-1150x767.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/ChatGPT-Image-Jul-24-2025-at-03_03_50-PM-1-750x500.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/ChatGPT-Image-Jul-24-2025-at-03_03_50-PM-1-400x267.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/ChatGPT-Image-Jul-24-2025-at-03_03_50-PM-1-250x167.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/ChatGPT-Image-Jul-24-2025-at-03_03_50-PM-1.png 1536w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>In this second part of our UART guide series, we will learn how to transmit data efficiently using&nbsp;<strong>interrupts and DMA<\/strong>.<br>These advanced methods free up CPU resources, enabling non-blocking communication for real-time embedded applications.<\/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 and advantage of interrupt and DMA.<\/li>\n\n\n\n<li>STM32CubeIDE setup.<\/li>\n\n\n\n<li>Firmware development.<\/li>\n\n\n\n<li>Results.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Introduction and Advantage of Interrupt and DMA:<\/h2>\n\n\n\n<p>In embedded systems, efficient data transmission is critical to achieve real-time performance while minimizing CPU load. In Part 1 of this series, we explored&nbsp;<strong>UART configuration and basic data transmission using polling<\/strong>. While polling is simple and suitable for small or infrequent data transfers, it quickly becomes inefficient for high-speed communication or when multiple tasks need to run concurrently.<\/p>\n\n\n\n<p>In this second part, we will delve into&nbsp;<strong>transmitting data using interrupts and DMA<\/strong>, two powerful techniques that overcome the limitations of polling by allowing the CPU to continue executing other tasks while data transmission occurs in the background.<\/p>\n\n\n\n<p><strong>Polling, Interrupt, and DMA \u2013 Detailed Comparison:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th><strong>Method<\/strong><\/th><th><strong>How it Works<\/strong><\/th><th><strong>Advantages<\/strong><\/th><th><strong>Disadvantages<\/strong><\/th><th><strong>Use Cases<\/strong><\/th><\/tr><\/thead><tbody><tr><td><strong>Polling<\/strong><\/td><td>The CPU actively checks the UART transmit flag in a loop, and sends data once the peripheral is ready.<\/td><td>Simple to implement and understand. Good for short, infrequent transmissions.<\/td><td>CPU is blocked during transmission, wasting cycles that could be used elsewhere. Inefficient for large or frequent transfers.<\/td><td>Debug print messages, initial bring-up tests, simple blocking communication.<\/td><\/tr><tr><td><strong>Interrupt<\/strong><\/td><td>Transmission is initiated, and the UART peripheral generates an interrupt when it is ready to send the next byte or when the transfer completes. The CPU executes an ISR to handle it.<\/td><td>Non-blocking \u2013 CPU can execute other code between interrupts. Suitable for medium-sized transfers. Flexible with moderate complexity.<\/td><td>Adds interrupt overhead; requires proper ISR implementation. Not ideal for large data streams where ISR latency can become significant.<\/td><td>Periodic data logging, sensor command-response protocols, real-time control loops.<\/td><\/tr><tr><td><strong>DMA (Direct Memory Access)<\/strong><\/td><td>The DMA controller transfers data directly from memory to UART peripheral without CPU intervention, only generating an interrupt on completion.<\/td><td>Fully non-blocking. CPU is completely free during data transfer. Ideal for large data transfers with minimal overhead.<\/td><td>Slightly more complex configuration. DMA availability may be limited based on other peripherals using it.<\/td><td>High-speed logging, streaming data (e.g. telemetry), large buffer transmissions, audio or video streaming.<\/td><\/tr><\/tbody><\/table><\/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=\"683\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/IMG_7575-1024x683.png\" alt=\"\" class=\"wp-image-3655\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/IMG_7575-1024x683.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/IMG_7575-300x200.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/IMG_7575-768x512.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/IMG_7575-1150x767.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/IMG_7575-750x500.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/IMG_7575-400x267.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/IMG_7575-250x167.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/IMG_7575.png 1536w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Using&nbsp;<strong>interrupt-based transmission<\/strong>&nbsp;allows the CPU to perform other tasks while small chunks of data are sent asynchronously. On the other hand,&nbsp;<strong>DMA-based transmission<\/strong>&nbsp;enables bulk data transfer with maximum efficiency, offloading the entire transfer process from the CPU. Understanding when to use each method is essential in embedded system design to achieve optimal performance and reliability.<\/p>\n\n\n\n<p>In this part, we will configure UART transmission with interrupts and DMA on STM32, understand their implementation, and demonstrate their practical use cases for robust and efficient communication in your projects.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. STM32CubeIDE Setup:<\/h2>\n\n\n\n<p>We shall continue from the previous guide <a href=\"https:\/\/blog.embeddedexpert.io\/?p=3634\" data-type=\"link\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=3634\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"950\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-05-05-950x1024.jpg\" alt=\"\" class=\"wp-image-3648\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-05-05-950x1024.jpg 950w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-05-05-278x300.jpg 278w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-05-05-768x828.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-05-05-1150x1240.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-05-05-750x808.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-05-05-400x431.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-05-05-250x269.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-05-05.jpg 1336w\" sizes=\"(max-width: 950px) 100vw, 950px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Once the CubeMX window appears, open UART2 as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"884\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-07-59-884x1024.jpg\" alt=\"\" class=\"wp-image-3649\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-07-59-884x1024.jpg 884w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-07-59-259x300.jpg 259w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-07-59-768x889.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-07-59-1327x1536.jpg 1327w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-07-59-1150x1332.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-07-59-750x868.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-07-59-400x463.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-07-59-250x289.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-07-59.jpg 1546w\" sizes=\"(max-width: 884px) 100vw, 884px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, from NVIC Settings, enable UART2 interrupts as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1004\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-09-45-1024x1004.jpg\" alt=\"\" class=\"wp-image-3650\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-09-45-1024x1004.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-09-45-300x294.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-09-45-768x753.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-09-45-750x735.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-09-45-400x392.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-09-45-250x245.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-09-45.jpg 1034w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, from DMA Settings, add UART2_TX DMA as follows:<\/p>\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=\"672\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-10-35-1024x672.jpg\" alt=\"\" class=\"wp-image-3651\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-10-35-1024x672.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-10-35-300x197.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-10-35-768x504.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-10-35-1150x755.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-10-35-750x492.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-10-35-400x263.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-10-35-250x164.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-10-35.jpg 1526w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Thats all for the configuration. Save the project this will generate the project with updated parameters.<\/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> Once the project has been generated, main.c will be open.<\/p>\n\n\n\n<p>In user code begin PV, declare the following volatile 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;}\">volatile uint8_t TxDone=0;<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Once the the transfer is completed, the following function will called:<\/p>\n\n\n\n<p>In user code begin 0:<\/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 HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)\n{\n\tif (huart-&gt;Instance==USART2)\n\t{\n\t\tTxDone=1;\n\t}\n}\n<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Function Purpose<\/strong><\/h3>\n\n\n\n<p><code>HAL_UART_TxCpltCallback<\/code>&nbsp;is a&nbsp;<strong>callback function provided by STM32 HAL library<\/strong>&nbsp;that is&nbsp;<strong>automatically called by the HAL driver<\/strong>&nbsp;when a&nbsp;<strong>UART transmission (Tx) is complete<\/strong>&nbsp;when using interrupt or DMA transmission functions such as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>HAL_UART_Transmit_IT()<\/code><\/li>\n\n\n\n<li><code>HAL_UART_Transmit_DMA()<\/code><\/li>\n<\/ul>\n\n\n\n<p><h3 data-start=\"415\" data-end=\"445\"><strong data-start=\"419\" data-end=\"445\">Line-by-line breakdown<\/strong><\/h3><\/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 HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)\n<\/pre><\/div>\n\n\n\n<p><h3 data-start=\"415\" data-end=\"445\"><div class=\"contain-inline-size rounded-2xl relative bg-token-sidebar-surface-primary\"><div class=\"flex items-center text-token-text-secondary px-4 py-2 text-xs font-sans justify-between h-9 bg-token-sidebar-surface-primary select-none rounded-t-2xl\"><\/div><\/div><\/h3><\/p>\n\n\n\n<p><p data-start=\"513\" data-end=\"661\"><strong data-start=\"515\" data-end=\"538\">Function definition<\/strong>:This is the user-implemented callback function with a pointer to the UART handle (<code data-start=\"624\" data-end=\"631\">huart<\/code>) that triggered the callback.<code class=\"whitespace-pre! language-c\"><br><\/code><\/p>\u2705\u00a0<strong data-start=\"711\" data-end=\"754\">Check which UART triggered the callback<\/strong>:<\/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;}\">if (huart-&gt;Instance == USART2)\n<\/pre><\/div>\n\n\n\n<p><li data-start=\"757\" data-end=\"845\"><p data-start=\"759\" data-end=\"845\"><code data-start=\"759\" data-end=\"776\">huart-&gt;Instance<\/code>\u00a0points to the specific USART peripheral (e.g. USART1, USART2, etc.).This\u00a0<code data-start=\"853\" data-end=\"857\">if<\/code>\u00a0condition ensures the callback only executes code for\u00a0<strong data-start=\"912\" data-end=\"936\">USART2 transmissions<\/strong>.Useful when your project uses multiple UARTs with different callback logic.<\/p><\/li>\u2705\u00a0<strong data-start=\"1053\" data-end=\"1067\">Set a flag<\/strong>:<\/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;}\">{\n\tTxDone = 1;\n}\n<\/pre><\/div>\n\n\n\n<p><li data-start=\"1070\" data-end=\"1186\"><p data-start=\"1072\" data-end=\"1186\"><code data-start=\"1072\" data-end=\"1080\">TxDone<\/code>\u00a0is a user-defined global or volatile variable acting as a\u00a0<strong data-start=\"1139\" data-end=\"1183\">flag to indicate transmission completion<\/strong>.Typically used in the main loop or other functions to know when it is safe to start a new transmission or perform actions dependent on Tx completion.<\/p><\/li><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In user code begin 3:<\/p>\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;}\">uint16_t len=sprintf(uart_data,&quot;Counter Value = %d\\r\\n&quot;,counter);\n\nHAL_UART_Transmit_DMA(&amp;huart2, uart_data, len);\n\nwhile(TxDone==0);\nTxDone=0;\n\nHAL_UART_Transmit_IT(&amp;huart2, uart_data, len);\n\nwhile(TxDone==0);\nTxDone=0;\n\ncounter++;\n\nHAL_Delay(10);<\/pre><\/div>\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;}\">HAL_UART_Transmit_DMA(&amp;huart2, uart_data, len);\nHAL_UART_Transmit_IT(&amp;huart2, uart_data, len);<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>&amp;huart2<\/code><\/strong>\n<ul class=\"wp-block-list\">\n<li>Pointer to the UART handle structure for&nbsp;<strong>USART2<\/strong>.<\/li>\n\n\n\n<li>Contains all configuration and status information for this UART peripheral.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>uart_data<\/code><\/strong>\n<ul class=\"wp-block-list\">\n<li>Pointer to the&nbsp;<strong>data buffer<\/strong>&nbsp;you want to transmit.<\/li>\n\n\n\n<li>In this case, it is a character array containing your formatted string.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>len<\/code><\/strong>\n<ul class=\"wp-block-list\">\n<li>The&nbsp;<strong>length of data<\/strong>&nbsp;to transmit, in bytes.<\/li>\n\n\n\n<li>Ensures the DMA controller knows exactly how many bytes to transfer from memory to the UART data register.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>uint16_t len = sprintf(uart_data, \"Counter Value = %d\\r\\n\", counter);<\/code>\n<ul class=\"wp-block-list\">\n<li>Formats a string with the current&nbsp;<code>counter<\/code>&nbsp;value.<\/li>\n\n\n\n<li>Stores the formatted string in the&nbsp;<code>uart_data<\/code>&nbsp;buffer.<\/li>\n\n\n\n<li><code>len<\/code>&nbsp;holds the length of the formatted string for transmission.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>HAL_UART_Transmit_DMA(&amp;huart2, uart_data, len);<\/code>\n<ul class=\"wp-block-list\">\n<li>Starts&nbsp;<strong>UART transmission using DMA<\/strong>&nbsp;on USART2.<\/li>\n\n\n\n<li>DMA transfers data directly from memory to the UART peripheral, freeing the CPU during transmission.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>while (TxDone == 0);<\/code>\n<ul class=\"wp-block-list\">\n<li>Waits until&nbsp;<strong>DMA transmission completes<\/strong>.<\/li>\n\n\n\n<li><code>TxDone<\/code>&nbsp;is set to 1 in the&nbsp;<code>HAL_UART_TxCpltCallback()<\/code>&nbsp;callback when transmission finishes.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>TxDone = 0;<\/code>\n<ul class=\"wp-block-list\">\n<li>Resets the&nbsp;<code>TxDone<\/code>&nbsp;flag to prepare for the next transmission.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>HAL_UART_Transmit_IT(&amp;huart2, uart_data, len);<\/code>\n<ul class=\"wp-block-list\">\n<li>Starts&nbsp;<strong>UART transmission using interrupt<\/strong>&nbsp;on USART2.<\/li>\n\n\n\n<li>The UART peripheral sends data and triggers an interrupt when done.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>while (TxDone == 0);<\/code>\n<ul class=\"wp-block-list\">\n<li>Waits until&nbsp;<strong>interrupt-based transmission completes<\/strong>.<\/li>\n\n\n\n<li>Again,&nbsp;<code>TxDone<\/code>&nbsp;is set in the transmit complete callback.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>TxDone = 0;<\/code>\n<ul class=\"wp-block-list\">\n<li>Resets the flag after interrupt-based transmission for the next use.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>counter++;<\/code>\n<ul class=\"wp-block-list\">\n<li>Increments the&nbsp;<code>counter<\/code>&nbsp;variable for the next loop iteration.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>HAL_Delay(10);<\/code>\n<ul class=\"wp-block-list\">\n<li>Adds a&nbsp;<strong>10 ms delay<\/strong>&nbsp;before repeating the loop.<\/li>\n\n\n\n<li>Prevents sending data too rapidly.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p>Thats all for the firmware. Save the project and run it.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Results:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>Using your favourite uart terminal and set the baud rate to 115200, you should get the following:<\/p>\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=\"707\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-18-12-1024x707.jpg\" alt=\"\" class=\"wp-image-3653\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-18-12-1024x707.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-18-12-300x207.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-18-12-768x530.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-18-12-1536x1060.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-18-12-1150x794.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-18-12-750x518.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-18-12-400x276.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-18-12-250x173.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-25_16-18-12.jpg 1866w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Noticed that the string is printed twice, once using DMA and the other using interrupt.<\/p>\n\n\n\n<p>Now, you have functioning UART DMA\/IT driver ready to be deployed.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Happy coding \ud83d\ude09<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this second part of our UART guide series, we will learn how to transmit data efficiently using&nbsp;interrupts and DMA.These advanced methods free up CPU resources, enabling non-blocking communication for real-time embedded applications. In this guide, we shall cover the following: 1. Introduction and Advantage of Interrupt and DMA: In embedded systems, efficient data transmission [&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-3645","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\/3645"}],"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=3645"}],"version-history":[{"count":3,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3645\/revisions"}],"predecessor-version":[{"id":3657,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3645\/revisions\/3657"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3645"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3645"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3645"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}