Capturing ETB Trace Data With ETBLib

From Texas Instruments Embedded Processors Wiki

Jump to: navigation, search
Translate this page to   

Chinese (中文) translation

Contents

Introduction

This page will walk through a demo on how to capture ETB Trace data and moving it off chip with assistance from ETBLib, an ETB programming library.

Tools Needed

Software Used

Demo Application

Overview

The demo application is called etblib_demo. It is a DSP/Bios based sample application. There are three tasks that get called in a round robin fashion, each with a priority level of 2. Each of these tasks will pend on a semaphore. When all three tasks have pended, a lower level task will get executed, which will post the semaphores to re-enable the higher level tasks. In addition, there is one more task with a priority level of three. Upon execution, it immediately pends on an additional semaphore.

In order to simulate an application crash, which would cause the application to end up in the SYS_ABORT routine, we create a PRD function that will get called after 15 seconds of execution. This function will post the semaphore that allows the high priority task to execute. This high priority task then calls SYS_ABORT to simulate a crash.

GOAL

The Goal of this exercise is to demonstrate the ability to look at the resulting trace data and trace back to the point of the crash. In this case, it will involve simply tracing back to the call to SYS_ABORT. In a more realistic scenario, there would be more detailed analysis needed to find the result of the crash. But the objective of this exercise is more in the capturing of the data, rather than in the analysis of it.

Application Source Code Description

Note: Many of these variables are declared global so that they are visible within any of the application functions. Depending on the situation, sometimes internal memory buffer that will hold the ETB contents can be declared dynamically. However, in this case, we are declaring a static buffer. The reason for this is because we won't be able to dynamically allocate once SYS_abort() has been called. So we allocate statically beforehand, and then copy the values into that buffer after SYS_abort() has been called. We have created our own function myExit, which replaces UTL_halt, which is called from the abort routine. This function will copy the ETB into internal memory, set a status bitfield recording progress, and then turn off hardware interrupts and spin in an infinite loop. This same routine could be used on an ordinary application to dump the ETB values to memory before shutting down.

Downloading the Example Prroject

You can download the example project from the following locations. Note that in order to build the projects, you will need to have the AETLib, ETBLib, and TraceLib libraries available. They can be downloaded from here

The two projects mane a few assumptions on the locations of include files and libraries. You will need to either tweak the projects to accommodate your configuration or update the macro variables accordingly. The assumptions are listed below.

Project File Description Link
Code Composer Studio 3.3 Project Link
Code Composer Studio v4 Project Link

main()

The following code, implemented in main, merely sets up ths DSP?Bios objects that are needed to execute the demo. We create each of the tasks, set the appropriate arguments, and also create the PRD one-shot function. If any of this fails, we notify the user through the Bios message log.

/* Initialize the TSK_Attrs structure for all tasks */
	TSK_Attrs tsk0_attrs = {0};
	TSK_Attrs tsk1_attrs = {0};
	TSK_Attrs tsk2_attrs = {0};
	TSK_Attrs lltask_attrs = {0};
	TSK_Attrs cleanup_attrs = {0};
 
    LOG_printf(&trace, "Faraday Test example started.\n");
 
	/* Start the PRD Clock */
	PRD_start(&PRD0);
 
 
	/* Create Task0 */
	tsk0_attrs.name = "Task0";
	tsk0_attrs.priority = 2;
	tsk0_attrs.stacksize = 512;
	tsk0_attrs.stack = NULL;
	tsk0_attrs.initstackflag = 1;
	hTask0 = TSK_create((Fxn)task0, &tsk0_attrs);
	if (!hTask0) 
	{
		SYS_abort("Can't create task 0");
	}
 
	/* Create Task1 */
	tsk1_attrs.name = "Task1";
	tsk1_attrs.priority = 2;
	tsk1_attrs.stacksize = 512;
	tsk1_attrs.stack = NULL;
	tsk1_attrs.initstackflag = 1;
	hTask1 = TSK_create((Fxn)task1, &tsk1_attrs);
	if (!hTask1) 
	{
		SYS_abort("Can't create task 1");
	}
 
	/* Create Task2 */
	tsk2_attrs.name = "Task2";
	tsk2_attrs.priority = 2;
	tsk2_attrs.stacksize = 512;
	tsk2_attrs.stack = NULL;
	tsk2_attrs.initstackflag = 1;
	hTask2 = TSK_create((Fxn)task2, &tsk2_attrs);
	if (!hTask2) 
	{
		SYS_abort("Can't create task 2");
	}
 
	/* Create Low Level Task */
	lltask_attrs.name = "LowLevel Task";
	lltask_attrs.priority = 1;
	lltask_attrs.stacksize = 512;
	lltask_attrs.stack = NULL;
	lltask_attrs.initstackflag = 1;
	hllTask = TSK_create((Fxn)lltask, &lltask_attrs);
	if (!hllTask) 
	{
		SYS_abort("Can't create low level task");
	}
 
	/* Create Clean Up Task */
	cleanup_attrs.name = "Cleanup Task";
	cleanup_attrs.priority = 3;
	cleanup_attrs.stacksize = 512;
	cleanup_attrs.stack = NULL;
	cleanup_attrs.initstackflag = 1;
	cleanupTask = TSK_create((Fxn)cleanup, &cleanup_attrs);
	if (!hllTask) 
	{
		SYS_abort("Can't create CleanUp task");
	}

