Event Recorder  Version 1.0.0
MDK Debugger Views for Status and Event Information
 All Files Functions Macros Groups Pages
Examples

This documentation contains several example projects and *.scvd files. Projects are located in the folder \projects of this application note.

All example projects are based on an ARM Cortex-M3 processor and are configured to use the µVision simulator. Additional instructions have been added to the project descriptions.

The following example projects are available:

Example Project Description
Simple SCVD Example Simple example that shows how to display two variables in the Component Viewer.
Complex SCVD Example More complex Component Viewer example.
MyComponent SCVD Example Example showing Component Viewer and Event Recorder.

Use Pack Installer to copy the projects to your computer. Build the selected project and enter a debug session (all projects run in simulation - no hardware required).

Simple SCVD example

If you just want to display execution status information, you only require Component Viewer. Use the example project Simple SCVD Example as an introduction to the Component Viewer.

The example shows:

  • how a simple *.scvd file looks like
  • how to build a hierarchy in the output
  • the use of Format Specifiers

The output shows the values of two structure members (in HEX and decimal). The low member is an integer running from [0..30], while the hi member is the square of low. The output shows the values as decimal and HEX on different rows.

My1stViewer.png
Values of structure

Simple_View.scvd Code Example

The following code creates a type called "MyGeneralType" that emulates the program structure MyType defined in main.c. The object that is to be displayed searches for the symbol mysymbol and shows the items hi and low in the viewer window:

<component_viewer schemaVersion="0.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="Component_Viewer.xsd">
<component name="MyFirstComponent" version="0.0.1"/> <!-- name and version of the component -->
<typedefs>
<typedef name="MyGeneralType" info="This is MyType with 2 members" size="12">
<member name="hi" type="uint32_t" offset="0" info="member 'mysymbol.hi'"/>
<member name="low" type="uint32_t" offset="4" info="member 'mysymbol.low'"/>
</typedef>
</typedefs>
<objects>
<object name="MyFirstObject">
<read name="MyFirstSymbol" type="MyGeneralType" symbol="mysymbol" const="0"/>
<out name="My First Viewer"> <!-- Window name -->
<item property="Square of numbers [0..30]"> <!-- Property entry -->
<!-- These items extend the entry above -->
<item property="Hi [dec]" value="%d[MyFirstSymbol.hi]" info="Show decimal value of 'mysymbol.hi'"/>
<item property="Low [dec]" value="%d[MyFirstSymbol.low]" info="Show decimal value of 'mysymbol.low'"/>
<item property="Hi [hex]" value="%x[MyFirstSymbol.hi]" info="Show HEX value of 'mysymbol.hi'"/>
<item property="Low [hex]" value="%x[MyFirstSymbol.low]" info="Show HEX value of 'mysymbol.low'"/>
</item>
</out>
</object>
</objects>
</component_viewer>

The Simple_View.scvd file has been added to the project as described in Manage Component Viewer Description Files.

  1. Open the project "Simple SCVD Example" from Pack Installer (search for uVision Simulator in the Boards tab).
  2. Compile and run the application.
  3. Open the window View - Watch Windows - My First Viewer and watch the values change while the program runs.
My1stViewerMenu.png
Menu in View - Watch Windows

Complex SCVD example

Use the example project Complex SCVD Example for more advanced topics.

This example is more complex than Simple SCVD example and shows:

  • The use of Expressions and conditional computing for various XML elements
  • The use of the built-in variable _count
  • The use of readlist and list for looping through arrays

Complex_view.scvd Code Example

The example uses the structures TypeA, TypeG, and TypeArray defined in the project and creates a static output showing initial member values and characteristics:

<component_viewer schemaVersion="0.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="Component_Viewer.xsd">
<component name="MyView2" version="0.0.1"/> <!-- name and version of the component -->
<typedefs>
<typedef name="XML_TypeA" size="12">
<member name="Nummer" type="uint32_t" offset="0" />
<member name="Status" type="uint32_t" offset="4" />
<member name="Size" type="uint32_t" offset="8" />
</typedef>
<typedef name="XML_TypeG" size="16">
<member name="Nummer" type="uint32_t" offset="0" />
<member name="Cluster" type="uint32_t" offset="4" />
<member name="ClusterSize" type="uint32_t" offset="8" />
<member name="Status" type="uint32_t" offset="12" />
<var name="TotalSize" type="uint64_t" info="calculated as: Cluster*ClusterSize"/>
</typedef>
<typedef name="XML_TypeArray" size="8">
<member name="type_ref" type="uint32_t" offset="0" info="Pointer to TypeA or TypeG" />
<member name="id0" type="uint8_t" size="2" offset="4" info="Type ID" />
<member name="id1" type="uint8_t" offset="5" info="Type ID" />
<member name="attr" type="uint8_t" offset="6" info="Type Attribute"/>
<var name="idx" type="uint32_t" info="calculated index in TypeX array" />
</typedef>
</typedefs>
<objects>
<object name="ListOfArrayTypes">
<var name="i" type="int32_t" value="0" /> <!-- variable for loops -->
<var name="j" type="int32_t" value="0" /> <!-- variable for loops -->
<readlist name="TypeA" type="XML_TypeA" />
<readlist name="TypeG" type="XML_TypeG" />
<readlist name="TArray" type="XML_TypeArray" symbol="type_array" count="5" />
<list name="i" start="0" limit="TArray._count"> <!-- for(i=0;i<TArray._count;i++) -->
<calc cond="TArray[i].attr==1">
TArray[i].idx=TypeA._count;
</calc>
<readlist cond="TArray[i].attr==1" name="TypeA" type="XML_TypeA" offset="TArray[i].type_ref" />
<calc cond="TArray[i].attr==2">
TArray[i].idx=TypeG._count;
</calc>
<readlist cond="TArray[i].attr==2" name="TypeG" type="XML_TypeG" offset="TArray[i].type_ref" />
</list>
<list name="i" start="0" limit="TypeG._count"> <!-- for(;;) -->
<calc>
TypeG[i].TotalSize = TypeG[i].Cluster * TypeG[i].ClusterSize;
</calc>
<calc>
j=TArray._count;
</calc>
</list>
<out name="Array and Structure Types"> <!-- name of window and menu entry -->
<!-- create output with two hierarchies -->
<item property="Array Identifiers"> <!-- the 'header' with sub entries -->
<list name="i" start="0" limit="TArray._count"> <!-- for(;;) -->
<item property="Data in TArray[%d[i]].id is:" value="%t[TArray[i].id0]" />
</list>
</item>
<item property="" value="" /> <!-- output empty line -->
<!-- create output with two and three hierarchies -->
<list name="i" start="0" limit="TArray._count"> <!-- for(;;) -->
<!-- two hierarchies for TypeA structure -->
<item cond="TArray[i].attr==1" property="Type A%d[TArray[i].id1-0x30]:" value="Memory address (type_ref) = %x[TArray[i].type_ref] idx=%d[TArray[i].idx]" >
<item property="Type A, size=%d[TypeA[TArray[i].idx].Size]" value="Num=%x[TypeA[TArray[i].idx].Nummer] Status=%x[TypeA[TArray[i].idx].Status]" />
</item>
<!-- three hierarchies for TypeG structure -->
<item cond="TArray[i].attr==2" property="Type G%d[TArray[i].id1-0x30]:" value="Memory address (type_ref) = %x[TArray[i].type_ref] idx=%d[TArray[i].idx]" >
<item property="Type G, Total size=%d[TypeG[TArray[i].idx].TotalSize]" value="Num=%x[TypeG[TArray[i].idx].Nummer] Status=%x[TypeG[TArray[i].idx].Status]" >
<item property="Cluster" value="n=%x[TypeG[TArray[i].idx].Cluster] Size=%x[TypeG[TArray[i].idx].ClusterSize]" />
</item>
</item>
</list>
<item property="" value="------ Types ------" /> <!-- output line with empty property but text in 'Value' column -->
<list name="i" start="0" limit="TypeA._count"> <!-- for(i=0;i<_count;i++) -->
<item property="Type A%d[i]" value="Num=%x[TypeA[i].Nummer], Size=%x[TypeA[i].Size]" />
</list>
<list name="i" start="0" limit="TypeG._count">
<item property="Type G%d[i]" value="Num=%x[TypeG[i].Nummer], Total size=%x[TypeG[i].TotalSize]" />
</list>
</out>
</object>
</objects>
</component_viewer>
  1. Open the project "Complex SCVD Example" from Pack Installer (search for uVision Simulator in the Boards tab).
  2. Compile and run the application
  3. Open the window View - Watch Windows - Array and Structure Types and verify the output
My2ndViewer.png
Array and Structure Types

MyComponent SCVD Example

MyComponent implements a data transfer using the functions MyComp_initialize, MyComp_send, and MyComp_receive. During operation, the component calls event functions that provide event data for recording by the Event Recorder.

This example shows how to:

Add Event Annotations

It is possible to add Event Annotations pragmatical as explained in the section Using Event Recorder. However, for more complex software components, it makes sense to use a structured approach as described in the following.

Event annotation should deliver meaningful information about the dynamic execution of a software component and can be grouped into the following categories using level information in the EventID.

  • EventLevelError indicates when an event relates to run-time errors in the component.
  • EventLevelAPI should be used when an event relates to API function calls.
  • EventLevelOp refers to events that related to internal operations.
  • EventLevelDetail allows to provided events with additional detailed information of operations.

