FreeRTOS Task Runtime Statistics for NXP i.MX RT1064

FreeRTOS has many cool features, and one is that it can report the CPU percentage spent in each task. The downside is that to get this kind of information some extra work is needed. In this article I show how to do this for the NXP i.MX1064.

FreeRTOS Runtime Information

FreeRTOS Runtime Information

Outline

In “Tutorial: Using Runtime Statistics with Amazon FreeRTOS V10” I described the approach how to measure task runtime and execution time. Basically the RTOS needs an extra timer to measure task execution time. This timer value is checked at task context switch time and stored in the task control block information section. With little overhead the RTOS knows how the time is spent between the tasks (this does not separate out time spent in interrupts).

In this article I show how this can be accomplished using the NXP i.MXRT1064 EVK board. The example project used in this article is available on GitHub.

i.MX RT1064-EVK Board Top Side

i.MX RT1064-EVK Board Top Side

Configuring the RTOS

To collect the runtime information, it is necessary to configure a few #defines in FreeRTOSConfig.h:

First configure to collect runtime statistics:

 
#define configGENERATE_RUN_TIME_STATS           1 /* 1: generate runtime statistics; 0: no runtime statistics */

It is possible to use the Systick timer, but this will not give us precise results, so we disable that one:

 
#define configGENERATE_RUN_TIME_STATS_USE_TICKS 0 /* 1: Use the RTOS tick counter as runtime counter. 0: use extra timer */

Next we need to configure how to use the timer: For this we specify the name of a timer configuration function and a function to get the timer value:

#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()   McuRTOS_AppConfigureTimerForRuntimeStats()
#define portGET_RUN_TIME_COUNTER_VALUE()           McuRTOS_AppGetRuntimeCounterValueFromISR()

I’m going with the default Implementation in the McuRTOS module which already covers the basics. That’s it.

The next step is to implement Initialize the timer and implement the ISR for it.

Initializing Timer Functions

💡 I could overwrite the McuRTOS_AppConfigureTimerForRuntimeStats() instead of doing a local AppConfigureTimerForRuntimeStats(). I prefer the local variant because this means less work.

First we need to include the needed driver for the driver. I’m going to use the GPT (General Purpose Timer) of the i.MX RT:

 
#include "fsl_gpt.h"

Next I need a 32bit counter which is used to measure the time:

 
uint32_t McuRTOS_RunTimeCounter; /* runtime counter, used for configGENERATE_RUNTIME_STATS */

Next I configure the timer to 0.1 ms (10 times the frequency of the RTOS tick timer which is set to 1 kHz:

static void AppConfigureTimerForRuntimeStats(void) {
  uint32_t gptFreq;
  gpt_config_t gptConfig;

  GPT_GetDefaultConfig(&gptConfig);

  /* Initialize GPT module */
  GPT_Init(GPT2, &gptConfig);

  /* Divide GPT clock source frequency by 3 inside GPT module */
  GPT_SetClockDivider(GPT2, 3);

  /* Get GPT clock frequency */
  gptFreq = CLOCK_GetFreq(kCLOCK_PerClk);

  /* GPT frequency is divided by 3 inside module */
  gptFreq /= 3;

  /* Set GPT module to 10x of the FreeRTOS tick counter */
  gptFreq = USEC_TO_COUNT(100, gptFreq); /* FreeRTOS tick is 1 kHz */
  GPT_SetOutputCompareValue(GPT2, kGPT_OutputCompare_Channel1, gptFreq);

  /* Enable GPT Output Compare1 interrupt */
  GPT_EnableInterrupts(GPT2, kGPT_OutputCompare1InterruptEnable);

  /* Enable at the Interrupt and start timer */
  EnableIRQ(GPT2_IRQn);
  GPT_StartTimer(GPT2);
}

Next the implementation of the timer interrupt service routine. Here the counter gets incrememented:

 
void GPT2_IRQHandler(void) {
  /* Clear interrupt flag.*/
  GPT_ClearStatusFlags(GPT2, kGPT_OutputCompare1Flag);
  McuRTOS_RunTimeCounter++; /* increment runtime counter */
#if defined __CORTEX_M && (__CORTEX_M == 4U || __CORTEX_M == 7U)
  __DSB();
#endif
}

Finally I have to call the Timer initialization function, for example just before starting the scheduler:

Initializing Timer

Initializing Timer

That’s it! Now the RTOS is collecting runtime information.

Getting the Information

The information is displayed in the ‘Runtime’ column of the FreeRTOS Tasklist in Eclipse (shown for MCUXpresso IDE):

Runtime Information in MCUXpresso IDE

Runtime Information in MCUXpresso IDE

Using a serial connection (UART, USB, SEGGER RTT) the same information can be retrieved using a command line interface too, no debug connection needed:

FreeRTOS Tasklist in Console

FreeRTOS Tasklist in Console

Summary

Collecting runtime information in FreeRTOS usually requires a timer (the SysTick can be used too). The collected information gives a good overview about where CPU time is spent so can help to check the system load.

Happy Runtiming 🙂

Links

11 thoughts on “FreeRTOS Task Runtime Statistics for NXP i.MX RT1064

  1. One thing I’ve been meaning to try to add is an elapsed idle time counter for each task. Would be nice to be able to see how long a task has been blocked. Seems like it ought to be easy enough, just haven’t had a chance to work on it.

    Like

    • Is this not already provided? I mean if a task is using x% of the CPU time, it has been blocked (100-x)% by other tasks. Means if a task shows 20% usage in the Runtime, it has been blocked 80%.
      Or are you thinking about something different?

      Like

        • hmm, the data is there: how many ticks (time) the system is running, and the precentage (or number of ticks) each task is running (or have been blocked).
          So it really would be about to present it somehow?

          Like

        • I’m not looking for a total, just the number of ticks elapsed since the current blocking event began.If the hooks are there for the transitions it should be easy, I just haven’t looked at it closely.

          Something like my network task will normally have a very small percentage of the runtime. Seeing how long the task has been blocked would let me see if it’s actually inactive or not.

          Like

  2. Hello Erich, I saw that you wrote the FreeRTOS port to the i.MX-RT1050 processor. I am trying to port Lib Metal onto that processor and I was wondering if you have any advice on how to achieve this or where the best place would be to get sources on this?

    Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.