http://www.percepio.com

Trace Recorder Library

Introduction

The trace recorder library is the embedded runtime component of Tracealyzer for FreeRTOS. The recorder is integrated in FreeRTOS and stores the event data in a RAM buffer for transfer to the development PC. Two alternative recorder implementations are provided, described below.

The streaming recorder is our latest and greatest solution. It allows for traces of unlimited length by streaming the data to the development PC. The data transfer can be channeled via SEGGER J-Link debug probes, TCP/IP, or any custom channel of your choice, for instance a device file system.

The snapshot recorder keeps the trace data in RAM and allows you to take a snapshot at any point, simply by making a RAM dump. This can be used as "black-box" on deployed systems, or as an alternative to streaming if no suitable transfer interface is available in your system.

Both are provided in C source code and found in the Tracealyzer for FreeRTOS installation directory (see "Trace Recorder Library" directory) as compressed files. The two recorders are quite similar with respect to source code structure, interface and integration, but they are not identical.

Streaming Recorder

When using the streaming recorder the data is continuously transferred to the host PC. The data is initially stored in a RAM buffer, which is periodically flushed to the transfer interface, that transfers the data to the host PC. The streaming recorder has explicit support for SEGGER J-Link debug probes, and also for network streaming via TCP/IP. However, you may configure the streaming recorder to use any data channel of your choice, if you have some way of receiving the data and writing it to a file.

The trace recorder library is provided in C source code, found in the Tracealyzer for FreeRTOS installation directory. The user API has less than 10 functions (well documented), of which only one is required to use the recorder (Trace_Init()). The whole recorder code compiles to just 3-5 KB of object code on ARM Cortex-M4 MCUs, depending on compiler and optimization level.

The streaming method is selected by TRC_RECORDER_TRANSFER_METHOD in trcConfig.h:

  • TRC_RECORDER_TRANSFER_METHOD_JLINK_RTT_BLOCK: J-Link streaming, blocking if the RAM buffer becomes full.
  • TRC_RECORDER_TRANSFER_METHOD_JLINK_RTT_NOBLOCK: Non-blocking J-Link streaming. Data will be lost if the RAM buffer gets full.
  • TRC_RECORDER_TRANSFER_METHOD_TCPIP: Transfers using TCP/IP as defined by trcTCPIP.c.
  • TRC_RECORDER_TRANSFER_METHOD_CUSTOM: Custom data transfer using the TRC_STREAM_CUSTOM macros.

SEGGER J-Link Streaming

If using this approach, the trace data is streamed from target to host via a SEGGER J-Link or J-Trace debug probe. This uses SEGGER's Real-Time Transfer (RTT) function, that works on all ARM Cortex-M MCUs and all Renesas RX MCUs. With a sufficient RAM buffer size, this allows for streaming the trace data at speeds upwards 700 KB/s on a standard J-Link (Version 9) and 2-3 times that on the high-end models. It works even on the J-Link On Board (OB), found integrated on many development boards, although these have lower (but still good) performance.

SEGGER RTT is based on RAM buffers in the target system, which the J-Link accesses in the background without disturbing the target system. The Tracealyzer for FreeRTOS recorder uses two RTT buffers, one control channel for receiving commands from Tracealyzer for FreeRTOS and a data channel for streaming the trace. SEGGER RTT is already integrated in the trace recorder library and is configured in SEGGER_RTT_Conf.h and trcConfig.h.

The control channel is only used when starting or stopping the trace recorder, and only requires a small RTT buffer of 32 bytes.