We also want to initialize the ETB and the DSP trace hardware. We also need to program AET to turn trace on and off at the appropriate points. The code comments will give you an idea of what's going on. We are configuring AET to trigger PC and Timing trace to start when we execute task0, and to end when we execute our exit function myExit. ETB will capture in a looping fashion so that when trace has ended, we will have a group of the last instructions executed.

/* Set Up the ETB Receiver */
	etbError = ETB_open(pETBErrCallBack, eETB_Circular, coreID, &pETBHandle, &etbSize);
	if(etbError != eETB_Success)
	{
		SYS_abort("Error opening ETB");
	} else {
		LOG_printf(&trace, "ETB Opened");
	}
 
		/* Enable ETB receiver */
	etbError = ETB_enable(pETBHandle, 0);
	if(etbError != eETB_Success)
	{
		SYS_abort("Error enabling ETB");
	} else {
		LOG_printf(&trace, "ETB Enabled");
	}
 
 
	/* AETLIB Programming should be done here */
 
	/* Configure AET to start at the task0 function
	   and to end at the custom myExit function
	*/
 
	startTraceParams = AET_JOBPARAMS;
	endTraceParams = AET_JOBPARAMS;
 
	startTraceParams.programAddress = (Uint32)&task0;
	startTraceParams.traceTriggers = AET_TRACE_TIMING | AET_TRACE_PA;
	startTraceParams.traceActive = AET_TRACE_ACTIVE;
 
	endTraceParams.programAddress = (Uint32) &myExit;
	endTraceParams.traceTriggers = AET_TRACE_TIMING | AET_TRACE_PA;
	endTraceParams.traceActive = AET_TRACE_INACTIVE;
 
	AET_init();
 
	if (AET_claim()){
		SYS_abort("AET not claimed");
	}else{
		LOG_printf(&trace, "AET Claimed");
	}
 
	/* Set Up the Trace Start Job */
	if (AET_setupJob(AET_JOB_START_STOP_TRACE_ON_PC, &startTraceParams)){
		SYS_abort("Start job program failure");
	}else{
		LOG_printf(&trace, "Start Job Programmed Success");
	}
 
	startJob = startTraceParams.jobIndex;
 
	LOG_printf(&trace, "Start Job #%d", startJob);
 
	/* Set Up the Trace End Job */
	if (AET_setupJob(AET_JOB_START_STOP_TRACE_ON_PC, &endTraceParams)){
		SYS_abort("End job program failure");
	}else{
		LOG_printf(&trace, "End Job Programmed Success");
	}
 
	endJob = endTraceParams.jobIndex;
 
	LOG_printf(&trace, "End Job #%d", endJob);
 
	/* Enable AET */
	if (AET_enable()){
		SYS_abort("Error Enabling AET");
	}else{
		LOG_printf(&trace, "AET Enabled");
	}
 
 
	/*** Setup Trace Export ***/
	/* Open DSP Trace export module */
	dspTraceError = DSPTrace_open( pDSPErrorCallBack, &pDSPHandle);
	if(dspTraceError != eDSPTrace_Success)
	{
		SYS_abort("Error opening DSP Trace Export block");
	}else{
		LOG_printf(&trace, "Trace Export Opened");
	}
 
	/* Setup trace export clock to FCLK/2 */
	dspTraceError= DSPTrace_setClock(pDSPHandle, 2);
	if(dspTraceError != eDSPTrace_Success)
	{
		SYS_abort("Error setting up DSP trace export clock");
	}else{
		LOG_printf(&trace, "Trace Clock Initialized");
	}
 
	/* Enable DSP Trace */
	dspTraceError= DSPTrace_enable(pDSPHandle, 0, testPattern);
 
	if(dspTraceError != eDSPTrace_Success)
	{
		SYS_abort("Error enabling DSP trace export");
	} else {
		LOG_printf(&trace, "DSP Trace Enabled");
	}
 
	/* Start the PRD Clock */
	PRD_start(&PRD0);

