To record traces from a FreeRTOS system, you need to integrate the Percepio trace recorder library in your application project. This library is provided in C source code, found in the Tracealyzer installation directory. If using Windows, this is typically found in C:\Program Files\Percepio\Tracealyzer 4\FreeRTOS\TraceRecorder.

Tracealyzer Trace Recorder Library

FreeRTOS Logo

The trace recorder library relies on the “trace hook macros” in the FreeRTOS kernel, such as traceTASK_SWITCHED_IN.

The FreeRTOS kernel contains over 100 such trace hooks at strategic locations, but they are inactive by default.

When integrating the trace recorder library as described below, the trace hooks are redefined to call the trace recorder library. This way, internal FreeRTOS events and calls to FreeRTOS API functions are traced automatically. You may also add you own events (“User Events” and ISR events) by adding direct calls to the recorder library in your application code, as described in the end of this guide.

This quick start guide is divided into two parts:

If not using a J-Link, check these guides for IAR Embedded Workbench, Keil µVision or the built-in support for ST-Link. Other setups for streaming are also possible.

If you encounter any difficulties, please refer to the Troubleshooting section in the end.

1. Enabling Snapshot Trace

Follow the steps below to integrate the trace recorder in an existing project, using snapshot mode with default settings.

Step 1.1. Add these source files to your project.

  • trcKernelPort.c
  • trcSnapshotRecorder.c
  • trcStreamingRecorder.c

Step 1.2. Copy all .h files from the config and include folders into a suitable folder, e.g. together with your other header files.

Step 1.3. Open trcConfig.h and check the following:

  • Replace the #error line with an #include of the processor header file (e.g. #include “stm32f4xx.h”).
  • Set TRC_CFG_HARDWARE_PORT to match your processor family.
    • If using an Arm Cortex-M device, use TRC_HARDWARE_PORT_ARM_Cortex_M.
    • All available ports are listed in trcHardwarePort.h.
  • Make sure that TRC_CFG_FREERTOS_VERSION matches your version of FreeRTOS.

Step 1.4. Open trcSnapshotConfig.h and make sure that the settings TRC_CFG_NTASK, TRC_CFG_NQUEUE etc. are large enough to accommodate the number of tasks, queues, semaphores etc. in your system. If not sure, use large values. You can optimize these settings later, once a trace has been recorded.

Step 1.5. Open FreeRTOSConfig.h and make sure you have the following lines included:

  • #define configUSE_TRACE_FACILITY 1
  • #include "trcRecorder.h" /* Should be in the end, after the #define. */

If using IAR or MPLAB X IDE, you need to use a conditional include like shown below.

/* If using IAR Embedded Workbench */

#ifndef __IASMARM__
#include "trcRecorder.h"
#endif
/* If using Microchip MPLAB X IDE */

#ifndef __LANGUAGE_ASSEMBLY
#include "trcRecorder.h"       
#endif

If using Xilinx SDK, you need to edit the FreeRTOSConfig.h file found in the libsrc folder, e.g. bsp/ps7_cortexa9_0/libsrc/freertos823_xilinx_v1_3/src/FreeRTOSConfig.h. Do not edit the FreeRTOSConfig.h found in the include folder, as this will be overwritten by the libsrc version during the BSP code generation.

Step 1.6. Initialize and start the trace recorder library by calling vTraceEnable(TRC_START).

This should be placed after the initial hardware setup, but before any FreeRTOS calls have been made (like xTaskCreate).

Step 1.7. Test it. Build the project, let the system run for a while, then halt the execution.

When halted, you can upload the trace data from the target system RAM to a host-side file, which is then opened in Tracealyzer. This can be automated in several ways, depending on your debugging tools. Please refer to the tool-specific documentation below.

Also see this section in the User Manual for additional options and more detailed instructions.

2. Enabling Streaming Trace

Using streaming trace allows for recording much longer traces, of several minutes or even hours. This requires a relatively fast connection between target and host, such as a premium debug probe or a network connection. The below guide describes the most common solution for streaming on Arm Cortex-M devices, using a SEGGER J-Link debug probe.

If not using a J-Link, check these guides for IAR Embedded Workbench, Keil µVision or the built-in support for ST-Link. Other setups for streaming are also possible.

Streaming using SEGGER J-Link

Step 2.1. Make sure you have followed the guide for snapshot tracing. Step 1.7 can however be omitted if you are only interested in streaming.

Step 2.2: Open trcConfig.h and set TRC_CFG_RECORDER_MODE to TRC_RECORDER_MODE_STREAMING.

Step 2.3. Copy all code found in /streamports/Jlink_RTT/ and /streamports/Jlink_RTT/include into your project.

Step 2.4. In your vTraceEnable call, make sure to use the parameter TRC_INIT.

Step 2.5. Start Tracealyzer and open File -> Settings -> PSF Streaming Settings and select Target Connection: SEGGER RTT. Also make sure you have the following settings (these are the defaults):

  • Target Connection: SEGGER RTT
  • RTT Control Block Address: auto-detect (= 0)
  • Target RTT Up Buffer Index: 1
  • Target RTT Down Buffer Index: 1
  • Reset Target on Connect: Not checked
  • Target Starts Tracing: Not checked

 

Step 2.6. Open File -> Settings -> J-Link Settings, and click Select Device, i.e. the processor you are using.

If your device is not listed in the J-Link Settings, download and install the latest J-Link driver.

 

Step 2.7. Start your target system, then click on “Record Streaming Trace” on the welcome screen, or “Start Recording” in the Tracealyzer navigation bar.

You should now see a live trace of your system in Tracealyzer, like this.

Adding User Events

To get more information from your application, such as variable values and debug messages, you can generate User Events that are displayed in Tracealyzer. They appear as yellow labels in the trace view.

To generate a User Event, you first register a User Event Channel using xTraceRegisterString(). This channel is used to group related events, and sets a name for this channel. You can have multiple such channels in parallel.

Then call vTracePrint() or vTracePrintF(), using the handle from xTraceRegisterString() as first parameter.

The syntax is similar to the classic “printf”, although not every format specifier is supported.

Example:

traceString chn = xTraceRegisterString("MyChannel"); 
... 
vTracePrint(chn, "Hello World!"); 
vTracePrintF(chn, "Value: %d", myValue);

Tracing Interrupt Handlers

To trace interrupt handlers, first call xTraceSetISRProperties() to specify the interrupt name and priority. This is typically done in your main function, not in the interrupt handler. This returns a handle, that you need to store in a global variable.

Then call vTraceStoreISRBegin() in the beginning of your handler, and vTraceStoreISREnd() in the end.

Example:

#define PRIO_ISR_TIMER1 3 /* the hardware priority level */ 
... 
traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1); 
... 
void ISR_handler(void)
{ 
    signed BaseType_t xHigherPriorityTaskWoken;
    vTraceStoreISRBegin(Timer1Handle); 

    /* Wakes up a pending task, causing a task-switch. */
    xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken); 

    vTraceStoreISREnd(xHigherPriorityTaskWoken); 
}

Troubleshooting

In case you have issues related to J-Link streaming, see our specific guide about Troubleshooting J-Link RTT Streaming.

For other issues, check the Troubleshooting section in the User Manual.

If you have any questions, feel free to contact us at support@percepio.com.

Learning More

Make sure to check out our RTOS Debug Portal, with many articles and hands-on examples.

To purchase Tracealyzer, see the Licensing page.