SWO Trace

From Texas Instruments Wiki
Jump to: navigation, search

Introduction

Profiling tools can be vital for debugging, validating and characterizing applications. ARM's Serial Wire Output(SWO) Trace capability is one such tool incorporated in Code Composer Studio for the following Cortex M based TI devices:

  • MSP432
  • Tiva C (TM4C129 and TM4C123)
  • CC26xx
  • CC13xx

SWO Trace is a single pin trace interface that supports profiling hardware events such as periodic sampling of program counter, data variable reads and writes, interrupt entry and exit, counters as well as application generated software messages. Use the following quick links for device specific support.


MSP432 Launchpad

Pre-requisites:

  • CCS Version 6.1.1 or higher
  • XDS110 debug probe


Step 1: Target Configuration

The MSP432 Launchpad has an onboard XDS110 debug probe which supports SWO Trace. MSP432 supports 2 debug protocols; JTAG and SWD. SWO Trace for MSP432 is output on the TDO pin in SWD mode only. As such SWO Trace is not available in JTAG mode. To use SWO Trace create your target configuration with SWD as the debug protocol with TDO connection to the Aux COM port as indicated in the snapshot below:

MSP432-config.jpg


Step 2: Basic Setup

Once the target configuration is selected, launch the debug session and load the application.

Important Note: SWO Trace requires trace clock setup which is dependent on the system clock of the target. If your application configures the system clock after main, run to the line after the system clock configuration and then we are ready to launch the trace capture.

In the code snippet below, as indicated in line 145 the subsequent lines configure the main clock. Run to the highlighted line (line 152) and then setup the trace capture.

MSP432-code.jpg


Step 3: Start Trace Capture

Trace can be configured by invoking the Tools menu and then selecting Hardware Trace Analyzer. CCS exposes the trace capabilities as 4 pre-configured Usecases:

  1. Statistical Function Profiling: Periodic program counter samples.
  2. Interrupt Profiling: Interrupt entry exit and preemption.
  3. Data variable trace: Variable reads and writes.
  4. Custom Usecase: Software messages and Customized trace generation.

For more details refer Usecase section.

Tiva/TM4C

Pre-requisites:

  • CCS Version 6.1.1 or higher
  • XDS200 debug probe firmware version 1.0.0.5 or later. (Contact your XDS200 vendor for details on how to determine debug probe version and update it if needed).


Step 1: Target Configuration

The Tiva/TM4C launchpads have the onboard ICDI debug probe that does not support SWO Trace. Instead use an external XDS200 debug probe. The XDS200 debug probe supports JTAG and SWD mode for Tiva/TM4C devices. SWO Trace is output on the TDO pin in SWD mode only. SWO Trace is not available in JTAG mode. To use SWO Trace create the target configuration as indicated in the snapshot below with SWD as the debug protocol and User COM port routed to TDO pin.

TivaC-config.jpg


Step 2: Basic Setup

Once the target configuration is selected, launch the debug session and load the application.

Important Note: SWO Trace requires trace clock setup which is dependent on the system clock of the target. If your application configures the system clock after main, run to the line after the system clock configuration and then we are ready to launch the trace capture.

In the code snippet below, line 408 configures the system clock. Run to the highlighted line (line 415) and then setup the trace capture.

TivaC-code.jpg


Step 3: Start Trace Capture

Trace can be configured by invoking the Tools menu and then selecting Hardware Trace Analyzer. CCS exposes the trace capabilities as 4 pre-configured Usecases:

  1. Statistical Function Profiling: Periodic program counter samples.
  2. Interrupt Profiling: Interrupt entry exit and preemption.
  3. Data variable trace: Variable reads and writes.
  4. Custom Usecase: Software messages and Customized trace generation.

For more details refer Usecase section.


CC26xx and CC13xx

Pre-requisites:

  • CCS Version 6.1.1 or higher
  • XDS110 debug probe

Step 1: Target Configuration

The CC26xx and CC13xx SensorTag development kits can be used with the optional Debugger DevPack (CC_DEVPACK_DEBUG) which is an XDS110 class debug probe that supports SWO Trace. These device families require the application to route the SWO Trace to a GPIO pin. The application will need to route the SWO Trace to TDO pin by including the line below in the application:

// Map Serial Wire Viewer to JTAG TDO pin

