http://www.percepio.com/

Recording Traces

Introduction

Tracealyzer for ThreadX relies on the standard event tracing in ThreadX, available since 2005. This monitors not only the ThreadX kernel, but also the NetX, UsbX and FileX stacks. All such events can be analyzed with Tracealyzer for ThreadX, as well as "user events" that allow for custom logging in the system.

Enabling Trace

To include event tracing in your build, define the ThreadX configuration option TX_ENABLE_EVENT_TRACE in tx_user.h or in the project build options.

Next step is to enable the tracing by calling tx_trace_enable:

UINT tx_trace_enable(VOID* trace_buffer_start, ULONG trace_buffer_size, ULONG registry_entries)

Where the parameters are:

  • trace_buffer_start: Pointer to a buffer for the recorded events, allocated by the user.
  • trace_buffer_size: The size of the buffer, in bytes.
  • registry_entries: The number of ThreadX objects to keep in the trace registry. This allows for displaying objects names, instead of just addresses.

Example:

#define TRC_BUF_SIZE (500*32)  /* Buffer size 500 events */
#define TRC_MAX_OBJ_COUNT (40) /* Max number of ThreadX objects */
...
UCHAR myBuf[TRC_BUF_SIZE];
...
status = tx_trace_enable(&myBuf, TRC_BUF_SIZE, TRC_MAX_OBJ_COUNT);

Possible return values from tx_trace_enable are:

  • TX_SUCCESS (0x00): Tracing was enabled correctly.
  • TX_SIZE_ERROR (0x05): The provided buffer was too small.
  • TX_NOT_DONE (0x20): Returned if tx_trace_enable has already been called.
  • TX_FEATURE_NOT_ENABLED (0xFF): Returned if event tracing is not enabled in the build (see TX_ENABLE_EVENT_TRACE above).

Assuming that trx_trace_enable return TX_SUCCESS, the event tracing is now active. The event data can be extracted from target RAM whenever suitable.

Enabling Trace, Renesas Synergy

Use the Renesas Synergy configuration tool (SSC) to enable event tracing. Under the "Threads" tab, click on "HAL/Common" and look for "ThreadX Source" in the "HAL/Common Stacks" view. If not available, add it using the "+" button and select Framework -> RTOS -> ThreadX Source.

Click on "ThreadX Source" and check the Properties window. A bit down the list, you will the "Event Trace" property that enables tracing, along with a few other trace-related settings.

When "Event Trace" has been set to "Enabled", this causes the Synergy startup code (tx_application_define) to call tx_trace_enable and thereby enable the tracing.

In this case, there is no need to call tx_trace_enable from your own application code. But it is no problem if you accidentally do, as repeated calls to tx_trace_enable are detected and ignored.

Saving the trace

To view the trace in Tracealyzer, you need to save a binary dump of the trace buffer (the one specified for tx_trace_enable) to a host-side file named "something.trx", that you open in Tracealyzer. The data should be in binary or Intel Hex format.

You can easily configure IAR Embedded Workbench and e2 studio to save the trace and also open it in Tracealyzer, as described below. Similar integrations are also possible using other IDEs.

If using Renesas Synergy, the default name of the trace buffer is g_tx_trace_buffer and the default size is 65536 bytes. This can be changed in the SSC tool, as described in Enabling Trace, Renesas Synergy.

Using IAR Embedded Workbench

The IAR debugger can be configured to save the trace buffer to a host-side file, either manually or automatically, using a debugger macro. Follow these steps:

  1. Create a macro file in the project directory (e.g. "save_trace_buffer.mac") with the following contents:
    __var start;
    __var size;
    
    save_trace_buffer()
    {
      start = __smessage "Memory:0x",&g_tx_trace_buffer:%x;
      end  =  __smessage "Memory:0x",(g_tx_trace_buffer + sizeof(g_tx_trace_buffer)-1):%x;
      __memorySave(start,end,"intel-extended", "$PROJ_DIR$\\trace.trx");
      
      return 0;
    }
    

    Make sure that the buffer name is the same as specified for tx_trace_enable(). If using Renesas Synergy, the default name is "g_tx_trace_buffer".
  2. Add the macro file under Options -> Debugger -> Use Macro File(s).
  3. When in a debug session, open View -> Macros -> Debugger Macros and check that "save_trace_buffer" is included.
  4. Now, to call the macro and thereby save the trace, you have three options:
    • Manually: In the Debugger Macros view, right-click on you macro and select "Add to Quicklaunch window". Now you can save the trace by double-clicking on the blue "refresh" icon in the Quicklaunch window.
    • On a breakpoint: Place a breakpoint on a suitable location in the code. Open it in the breakpoint editor and enter your macro name (e.g., "save_trace_buffer()") in the Action -> Expression field. The trace is now saved every time that breakpoint is hit.
    • On every halt: To update the trace on every halt, rename the "save_trace_buffer" function to execUserExecutionStopped(). That is a special hook that is called every time the execution is halted. Note that this can slow down single-stepping if the buffer is large.

