Mbed, RTX5 and µVision Event Recorder

CMSIS5 contains a new RTOS, a.k.a. RTOS2 or RTX5. Since Mbed OS 5.5 this is also included into Mbed.

Part of RTX5 is an interface to an Event Recorder. This provides information to analyse the behaviour of the RTOS function. And it is possible to define and use own events. The MDK libraries uses this event system in different components beside the RTX5, e.g. in filesystem and USB components. The code at the MCU side need so few resources that it can stay in release code, as described in the documentation.

Please see the Keil documentation here:

and here:

Additionally, a YouTube tutorial exists:

and an application note, which describes among other the usage of the Event Recorder:

It is also possible to use the event system with Mbed OS 5. Currently, the Keil µVision IDE is the only known tool which has an Event Recorder, i.e. the PC side of the event system. Three files are necessary. They are part of the Keil MDK Component library and can be copied from there:

  • EventRecorderConf.h
  • EventRecorder.c
  • EventRecorder.h

For the event system configuration in EventRecorderConf.h, please see the above documentation or the YouTube tutorial.

In EventRorder.c it is necessary to change the include section from:

/*------------------------------------------------------------------------------
 * MDK - Component ::Event Recorder
 * Copyright (c) 2016 ARM Germany GmbH. All rights reserved.
 *------------------------------------------------------------------------------
 * Name:    EventRecorder.c
 * Purpose: Event Recorder for Debug Messages
 * Rev.:    V1.2.0-Beta
 *----------------------------------------------------------------------------*/
 
#include "RTE_Components.h"
#include CMSIS_device_header

to

/*------------------------------------------------------------------------------
 * MDK - Component ::Event Recorder
 * Copyright (c) 2016 ARM Germany GmbH. All rights reserved.
 *------------------------------------------------------------------------------
 * Name:    EventRecorder.c
 * Purpose: Event Recorder for Debug Messages
 * Rev.:    V1.2.0-Beta
 *----------------------------------------------------------------------------*/

#include "cmsis.h"

To start the recording of events, it is necessary to call:

EventRecorderInitialize(EventRecordAll, 1);

This should be done before the RTOS kernel is started, i.e. before:

osKernelInitialize ();

to be able to record the complete kernel initialization.

In Mbed a hook method for user code, which is called before the kernel initialization, does not exit. Therefore, the easiest possibility is calling the event record initialisation at the begin of main:

int main() {
  EventRecorderInitialize(EventRecordAll, 1);

  thread1.start(callback(blink1));
  thread2.start(callback(blink2));
  while(true) {
    thread1.signal_set(0x1);
    Thread::wait(500);		
    thread2.signal_set(0x1);
    Thread::wait(500);
  }
  Thread::wait(osWaitForever);
}

Resulting in: /media/uploads/ohagendorf/image2.png

A better method is adding a code line at the end of mbed_sdk_init() in mbed_overrides.c (here in TARGET_STM):

// This function is called after RAM initialization and before main.
void mbed_sdk_init()
{
    // Update the SystemCoreClock variable.
    SystemCoreClockUpdate();
    HAL_Init();

#if TARGET_STM32F7
    // Enable CPU L1-Cache
    SCB_EnableICache();
    SCB_EnableDCache();
#endif /* TARGET_STM32F7 */

    /* Configure the System clock source, PLL Multiplier and Divider factors,
       AHB/APBx prescalers and Flash settings */
    SetSysClock();
    SystemCoreClockUpdate();
	
    EventRecorderInitialize(EventRecordAll, 1);
}

plus an

#include "EventRecorder.h"

in the include section of mbed_overrides.c.

This results in: /media/uploads/ohagendorf/image1.png

The first user message in variant 1 has number 30 but in variant 2 number 121. The difference between both variants are ca. 90 events, everything from the kernel and Mbed OS initialization is missing in the 1st variant.

The example used for both event record listings is the following blinky code:

#include "mbed.h"
#include "EventRecorder.h"

Thread thread1;
Thread thread2;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
	
// Blink function toggles the led in a long running loop
void blink1() {
  while (true) {
    led1 = !led1;
    EventRecord2(0xA501, led1.read(), 0);
    wait(1);
  }
}
void blink2() {
  while (true) {
    led2 = !led2;
    EventRecord2(0xA502, led2.read(), 0);
    wait(1);
  }
}

// Spawns a thread to run blink for 5 seconds
int main() {
//  EventRecorderInitialize(EventRecordAll, 1);

	thread1.start(callback(blink1));
	Thread::wait(0.5);
	thread2.start(callback(blink2));
  Thread::wait(osWaitForever);
}

The project can be built as described in the Mbed documentation. The above mentioned three files has to be added and one variant of calling EventRecorderInitialize.

Additionally a few project options has to be configured:

  • Two defines are necessary: RTE_Compiler_EventRecorder, RTE_Compiler_EventRecorder_DAP

  • The correct system core clock has to be set. This number is used by the Event Recorder view in µVision for calculating the event time column.

To show event names instead of event id, Keil delivers scvd files for the various components. To transform RTX5 event ids and values, the file RTX5.scvd is needed. For user events, an own svcd file can be written. The above example uses the following:

<?xml version="1.0" encoding="utf-8"?>

<component_viewer schemaVersion="0.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="Component_Viewer.xsd">

<component name="myBlinky" version="1.0.0"/>       <!--name and version of the component-->
  <events>
    <group name="Blinky">
      <component name="myBlinky" brief="Blinky event" no="0xA5" info="myInfo"/>
    </group>

    <event id="0xA501" level="API" property="LED1 state" value="value=%d[val1]"></event>
    <event id="0xA502" level="API" property="LED2 state" value="value=%d[val1]"></event>
  </events>
</component_viewer>

How to write these files can be read in the above mentioned documentation or seen in the YouTube tutorial.

These files has to be added to the Options for Target dialog at the Debug register card:

Additional tools based on the event system exists, e.g. Traceanalyzer for Keil RTX5 from percepio: https://percepio.com/tz/keil-rtx5/

With the described example and project configuration, this tool can be used: /media/uploads/ohagendorf/image6.png

Unfortunately, through the callback interface of the Thread class, each Thread has only the name _thunk. Traceanalyzer uses the name of the thread method. In Mbed OS the real method is hidden within the callback instance behind the _thunk method. That’s why every thread in Traceanalyzer gets the name _thunk in comparison to clear names in an ‘handwritten’ CMSIS example: /media/uploads/ohagendorf/image7.png


Please log in to post comments.