Debugging Synergy Applications: Using printf with the ITM

In the last post, we saw how we could setup the Renesas Synergy™ toolchain to transmit character data over the ITM. This is useful but it would be far more effective if a developer could redirect printf to output directly to the ARM CoreSight ITM Live Trace Console. In this post, we will do exactly that!

The first step to redirecting printf is to decide the best way to go about doing so. In an Eclipse based IDE, a developer normally has several options such as writing a fputc function or as we are going to do, creating a _write function. e2 Studio uses the nanolib library for its printf implementation which can have its behavior overwritten by creating the following function with the following prototype:

int _write(int file, char *ptr, int len);

All that a developer needs to do is create a function that uses this definition and uses ITM_SendChar in order to redirect printf to the ITM. The function does nothing more than process a character buffer pointed to by ptr that has length len. The code can be found below:

int _write(int file, char *ptr, int len)

{

  int i=0;

  (void)file;

  for(i=0 ; i<len ; i++)

  {

    ITM_SendChar((uint32_t)(*ptr++));

  }

  return len;

}

Once this code is added, all printf statements are redirected to the ITM. For example, an application that turns an LED on and then off might output debug information to tell the developer the LED state. Using the printf statements, a developer would see the following on their ARM CoreSight ITM Live Trace Console:

The code used to print these statements to the console were the following:

printf(“LED Off!”);

printf(“LED On!”);

That simple!

The great part about using the ITM is that it is extremely fast! Below is a quick measurement that shows how long it took to transmit the “LED Off!” message:

Notice that it took approximately 5 microseconds! This is far faster than a UART or Semi-Hosting can provide! The transfer time is also dependent on the debugger that is being used. This debugger was the J-Link onboard. Using an external debugger such as a J-Link Pro or J-Link Ultra+ would undoubtedly get the transfer to under a microsecond.

One additional useful feature about the ARM CoreSight ITM Live Trace Console is that all the trace data is automatically saved when the debug sessions closes. The traces are stored in the project under a trace folder and can be opened to view the recorded data. An example can be seen below:

With the data stored, a developer can further analyze their system to determine how it is behaving and find root causes to system issues.

In most instances, a developer will just want to use the ITM stimulus port 0 using printf. However, if a developer wants to have a generic function that they can use to write a character to the ITM, they will have to create one themselves. This will involve the following several steps:

  • Create an ITM function that takes a character and the port as a parameter
  • Create a custom printf function, such as printf_itm that also includes the itm port

These aren’t necessarily hard things to do. For example, the ITM function could be based on the ITM_SendChar function located in core_cm4.h which can be seen below:

__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch)

{

  if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) &&      /* ITM enabled */

      ((ITM->TER & 1UL               ) != 0UL)   )     /* ITM Port #0 enabled */

  {

    while (ITM->PORT[0].u32 == 0UL) { __NOP(); }

    ITM->PORT[0].u8 = (uint8_t)ch;

  }

  return (ch);

}

A developer would start by copying this function and renaming it to ITM_SendCharPort. The important modifications to this function would be to:

  • Add the ITM port as parameter to the function
  • Perform a check that the specified port is less than 32
  • Modify the check for ITM->TER & 1UL to shift the 1UL based on the port that was specified (this just makes sure that the ITM port is enabled in hardware)
  • Modify all ITM->PORT[0] accesses so that 0 is replaced by the port variable

Once these things are done, a developer will have an ITM function that is generic and can easily be used to transmit debugging information to any ITM Stimulus port.

In the next post, we’ll move on from the ITM and start examining more advanced techniques such as statistical profiling, RTOS aware debugging and deep insight analysis.

Until next time,

Live long and profit!

Professor_IoT

 

Hot Tip of the WeekLast week’s post on “Getting Started with the ITM” as well as this week’s post use an example design to demonstrate the use of the ITM_SendChar function. This example program is now available on the Renesas Synergy Knowledge Base. You can find it here: https://knowledgebase.renesas.com/English_Content/Renesas_Synergy™_Platform/Renesas_Synergy_Knowledge_Base/Where_can_I_find_the_example_project_used_in_the_Prof_IoT_article_on_the_ITM%3F

Simply import the zip file and try it out!