{"id":3744,"date":"2025-09-06T12:39:21","date_gmt":"2025-09-06T12:39:21","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=3744"},"modified":"2025-09-06T12:41:50","modified_gmt":"2025-09-06T12:41:50","slug":"stm32-uart-part-4-receiving-unknown-length-of-data","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=3744","title":{"rendered":"STM32 UART Part 4: Receiving Unknown Length of Data"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/ChatGPT-Image-Jul-24-2025-at-03_03_50-PM-1.png\" alt=\"\" \/><\/figure>\n\n\n\n<p>In this part of our UART guide series, we will explore how to receive data of\u00a0<strong>unknown length<\/strong>\u00a0using\u00a0<strong>interrupts triggered on each incoming character<\/strong>.<br>This approach allows the STM32 to handle variable-length messages efficiently, reacting in real time without blocking the CPU.<\/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>Firmware Setup.<\/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>Up to this point, we have explored UART transmission and reception using polling, interrupts, and DMA, each suited for specific scenarios. However, many real-world applications introduce a new challenge: the incoming data does not always have a fixed or known length. For example, commands from a PC terminal, GPS NMEA sentences, or sensor messages may vary in length and arrive asynchronously. In such cases, simply waiting for a predefined number of bytes is not practical.<\/p>\n\n\n\n<p>This is where&nbsp;<strong>single-character interrupt reception<\/strong>&nbsp;becomes a powerful tool. Instead of waiting for an entire buffer to be filled, the UART peripheral can be configured to generate an interrupt every time a new character (byte) arrives. The CPU then quickly retrieves this character inside the interrupt service routine (ISR) and stores it in a buffer for further processing. This allows the system to build a message byte by byte, handling variable-length data streams naturally.<\/p>\n\n\n\n<p>From a system design perspective, this approach provides several advantages:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Responsiveness<\/strong>&nbsp;\u2013 The CPU reacts immediately to each new character, ensuring that data is not lost, even at higher baud rates.<\/li>\n\n\n\n<li><strong>Flexibility<\/strong>&nbsp;\u2013 Since the length of incoming data is not fixed, the application can define its own rules for detecting the end of a message. Common methods include looking for a special termination character (e.g., newline&nbsp;<code>\\n<\/code>), monitoring for a timeout between bytes, or using higher-level protocols.<\/li>\n\n\n\n<li><strong>Efficiency<\/strong>&nbsp;\u2013 While this method still requires frequent interrupts (one per byte), it prevents the CPU from blocking in polling loops and allows it to perform other tasks when no data is arriving.<\/li>\n<\/ul>\n\n\n\n<p>It is important to note the&nbsp;<strong>trade-offs<\/strong>&nbsp;as well. Handling every single character in an interrupt can introduce overhead, especially at very high baud rates, since the CPU must service many interrupts per second. This makes buffer management and ISR efficiency critical to avoid data loss. For most medium-speed UART applications, however, this method provides an excellent balance between reliability and flexibility.<\/p>\n\n\n\n<p>In summary,&nbsp;<strong>single-character interrupt reception<\/strong>&nbsp;is one of the most practical solutions for working with UART when the message size cannot be determined in advance. It gives developers full control over how to interpret the incoming stream, while still maintaining non-blocking, event-driven operation that fits well into multitasking or real-time systems.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Firmware Development:<\/h2>\n\n\n\n<p>We shall continue from this guide <a href=\"https:\/\/blog.embeddedexpert.io\/?p=3735\" data-type=\"link\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=3735\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p>Open main.c. In user code begin PV, declare the following:<\/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 the buffer to hold the received data, the size is determined by BufferSize, in this guide, 100 bytes is enough.<\/p>\n\n\n\n<p>Next, 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;}\">uint8_t idx=0;<\/pre><\/div>\n\n\n\n<p>This variable will track the number of received data and store it in the correct place in the buffer.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Finally, 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;}\">uint8_t TempData=0;<\/pre><\/div>\n\n\n\n<p>This will hold the incoming data from the UART. Then we shall move it to the buffer.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, in user code begin 2 in main function, start the UART reception in interrupt mode 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;}\"> HAL_UART_Receive_IT(&amp;huart2, &amp;TempData, 1);<\/pre><\/div>\n\n\n\n<p>This with first character is received, an interrupt callback will be called:<\/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_RxCpltCallback(UART_HandleTypeDef *huart)\n{\n\tif(huart-&gt;Instance==USART2)\n\t{\n\n\t\tuart_rx_data[idx]=TempData;\n\t\tif(++idx&gt;=BufferSize){idx=0;}\n\t\tHAL_UART_Receive_IT(huart, &amp;TempData, 1);\n\t}\n\n}<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Function:<\/h3>\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_RxCpltCallback(UART_HandleTypeDef *huart)\n<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>This is a&nbsp;<strong>HAL-provided weak callback<\/strong>&nbsp;function.<\/li>\n\n\n\n<li>It is automatically called by the HAL library&nbsp;<strong>whenever a UART reception (in interrupt mode)<\/strong>&nbsp;is completed.<\/li>\n\n\n\n<li>You override it in your code to define what should happen when a byte is received.<\/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\">Inside the function<\/h3>\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<ul class=\"wp-block-list\">\n<li>Ensures this code only runs for&nbsp;<strong>USART2<\/strong>.<\/li>\n\n\n\n<li>Useful because the same callback is shared by all UART peripherals (USART1, USART2, etc.).<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\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;}\">uart_rx_data[idx] = TempData;\n<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Stores the newly received byte (<code>TempData<\/code>) into the&nbsp;<strong>receive buffer<\/strong>&nbsp;(<code>uart_rx_data<\/code>) at position&nbsp;<code>idx<\/code>.<\/li>\n\n\n\n<li>This is building your&nbsp;<strong>ring buffer<\/strong>&nbsp;byte by byte.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\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 (++idx &gt;= BufferSize) { idx = 0; }\n<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Increments the buffer index (<code>idx<\/code>).<\/li>\n\n\n\n<li>If the index reaches the buffer\u2019s maximum size, it wraps around to&nbsp;<code>0<\/code>.<\/li>\n\n\n\n<li>This creates the&nbsp;<strong>circular behavior<\/strong>&nbsp;of the ring buffer \u2192 new data overwrites from the beginning when the buffer is full.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\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_Receive_IT(huart, &amp;TempData, 1);\n<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Re-arms the UART reception interrupt for the&nbsp;<strong>next byte<\/strong>.<\/li>\n\n\n\n<li>Without this line, you would only capture one character and stop.<\/li>\n\n\n\n<li>This makes reception&nbsp;<strong>continuous<\/strong>, one byte at a time.<\/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<p>This callback:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Runs when a byte is received by&nbsp;<strong>USART2<\/strong>.<\/li>\n\n\n\n<li>Stores the byte into your buffer at the current index.<\/li>\n\n\n\n<li>Advances the index (with wrap-around).<\/li>\n\n\n\n<li>Restarts UART reception in interrupt mode for the next byte.<\/li>\n<\/ol>\n\n\n\n<p>In effect, it creates a&nbsp;<strong>continuous stream receiver<\/strong>, feeding data into a circular buffer, which the rest of your program can later read and process.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>That all for the firmware. Save the project and start a debugging session as follows:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"43\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-1024x43.png\" alt=\"\" class=\"wp-image-3600\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-1024x43.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-300x13.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-768x32.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-1536x65.png 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-1150x48.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-750x31.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-400x17.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image-250x10.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/07\/image.png 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Results:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"457\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2025\/09\/ezgif-415bfdb09e29cb.gif\" alt=\"\" class=\"wp-image-3745\" \/><\/figure>\n\n\n\n<p>As you can see, the buffer is being filled despite we are transmitting variable length of data.<\/p>\n\n\n\n<p>Next, we shall use more advanced techniques o handle this using DMA.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Stay tuned.<\/p>\n\n\n\n<p>Happy coding \ud83d\ude09<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this part of our UART guide series, we will explore how to receive data of\u00a0unknown length\u00a0using\u00a0interrupts triggered on each incoming character.This approach allows the STM32 to handle variable-length messages efficiently, reacting in real time without blocking the CPU. In this guide, we shall cover the following: 1. Introduction: Up to this point, we have [&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-3744","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\/3744"}],"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=3744"}],"version-history":[{"count":2,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3744\/revisions"}],"predecessor-version":[{"id":3747,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/3744\/revisions\/3747"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3744"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3744"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3744"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}