IOCPortConfigureSet(IOID_16, IOC_PORT_MCU_SWV, IOC_STD_OUTPUT);

And including the header file:

#include <driverlib/ioc.h>

Now, to use SWO Trace create the target configuration as indicated in the snapshot below with debug protocol as 2-pin cJTAG and TDO routed to Aux COM.

CC2650-config.jpg


Step 2: Basic Setup

Once the target configuration is selected, launch the debug session and load the application.

Important Note: SWO Trace requires trace clock setup which is dependent on the system clock of the target. If your application halts at main and the application configures the system clock after main, run to the line after the system clock configuration and then we are ready to launch the trace capture.


Step 3: Start Trace Capture

Trace can be configured by invoking the Tools menu and then selecting Hardware Trace Analyzer. CCS exposes the trace capabilities as 4 pre-configured Usecases:

  1. Statistical Function Profiling: Periodic program counter samples.
  2. Interrupt Profiling: Interrupt entry exit and preemption.
  3. Data variable trace: Variable reads and writes.
  4. Custom Usecase: Software messages and Customized trace generation.

For more details refer Usecase section.


Usecases

CCS exposes trace capabilities in the form of usecases. SWO Trace has 4 pre-configured usecases:

  1. Statistical Function Profiling
  2. Interrupt Profiling
  3. Data Variable Trace
  4. Custom core trace (Software messages)

To select a usecase, go to the Tools -> Hardware Trace Analyzer. A window pane opens which lists the 4 usecases as indicated in the snapshot below:

Usecases list.jpg


Each usecase is presented in detail in the following sub sections.

Statistical Function Profiling:

Statistical function profiling is useful for analyzing code execution. It brings to light the execution intensive functions which could either be smaller functions occurring frequently or larger functions taking more execution time.

The PC sample hardware events are generated by the DWT (Data Watchpoint and Trace Unit) and can be configured to output PC samples periodically at configurable intervals. When you select the Statistical Function Profiling usecase, the setup dialog box appears. The UI shows a drop down that allows you to control how frequently PC is sampled. The lowest interval is 64 processor clocks.

Stat-Func-UI.jpg

Important Note: Smaller intervals yield higher density trace which could cause overflows and packet loss if the data cannot be drained fast enough. If the trace data shows overflows increase the interval and try again.

Once you click on Start in the dialog box, 2 tabs appear in CCS; one shows the raw data trace, the other shows analysis of the PC samples in terms of function execution. Now, run the core and when a halt occurs either due to a breakpoint or a user initiated halt, the trace data gets processed. The analysis window shows the percentage of time the various functions were encountered. The following snapshot was captured using the onboard XDS110 debug probe on a MSP432 launchpad with the target executing the OutOfBox demo application.

Stat-Func-views.jpg

The raw trace data also outputs messages indicating if the core is in sleep executing a wfi or wfe.


Interrupt Profiling:

Interrupt profiling can be used to determine if interrupts are occurring as expected and if interrupt priorities have been setup correctly. It can also be used to characterize interrupt execution times.

Interrupt entry, exit and return hardware events are generated by the DWT (Data Watchpoint and Trace) unit. Interrupt profiling is not statistical. When the Interrupt profiling usecase is selected, the setup dialog box appears. There are no configurable parameters for this usecase as indicated in the snapshot below.

Interrupt-UI.jpg

Once you click on Start, 3 windows appear; the raw trace data, analysis graph and analysis summary window. Now run your application. When a halt occurs either due to a breakpoint or a user initiated halt the graph shows the interrupt occurrence on the execution timeline. For example in the snapshot below the interrupt on Port 1 was executing and then was subsequently preempted by a higher priority interrupt Timer TA1. The summary view shows information on the execution occurrence and duration of the interrupts. The Inclusive counts include time spent in preemption whereas the Exclusive counts exclude any time spent in preemption state. The following snapshot was captured using the onboard XDS110 debug probe on a MSP432 launchpad with the target executing the OutOfBox demo application.

Interrupt-Views.jpg


Data Variable Trace:

Data Variable Trace can be used to profile variable reads and writes.

