Many Armv7-M/Armv8-M devices include an Embedded Trace Macrocell (ETM) which provides instruction trace. When streaming instruction trace directly to your PC, the µVision debugger enables review of historical sequences , execution profiling , performance optimization , and code coverage analysis .
There are certain types of problems that can only be found with a quality trace, such as:
The Corstone-300 FVP can be used to collect instruction trace data with a two-step approach. First, you run the simulation and collect the data. Then, you restart the simulation and load the coverage file that was created in the first step to use the data in µVision. Follow these steps to set this up in µVision:
MTItoCoverage.dll from C:\Keil_v5\ARM\VHT to C:\Keil_v5\ARM\FVP\Corstone-300\models\Win64_VC2017. This file is required to extract the coverage data from a previous run. Project - Options for Target… (Alt+F7) and switch to the Debug tab.
 Project - Options for Target… (Alt+F7) and switch to the Debug tab.
When you now start a debug session, the coverage information is recorded. When you leave the debug session, the data is written to the coverage file specified. Next time you start a debug session, the file is opened and the information is used. This method does not provide Instruction Trace data, so you can move directly to the Code Coverage section.
For the following, you need to connect a ULINKpro debug and trace adapter to your target board using the 20-pin Cortex+ETM connector .
 Project - Options for Target… (Alt+F7) and switch to the Debug tab.
 Project - Options for Target… (Alt+F7) and switch to the Debug tab.
Instruction trace enables the review of historical data of the application execution.
 Go to View - Trace and select Trace Data.
 Go to View - Trace and select Trace Data.
LDR instruction in the RESET_Handler function as shown below:
0x04, you will find the address of the first instruction there and this will match with that displayed in the first frame. In my case it is 0x1A00_1330 + 1 = 0x1A00_1331 (+1 says it is a
Thumb® instruction
). The first occurrence in a function is highlighted in orange to make the start of functions easier to find.If you unselect Run to main() in the Debug tab of the  Options for Target… window, no instructions will be executed when you enter debug mode. The program counter will be
 Options for Target… window, no instructions will be executed when you enter debug mode. The program counter will be 0x1A00_1330. You can run or single-step from that point and this will be recorded in the Trace Data window.
Capturing all the instructions executed is possible in simulation and with ULINKpro but this might not be practical. It is not easy sorting through millions of trace frames or records looking for the ones you want. Use Trace Filters, Find, or save everything to a file and search with a different application program such as a spreadsheet.
Trace Filters
In the Trace Data window, you can select various types of frames to be displayed. The Display: box shows the various options available:
These filters are post collection.
In the Find a Trace Record box, enter bx as shown here:
You can select properties/columns where you want to search in the “in” box.
Select the Find a Trace Record icon  and the following screen opens:
 and the following screen opens:
Click on Find Next and each time it will step through the trace records highlighting each occurrence of the instruction bx. Or you can press “Enter” to go to the next occurrence of the search term.
The data stream capture can be controlled and filtered by using tracepoints. μVision has three types of trace trigger commands:
They are selected from the context menu by right-clicking on a valid assembly instruction in the Disassembly window or a C source line:

When a TraceRun is encountered on an instruction while the program is running, ULINKpro will start collecting trace records. When a TraceSuspend is encountered, trace records collection will stop there. Everything in between these two will be collected. This includes all instructions through any branches, exceptions and interrupts. Sometimes there is some skid past the trigger point which is normal.
Setup the current application:
Blinky.c, set a breakpoint near line 46: EventStartA(11);. Run (F5) the application. Once it hits the breakpoint, it stops.
 Run (F5) the application. Once it hits the breakpoint, it stops. Step (F11) once to enter the function
 Step (F11) once to enter the function EventRecord2.Setup the Trace Triggers:
EventRecorder.c, right click on the grey (or green) block opposite near line 1120.return ret;.
 Run (F5) the application and after a few seconds click
 Run (F5) the application and after a few seconds click  Stop.
 Stop.

TL and press “Enter” to display the two tracepoints:

TK* in the Command window and press “Enter” to delete all tracepoints.The trace triggers use the same CoreSight hardware as the Watchpoints . This means that it is possible a program counter skid might happen. The program might not start or stop on the exact location you set the trigger to. You might have to adjust the trigger point location to minimize this effect. This is because of the nature of the comparators in the CoreSight module and it is normal behavior.
Code Coverage tells what assembly instructions were executed. It is important to ensure all assembly code produced by the compiler is executed and tested. You do not want a bug or an unplanned circumstance to cause a sequence of untested instructions to be executed. The result could be catastrophic. Functional safety applications require Code Coverage for certification.
The µVision debugger provides Code Coverage with the FVP or via ETM using ULINKpro.
 Start a Debug Session (Ctrl+F5) to enter the µVision debugger.
 Start a Debug Session (Ctrl+F5) to enter the µVision debugger.if (g_ledSet) { (near line 56). Run (F5) the application. Once it hits the breakpoint, it stops. Remove the breakpoint.
 Run (F5) the application. Once it hits the breakpoint, it stops. Remove the breakpoint.
Color blocks indicate which assembly instructions have been executed:
 There is no assembly instruction here.
 There is no assembly instruction here. This assembly instruction was not executed.
 This assembly instruction was not executed. This assembly instruction was executed.
 This assembly instruction was executed. A Branch is never taken.
 A Branch is never taken. A Branch is always taken.
 A Branch is always taken. A Breakpoint is set here.
 A Breakpoint is set here. This points to the next instruction to be executed.
 This points to the next instruction to be executed.
Code Coverage is visible in both the Disassembly and source code windows. Click on a line in one window and this place will be matched in the other window.
A separate Code Coverage window is available that shows statistics.
 Go to View - Analysis Windows and select Code Coverage:
 Go to View - Analysis Windows and select Code Coverage:
In the
Command
window, you can show Code Coverage in many ways, for example, enter coverage \Blinky.c\main details:
You can copy and paste the result from the Command window by right-clicking into it. Save the data in a convenient format.
Code Coverage information is temporarily saved during a run and is displayed in various windows as shown. It is possible to save this information in an ASCII file for use in other programs. You can save Code Coverage data in two formats:
    
        
        
COVERAGE GCOV module
    
or
    
        
        
COVERAGE GCOV *
    
log command.
    
        
        
log > c:\cc\test.txt
    
Provides the data for log (you can also specify a module or function):
    
        
        
coverage asm
    
Turn the log function off:
    
        
        
log off
    
It is useful to optimize your code for speed. Performance Analyzer tells you how much time was spent in each function as well as the total number of total calls. A graphical display is generated for a quick reference. If you are optimizing for speed, work first on those functions taking the longest time to execute.
The µVision debugger provides Performance Analysis with the FVP (number of calls only) or via ETM using ULINKpro.
 Start a Debug Session (Ctrl+F5) to enter the µVision debugger.
 Start a Debug Session (Ctrl+F5) to enter the µVision debugger. Go to View - Analysis Windows and select Performance Analysis:
 Go to View - Analysis Windows and select Performance Analysis:
 Run (F5) yet!
 Run (F5) yet!main(). Run (F5) the application. The Performance Analyzer window updates in real-time:
 Run (F5) the application. The Performance Analyzer window updates in real-time:
 . Watch as new data is displayed in the window.
. Watch as new data is displayed in the window.Execution Profiling is used to display how much time a C source line took to execute and how many times it was called. This information is provided by the ETM trace in real time while the program keeps running.
The µVision debugger provides Execution Profiling with the FVP (number of calls only) or via ETM using ULINKpro.
 Start a Debug Session (Ctrl+F5) to enter the µVision debugger.
 Start a Debug Session (Ctrl+F5) to enter the µVision debugger. Run (F5) the application.
 Run (F5) the application.
At some places, there is an  Outlining sign that can be used to collapse a code section and to compress the associated source files together.
 Outlining sign that can be used to collapse a code section and to compress the associated source files together.
Blinky.c, click in the Outlining square near the while (1) { loop near line 46:
 to expand it.
 to expand it.Outlining can be useful to hide sections of code to simplify the window you are reading.
This part of the tutorial requires real hardware with ETM trace capabilities as the Traca Data window is not available for FVP models.
Some of the hardest problems to solve are those when a crash has occurred and you have no clue what caused this – you only know that it happened and the stack is corrupted or provides no useful clues.
Modern programs tend to be asynchronous with interrupts and RTOS thread switching plus unexpected and spurious events. Having a recording of the program flow is useful especially when a problem occurs and the consequences are not immediately visible. Another problem is detecting race conditions and determining how to fix them. ETM trace handles these problems and others easily and it is easy to use.
In this example, a hard fault occurs and the CPU ends up at 0x1A00_133A as shown in the Disassembly window (note that your address might not be the same as shown here):
This is the HardFault_Handler. This is a branch to itself and will run this instruction forever. The trace buffer will save millions of the same branch instructions, which is not very useful.
The hard fault handler exception vector is found in the startup file of your device. Set a breakpoint by clicking on the HardFault_Handler and run the program. At the next hard fault event, the CPU jumps to the HardFault_Handler and halts processing. The difference this time is the breakpoint will stop the CPU and also the trace collection. The trace buffer will be visible and is useful to investigate and determine the cause of the crash.
 start a Debug Session (Ctrl+F5) to enter the µVision debugger.
 start a Debug Session (Ctrl+F5) to enter the µVision debugger.HardFault_Handler in the startup_device.s/c file.
    
        
        
g, EventRecord2
    
This puts the PC at the start of this function. EventRecord2 returns with a POP instruction which you will use to create a hard fault with LR = 0. The assembly and sources in the Disassembly window do not always match up and this is caused by anomalies in ELF/DWARF specification. In general, scroll downwards in this window to provide the best match. clear trace icon. This helps to see what is happening.
 clear trace icon. This helps to see what is happening.R14 (LR) register and set it to '0'. This will cause a hard fault when the processor places LR = 0 into the PC and tries to execute the non-existent instruction at memory location 0x0. Run (F5) the application and almost immediately it will stop on the hard fault exception branch instruction.
 Run (F5) the application and almost immediately it will stop on the hard fault exception branch instruction.EventRecord2 function with the POP instruction at the end. When the function tried to return, the bogus value of LR caused a hard fault.B instruction at the hard fault vector was not executed because CoreSight hardware breakpoints do not execute the instruction they are set to when they stop the program. They are no-skid breakpoints. Step (F11) once. You will now see the hard fault branch as shown in the bottom screen:
 Step (F11) once. You will now see the hard fault branch as shown in the bottom screen:
This example clearly shows how quickly ETM trace can help debug program flow bugs.
Instead of setting a breakpoint on the hard fault vector, you could also right-click on it and select Insert Tracepoint and select TraceHalt. When hard fault is reached, trace collection will halt but the program will keep executing for testing and hard fault handlers.