The trace upload channel needs a bit larger RTT buffer. We recommend a buffer size of 1024 byte if available, otherwise 512 byte (or even less) is often sufficient. The J-Link pulls out the buffer data periodically, but if the buffer is too small, it will become full between the J-Link reads. The behavior when the buffer gets full depends on the transfer method (TRC_RECORDER_TRANSFER_METHOD) in trcConfig.h:

  • TRC_RECORDER_TRANSFER_METHOD_JLINK_RTT_BLOCK: The recorder blocks (stalls) the system until there is room in the RTT buffer. Such blocking can be several milliseconds in bad cases. If this occurs, Tracealyzer for FreeRTOS generates warning events in the main trace view (you may need to enable them in the "View Filter").
  • TRC_RECORDER_TRANSFER_METHOD_JLINK_RTT_NOBLOCK: Events are dropped if the RTT buffer is full. This avoid blocking on occasional peaks in the data rate, but the display in Tracealyzer for FreeRTOS may then be inaccurate. If events are dropped, Tracealyzer for FreeRTOS visualizes the intervals of dropped events with a light red background color in the main trace view.

If there would be recorder blocking or dropped trace events, try the following:

  • Verify the J-Link Speed in the Settings dialog of Tracealyzer for FreeRTOS. Default is 4 MHz, but can be increased a lot depending on your J-Link model (typically at least 10 MHz).
  • Increase the trace buffer size (SEGGER_RTT_Conf.h).
  • Reduce the amount of data produced, e.g., by excluding frequent User Events.

Note: If you set the J-Link Speed higher than the maximum supported speed, the J-Link driver will instead use the highest speed supported. The actual speed used is shown in the title bar of the Target Connection window. The RTT transfer may become unstable and drop packets if very high speeds are selected.