dumpEtb()

Once the application has executed for ~15 seconds, the PRD function will be executed, posting the semaphore that allows the high priority task to call SYS_abort() to simulate the application crash. The custom exit function calls dumpEtb(), which reclaims the resources used by AET, moves the ETB Data from the ETB to processor memory, disables and closes the DSP Trace interface, and disables and closes the ETB interface. Through each of these steps, we monitor sucess by updating the bits in the global variable statusCode. When we end up in the infinite loop after SYS_abort(), the value signaling total success in the transport is one of either 0x1F7 (ETB has not wrapped) or 0x1EF (ETB Wrapped). In a typical case, rather than using these bit fields, we'd just use a printf to tell the user where the error occurred. We can't do that here because we can't call printf after we've called SYS_abort.

void dumpEtb(){
 
 
	// Release all of the AETLIB Resources
	AET_releaseJob(startJob);
	AET_releaseJob(endJob);
	AET_release();	
 
	// Disable Trace export
	dspTraceError = DSPTrace_disable(pDSPHandle);
	if (dspTraceError == eDSPTrace_Success) {
		statusCode |= STS_TRACE_EXPORT_DISABLED;
	}
 
	/* Disable Trace Capture - ETB Receiver */
	etbError = ETB_disable(pETBHandle);
	if (etbError == eETB_Success){
		statusCode |= STS_ETB_DISABLED;
	}
 
	/* Check the ETB status */
	etbError = ETB_status(pETBHandle, &etbStatus);
	if (etbError == eETB_Success){
		statusCode |= STS_ETB_STATUS;
	}
 
	/* Move the ETB data into memory */
	if (etbStatus.canRead == 1)
	{
		etbWordsAvailable = etbStatus.availableWords;
		if (etbStatus.isWrapped == 1){
			statusCode |= STS_ETB_WRAPPED;
		}else{
			statusCode |= STS_ETB_NOT_WRAPPED;
		}
 
		/* 
		 * Allocate the buffer for copying the ETB to
		 * Set the memPtr to the array that we've statically allocated
		 */ 
		memPtr = (uint32_t*)&etb_buf;
 
		if (memPtr)
		{
			etbError = ETB_read(pETBHandle, memPtr, etbStatus.availableWords, 0, etbStatus.availableWords, &retSize);
 
			if (etbError == eETB_Success)
			{
				statusCode |= STS_ETB_READ;
			}
			statusCode |= STS_BUF_ALLOCATE;
		}
	}
 
 
	/* Close the handle to the ETB */
	etbError = ETB_close(pETBHandle);
 
	if (etbError == eETB_Success)
	{
		statusCode |= STS_ETB_CLOSED;
	}	
 
	/* Close the handle to DSPTrace */
	dspTraceError = DSPTrace_close(pDSPHandle);
	if (dspTraceError == eDSPTrace_Success)
	{
		statusCode |= STS_TRACE_EXPORT_CLOSED;
	}
 
}

Exporting the Data

Typically, I set a breakpoint on the asm(" nop") instruction in the myExit() function. The breakpoint will get hit as soon as the application has _crashed_. You can also potentially just wait for the application to execute a sufficient amount of time, and then manually halt it. In both cases, the PC should be in the same location.

When we have halted, the ETB contents will have been copied to CPU memory at the location of the array etb_buf. You should now put the following three values in the CCS watch window

If the error status code is either 0x1F7 or 0x1EF, it is safe to proceed. You then want to open the CCS Scripting Console window and enter a command to export the data to a bin file. In this case, we will use the name "etb_test.bin". You can use whatever name you choose. We will assume that the .out file is stored in c:\temp\, and will use the same path for the bin file.