Instead of using the general purpose Event Data Recording functions, specify component specific functions that can be tagged with an EventID. These component specific functions are calling then the Event Data Recording functions.

The event recorder functions for the MyComponent software component are using severity level information in their EventIDs (refer to the file EvrMyComponent.h in the example project):

#define EvtMyCo_No 0x0A /// < Number of the component with short name 'EvtMyCo_No'
// Event id list for "MyComponent"
#define EvtMyCo_InitEntry EventID (EventLevelAPI, EvtMyCo_No, 0x00)
#define EvtMyCo_InitStatus EventID (EventLevelAPI, EvtMyCo_No, 0x01)
#define EvtMyCo_SendNoData EventID (EventLevelError, EvtMyCo_No, 0x0A)
#define EvtMyCo_SendComplete EventID (EventLevelOp, EvtMyCo_No, 0x0B)
#define EvtMyCo_SendFailed EventID (EventLevelError, EvtMyCo_No, 0x0C)
#define EvtMyCo_ReceiveNoData EventID (EventLevelError, EvtMyCo_No, 0x15)
#define EvtMyCo_ReceiveComplete EventID (EventLevelAPI, EvtMyCo_No, 0x16)
#define EvtMyCo_ReceiveFailed EventID (EventLevelError, EvtMyCo_No, 0x17)

The EventID also contains information about the component number (to identify the event) and the specific message number that is used to display additional information in the Event Recorder window.

Create an SCVD file

The SCVD file for MyComponent uses this message number information to display the correct messages in Event Recorder.

<!-- event list for MyComponent -->
<events>
<group>
<component name="MyComponent" brief="MyCo" no="0x0A" prefix="EvrMyCo_" info="My Component - Demo example"/>
</group>
<event id="0xA00" level="API" property="InitEntry" info="Event on MyComp_initialize start"/>
<event id="0xA01" level="API" property="InitStatus" info="Event on MyComp_initialize return"/>
<event id="0xA0A" level="Error" property="SendNoData" info="Event on MyComp_initialize return"/>
<event id="0xA0B" level="Op" property="SendComplete" value="size=%d[val1]" info="Event on MyComp_send - completed"/>
<event id="0xA0C" level="Error" property="SendFailed" value="" info="Event on MyComp_send - send failed"/>
<event id="0xA15" level="Error" property="ReceiveNoData" value="" info="Event on MyComp_receive - no data received"/>
<event id="0xA16" level="Op" property="ReceiveComplete" value="size=%d[val1]" info="Event on MyComp_receive - completed"/>
<event id="0xA17" level="Error" property="ReceiveFailed" value="" info="Event on MyComp_receive - receive failed"/>
</events>
MyComponentEvents_withAnnotations.png
Event Recorder displaying the event annotations

Generate documentation

Software components are frequently a black-box to the application programmer and event annotations need additional descriptions that interlinks with API related documentation.

Doxygen is frequently used to generate API documentation. Using this approach, event annotations can be documented in a similar way. Once the software component is framed as a CMSIS-Pack, the documentation for event annotations opens using hyperlinks in the Event Recorder.

A full documentation of the software component is available in the software pack that is built in the next step. You will find the Doxygen source code in ./SCVD_Examples/MyComponent/Doxygen. Run the script gen_doc.bat to create the documentation.

Create a pack

CMSIS-Pack describes a mechanism to deliver software components, device parameters, and evaluation board support. The XML-based package description file (PDSC) describes the content of a software pack (file collection) that may include:

  • Source code, header files, and software libraries
  • Documentation and source code templates
  • Device parameters along with startup code and programming algorithms
  • Example projects

For the software component "MyComponent", as pack is available in the directory ./SCVD_Examples/MyComponent_Pack. Double-click MyVendor.MyComponent.1.0.0.pack to install it on your system. It contains one software component called :MyVendor:MyComponent with related documentation.

mycomponent.png
MyComponent in the Manage Run-time Environment window

The PDSC file is very simple. It declares a single software component that comes with source files, SCVD and HTML documentation:

<component Cclass="MyVendor" Cgroup="MyComponent" Cversion="1.0.0" condition="Cortex-M Device">
<description>MyComponent software component example</description>
<files>
<file category="header" name="Source/MyComponent.h"/>
<file category="source" name="Source/MyComponent.c"/>
<file category="doc" name="html/index.html"/>
<file category="other" name="Source/MyComponent.scvd"/>
</files>
</component>

An example project called "MyComponent Pack Example" is also part of the pack. It is basically the same example as MyComponent SCVD Example, only that it is using the "MyComponent" software component.

If you build and run the example, you will see that the events that are recorded now contain hyperlinks that bring up the related documentation.

er_doxygen_links.png
Event recorder links to related documentation

With this, you can create re-usable software components that can be equipped with Event Recorder information and related documentation. This is useful if you intend to share the software component within your company or with third parties.