{"id":8464,"date":"2023-10-04T14:04:32","date_gmt":"2023-10-04T21:04:32","guid":{"rendered":"https:\/\/visualgdb.com\/w\/?p=8464"},"modified":"2023-10-11T10:36:59","modified_gmt":"2023-10-11T17:36:59","slug":"using-live-tracing-to-trace-freertos-events","status":"publish","type":"post","link":"https:\/\/visualgdb.com\/tutorials\/tracing\/embedded\/freertos\/","title":{"rendered":"Using Live Tracing to Trace FreeRTOS Events"},"content":{"rendered":"<p>This tutorial shows how to use the <a href=\"https:\/\/visualgdb.com\/documentation\/tracing\/\">VisualGDB&#8217;s Live Tracing<\/a> feature to record the flow of a simple 2-thread program that reads bytes via UART and replies back to them with the &#8220;<strong>You typed &lt;&#8230;&gt;<\/strong>&#8221; messages. The program will consist of 2 threads (<strong>ProcessingThread()<\/strong> and <strong>SendingThread()<\/strong>), 2 queues (<strong>s_RXQueue<\/strong> and <strong>s_TXQueue<\/strong>) and one semaphore (<strong>s_TXReadySemaphore<\/strong>) used to determine when a UART transmission has been completed and a new character is ready to be sent:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/threads.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8465\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/threads.png\" alt=\"\" width=\"1200\" height=\"513\" \/><\/a>We will use Live Tracing to create a detailed recording of the program flow (exact functions called, queue sizes, sent\/received data) without having to instrument it or change any code. The tracepoints will be injected into the program dynamically, will run directly on the device with minimal overhead, and VisualGDB will use them to generate a detailed report showing what exactly happened on the device.<\/p>\n<ol>\n<li>Start Visual Studio and locate the VisualGDB Embedded Project Wizard:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/01-newprj.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8466\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/01-newprj.png\" alt=\"\" width=\"890\" height=\"625\" \/><\/a><\/li>\n<li>Enter the name and location for the new project: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/02-name.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8467\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/02-name.png\" alt=\"\" width=\"890\" height=\"625\" \/><\/a><\/li>\n<li>Select &#8220;Create an embedded application -&gt; Advanced CMake&#8221;. Live Tracing will also work with other project types (including unit test projects):<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/03-cmake.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8468\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/03-cmake.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>Select the latest ARM toolchain and pick your device:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/04-device.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8469\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/04-device.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>Select the &#8220;LEDBlink (FreeRTOS)&#8221; sample: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/05-sample.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8470\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/05-sample.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>On the last page of the wizard select the debug settings that work in your configuration and make sure tracing and FLASH patching are enabled:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/06-debug.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8471\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/06-debug.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>Now we will add the UART functionality to the basic FreeRTOS project. The easiest way to do it would be to clone a UART sample for your board into a separate project (or use STM32CubeMX to generate it):<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/uart.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8495\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/uart.png\" alt=\"\" width=\"886\" height=\"693\" \/><\/a><\/li>\n<li>Create a separate file\u00a0 called <strong>UARTFunctions.c<\/strong> and copy the the following logic from the UART sample:<br \/>\n<table style=\"border-collapse: collapse; width: 100%; height: 96px;\" border=\"1\">\n<tbody>\n<tr style=\"height: 24px;\">\n<td style=\"width: 33.3333%; height: 24px;\">Logic<\/td>\n<td style=\"width: 33.3333%; height: 24px;\">Description<\/td>\n<td style=\"width: 33.3333%; height: 24px;\">Destination function<\/td>\n<\/tr>\n<tr style=\"height: 24px;\">\n<td style=\"width: 33.3333%; height: 24px;\"><strong>SystemClock_Config()<\/strong><\/td>\n<td style=\"width: 33.3333%; height: 24px;\">Configures system clock so that UART can run with correct frequency<\/td>\n<td style=\"width: 33.3333%; height: 24px;\">SystemClock_Config()<\/td>\n<\/tr>\n<tr style=\"height: 24px;\">\n<td style=\"width: 33.3333%; height: 24px;\">Calls to <strong>HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &#8230;)<\/strong><\/td>\n<td style=\"width: 33.3333%; height: 24px;\">Configures I\/O pins used by UART<\/td>\n<td style=\"width: 33.3333%; height: 24px;\">UART_Init()<\/td>\n<\/tr>\n<tr style=\"height: 24px;\">\n<td style=\"width: 33.3333%; height: 24px;\">Call to <strong>HAL_UART_Init()<\/strong><\/td>\n<td style=\"width: 33.3333%; height: 24px;\">Configures UART frequency, bit count, parity, etc<\/td>\n<td style=\"width: 33.3333%; height: 24px;\">UART_Init()<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>You can find sample <a href=\"https:\/\/github.com\/sysprogs\/tutorials\/blob\/master\/visualgdb\/tracing\/FreeRTOSTracingDemo\/UARTFunctions.c\">UARTFunctions.c<\/a> and <a href=\"https:\/\/github.com\/sysprogs\/tutorials\/blob\/master\/visualgdb\/tracing\/FreeRTOSTracingDemo\/UARTFunctions.h\">UARTFunctions.h<\/a> files for the Nucleo-STM32F446RE board in our <a href=\"https:\/\/github.com\/sysprogs\/tutorials\/tree\/master\/visualgdb\/tracing\/FreeRTOSTracingDemo\">GitHub repository<\/a>.<\/li>\n<li>Call <strong>SystemClock_Config()<\/strong> and <strong>UART_Init()<\/strong> from the main() function. Then modify it to enable the UART interrupt:\n<pre class=\"\">void USART2_IRQHandler()\r\n{\r\n    HAL_UART_IRQHandler(&amp;UartHandle);\r\n}\r\n\r\nint main()\r\n{\r\n    \/* ... *\/\r\n    NVIC_SetPriority(USART2_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY);\r\n    NVIC_EnableIRQ(USART2_IRQn);\r\n}<\/pre>\n<\/li>\n<li>Define and create the RX\/TX queues and a semaphore described at the beginning of the tutorial:\n<pre class=\"\">static QueueHandle_t s_RXQueue, s_TXQueue;\r\nstatic SemaphoreHandle_t s_TXReadySemaphore;\r\nstatic uint8_t s_RxCharacter, s_TxCharacter;\r\nint main()\r\n{\r\n    \/* ... *\/\r\n    s_RXQueue = xQueueCreate(128, 1);\r\n    s_TXQueue = xQueueCreate(128, 1);\r\n    s_TXReadySemaphore = xSemaphoreCreateBinary();\r\n}<\/pre>\n<\/li>\n<li>Define the <strong>ProcessingThread()<\/strong> function that will initiate a UART receive operation, wait for the data to come from the <strong>s_RXQueue<\/strong>, format the reply and send it into s_TXQueue. Also add a <strong>HAL_UART_RxCpltCallback()<\/strong> handler that will push the received characters into <strong>s_RXQueue<\/strong>:\n<pre class=\"\">static void ProcessingThread(void const *argument)\r\n{\r\n    HAL_UART_Receive_IT(&amp;UartHandle, &amp;s_RxCharacter, 1);\r\n    \r\n    for (int i = 0;;i++)\r\n    {\r\n    \tuint8_t ch;\r\n    \tstatic char reply[64];\r\n    \txQueueReceive(s_RXQueue, &amp;ch, portMAX_DELAY);\r\n    \tsprintf(reply, \"You typed '%c'\\r\\n\", ch);\r\n    \t\r\n    \tfor (char *p = reply; *p; p++)\r\n    \t{\r\n       \t    xQueueSend(s_TXQueue, p, portMAX_DELAY);\r\n    \t}\r\n    }\r\n}\r\n\r\nvoid HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)\r\n{\r\n    BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r\n    xQueueSendFromISR(s_RXQueue, &amp;s_RxCharacter, &amp;xHigherPriorityTaskWoken);\r\n    HAL_UART_Receive_IT(&amp;UartHandle, &amp;s_RxCharacter, 1);\r\n    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);\r\n}<\/pre>\n<\/li>\n<li>Similarly, add a <strong>SendingThread()<\/strong> function that will send the contents of <strong>s_TXQueue<\/strong> to UART, along with the <strong>HAL_UART_TxCpltCallback()<\/strong> handler that will signal the semaphore:\n<pre class=\"\">static void SendingThread(void const *argument)\r\n{\r\n    for (;;)\r\n    {\r\n        uint8_t ch;\r\n        xQueueReceive(s_TXQueue, &amp;ch, portMAX_DELAY);\r\n        \r\n        HAL_UART_Transmit_IT(&amp;UartHandle, &amp;ch, 1);\r\n        xSemaphoreTake(s_TXReadySemaphore, portMAX_DELAY);\r\n    }\r\n}\r\n\r\nvoid HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)\r\n{\r\n    BaseType_t xHigherPriorityTaskWoken;\r\n    xSemaphoreGiveFromISR(s_TXReadySemaphore, &amp;xHigherPriorityTaskWoken);\r\n    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);\r\n}<\/pre>\n<\/li>\n<li>Finally, create and start both threads from <strong>main()<\/strong>:\n<pre class=\"\">\u00a0   osThreadDef(Process, ProcessingThread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);\r\n    osThreadDef(Sender, SendingThread, osPriorityAboveNormal, 0, configMINIMAL_STACK_SIZE);\r\n    osThreadCreate(osThread(Process), NULL);\r\n    osThreadCreate(osThread(Sender), NULL);<\/pre>\n<\/li>\n<li>The final version of the code should look like <a href=\"https:\/\/github.com\/sysprogs\/tutorials\/blob\/master\/visualgdb\/tracing\/FreeRTOSTracingDemo\/FreeRTOSTracingDemo.c\">this<\/a>. Build it, and run it under the debugger:<br \/>\n<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/07-built.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8472\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/07-built.png\" alt=\"\" width=\"1141\" height=\"764\" \/><\/a><\/li>\n<li>Connect to the virtual COM port provided by ST-Link using <a href=\"https:\/\/sysprogs.com\/SmarTTY\/\">SmarTTY<\/a> or any other terminal client, and try typing some characters there. You will see the program reply back with the &#8220;You typed&#8221; messages:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/08-running.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8473\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/08-running.png\" alt=\"\" width=\"1141\" height=\"764\" \/><\/a><\/li>\n<li>Now we will use the Live Tracing GUI to record what exactly happens inside the program without interrupting it. Open the <strong>Debug-&gt;Windows-&gt;Live Tracing<\/strong> window, click &#8220;Create a function tracepoint&#8221;, enter &#8220;UART in the filter&#8221;, and press Ctrl-A, &lt;space&gt; to select all of them for tracing: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/09-addmany.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8474\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/09-addmany.png\" alt=\"\" width=\"1141\" height=\"764\" \/><\/a><\/li>\n<li>If you have not created any tracepoints before, VisualGDB will suggest restarting the debug session so that it could reserve memory for the tracepoints. Once this is done, you can add and remove tracepoints during debugging without any further restarts:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/10-restart.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8475\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/10-restart.png\" alt=\"\" width=\"1141\" height=\"764\" \/><\/a><\/li>\n<li>Type something in the terminal window and watch how the <strong>Events<\/strong> view in the Tracepoints window now shows which exact UART-related functions were called. You can navigate between the events in the Tracepoints view to have their locations highlighted in the editor: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/11-events.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8476\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/11-events.png\" alt=\"\" width=\"1141\" height=\"764\" \/><\/a><\/li>\n<li>Locate the <strong>HAL_UART_IRQHandler()<\/strong> tracepoint and switch the <strong>Trace Data<\/strong> view to <strong>Properties<\/strong>. Select to trace the <strong>USART2-&gt;SR<\/strong> register: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/12-sr.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8477\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/12-sr.png\" alt=\"\" width=\"1141\" height=\"764\" \/><\/a><\/li>\n<li>Go to the <strong>HAL_UART_Transmit_IT()<\/strong> tracepoint and start tracing <strong>pData<\/strong> as a dynamic array. Drag <strong>Size<\/strong> into the &#8220;<strong>number of elements<\/strong>&#8221; field:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/13-size.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8478\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/13-size.png\" alt=\"\" width=\"1141\" height=\"764\" \/><\/a><\/li>\n<li>Click &#8220;Apply&#8221; to modify the tracepoints. Now VisualGDB will record the UART flags each time an interrupt happens: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/14-nav1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8479\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/14-nav1.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>Similarly, it will record the exact sent data on each call to <strong>HAL_UART_Transmit_IT()<\/strong>: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/15-data.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8480\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/15-data.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>Select all tracepoints in the Tracepoitns view, right-click and select &#8220;<strong>Export Selected Tracepoints to File<\/strong>&#8220;. Save the tracepoint set somewhere near the project directory: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/16-export.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8482\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/16-export.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a>At the end of the tutorial we will show how to record traces from saved tracepoint sets using command line, so you can easily compare what different versions of the firmware are doing, or how they react to different environments.<\/li>\n<li>Now we will create additional tracepoints to record the queue read\/write operations. First of all, add a tracepoint in <strong>main()<\/strong> just after the queues got created. Select to trace <strong>s_TXQueue<\/strong>, <strong>s_RXQueue<\/strong> and <strong>s_TXReadySemaphore<\/strong>. If you hold <strong>Shift<\/strong> while checking the variables, VisualGDB will trace them in the shallow mode (i.e. will record the pointer value, but not the values of all fields). The <strong>(1\/13)<\/strong> hint next to the variable names will indicate that only 1 out of 13 sub-variables is being recorded:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/17-objects.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8483\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/17-objects.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>Go to the <strong>xQueueReceive()<\/strong> function in FreeRTOS and set a tracepoint to the line that decrements <strong>uxMessagesWaiting<\/strong>. Configure it to trace the pointer value of <strong>xQueue<\/strong> and the <strong>uxMessagesWaiting<\/strong> field: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/18-receive.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8484\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/18-receive.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a>You can rename the newly created tracepoint via the Tracepoints window to see a meaningful name instead of just file:line.<\/li>\n<li>Create a tracepoint in <strong>xQueueGenericSend()<\/strong> and similarly trace <strong>uxMessagesWaiting<\/strong> and the pointer value of <strong>xQueue<\/strong>:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/19-send.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8485\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/19-send.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>VisualGDB will now record the creation of the queues, and each time a queue is being used. To quickly separate events belonging to different queues (<strong>s_RXQueue, s_TXQueue <\/strong>and even <strong>s_TXReadySemaphore<\/strong> that is implemented as a queue), go to the Trace Data window and click &#8220;<strong>Edit quick search indexes<\/strong>&#8220;: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/20-tx.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8486\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/20-tx.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>Drag the <strong>s_RXQueue<\/strong> and <strong>s_TXQueue<\/strong> fields from the initial tracepoint and the <strong>xQueue<\/strong>\/<strong>pxQueue<\/strong> from other tracepoints into the same index. This will mark them as interchangeable, so VisualGDB will know they are related: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/21-queues.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8487\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/21-queues.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>Go to the initial event and click the event symbol near <strong>s_TXQueue<\/strong>: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/22-events.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8488\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/22-events.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>VisualGDB will quickly find all events having the same value of <strong>xQueue<\/strong>\/<strong>pxQueue<\/strong>: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/23-fav.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8489\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/23-fav.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>In order to minimize overhead, live Tracing does not record the call stack, so you cannot quickly see who called the <strong>xQueueGenericSend()<\/strong> function to push the charater into the queue. However, you can dynamically add tracepoints in common locations of your code (e.g. <strong>ProcessingThread()<\/strong>) and trace arbitrary global variables (e.g. current thread pointer): <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/24-newtp.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8490\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/24-newtp.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>Then use the navigation buttons in the <strong>Trace Data<\/strong> window to quickly go to the previous\/next event: <a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/25-nav.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8491\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/25-nav.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>This way you can see that last traced line before the first call to <strong>xQueueGenericSend()<\/strong> was the sprintf() call in <strong>ProcessingThread()<\/strong>:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/26-print.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8492\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/26-print.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>At the end of each tracing session VisualGDB will produce a tracing report containing all recorded data. You can replay old reports at any time via the Profiling\/Tracing Reports window:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/files.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8497\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/files.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>You can also create tracing reports via command line. Modify the <strong>ProcessingThread()<\/strong> function to trigger a breakpoint after 3 iterations:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/28-bkpt.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-8494\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2023\/10\/28-bkpt.png\" alt=\"\" width=\"1258\" height=\"837\" \/><\/a><\/li>\n<li>Then build the project and run the following command line from the project directory:\n<pre class=\"\">\"%VISUALGDB_DIR%\\VisualGDB.exe\" \/trace FreeRTOSTracingDemo.vgdbcmake \/traceconfig:TracepointSets\\UARTFunctions.xml \/tracereport:UARTFunctions.vgdbtrace \/xmltracereport:UARTFunctions.xml \/targetpath:build\\VisualGDB\\Debug\\FreeRTOSTracingDemo<\/pre>\n<p>VisualGDB will create 2 reports: a <strong>UARTFunctions.vgdbtrace<\/strong> report that can be opened in <strong>Visual Studio<\/strong> and replayed, and <a href=\"https:\/\/github.com\/sysprogs\/tutorials\/blob\/master\/visualgdb\/tracing\/FreeRTOSTracingDemo\/UARTFunctions.xml\"><strong>UARTFunctions.xml<\/strong><\/a> report that can be analyzed programmatically.<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to use the VisualGDB&#8217;s Live Tracing feature to record the flow of a simple 2-thread program<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[247],"tags":[53,248,204,61],"_links":{"self":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/8464"}],"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=8464"}],"version-history":[{"count":4,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/8464\/revisions"}],"predecessor-version":[{"id":8503,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/8464\/revisions\/8503"}],"wp:attachment":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/media?parent=8464"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/categories?post=8464"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/tags?post=8464"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}