Data variable read and write events are generated by the DWT (Data Watchpoint and Trace) Unit. The trace hardware outputs a packet every time the variable is read and/or written with the corresponding value and so this usecase is not statistical. When this usecase is selected in CCS, the setup dialog box appears. The dialog box requires the user to enter the variable address. The hex value of the address can be entered directly or if symbols are loaded, a symbol can be specified in the format “&<variable_name>. For example the snapshot below shows that variable “port_num” is to be traced.

Data-Var-UI.jpg

Once you click on Start in the dialog box, 2 tabs appear in CCS. One shows the raw data trace, the other shows the read and write events graphically. Now, run the core and when a halt occurs either due to a breakpoint or a user initiated halt, the trace data gets processed. The graph window shows the reads and writes over the data capture duration. For example in the snapshot below trace captured reads and writes to port_num a counter which increments from 1 to 32. The snapshot was captured using the onboard XDS110 debug probe on a MSP432 launchpad with the target executing the sample application in the "Software Messages" section.

Data-Var-views.jpg

You can also get a list view of all the data variable reads and writes by clicking on the Analyze icon in the Graph view and then selecting Detail from the dropdown.

Data-Var-analyze.jpg

The snapshot below shows the list view.

Data-Var-analyze1.jpg


Software Messages:

Software messages are application initiated messages. To use software messages, select Custom Core Trace from the Trace menu.

Software Messages are issued through the ITM (Instrumentation Trace Macrocell). The ITM in Cortex M has 32 stimulus ports. Writes to the stimulus ports result in a data packet of size word, half-word or byte depending on the size of the data written. CCS reserves port 0 as a character port which means any data written to port 0 is interpreted by CCS as characters and not binary values. Use port 0 for printing strings and use ports 1 to 31 for printing binary values.

Sample code with APIs to use ITM can be found below:

//*****************************************************************************
//
// main.c template
//
//****************************************************************************

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

const unsigned ITM_BASE_ADDRESS = 0xE0000000;
const unsigned ITM_NUM_PORTS = 32;
const unsigned NUM_TRIALS = 2;


typedef volatile unsigned* ITM_port_t;


void delay(unsigned num_loops)
{
  unsigned i;
  for (i=0; i<num_loops; i++)
  {
	  asm ("NOP");
  }
}

void port_wait(ITM_port_t port)
{
	delay(10);
	/* Wait while fifo ready */
	while (*port == 0);
}


/* Send a nul terminated string to the port */
void ITM_put_string(ITM_port_t port, const char* data)
{
	unsigned datapos  = 0;
	unsigned portpos  = 0;
	unsigned portdata = 0;

	while('\0' != data[datapos])
	{
		port_wait(port);
		portdata = 0;

		/* Get the next 4 bytes of data */
		for (portpos=0; portpos<4; ++portpos) {
			portdata |= data[datapos] << (8*portpos);
			if ('\0' != data[datapos]) {
				++datapos;
			}
		}

		/* Write the next 4 bytes of data */
		*port = portdata;
	}
}

/* Send a 32 bit value to the port */
void ITM_put_32(ITM_port_t port, unsigned data)
{
	port_wait(port);
	*port = data;
}


/* Send a 16 bit value to the port */
void ITM_put_16(ITM_port_t port, unsigned short data)
{
	/* Cast port for 16-bit data */
	volatile unsigned short* myport = (volatile unsigned short*)port;
	port_wait(port);
	*myport = data;
}


/* Send a 8 bit value to the port */
void ITM_put_08(ITM_port_t port, unsigned char data)
{
	/* Cast port for 8-bit data */
	volatile unsigned char* myport = (volatile unsigned char*)port;
	port_wait(port);
	*myport = data;
}