Before making your first trace recording, check J-Link Settings and Streaming Trace Settings, found under File -> Settings... in Tracealyzer for FreeRTOS.

  • Debugger: Select the connected debugger to use for RTT Streaming.
  • J-Link Speed: The debugger speed (JTAG/SWD) in kHz.
  • Debugger Interface: The debugger interface to use.
  • Debugger Interface:
    • JTAG: Configures the debug probe for JTAG. This is the default setting of J-Link debug probes.
    • SWD: Configures the debug probe for SWD.
    • Default (don't change): With this setting, Tracealyzer for FreeRTOS does not change the JTAG/SWD setting of the debug probe.
  • Target Device: Opens a SEGGER J-Link dialog to allow selecting device (processor). This is necessary in order for SEGGER RTT to work properly.

  • Target Connection: Should be "SEGGER RTT".
  • RTT Up Buffer Index: The RTT buffer to use for the trace data channel (target -> host). Should match the setting in trcConfig.h.
  • RTT Down Buffer Index: The RTT buffer to use for the control channel (host -> target). Should match the setting in trcConfig.h.

All tools using the J-Link driver (i.e., Tracealyzer for FreeRTOS and the debugger IDE) must use the same setting for Debugger Interface (JTAG/SWD). If using the "Default" setting for Debugger Interface, the J-Link debugger will use JTAG by default until the J-Link driver is told otherwise, e.g., by the debugger IDE.

A higher J-Link Speed gives better streaming performance, i.e., lower risk of blocking or lost data. In many cases speeds of 10-20 MHz is possible, but according to SEGGER there is a small risk of getting poor signal quality (i.e., problems) if going above 6 MHz, depending on the development board. Default is therefore set to 4 MHz. However, we recommend that you try higher speeds, 10 MHz or higher. Don't worry, nothing will break and any corrupted data will most likely manifest directly as error messages when processing the trace.

Network Streaming (TCP/IP)

To stream the trace data over a network connection, i.e., TCP/IP transfer, select TRC_RECORDER_TRANSFER_METHOD_TCPIP in trcConfig.h. The TCP/IP support also needs to be configured for the available TCP/IP stack. To do this, modify the functions stubs in trcTCPIPConfig.h.

In TCP/IP mode, the streaming recorder stores the event data in a multi-page RAM buffer. Once a page is full, the recorder switches to a new page and the full page is sent over the network connection. This separate RAM buffer is needed since a TCP/IP stack often can't be called directly from the kernel instrumentation code, as this might cause infinite recursive calls.

On the applicataion side, check the Streaming Trace Settings, found under File -> Settings... in Tracealyzer for FreeRTOS.

  • Target Connection: Should be "TCP".
  • TCP/IP Address: The IP address of your target system.
  • Port: The port used by target-side TCP/IP socket that you have created for the recorder.

Custom Streaming

You may configure the streaming recorder to use any data channel of your choice, if you have some way of receiving the data and writing it to a file. For instance, you may use a fast serial connection (over USB). Or if you have permanent storage on your target system, e.g., a memory card, you can stream to a local file.

To setup a custom transfer method, select TRC_RECORDER_TRANSFER_METHOD_CUSTOM in trcConfig.h and define your transfer interface using the TRC_STREAM_CUSTOM macros. For examples on how to implement custom trace streaming, please refer to trcStreamPort.h.

In some cases, custom streaming needs to use our multi-page RAM buffer (trcPagedEventBuffer.c). The data is then read by a periodic task (TzCtrl) and written to the specified interface. It is however possible to omit the multi-page buffer and instead write directly to the transfer channel, if (1) the channel is a dedicated for this purpose and if (2) the writes do not generate any kernel events, e.g., from Mutex or Semaphore operations.

The trace data is a binary format and should be stored in raw format. Name the output file ".psf" to make it easier to find in Tracealyzer. The required channel throughput depends on your application, but typically you need something like 20-200 KB/s, the faster the better.

Connecting and Recording

To connect to the target system, select "Connect to Target System..." in the File menu. This opens the Target Connection dialog, which directly establishes a connection with the target. You may connect while the target is running (with or without a debugger IDE) and, in the case of SEGGER RTT, also if halted, e.g. on a breakpoint. Do not try to connect while a debugger session is being initialized, i.e., during programming of the device, wait until the debugger IDE is ready.

Recording a Trace

The Target Connection dialog contains four buttons (explained below) and a "live", animated graph showing the target CPU usage profile while recording.

The blue line shows the CPU usage of the application tasks, i.e., the relative number of clock cycles used, excluding the idle task. If you enable tracing of Interrupt Service Routines (i.e., ISRs), a red line is also displayed showing the CPU usage of the traced ISRs.

Note
Tasks and kernel calls are traced automatically. To trace ISRs, you need to call vTraceStoreISRBegin() in the beginning of the interrupt handler and vTraceStoreISREnd() when returning from it. See trcRecorder.h for further details.

Note
If using Tracealyzer for FreeRTOS in parallel with a debugger IDE, the recording must not be active while launching a new debug session, otherwise you may get junk data on the RTT trace channel when the device is programmed.

Connection Issues

The first time you try to connect over SEGGER RTT you may be presented with a dialog where you should specify your device. This is required for Tracealyzer for FreeRTOS to locate the RAM address range(s) and find the RTT data structure. You can also access this dialog via File -> Settings... -> J-Link Settings -> Select Device....

When using the Debugger Interface setting "Default (don't change)" and the J-Link has just been powered up, the following issue may occur when starting a parallel debug session. If opening the Tracealyzer for FreeRTOS Target Connection before the debugger session is launched, the Tracealyzer for FreeRTOS J-Link connection will use the default mode, JTAG. When then launching a debug session using SWD mode, the J-Link driver will get conflicting settings. In that case, the J-Link driver will ask what to do, as illustrated below.

In this case, click YES to make sure that the debugger IDE works as expected, and after that close and re-open the Target Connection dialog to establish a new connection in SWD mode.

Using the Streaming Recorder

The trace recorder library is implemented in C and provided with full source code. In the current version (v3.0.7), the recorder can only be started and stopped from the host-side application, which sends commands to the trace control task (TzCtrl). We plan to change this soon, to allow the target application to control the recording.

To integrate the recorder in an existing project, we recommend the following steps:

  1. Locate the streaming recorder library, found as a zip file in Help -> Trace Recorder Library. Extract the recorder source code to a suitable directory in your target code repository.
  2. Add trcRecorder.c and trcKernelPort.c to your build.
  3. Depending on the streaming type, you also need these .c files:
    • J-Link streaming: Include SEGGER_RTT.c.
    • Network (TCP/IP) streaming: Include trcTCPIP.c and trcPagedEventBuffer.c.
    • Custom streaming: You probably need trcPagedEventBuffer.c.
  4. Make sure the recorder header files are found by the compiler by updating the "include" path.
  5. In your FreeRTOSConfig.h, make sure you have the following setting:
    #define configUSE_TRACE_FACILITY 1
  6. Add the following line in the very end of your FreeRTOSConfig.h:
    #include "trcKernelPort.h"
  7. Add a call to Trace_Init() in your main function, before the FreeRTOS scheduler is started and any tasks and objects are created.
  8. Verify the settings in these header files, when relevant:
    • trcConfig.h: Main recorder settings. Always make sure these settings are suitable for your project.
    • SEGGER_RTT_Conf.h: Settings for SEGGER J-Link streaming.
    • trcTCPIPConfig.h: The TCP/IP interface (function stubs) if trcTCPIP.c is included. This needs to be modified for the specific TCP/IP stack.
    • trcPagedEventBufferConfig.h: Settings for the paged event buffer, used for TCP/IP streaming and in custom streaming setups.

Note
The ARM Cortex-M ports uses ARM's CMSIS library to access the PRIMASK register. If you get compilation errors related to PRIMASK functions, trcConfig.h needs to include your board support header (e.g., "lpc17xx.h", "stm32f4xx.h", "board.h", etc), which in turn typically includes CMSIS. We recommend that you put this #include statement right after the definition of SELECTED_PORT.

Note
When including trcKernelPort.h in FreeRTOSConfig.h, some development environments require you to use a conditional include to exclude it from the assembler's processing of FreeRTOSConfig.h.

For instance, if using IAR Embedded Workbench for ARM:
							  #ifdef __ICCARM__
							  #include "trcKernelPort.h"
							  #endif
						  

Public Interface

void Trace_Init(void)

The main initialization routine for the trace recorder. This is the only function that is required for basic use of the recorder. This initializes the selected trace transfer method and creates the TzCtrl task that listens for start and stop commands from the host application.

void vTracePrintF(const char* chn, const char* fmt, ...)

Parameter chn: User Event Channel (can be NULL)
Parameter fmt: Format string
Parameter ...: 0 - 15 data arguments (32-bit integers or char*)

Generates "User Events", with formatted text and data, similar to a "printf". It is very fast since the actual formatting is done on the host side when the trace is displayed in Tracealyzer for FreeRTOS.

User Events can be used for very efficient application logging, and are shown as yellow labels in the main trace view of Tracealyzer for FreeRTOS. An advantage of User Events is that data can be plotted in the "User Event Signal Plot" view, visualizing any data you log as User Events, discrete states or control system signals (e.g. system inputs or outputs).

You may group User Events into User Event Channels. The yellow User Event labels show the logged string, preceeded by the channel name within brackets. For example:

"[MyChannel] Hello World!"
The User Event Channels are shown in the View Filter, which makes it easy to select what User Events you wish to display. User Event Channels are created using vTraceStoreUserEventChannelName().

char* vTraceStoreUserEventChannelName(const char* name)

Parameter name: the channel name to store (const string literal)

Stores a name for a user event channel, returns the handle (just a pointer to the provided string). Typically assigned to a "channel" variable that keeps it for later calls to vTracePrintF();

void vTraceStoreKernelObjectName(void* object, const char* name)

Parameter object: pointer to the kernel object that shall be named.
Parameter name: the name to store (const string literal).

Stores a name for a kernel objects (Task, Semaphore, Mailbox, etc.) for display in Tracealyzer for FreeRTOS.

void vTraceSetISRProperties(const char* name, char priority)

Parameter name: the name to give the the ISR, also serves as handle.
Parameter priority: the priority level of the ISR.

Stores a name and priority level for an Interrupt Service Routine, to allow for better visualization. The string address is used as a unique handle.

void vTraceStoreISRBegin(void* handle)

Parameter handle: ID of the ISR, which is "name" in vTraceSetISRProperties.

Registers the beginning of an Interrupt Service Routine (ISR). Must have a matching call to TraceStoreISREnd().

void vTraceStoreISREnd()

Used in combination with vTraceStoreISRBegin, to store the end of an Interrupt Service Routine. Will attempt to automatically detect any task switches caused by this Interrupt Service Routine. Not available for all kernels!

void vTraceStoreISREndManual(int taskSwitchRequested)

Parameter taskSwitchRequested: Manually tells if the interrupt has requested a task-switch (= 1) or if the interrupt returns to the earlier context (= 0)

Used in combination with vTraceStoreISRBegin, to store the end of an Interrupt Service Routine.

void vTraceInstanceFinishedNow(void)

Marks the current "task instance" (task loop iteration) as finished at this very instant. This is just for the Tracealyzer for FreeRTOS analysis. This causes Tracealyzer for FreeRTOS to split the current fragment at this point and begin a new "actor instance", even if no task-switch has occurred.

void vTraceInstanceFinishedNext(void)

Marks the current "task instance" (task loop iteration) as finished on the next kernel call. If that kernel call is blocking, the instance ends after the blocking event. If the kernel call is not blocking, the viewer instead splits the current fragment right before the entry of the kernel call.

Snapshot Recorder

When streaming trace is not suitable or possible, the Snapshot Recorder allows you to keep a small trace in RAM. This recorder is very memory efficient and often uses only four bytes per event, in some cases more. The trace data is typically uploaded to your host PC by taking a RAM dump using your debugger. This is a very common feature available in most debuggers, and usually called "Save Memory" or similar. Tracealyzer for FreeRTOS can open trace data files in binary format (.bin) and in Intel Hex format (.hex). The RAM dump does not need to match the exact location of the trace data, as long as the recorder data is included somewhere in the RAM dump. Tracealyzer for FreeRTOS locates the data automatically due to a special numeric signature found in the beginning and end of the trace data.

The snapshot recorder has two modes of operation:

  • Stop-when-full mode
  • Ring-buffer mode
The stop-when-full mode stops the recorder when the buffer gets full. This is suitable when you want to capture the events following a particular point in your code, where you call uiTraceStart() to start the recorder. The ring-buffer mode allows you to use the recorder as a "black-box", as it overwrites the oldest events with new events and thereby always keeps the latest history.

The recorder library has several settings which you should inspect before using it, such as the two modes described above. The settings are found in the header file trcConfig.h, together with detailed documentation.

By default, all events are stored in the same buffer. User events, which are generated by the application, can however be stored in a separate buffer by enabling USE_SEPARATE_USER_EVENT_BUFFER in trcConfig.h. This allows for a longer history of less frequent but important user events, since they are not overwritten by kernel events. The size of the separated user event buffer is defined by the macro USER_EVENT_BUFFER_SIZE, also in trcConfig.h.

Note
If using USE_SEPARATE_USER_EVENT_BUFFER, you may get an artificial task instance in the beginning of the trace, named "Unknown Actor". This is added as a placeholder for user events when there is a longer history of user events than there is for kernel events, such as task scheduling.

For further information about the recorder library, see trcUser.h (and trcUser.c, if you want to study the detailed implementation).

Integrating the Snapshot Recorder

To integrate the recorder trace library in an existing FreeRTOS project, the following steps are suggested:

  1. Check that your FreeRTOS version is v7.3 or later.
  2. Locate the Snapshot recorder library package via the Help menu in Tracealyzer and extract its contents.
  3. Add the .c files from GenericRecorderLibSrc in your build project.
  4. Add GenericRecorderLibSrc/Include to your compiler's include path (i.e., in the project settings).
  5. Copy GenericRecorderLibSrc/ConfigurationTemplate/trcConfig.h to GenericRecorderLibSrc/Include.
  6. Open trcConfig.h and...
    • Set SELECTED_PORT to match your target processor.
    • Verify that the FREERTOS_VERSION setting matches your version of FreeRTOS.
    • Check the N[Type] settings (e.g., NTask, NQueue, etc.). They define the maximum allowed number of simultaneously active objects, i.e., objects that have been created by not deleted.
    • Check the other settings, especially TRACE_RECORDER_STORE_MODE and EVENT_BUFFER_SIZE. You don't need to change them, but we recommend you have a look.
  7. In your FreeRTOSConfig.h, make sure you have the following setting.
    #define configUSE_TRACE_FACILITY 1
  8. Add the following line in the very end of your FreeRTOSConfig.h
    #include "trcKernelPort.h"
  9. In your main() routine, call vTraceInitTraceData() as early as possible. It must be placed before any other calls to the recorder or FreeRTOS.
  10. Call uiTraceStart() at the point you wish to begin recording, in the startup or at some later point in the application code. Remember to check the return value. A value of 1 indicates that the recorder configuration was OK. Otherwise an error message is found in RecorderDataPtr->systemInfo.
For further information about the recorder library, see trcUser.h.

Note
The ARM Cortex-M ports uses ARM's CMSIS library to access the PRIMASK register. If you get compilation errors related to PRIMASK functions, trcConfig.h needs to include your board support header (e.g., "lpc17xx.h", "stm32f4xx.h", "board.h", etc), which in turn typically includes CMSIS. We recommend that you put this #include statement right after the definition of SELECTED_PORT.

Note
When including trcKernelPort.h in FreeRTOSConfig.h, some development environments require you to use a conditional include to exclude it from the assembler's processing of FreeRTOSConfig.h.

If using IAR Embedded Workbench for ARM:
							  #ifdef __ICCARM__
							  #include "trcKernelPort.h"
							  #endif
						  
If using MPLAB X IDE:
							  #ifndef __LANGUAGE_ASSEMBLY
							  #include "trcKernelPort.h"
							  #endif
						  

Making a snapshot

This section describes how to upload the trace data from the target system to Tracealyzer, when using the snapshot recorder. Your existing debugger is used to upload the trace data from the chip RAM. This is a plain RAM dump, that is done whenever you want to look at the trace buffer contents. This means it works with essentially with any debug probe and debugger IDE on the market, since saving the RAM contents is a commonly available function.

Built-in support for SEGGER J-Link/J-Trace
Tracealyzer supports SEGGER J-Link and J-Link compatible debuggers directly, without any debugger IDE involved. Using other debug probes is also possible, as described below. If you have a SEGGER J-Link/J-Trace debug probe or another J-Link compatible debug probe, just select "Read Trace" in the "J-Link" menu.

This opens a dialog where you get to enter the memory region where the recorder data structure is located. Normally you select the entire internal RAM according to the datasheet of your MCU, but the exact address can be found can by inspecting "RecorderDataPtr" with your debugger. Typical values are 0x0, 0x10000000 or 0x20000000 as start address and 0x10000 or 0x20000 as size (64 KB or 128 KB). This makes Tracealyzer read the chip RAM and locate the trace data. Note that this option is only available if a compatible debug probe is found. J-Link compatible debug probes also include Atmel SAM-ICE and many built-in debug interfaces on demonstration/evaluation boards (where there is a USB connection directly to the board). Look for a SEGGER J-Link label on the board.

Note: The J-Link integration does not work together with Renesas HEW, since this seems to lock the J-Link interface. Renesas HEW users are recommended to use the "Save Memory" function of Renesas HEW to save a RAM dump, as described below.

Atmel Studio Integration
Use the Atmel Studio plugin for Tracealyzer available in Atmel Gallery. This provides a launch button in Atmel Studio (see "Tools" menu) and allows for uploading through any Atmel-supported debugger.

When Tracealyzer is launched from Atmel Studio it reads the trace directly, if possible. The upload requires that a debug session is active and the target system is halted, e.g., on a breakpoint.

If the plugin is installed in Atmel Studio, you may also note the "Atmel Studio" menu in Tracealyzer. This contains a command named "Read Trace", that uploads the trace from target into a file, which is then opened.

Note: If your are using an Atmel SAM-ICE or another J-Link compatibe device (such as a development board with an integrated J-Link debugger), you may also upload the trace using the integrated J-Link upload in Tracealyzer.

Using Microchip MPLAB X IDE
To upload the trace, use our MPLAB plugin. This is available on the Percepio downloads page.

Using other development environments and debug probes
Most debuggers are able to save the RAM contents to a file. Tracealyzer supports the following common formats:

  • Binary (.bin or .dump), supporting gdb, J-Link and Renesas HEW.
  • Intel Hex (.hex), supporting IAR Embedded Workbench and Atmel MemoryLogger.
  • MCH (.mch), supporting Microchip MPLAB 8.
When you store the RAM dump, you must also make sure to select the right region, i.e., start address and size. The recorder data is stored in a single data block, identified by the pointer RecorderDataPtr. It is not necessary to match the begin and end of the recorder data, as long as it is fully included by the dumped memory region. Tracealyzer automatically finds the trace data in the RAM dump, thanks to special signatures. For chips with on-chip RAM only, we therefore recommend to dump the entire RAM. This is usually very fast. For chips with larger amounts of (external) RAM, it is typically possible to dump a limited region where the data is typically found.

Using IAR Embedded Workbench for ARM
We recommend using our Percepio Trace Exporter plugin for IAR Embedded Workbench for ARM, which provides a smooth integration with Tracealyzer. This is available at http://www.percepio.com/IAR and works for EWARM v7.x.

If using an older version of EWARM, you can save a RAM dump manually. In the debugger view, when stopped on a breakpoint:

  • Select "Debug" menu, "Memory" submenu, "Save..." (keyboard shortcut: ALT,d,y,s)
  • In the Save dialog
    • Zone: Memory
    • Start Adress: 10000000 (example start address)
    • End Adress: 1000FFFF (example end address)
    • File format: Intel Extended
    • Filename: "name.hex"
  • Press "Save" button and open "name.hex" in Tracealyzer.
To find the right Start and End addresses, check "RecorderDataPtr" that points to the recorder data structure. The address does not need to match this symbol exactly, as long as the whole data is included.

Using Renesas High-performance Embedded Workshop
In the debugger view, when stopped on a breakpoint:

  • Select "Debug" menu, "Save Memory..." (keyboard shortcut: ALT,d,a)
  • In the Save dialog
    • Format: Binary
    • Filename: "name.bin"
    • Start Address: 00000000 (example start address)
    • End Address: 0000FFFF (example end address)
    • Access size: 1
  • Press "Save" button and open "name.bin" in Tracealyzer.

Using Microchip MPLAB v8

  • Select "View" -> "File Registers". This shows you the memory contents.
  • Make sure "Hex" is selected in the bottom left (instead of "Symbolic"). Hex mode seems to be default.
  • Right click in the view and select "Export Table...".
  • In the dialog ("Export As"), make sure "Single Column Output" is selected (seems to be default).
  • Select start address 0x0000 and make sure the end address is beyond the RecorderData structure. The default values seems to be the whole RAM, so you probably don't need to change this.
  • Save as a .mch file and open this file in Tracealyzer.

Using STM32 ST-Link

  • Start "ST-Link Utility"
  • Connect to the device and view the device memory.
  • Set the view to display the entire RAM, or at least the section containing the RecorderData structure.
  • Select "Save as" and choose binary (.bin) or Intel Hex (.hex) format.
  • Open the resulting file in Tracealyzer.

Using Rowley CrossStudio for ARM v3.2

  • Open a "Watch" window and enter "*RecorderDataPtr" (click in the right-side part of the "Name" field to enable editing).
  • Right click on "*RecorderDataPtr" and select "Locate Memory", which opens the Memory view on that specific address range.
  • Right-click anywhere in the Memory view table and select "Save As" and then "Intel Hex" or "Binary".
  • Open the resulting file in Tracealyzer.

Using Keil µVision v4.x or v5.x

  • Open the "Command" window
  • Enter the command
    exec("SAVE \"out.hex\"  RecorderDataPtr , (RecorderDataPtr + 1)");
  • Open the resulting file in Tracealyzer, located in the project directory.
You can automate this procedure and get a toolbar button for this command. To do this, open the "Function Editor" (in "Debug" menu, enabled when debugging…) and add the below code:
	FUNC void SavePercepioRecorderData(void) {
	    printf("Saving Recorder Data in out.hex!\n") ;
	    exec("SAVE \"out.hex\"  RecorderDataPtr , (RecorderDataPtr + 1)");
	}
	DEFINE BUTTON "Save Recorder Data", "SavePercepioRecorderData()"

Using other development environments and debug probes
Most debuggers are able to save the RAM contents to a file. Tracealyzer supports the following common formats:

  • Binary (.bin or .dump), supporting gdb, J-Link and Renesas HEW.
  • Intel Hex (.hex), supporting IAR Embedded Workbench and Atmel MemoryLogger.
  • MCH (.mch), supporting Microchip MPLAB 8.
When you store the RAM dump, you must also make sure to select the right region, i.e., start address and size. The recorder data is stored in a single data block, identified by the pointer RecorderDataPtr. It is not necessary to match the begin and end of the recorder data, as long as it is fully included by the dumped memory region. Tracealyzer automatically finds the trace data in the RAM dump, thanks to special signatures. For chips with on-chip RAM only, we therefore recommend to dump the entire RAM. This is usually very fast. For chips with larger amounts of (external) RAM, it is typically possible to dump a limited region where the data is typically found.

Hardware Timer Porting

The recorder library needs a hardware timer port in order to give accurate timestamps on the recorded events. This is the only hardware dependency of the recorder library. Some hardware architectures are already supported in the recorder library, such as ARM Cortex M0, M3 and M4 (all chips using Cortex M cores), and other ports are in development. However, there are many chips that we do not yet have direct support for, with respect to hardware timestamping. In case your chip is not yet directly supported, the recorder library includes a hardware independent fallback option providing low resolution time stamping equivalent to the Real Time Engineers ltd tick, typically 1 ms. However, it is strongly recommended to use to a hardware timer for any serious use of this tool. Fortunatly, developing a hardware timer port yourself is quite easy. Read more in the "Developing a Hardware Timer Port" section below.

Developing a Hardware Timer Port

Developing a hardware timer port is quite easy if you already have a Real Time Engineers ltd environment up and running. The recorder library file trcHardwarePort.c contains a function vTracePortGetTimeStamp that is expected to read the time from the configured hardware timer/counter. This function is based on a set of macros (prefixed "HWTC") that you define according to your specific hardware in trcHardwarePort.h. Please refer to the comments in trcHardwarePort.h for detailed instructions. Note that it is typically not necessary to change the vTracePortGetTimeStamp function in trcHardwarePort.c, just the HWTC macros in the header file.

Note
The hardware timer/counter used that drives the FreeRTOS tick can be identified in FreeRTOS file port.c, where it is initialized. Using hardware timers other than the one driving the OS tick is possible, but is a less generic solution, since it might not work for other FreeRTOS users that might be using the timer/counter for other purposes and in other configurations. However, if the hardware timer/counter used by your FreeRTOS port does not fit our assumptions (e.g., that the current value can be read), another timer solution is of course necessary.

When you have identified the right hardware feature, you need to study the data sheet for your specific hardware to find the right registers to use. Make sure to read the timer/counter value in a way that does not also reset the timer/counter. For instance, the AT91SAM7 has two registers for accessing the PIT counter value, one just reads the value while the other also resets it When defining the HWTC_PERIOD macro, please use the timer/counter reload register, if possible, rather than a literal constant. This is to make the solution more portable between different versions of the same chip family.

For questions about hardware timer ports of the trace library, please contact support@percepio.com


Copyright Percepio AB 2016, all rights reserved.