In the command window, enter the following command, replacing the values as necessary. Replace startAddr with the value in etb_buf in the watch window Replace length with the value in etbWordsAvailable in the watch window.
saveRaw(startAddr, PAGE_PROGRAM, "C:\\temp\\etb_test.bin", length , 32, true)

Converting the Data

To this point, the data that we have captured is simply raw etb data in binary form. We need to convert this data to a trace data format (.tdf) in order to be able to view it. There is a tool supplied with Code Composer Studio v4 that will accomplish this task. It's called bin2tdf.exe and is located in the <%CCS_INSTALL_DIR%>\CCSv4\emulation]analysis\bin directory.

The first step to using bin2tdf is to create a bin2tdf configuration file that will need to be passed to the utility. You can create one for this demo by copying the text in the box below into a text file and saving it with a name like bin2tdf.cfg

Trace Mode = 0
Encoding Mode = 0
Number of AEG = 0
Memory Mode = 0
CEMU Status = 0

There are a number of parameters that need to be specified on the command line.

Assuming that all of the necessary files are in the current directory and the location of the .exe is in the path, the following command line can be used for this example

bin2tdf.exe -bin etb_test.bin -coffname etblib_demo.out -cpuid 64x+ -rcvrname ETB -dcmfile bin2tdf.cfg

The .tdf file will be created with the same name as the .bin file, so in this case, it would be etb_test.tdf. It will be created in the current directory.

Viewing the Data

There are actually two different viewer applications shipped with Code Composer Studio 4 that will allow you to display the captured .tdf file. It's your choice as to which you use.

Trace Analyzer Display

Code Composer Studio v4 comes with a built in trace viewer called trace analyzer. The Trace Analyzer window can be opened from within CCS by choosing Tools->Trace Analyzer. In order to open the .tdf file, perform the following steps.

Decoded etb data ta.PNG
In the image to the right, we can see what the trace data looks like after it's been decoded in the trace analyzer.


Stand Alone Trace Display

Code Composer Studio v4 comes with a stand alone trace display viewer that can be used to view .tdf files. The application is called TraceDisplay.exe and can be found in the <%CCS_INSTALL_DIRECTORY%>/ccsv4/emulation/analysis/bin directory. When opening TraceDisplay.exe, you will get a dialog box that mentions that it is unable to connect to the trace data server and will operate in Standalone mode. You can just acknowledge the dialog, as we want to be operatign in Standalone mode.

Once the trace display application has been opened, you can choose File->Open and navigate to and select the .tdf file that you wish to view through dialog. In some cases, once you specicify the .tdf, the trace display will ask you to specify the associated .out file. If this occurs, just point the dialog to the .out file that was used when the trace data was captured. (If you are saving these files to be viewed at a later time, it is important that you also save the associated .out file. If the .out file is not precisely the same file that was used when the trace data was captured, the trace decoder will not be able to retrieve the data.)

Decoded etb data.PNG
In the image to the right, we can see what the trace data looks like after it's been decoded. The top frame shows the raw assembly level execution of the application. We see the program address for each instruction, a timing cycle count associated with each instruction, and the disassembly of each instruction. In the lower pane, we see the C source code. As we scroll through the top pane, the lower pane will stay in sync when we are in code that is contained in the directories that we have specified as source directories

Specifying source directories

To indicate to the Trace Display which folders contain the source code, right click in the top pane of the display above, and select Source->Set Source Directory. To add a directory to the list, select New Folder and navigate to the desired directory and select "OK." Repeat as necessary. You can choose to automatically include sub directories, but if there are too many of them, it will significantly slow down the search.

FAQ

Q: Do I need an XDS560 Trace emulator to use this?

Related


CN Capturing ETB Trace Data With ETBLib

E2e.jpg For technical support please post your questions at http://e2e.ti.com. Please post only comments about the article Capturing ETB Trace Data With ETBLib here.
Hyperlink blue.png Links
ARM Microcontroller MCU ARM Processor Digital Media Processor Digital Signal Processing Microcontroller MCU Multi Core Processor
Ultra Low Power DSP 8 bit Microcontroller MCU 16 bit Microcontroller MCU 32 bit Microcontroller MCU

Leave a Comment
Personal tools
Namespaces
Variants
Actions
Navigation
Print/export
Toolbox