void main(void)
{
	unsigned trial_num, port_num = 1, port_address;
	ITM_port_t port;

	for (trial_num=0; trial_num < 10; ++trial_num) {
		for (port_num=1; port_num<ITM_NUM_PORTS; ++port_num) {

			// Send text to port 0
			ITM_put_string((ITM_port_t)ITM_BASE_ADDRESS, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()-_=+[{]}\\|;:'\",<.>/? ");
			ITM_put_string((ITM_port_t)ITM_BASE_ADDRESS, "hello\nworld");
			delay(100);


			// Get this port address
			port_address = ITM_BASE_ADDRESS + (4*port_num);
			port = (ITM_port_t)port_address;

			// Send numeric data to this ports
			ITM_put_32(port, 33);
			delay(100);
			ITM_put_32(port, 0x12345678);
			delay(100);
			ITM_put_16(port, 33);
			delay(100);
			ITM_put_16(port, 0x9abc);
			delay(100);
			ITM_put_08(port, 33);
			delay(100);
			ITM_put_08(port, 0xde);
			delay(100);
			ITM_put_string((ITM_port_t)ITM_BASE_ADDRESS, "end\n");
			delay(10000);
		}
		delay(10000);
	}
}


Select Custom Core Trace from the Trace menu, click on Start in the UI. There are no configuration options for using this usecase for software messages.

Custom-Core-UI.jpg

When you run and then halt the core, the trace display will output the SW messages. Below is a sample output. The data sent on stimulus port 0 is interpreted as characters and data on the other stimulus port is interpreted as binary values. The snapshot was captured using the onboard XDS110 debug probe on a MSP432 launchpad executing the sample application provided above.

Custom-Core-SW-messages.jpg


Advanced triggering using Custom Core Trace:

Custom Core Usecase can be used to setup custom trigger configurations including multiple trigger sources like more than one data variable traces or PC trace with Interrupt Trace etc.

To configure the triggers, select the Custom Core Trace Usecase and click on the Advanced Settings button in the UI.

Custom-Core-UI-1.jpg

The Advanced Settings window has pre-configured receiver definitions. It has a trigger icon on the extreme left as indicated in the snapshot.

Custom-Core-Trigger.jpg

Once you click on this trigger icon, a Trigger definition appears. The trigger can be configured for Data Variable Trace or for Hardware trace events. For the Hardware events, the checkbox can be used to select the event. By clicking on the trigger icon again you can define another trigger.

Custom-Core-Trigger-2.jpg

Once you specify your triggers. Click on OK and Start the usecase. Once you run and halt the core you will see the raw trace data. To visualize the data click on the visualization icon as indicated below and select the type of analysis you want to perform based on the trigger selection.

Custom-Core-Views.jpg


Troubleshooting

1. I am seeing overflow packets in the trace data stream. How do I avoid them? The first knob to exercise is the timestamp resolution. The timestamp resolution can be set at 4 different levels; divide by 1, divide by 4, divide by 16 and divide by 64. Divide by 1 gives the finest granularity and divide by 64 the lowest granularity but also fewer trace packets. To change the timestamp granularity, select the “Advanced Settings” button on the UI and select the Receiver in the settings window. Drill down to the Timestamping option and choose a higher resolution value.

Receiver-Timestamp.jpg

If you are using Statistical Function profiling, then the density of the stream can be reduced by increasing the “Sampling interval” in the usecase setup UI.

2. When I start a usecase I get an error message indicating that the System clock could not be determined and to enter it manually. For some devices the system clock cannot be determined because of certain clock configuration settings such as external crystal dependency. To set the system clock manually, click on the “Advanced Settings” button in the Usecase UI and then select the Receiver. Drill down to the UART Options section and change the setting for Clock frequency from “Auto” to “Manual” as indicated in the snapshot below. A text box appears. Specify the System clock in Hz in the text box.

Receive Settings.jpg

3. How do I setup SWO Trace for a particular baud rate? By default CCS will try and configure the hardware for the highest possible baud rate. However if you need to specify your own baud rate you can override the automatic configuration and enter it manually. Click on the “Advanced Settings” button in the Usecase UI and then select the Receiver in the Advanced Properties button. Drill down to the “UART Options” group and select the “Clock frequency” entry. Change the setting from “Auto” to “Manual”. An input text box appears. Enter the system clock in Hz. Now drill down to the “SWO Selection” section and select the “Prescalar” entry. Change the setting from “Auto” to “Manual”. An input text box appears. Enter a divide by factor to divide the clock to the desired baud rate based on the formula below:

BaudRate = Clock frequency / (Prescalar + 1)

For example, if System clock frequency is 120Mhz, and desired baud rate is 115200, then based on the formula above:

	Prescalar = (Clock frequency/BaudRate) - 1
		   = (120 * 1000 * 1000 / 115200) – 1
		   =  1041.667 – 1
   		   = 1041 (rounded to the nearest decimal)


Enter this value(1041) in the Prescalar input text box.