{"id":3769,"date":"2025-09-17T12:42:09","date_gmt":"2025-09-17T12:42:09","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=3769"},"modified":"2025-10-02T14:23:12","modified_gmt":"2025-10-02T14:23:12","slug":"stm32-uart-part-4-receive-unknown-length-using-dma","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=3769","title":{"rendered":"STM32 UART Part 5: Receive Unknown Length Using 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\/09\/image-1-1024x683.png\" alt=\"\" class=\"wp-image-3777\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/image-1-1024x683.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/image-1-300x200.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/image-1-768x512.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/image-1-1150x767.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/image-1-750x500.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/image-1-400x267.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/image-1-250x167.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/image-1.png 1536w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Using&nbsp;<strong>DMA in normal (non-circular) mode<\/strong>&nbsp;with the&nbsp;<strong>IDLE line interrupt<\/strong>&nbsp;turns UART reception into a smart, event-driven system. Instead of blindly filling buffers, the DMA captures bursts of unknown-length data in one shot, and the IDLE flag elegantly signals the firmware to process the frame and re-arm DMA for the next transfer.<\/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>Interrupt vs DMA-IDLE line approach.<\/li>\n\n\n\n<li>STM32CubeMX configuration.<\/li>\n\n\n\n<li>Firmware development.<\/li>\n\n\n\n<li>Results.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. Interrupt vs DMA-IDLE Line Approach:<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Interrupt-driven (single character per interrupt)<\/h3>\n\n\n\n<p><strong>How it works:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Each received character triggers an interrupt (<code>RxCpltCallback<\/code>).<\/li>\n\n\n\n<li>The CPU stores the character in a buffer and re-enables the receive interrupt for the next byte.<\/li>\n<\/ul>\n\n\n\n<p><strong>Advantages:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Very simple to implement and debug.<\/li>\n\n\n\n<li>Works well for short, low-speed transmissions.<\/li>\n\n\n\n<li>Fine-grained control over each received character (can parse on the fly).<\/li>\n<\/ul>\n\n\n\n<p><strong>Disadvantages:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>High interrupt load at higher baud rates (e.g., 115200 bps and above).<\/li>\n\n\n\n<li>CPU overhead increases linearly with data rate.<\/li>\n\n\n\n<li>Risk of missing characters if interrupts are delayed.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">DMA + IDLE Line method<\/h3>\n\n\n\n<p><strong>How it works:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>DMA transfers multiple characters directly into a buffer without CPU intervention.<\/li>\n\n\n\n<li>The IDLE line interrupt signals when the sender has stopped transmitting.<\/li>\n\n\n\n<li>At that point, the firmware processes all data at once and restarts DMA.<\/li>\n<\/ul>\n\n\n\n<p><strong>Advantages:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Very efficient \u2014 DMA handles transfers, reducing CPU overhead.<\/li>\n\n\n\n<li>Much better for high baud rates and large bursts of data.<\/li>\n\n\n\n<li>Lower risk of overrun compared to per-character interrupts.<\/li>\n\n\n\n<li>Easy to detect end-of-frame with IDLE flag.<\/li>\n<\/ul>\n\n\n\n<p><strong>Disadvantages:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Slightly more complex to set up (DMA + UART + IDLE ISR).<\/li>\n\n\n\n<li>Data is processed in blocks, not per-character (requires buffering logic).<\/li>\n\n\n\n<li>Buffer size must be carefully chosen to avoid overflow.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\">Summary<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Interrupt method<\/strong>&nbsp;\u2192 Best for small, sporadic messages or low baud rates (simple systems).<\/li>\n\n\n\n<li><strong>DMA + IDLE line<\/strong>&nbsp;\u2192 Best for high-throughput, unknown-length data streams (e.g., communication with GPS, modems, RS485, etc.).<\/li>\n<\/ul>\n\n\n\n<p>In short:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Feature<\/th><th>Interrupt-driven (per byte)<\/th><th>DMA + IDLE Line<\/th><\/tr><\/thead><tbody><tr><td><strong>Working principle<\/strong><\/td><td>Each received character triggers an interrupt and is copied to buffer.<\/td><td>DMA continuously transfers incoming data to buffer, IDLE interrupt indicates end of transmission.<\/td><\/tr><tr><td><strong>CPU load<\/strong><\/td><td>High (interrupt on every byte).<\/td><td>Low (interrupt only on IDLE or buffer full).<\/td><\/tr><tr><td><strong>Efficiency at high baud rates<\/strong><\/td><td>Poor \u2014 CPU easily overloaded.<\/td><td>Excellent \u2014 DMA handles data movement.<\/td><\/tr><tr><td><strong>Implementation complexity<\/strong><\/td><td>Simple, beginner-friendly.<\/td><td>More complex (DMA + UART + IDLE handling).<\/td><\/tr><tr><td><strong>Data processing<\/strong><\/td><td>Real-time, per-character.<\/td><td>Processed in chunks when IDLE line is detected.<\/td><\/tr><tr><td><strong>Risk of data loss<\/strong><\/td><td>Higher \u2014 interrupts can be delayed.<\/td><td>Lower \u2014 DMA buffers reduce risk.<\/td><\/tr><tr><td><strong>Best suited for<\/strong><\/td><td>Short, low-rate messages (commands, debug).<\/td><td>High-speed, unknown-length streams (GPS, modems, RS485, logs).<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. STM32CubeMX Configuration:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>We shall continue from <a href=\"https:\/\/blog.embeddedexpert.io\/?p=3744\" data-type=\"link\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=3744\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p>Open the .ioc as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"750\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-37-56-1024x750.jpg\" alt=\"\" class=\"wp-image-3771\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-37-56-1024x750.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-37-56-300x220.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-37-56-768x562.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-37-56-1150x842.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-37-56-750x549.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-37-56-400x293.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-37-56-250x183.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-37-56.jpg 1388w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Next, head to connectivity, select the desired UART (USART2 in this guide), and select DMA as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"962\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-14-962x1024.jpg\" alt=\"\" class=\"wp-image-3772\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-14-962x1024.jpg 962w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-14-282x300.jpg 282w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-14-768x818.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-14-1443x1536.jpg 1443w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-14-1150x1225.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-14-750x799.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-14-400x426.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-14-250x266.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-14.jpg 1512w\" sizes=\"(max-width: 962px) 100vw, 962px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, add DMA for UART_RX as follows:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Set Mode to Normal.<\/li>\n\n\n\n<li>Make sure Data Width for both to Byte.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"709\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-53-1024x709.jpg\" alt=\"\" class=\"wp-image-3773\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-53-1024x709.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-53-300x208.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-53-768x531.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-53-1536x1063.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-53-1150x796.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-53-750x519.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-53-400x277.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-53-250x173.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-39-53.jpg 1584w\" 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 and this will configure the project.<\/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><\/p>\n\n\n\n<p>Once the project has been configured, main.c shall be opened. <\/p>\n\n\n\n<p>In main.c, these are already defined in user code begin PV from the previous guide:<\/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;}\">#define BufferSize 100\n\nuint8_t uart_rx_data[BufferSize]={0};<\/pre><\/div>\n\n\n\n<p>This is where the received data shall be stored.<\/p>\n\n\n\n<p>Next, in user code begin 2 in main 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;}\">HAL_UARTEx_ReceiveToIdle_DMA(&amp;huart2, uart_rx_data, BufferSize);<\/pre><\/div>\n\n\n\n<p><strong><code>&amp;huart2<\/code><\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Handle for&nbsp;<strong>USART2 peripheral<\/strong>.<\/li>\n\n\n\n<li>Contains all the configuration info (baud rate, word length, parity, DMA linkage, etc.) needed for this UART instance.<\/li>\n\n\n\n<li>Tells HAL which UART to use for this operation.<\/li>\n<\/ul>\n\n\n\n<p><strong><code>uart_rx_data<\/code><\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Pointer to the&nbsp;<strong>receive buffer in RAM<\/strong>&nbsp;where incoming UART bytes will be stored.<\/li>\n\n\n\n<li>DMA writes received bytes directly into this buffer without CPU involvement.<\/li>\n<\/ul>\n\n\n\n<p><strong><code>BufferSize<\/code><\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The&nbsp;<strong>maximum number of bytes<\/strong>&nbsp;the DMA is allowed to transfer into the buffer before stopping.<\/li>\n\n\n\n<li>Prevents overwriting memory outside the buffer.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p>Once the buffer is filled or IDLE line is detected, the <strong><code>HAL_UARTEx_RxEventCallback<\/code><\/strong> will be called.<\/p>\n\n\n\n<p>In user code begin 0, declare the function as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)\n{\n\n\tif(huart-&gt;Instance==USART2)\n\t{\n\n\t\tHAL_UART_Transmit(&amp;huart2, uart_rx_data, Size, 100);\n\t\tHAL_UARTEx_ReceiveToIdle_DMA(&amp;huart2, uart_rx_data, BufferSize);\n\t}\n\n}<\/pre><\/div>\n\n\n\n<p>This callback is&nbsp;<strong>automatically called by HAL<\/strong>&nbsp;when:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The&nbsp;<strong>IDLE line<\/strong>&nbsp;is detected (receiver goes idle).<\/li>\n\n\n\n<li>Or the&nbsp;<strong>DMA buffer gets full<\/strong>&nbsp;(all&nbsp;<code>BufferSize<\/code>&nbsp;bytes are received).<\/li>\n<\/ul>\n\n\n\n<p>The&nbsp;<code>Size<\/code>&nbsp;argument tells you how many bytes were actually received before the event occurred.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Inside the function:<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Check which UART triggered the event<\/strong><code>if(huart-&gt;Instance == USART2)<\/code>\n<ul class=\"wp-block-list\">\n<li>Ensures this code only runs if the event came from&nbsp;<code>USART2<\/code>.<\/li>\n\n\n\n<li>Useful if you have multiple UARTs running.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Echo the received data back<\/strong><code>HAL_UART_Transmit(&amp;huart2, uart_rx_data, Size, 100);<\/code>\n<ul class=\"wp-block-list\">\n<li>Immediately sends the received data back over UART2.<\/li>\n\n\n\n<li>Acts like an&nbsp;<strong>echo test<\/strong>, confirming that reception worked.<\/li>\n\n\n\n<li><code>Size<\/code>&nbsp;ensures only the valid portion of the buffer is transmitted (not the whole buffer).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Restart DMA reception<\/strong><code>HAL_UARTEx_ReceiveToIdle_DMA(&amp;huart2, uart_rx_data, BufferSize);<\/code>\n<ul class=\"wp-block-list\">\n<li>Re-arms the DMA + IDLE receive mechanism.<\/li>\n\n\n\n<li>Necessary because after each event, DMA is no longer active.<\/li>\n\n\n\n<li>Without this line, the system would stop receiving after the first chunk.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<p>Thats all for the polling mode. Save the project and run it on your MCU 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\/2025\/07\/2025-07-03_17-48-35-1024x34.jpg\" alt=\"\" class=\"wp-image-3598\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-1024x34.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-300x10.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-768x25.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-1536x51.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-2048x68.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-1150x38.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-750x25.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-400x13.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/2025-07-03_17-48-35-250x8.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Results:<\/h2>\n\n\n\n<p>Using you favourite terminal UART application:<\/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\/09\/2025-09-17_14-51-30-1024x707.jpg\" alt=\"\" class=\"wp-image-3774\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-51-30-1024x707.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-51-30-300x207.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-51-30-768x530.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-51-30-1536x1060.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-51-30-1150x794.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-51-30-750x518.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-51-30-400x276.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-51-30-250x173.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/2025-09-17_14-51-30.jpg 1866w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Noticed that we managed to receive variable string length and echo back them without any issue.<\/p>\n\n\n\n<p>Feel free to improve it and make it able to work with your application.<\/p>\n\n\n\n<p>Happy coding \ud83d\ude09 <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using&nbsp;DMA in normal (non-circular) mode&nbsp;with the&nbsp;IDLE line interrupt&nbsp;turns UART reception into a smart, event-driven system. Instead of blindly filling buffers, the DMA captures bursts of unknown-length data in one shot, and the IDLE flag elegantly signals the firmware to process the frame and re-arm DMA for the next transfer. In this guide, we shall cover [&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-3769","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\/3769"}],"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=3769"}],"version-history":[{"count":4,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3769\/revisions"}],"predecessor-version":[{"id":3821,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3769\/revisions\/3821"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3769"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3769"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3769"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}