{"id":3145,"date":"2017-09-12T22:40:09","date_gmt":"2017-09-13T05:40:09","guid":{"rendered":"https:\/\/visualgdb.com\/w\/?p=3145"},"modified":"2017-09-12T22:40:09","modified_gmt":"2017-09-13T05:40:09","slug":"using-the-stm32-uart-interface-with-hal","status":"publish","type":"post","link":"https:\/\/visualgdb.com\/tutorials\/arm\/stm32\/uart\/hal\/","title":{"rendered":"Using the STM32 UART interface with HAL"},"content":{"rendered":"<p>This tutorial shows how to use the STM32 UART interface in different modes using the HAL libraries. We will show how to use direct mode, interrupt-based mode and DMA-controlled mode and will use a logic analyzer to compare the precise timings of various events.<\/p>\n<p>Before you begin, install VisualGDB 5.2 or later.<\/p>\n<ol>\n<li>Start Visual Studio and open VisualGDB Embedded Project Wizard:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/01-newprj1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3146\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/01-newprj1.png\" alt=\"01-newprj\" width=\"833\" height=\"492\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/01-newprj1.png 833w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/01-newprj1-300x177.png 300w\" sizes=\"(max-width: 833px) 100vw, 833px\" \/><\/a><\/li>\n<li>Select &#8220;Create a new project with MSBuild -&gt; Embedded Binary&#8221;:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/02-msbuild1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3147\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/02-msbuild1.png\" alt=\"02-msbuild\" width=\"836\" height=\"630\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/02-msbuild1.png 836w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/02-msbuild1-300x226.png 300w\" sizes=\"(max-width: 836px) 100vw, 836px\" \/><\/a><\/li>\n<li>On the next page select your STM32 device. We will use the Nucleo-F410RB board that has the STM32F410RB chip:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/03-device2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3148\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/03-device2.png\" alt=\"03-device\" width=\"836\" height=\"630\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/03-device2.png 836w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/03-device2-300x226.png 300w\" sizes=\"(max-width: 836px) 100vw, 836px\" \/><\/a><\/li>\n<li>Proceed with the default &#8220;LEDBlink (HAL)&#8221; sample:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/04-sample2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3149\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/04-sample2.png\" alt=\"04-sample\" width=\"836\" height=\"630\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/04-sample2.png 836w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/04-sample2-300x226.png 300w\" sizes=\"(max-width: 836px) 100vw, 836px\" \/><\/a><\/li>\n<li>Connect your board to USB and let VisualGDB automatically recognize it and configure debug settings:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/05-debug1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3150\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/05-debug1.png\" alt=\"05-debug\" width=\"836\" height=\"630\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/05-debug1.png 836w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/05-debug1-300x226.png 300w\" sizes=\"(max-width: 836px) 100vw, 836px\" \/><\/a><\/li>\n<li>Press &#8220;Finish&#8221; to create the project. We will begin with a simple program that will read bytes via UART and echo them back in groups of 4. This requires four steps:\n<ol style=\"list-style-type: lower-alpha;\">\n<li>Enabling the clocks for the UART and GPIO peripherals.<\/li>\n<li>Configuring the GPIO pins corresponding to UART to actually act as UART pins (as opposed to manually controlled GPIO) pins.<\/li>\n<li>Initializing the UART module by specifying the operating parameters.<\/li>\n<li>Actually reading and writing the data.<\/li>\n<\/ol>\n<p>Replace the code in your main source file with the following:<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"\">#include &lt;stm32f4xx_hal.h&gt;\r\n#include &lt;stm32_hal_legacy.h&gt;\r\n\r\n#ifdef __cplusplus\r\nextern \"C\"\r\n#endif\r\nvoid SysTick_Handler(void)\r\n{\r\n\u00a0\u00a0 \u00a0HAL_IncTick();\r\n\u00a0\u00a0 \u00a0HAL_SYSTICK_IRQHandler();\r\n}\r\n\r\nstatic UART_HandleTypeDef s_UARTHandle = UART_HandleTypeDef();\r\n\r\nint main(void)\r\n{\r\n\u00a0\u00a0 \u00a0HAL_Init();\r\n\r\n\u00a0\u00a0\u00a0 __USART2_CLK_ENABLE();\r\n\u00a0\u00a0\u00a0 __GPIOA_CLK_ENABLE();\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 GPIO_InitTypeDef GPIO_InitStructure;\r\n\r\n\u00a0\u00a0\u00a0 GPIO_InitStructure.Pin = GPIO_PIN_2;\r\n\u00a0\u00a0\u00a0 GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;\r\n\u00a0\u00a0\u00a0 GPIO_InitStructure.Alternate = GPIO_AF7_USART2;\r\n\u00a0\u00a0\u00a0 GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;\r\n\u00a0\u00a0\u00a0 GPIO_InitStructure.Pull = GPIO_NOPULL;\r\n\u00a0\u00a0\u00a0 HAL_GPIO_Init(GPIOA, &amp;GPIO_InitStructure);\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 GPIO_InitStructure.Pin = GPIO_PIN_3;\r\n\u00a0\u00a0\u00a0 GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;\r\n\u00a0\u00a0\u00a0 HAL_GPIO_Init(GPIOA, &amp;GPIO_InitStructure);\r\n\r\n\u00a0\u00a0\u00a0 s_UARTHandle.Instance\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = USART2;\r\n\u00a0\u00a0\u00a0 s_UARTHandle.Init.BaudRate\u00a0\u00a0 = 115200;\r\n\u00a0\u00a0\u00a0 s_UARTHandle.Init.WordLength = UART_WORDLENGTH_8B;\r\n\u00a0\u00a0\u00a0 s_UARTHandle.Init.StopBits\u00a0\u00a0 = UART_STOPBITS_1;\r\n\u00a0\u00a0\u00a0 s_UARTHandle.Init.Parity\u00a0\u00a0\u00a0\u00a0 = UART_PARITY_NONE;\r\n\u00a0\u00a0\u00a0 s_UARTHandle.Init.HwFlowCtl\u00a0 = UART_HWCONTROL_NONE;\r\n\u00a0\u00a0\u00a0 s_UARTHandle.Init.Mode\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 = UART_MODE_TX_RX;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 if (HAL_UART_Init(&amp;s_UARTHandle) != HAL_OK)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 asm(\"bkpt 255\");\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 for (;;)\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 uint8_t buffer[4];\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HAL_UART_Receive(&amp;s_UARTHandle, buffer, sizeof(buffer), HAL_MAX_DELAY);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HAL_UART_Transmit(&amp;s_UARTHandle, buffer, sizeof(buffer), HAL_MAX_DELAY);\r\n\u00a0\u00a0\u00a0 }\r\n}<\/pre>\n<\/li>\n<li>We are using UART2 and pins PA2 and PA3 as the Nucleo-F410RB board has them connected to the on-board ST-Link UART interface, so we can use a terminal to interact with the board. You can find the GPIO pin numbers and the alternate function numbers corresponding to the UART interface on your device by searching the datasheet for the Alternate Function Mapping section:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/aftable.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3168\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/aftable.png\" alt=\"aftable\" width=\"1075\" height=\"455\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/aftable.png 1075w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/aftable-300x127.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/aftable-1024x433.png 1024w\" sizes=\"(max-width: 1075px) 100vw, 1075px\" \/><\/a>For STM32F410RB connecting UART2 to pins PA2 and PA3 requires enabling alternate function #7.<\/li>\n<li>Build the code by pressing Ctrl-Shift-B:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/06-build2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3151\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/06-build2.png\" alt=\"06-build\" width=\"1313\" height=\"802\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/06-build2.png 1313w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/06-build2-300x183.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/06-build2-1024x625.png 1024w\" sizes=\"(max-width: 1313px) 100vw, 1313px\" \/><\/a><\/li>\n<li>You can use a terminal program to talk to your STM32 board over the UART interface. If you are using VisualGDB Custom Edition, simply enable the Raw Terminal in VisualGDB Project Properties and it will show a terminal window inside the Visual Studio window:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/07-terminal.png\"> <img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3152\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/07-terminal.png\" alt=\"07-terminal\" width=\"1313\" height=\"802\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/07-terminal.png 1313w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/07-terminal-300x183.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/07-terminal-1024x625.png 1024w\" sizes=\"(max-width: 1313px) 100vw, 1313px\" \/><\/a><\/li>\n<li>Press F5 to start debugging. Try typing some text in the terminal window and see how after every 4 characters the program echoes them back:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/08-echo.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3153\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/08-echo.png\" alt=\"08-echo\" width=\"1313\" height=\"802\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/08-echo.png 1313w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/08-echo-300x183.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/08-echo-1024x625.png 1024w\" sizes=\"(max-width: 1313px) 100vw, 1313px\" \/><\/a><\/li>\n<li>Now we will explore the UART timings using a logic analyzer. First of all, modify your code to continuously output &#8220;test\\r\\n&#8221; and use GPIOC10 to signal the lifetime of the <strong>HAL_UART_Transmit()<\/strong> function:\n<pre class=\"\">\u00a0\u00a0\u00a0 __GPIOC_CLK_ENABLE();\r\n\u00a0\u00a0\u00a0 GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;\r\n\u00a0\u00a0\u00a0 GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;\r\n\u00a0\u00a0\u00a0 HAL_GPIO_Init(GPIOC, &amp;GPIO_InitStructure);\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 for (;;)\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 char buffer[] = \"test\\r\\n\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HAL_UART_Transmit(&amp;s_UARTHandle, buffer, sizeof(buffer), HAL_MAX_DELAY);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HAL_Delay(2);\r\n\u00a0\u00a0\u00a0 }<\/pre>\n<\/li>\n<li>We will use <a href=\"http:\/\/analyzer2go.com\/\">Analyzer2Go<\/a> to turn another STM32 board into a full-featured logic analyzer. Connect your second board to your computer, start Analyzer2Go and select the board type: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/09-a2go.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3154\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/09-a2go.png\" alt=\"09-a2go\" width=\"848\" height=\"534\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/09-a2go.png 848w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/09-a2go-300x189.png 300w\" sizes=\"(max-width: 848px) 100vw, 848px\" \/><\/a><\/li>\n<li>Connect the following signals between the boards:<br \/>\n<table>\n<tbody>\n<tr>\n<td>Signal<\/td>\n<td>Board running firmware<\/td>\n<td>Board running logic analyzer<\/td>\n<\/tr>\n<tr>\n<td>Ground<\/td>\n<td>GND<\/td>\n<td>GND<\/td>\n<\/tr>\n<tr>\n<td>UART output<\/td>\n<td>TX<\/td>\n<td>Any of the supported inputs<\/td>\n<\/tr>\n<tr>\n<td><strong>HAL_UART_Transmit()<\/strong> lifetime indicator<\/td>\n<td>PC10<\/td>\n<td>Any of the supported inputs<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/2boards.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3170\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/2boards.jpg\" alt=\"2boards\" width=\"1280\" height=\"977\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/2boards.jpg 1280w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/2boards-300x229.jpg 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/2boards-1024x782.jpg 1024w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/a><\/li>\n<li>Enable the connected signals in Analyzer2go to begin watching them. See how the <strong>HAL_UART_Transmit()<\/strong> function (red) is active during the entire transmission (blue):<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/10-capture.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3155\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/10-capture.png\" alt=\"10-capture\" width=\"1483\" height=\"823\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/10-capture.png 1483w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/10-capture-300x166.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/10-capture-1024x568.png 1024w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/10-capture-800x445.png 800w\" sizes=\"(max-width: 1483px) 100vw, 1483px\" \/><\/a><\/li>\n<li>Press the &#8220;Record&#8221; button to record several packets in a\u00a0 row. Then stop recording and zoom into one of them:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/12-zoomed.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3157\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/12-zoomed.png\" alt=\"12-zoomed\" width=\"1483\" height=\"467\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/12-zoomed.png 1483w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/12-zoomed-300x94.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/12-zoomed-1024x322.png 1024w\" sizes=\"(max-width: 1483px) 100vw, 1483px\" \/><\/a><\/li>\n<li>In order to automatically decode the UART bytes, open the Protocol Analyzers tab, drag\/drop the UART analyzer and connect it to the corresponding signal:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/13-parsed.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3158\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/13-parsed.png\" alt=\"13-parsed\" width=\"1425\" height=\"823\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/13-parsed.png 1425w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/13-parsed-300x173.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/13-parsed-1024x591.png 1024w\" sizes=\"(max-width: 1425px) 100vw, 1425px\" \/><\/a><\/li>\n<li>You can analyze the raw encoding of the UART signals by selecting the decoded characters and creating notes for some of them:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/14-note.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3159\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/14-note.png\" alt=\"14-note\" width=\"1425\" height=\"823\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/14-note.png 1425w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/14-note-300x173.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/14-note-1024x591.png 1024w\" sizes=\"(max-width: 1425px) 100vw, 1425px\" \/><\/a><\/li>\n<li>Then switch to the &#8220;Raw&#8221; view to see the signal shape. You can click the &#8220;set clock period&#8221; button to highlight individual zeroes and ones:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/15-period.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3160\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/15-period.png\" alt=\"15-period\" width=\"1425\" height=\"823\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/15-period.png 1425w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/15-period-300x173.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/15-period-1024x591.png 1024w\" sizes=\"(max-width: 1425px) 100vw, 1425px\" \/><\/a><\/li>\n<li>The &#8216;t&#8217; character was encoded as 0 0010 1110 1, which corresponds to a start bit (0) followed by a value of 0x74 (ASCII code for &#8216;t&#8217;) followed by a stop bit (1):<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/16-data.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3161\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/16-data.png\" alt=\"16-data\" width=\"1425\" height=\"823\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/16-data.png 1425w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/16-data-300x173.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/16-data-1024x591.png 1024w\" sizes=\"(max-width: 1425px) 100vw, 1425px\" \/><\/a><\/li>\n<li>Try changing the stop bit amount to 2:\n<pre class=\"\">\u00a0\u00a0\u00a0 s_UARTHandle.Init.StopBits\u00a0\u00a0 = UART_STOPBITS_2;<\/pre>\n<p>See how the stop bit is now twice longer:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/17-2stopbits.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3162\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/17-2stopbits.png\" alt=\"17-2stopbits\" width=\"1425\" height=\"823\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/17-2stopbits.png 1425w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/17-2stopbits-300x173.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/17-2stopbits-1024x591.png 1024w\" sizes=\"(max-width: 1425px) 100vw, 1425px\" \/><\/a><\/li>\n<li>Although calling HAL_UART_Transmit() for every transmission is simple, it has one major disadvanrage. While the transmission is active, the program cannot do anything else and has to wait for it to complete. We will now use the interrupt-based transmission to free up some of the CPU cycles. Replace the code in your main source file with this:\n<pre class=\"\">#include &lt;stm32f4xx_hal.h&gt;\r\n#include &lt;stm32_hal_legacy.h&gt;\r\n\r\n#ifdef __cplusplus\r\nextern \"C\"\r\n#endif\r\nvoid SysTick_Handler(void)\r\n{\r\n\u00a0\u00a0 \u00a0HAL_IncTick();\r\n\u00a0\u00a0 \u00a0HAL_SYSTICK_IRQHandler();\r\n}\r\n\r\nstatic UART_HandleTypeDef s_UARTHandle = UART_HandleTypeDef();\r\n\r\nextern \"C\" void USART2_IRQHandler()\r\n{\r\n\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET);\r\n\u00a0\u00a0\u00a0 HAL_UART_IRQHandler(&amp;s_UARTHandle);\r\n\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET);\r\n}\r\n\r\nvoid HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)\r\n{\r\n\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET);\r\n}\r\n\r\nint main(void)\r\n{\r\n\u00a0\u00a0 \u00a0HAL_Init();\r\n\r\n\u00a0\u00a0 \u00a0\/\/ &lt;Initialize UART and GPIO as before&gt;\r\n\r\n\u00a0\u00a0\u00a0 __GPIOC_CLK_ENABLE();\r\n\u00a0\u00a0\u00a0 GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;\r\n\u00a0\u00a0\u00a0 GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;\r\n\u00a0\u00a0\u00a0 HAL_GPIO_Init(GPIOC, &amp;GPIO_InitStructure);\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 NVIC_EnableIRQ(USART2_IRQn);\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 for (;;)\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 char buffer[] = \"test\\r\\n\";\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10 | GPIO_PIN_11, GPIO_PIN_SET);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HAL_UART_Transmit_IT(&amp;s_UARTHandle, (uint8_t *)buffer, sizeof(buffer));\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 HAL_Delay(2);\r\n\u00a0\u00a0\u00a0 }\r\n}<\/pre>\n<p>Don&#8217;t forget to copy the previous initialization code for UART and GPIO.<\/li>\n<li>Set a breakpoint in <strong>HAL_UART_TxCpltCallback()<\/strong>, start debugging and wait for it to trigger. Then check the call stack:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/stack.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3173\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/stack.png\" alt=\"stack\" width=\"1313\" height=\"802\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/stack.png 1313w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/stack-300x183.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/stack-1024x625.png 1024w\" sizes=\"(max-width: 1313px) 100vw, 1313px\" \/><\/a>You can see how the UART interrupt got invoked when the main() function was already running HAL_Delay(). The <strong>USART2_IRQHandler()<\/strong> handler called the <strong>HAL_UART_IRQHandler()<\/strong> and the <strong>HAL_UART_IRQHandler()<\/strong> in turn called the <strong>HAL_UART_TxCpltCallback()<\/strong> once it determined that the last byte got transmitted.<\/li>\n<li>Remove the breakpoint and restart the program. Then add the C11 and C12 signals to Analyzer2Go and make another recording. Note how the <strong>HAL_UART_Transmit_IT()<\/strong> function returns immediately (red) and the interrupt handler (green) is called after each byte is queued for transmission. Finally, the <strong>HAL_UART_TxCpltCallback()<\/strong> (orange signal switching to 0) is called once the last byte was physically sent:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/18-isrmode.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3163\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/18-isrmode.png\" alt=\"18-isrmode\" width=\"1668\" height=\"858\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/18-isrmode.png 1668w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/18-isrmode-300x154.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/18-isrmode-1024x527.png 1024w\" sizes=\"(max-width: 1668px) 100vw, 1668px\" \/><\/a><\/li>\n<li>Most of the time during the transmission the CPU will be able to run code unrelated to the transmission. It will only be interrupted by occasional UART interrupts. You can measure the overhead of the UART interrupts by comparing the byte transmission period to the width of the &#8216;ISR&#8217; pulse. For STM32F410RB the overhead is 12 out of 96 microseconds (12.5%) regardless of the buffer size:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/19-usage.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3164\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/19-usage.png\" alt=\"19-usage\" width=\"1668\" height=\"858\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/19-usage.png 1668w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/19-usage-300x154.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/19-usage-1024x527.png 1024w\" sizes=\"(max-width: 1668px) 100vw, 1668px\" \/><\/a><\/li>\n<li>In order to reduce the interrupt-related overhead, we will show switch UART to use DMA (direct memory access). In this mode the DMA controller will automatically feed the entire buffer to the UART byte-by-byte and only raise an interrupt once the entire buffer is sent.\u00a0 Add the following static variable:\n<pre class=\"\">static DMA_HandleTypeDef s_DMAHandle = DMA_HandleTypeDef();<\/pre>\n<p>Then replace the code below the code initializing GPIOC with the following:<\/p>\n<pre class=\"\">\u00a0\u00a0\u00a0 __DMA1_CLK_ENABLE();\r\n\u00a0\u00a0\u00a0 s_DMAHandle.Instance = DMA1_Stream6;\r\n\u00a0\u00a0\u00a0 s_DMAHandle.Init.Channel = DMA_CHANNEL_4;\r\n\u00a0 \r\n\u00a0\u00a0\u00a0 s_DMAHandle.Init.Direction = DMA_MEMORY_TO_PERIPH;\r\n\u00a0\u00a0\u00a0 s_DMAHandle.Init.PeriphInc = DMA_PINC_DISABLE;\r\n\u00a0\u00a0\u00a0 s_DMAHandle.Init.MemInc = DMA_MINC_ENABLE;\r\n\u00a0\u00a0\u00a0 s_DMAHandle.Init.Mode = DMA_CIRCULAR;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 s_DMAHandle.Init.Priority = DMA_PRIORITY_VERY_HIGH;\r\n\r\n\u00a0\u00a0\u00a0 s_DMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;\r\n\u00a0\u00a0\u00a0 s_DMAHandle.Init.MemDataAlignment = DMA_PDATAALIGN_BYTE;\r\n\r\n\u00a0\u00a0\u00a0 if (HAL_DMA_Init(&amp;s_DMAHandle) != HAL_OK)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 asm(\"bkpt 255\");\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 __HAL_LINKDMA(&amp;s_UARTHandle, hdmatx, s_DMAHandle);\r\n\u00a0\u00a0\u00a0 NVIC_EnableIRQ(DMA1_Stream6_IRQn);\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET);\r\n\u00a0\u00a0\u00a0 HAL_UART_Transmit_DMA(&amp;s_UARTHandle, (uint8_t *)s_Buffer, sizeof(s_Buffer));\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0 for (;;)\r\n\u00a0\u00a0\u00a0 {\r\n\u00a0\u00a0\u00a0 }<\/pre>\n<p>Remove the UART interrupt handler and add the DMA interrupt handler and 2 UART callbacks:<\/p>\n<pre class=\"\">extern \"C\" void DMA1_Stream6_IRQHandler()\r\n{\r\n\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET);\r\n\u00a0\u00a0\u00a0 HAL_DMA_IRQHandler(&amp;s_DMAHandle);\r\n\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET);\r\n}\r\n\r\nvoid HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)\r\n{\r\n\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET);\r\n\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET);\r\n}\r\n\r\nvoid HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)\r\n{\r\n\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_SET);\r\n\u00a0\u00a0\u00a0 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET);\r\n}<\/pre>\n<p>Note that different devices have different DMA channel and stream numbers assigned to UART. Use the DMA Request Mapping table in your device&#8217;s reference manual (not datasheet) to get the correct numbers:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/dma.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3176\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/dma.png\" alt=\"dma\" width=\"783\" height=\"346\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/dma.png 783w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/dma-300x133.png 300w\" sizes=\"(max-width: 783px) 100vw, 783px\" \/><\/a><\/li>\n<li>Start the program and ensure you still can see the stream of &#8216;test&#8217; messages:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/20-dmarun.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3165\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/20-dmarun.png\" alt=\"20-dmarun\" width=\"1313\" height=\"802\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/20-dmarun.png 1313w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/20-dmarun-300x183.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/20-dmarun-1024x625.png 1024w\" sizes=\"(max-width: 1313px) 100vw, 1313px\" \/><\/a><\/li>\n<li>Go back to Analyzer2Go and and check the timing. See how now the DMA interrupt is only called twice per the entire transmission (once for each half of the buffer):<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/21-dma.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3166\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/21-dma.png\" alt=\"21-dma\" width=\"1668\" height=\"858\" srcset=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/21-dma.png 1668w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/21-dma-300x154.png 300w, https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2017\/09\/21-dma-1024x527.png 1024w\" sizes=\"(max-width: 1668px) 100vw, 1668px\" \/><\/a>If you measure the interrupt overhead now you should get 41 microseconds out of 670 (for the entire packet) or ~6%. The DMA interrupt overhead also doesn&#8217;t scale up when you increase buffer size, so sending 70 bytes in a packet instead of 7 would reduce the overhead to 0.6%.<\/li>\n<li>Having a separate callback for each half of the buffer allows implementing double-buffering. While the DMA is transferring the first half of the buffer, you program could fill the second part with the next frame and vice versa. The same technique would also work for other DMA-capable peripherals, such as SPI (see the <a href=\"https:\/\/visualgdb.com\/tutorials\/arm\/stm32\/spi\/\">SPI tutorial<\/a> for more details).<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to use the STM32 UART interface in different modes using the HAL libraries. We will show<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16],"tags":[61,70],"_links":{"self":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/3145"}],"collection":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/comments?post=3145"}],"version-history":[{"count":7,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/3145\/revisions"}],"predecessor-version":[{"id":3229,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/3145\/revisions\/3229"}],"wp:attachment":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/media?parent=3145"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/categories?post=3145"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/tags?post=3145"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}