To enable quick access to Tracealyzer and the current trace, you may include Tracealyzer in the Tools menu, with "trace.trx" specified as parameter.

  1. Select "Configure Tools..." in the Tools menu
  2. Add a new entry "Tracealyzer"
  3. Set the path to the Tracealyzer executable (the ".exe" file).
  4. Set the argument to "$PROJ_DIR$\trace.trx"
This will open Tracealyzer and load the provided trace file.

Using e2 studio

Tracealyzer can utilize the same e2 studio integration as the older tool TraceX, from Express Logic.

To configure e2 studio to use Tracealyzer as trace viewer, go to Window -> Preferences -> Renesas -> TraceX, and enter the path to Tracealyzer instead of TraceX. The path is normally:

C:\Program Files (x86)\Percepio\Tracealyzer for ThreadX\TzForThreadX.exe

Then, to upload the trace from e2 studio, select Run -> TraceX -> Launch TraceX Debugging. Enter the address of the trace buffer (e.g. "&g_tx_trace_buffer") and the size ("sizeof(g_tx_trace_buffer)"). Click OK. Now e2 studio will save the trace buffer into a file and open it with Tracealyzer.

Timestamping

The ThreadX recorder assigns a high-resolution timestamp to each event, but it does not report the "timestamp frequency", i.e., the clock frequency of the time source. So, to get an accurate time scale in Tracealyzer, you need to specify the timestamp frequency in File -> Settings -> Timestamp Frequency.

This setting should reflect how frequently the time source is updated. Depending on your ThreadX port, the timestamp frequency is often the processor's core clock frequency. For instance, if using a Renesas Synergy S7G2 processor at 240 Mhz, you should enter 240000000. After updating the timestamp frequency, you need to reload the trace for the setting to take effect.

Custom Timestamping
The ThreadX timestamping is defined by these two macros in tx_port.h. In case you want to use a custom time source for the tracing, you can overriding these definitions, e.g., in tx_user.h.

  • TX_TRACE_TIME_SOURCE: How to read the current time (i.e., the time source).
  • TX_TRACE_TIME_MASK: A bit mask applied to the timestamp (e.g., 0x00FFFFFFUL for a 24-bit timer).

User Events

The ThreadX trace library allows for inserting your own custom events, or User Events, by calling tx_trace_user_event_insert.

UINT tx_trace_user_event_insert(ULONG event_id, ULONG info_field_1, 
                                                ULONG info_field_2,
                                                ULONG info_field_3, 
                                                ULONG info_field_4)

The parameter event_id is a numeric code that you assign as a unique identifier for this event, in the range TX_TRACE_USER_EVENT_START (4096) to TX_TRACE_USER_EVENT_END (65535). The "info_field" parameters allow for logging up to four 32-bit integer values in a single timestamped event.

User Event are saved quickly and can usually be used also in time-critical code without adding significant overhead. If taking ARM Cortex-M MCUs as example, a User Event takes about 100-200 clock cycles depending on compiler and optimization level. That is often less than 1 microsecond.

Possible return values from tx_trace_user_event_insert are:

  • TX_SUCCESS (0x00): The user event was logged correctly.
  • TX_NOT_DONE (0x20): If the tracing has not been enabled (tx_trace_enable not called).
  • TX_FEATURE_NOT_ENABLED (0xFF): Returned if event tracing is not enabled in the build (see TX_ENABLE_EVENT_TRACE above).

User Events can be used to trace and visualize any event or data in your firmware, in several different ways as described in the User Events section.

ISR tracing

To trace Interrupt Service Routines, you need to add calls to tx_trace_isr_enter_insert and tx_trace_isr_exit_insert in each handler function you wish to trace.

VOID tx_trace_isr_enter_insert(ULONG isr_id)

Call tx_trace_isr_enter_insert in the very beginning of the ISRs you want to trace.

VOID tx_trace_isr_exit_insert(ULONG isr_id)

Each call to "isr_enter" call should have a matching "isr_exit" call, in the very end of the traced ISR.

The parameter isr_id is the identifier displayed in Tracealyzer. For instance, if isr_id is 1, Tracealyzer will label this execution as "ISR1".


Copyright Percepio AB 2017, all rights reserved.