Tutorial: FreeRTOS with NXP Kinetis SDK V2.0 and Processor Expert

In “Tutorial: Blinky with NXP Kinetis SDK V2.0 and Processor Expert” I used Processor Expert components with the NXP Kinetis SDK to blink some LEDs. This tutorial extends the earlier project and adds FreeRTOS.

FreeRTOS running on a NXP FRDM-K22F Board

FreeRTOS running on a NXP FRDM-K22F Board

Outline

In this tutorial I show how to add FreeRTOS to the ‘Mother’ Processor Expert project and to add a ‘blinky’ task with FreeRTOS. I’m using the Kinetis SDK V2.0 for the NXP FRDM-K22F board with the Eclipse based Kinetis Design Studio V3.2.0. As application a ‘blinky’ task is added to the project.

FreeRTOS Component

Adding FreeRTOS with components is very easy: simply add the McuOnEclipse FreeRTOS component to the mother project:

FreeRTOS added

FreeRTOS added

Check the ARM Family/core selection in the FreeRTOS component to match the microcontroller used:

ARM Core Family Selection

ARM Core Family Selection

For an SDK project, I have to enable the SDK option in the FreeRTOS settings:

Enabled SDK in FreeRTOS

Enabled SDK in FreeRTOS

With this code can be generated by Processor Expert and used in the Kinetis SDK project. This is the topic of the next steps.

FreeRTOS Hooks

Because the component has hooks enabled, I add the following lines to main.c: they add empty/default RTOS hooks for when I have them enabled in FreeRTOSConfig.h.

#include "FreeRTOS.h"
#include "FRTOS1.h"
void FRTOS1_vApplicationStackOverflowHook(xTaskHandle pxTask, char *pcTaskName) {
/* This will get called if a stack overflow is detected during the context
   switch.  Set configCHECK_FOR_STACK_OVERFLOWS to 2 to also check for stack
   problems within nested interrupts, but only do this for debug purposes as
   it will increase the context switch time. */
  (void)pxTask;
  (void)pcTaskName;
  taskDISABLE_INTERRUPTS();
  /* Write your code here ... */
  for(;;) {}
}

void FRTOS1_vApplicationTickHook(void) {
  /* Called for every RTOS tick. */
  /* Write your code here ... */
}

void FRTOS1_vApplicationIdleHook(void) {
  /* Called whenever the RTOS is idle (from the IDLE task).
     Here would be a good place to put the CPU into low power mode. */
  /* Write your code here ... */
}

void FRTOS1_vApplicationMallocFailedHook(void) {
  /* Called if a call to pvPortMalloc() fails because there is insufficient
     free memory available in the FreeRTOS heap.  pvPortMalloc() is called
     internally by FreeRTOS API functions that create tasks, queues, software
     timers, and semaphores.  The size of the FreeRTOS heap is set by the
     configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */
  taskDISABLE_INTERRUPTS();
  /* Write your code here ... */
  for(;;) {}
}

Like any other component, I initialize the component in main() first with:

NEW version

Next I add the code to create a task into main() followed by starting the scheduler:

  FRTOS1_Init();
  if (xTaskCreate(AppTask, "App", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+1, NULL) != pdPASS) {
    for(;;){} /* error */
  }
  vTaskStartScheduler();

Finally, the code for the blinky application task gets added:

static void AppTask(void *pvParameters) {
  (void)pvParameters;
  for(;;) {
    LED1_Neg();
    vTaskDelay(pdMS_TO_TICKS(100));
  }
}

Below is the full source code of main.c:

/*
 * Copyright (c) 2013 - 2016, Freescale Semiconductor, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 * of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 * list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.
 *
 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * This is template for main module created by New Kinetis SDK 2.x Project Wizard. Enjoy!
 **/

#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"

#include "LED1.h"
#include "LED2.h"
#include "LED3.h"
#include "WAIT1.h"
#include "fsl_port.h"

#define USE_FREERTOS 1 /* turns on using FreeRTOS */

#if USE_FREERTOS
#include "FreeRTOS.h"
#include "FRTOS1.h"

void FRTOS1_vApplicationStackOverflowHook(xTaskHandle pxTask, char *pcTaskName) {
 /* This will get called if a stack overflow is detected during the context
 switch. Set configCHECK_FOR_STACK_OVERFLOWS to 2 to also check for stack
 problems within nested interrupts, but only do this for debug purposes as
 it will increase the context switch time. */
 (void)pxTask;
 (void)pcTaskName;
 taskDISABLE_INTERRUPTS();
 /* Write your code here ... */
 for(;;) {}
}

void FRTOS1_vApplicationTickHook(void) {
 /* Called for every RTOS tick. */
 /* Write your code here ... */
}

void FRTOS1_vApplicationIdleHook(void) {
 /* Called whenever the RTOS is idle (from the IDLE task).
 Here would be a good place to put the CPU into low power mode. */
 /* Write your code here ... */
}

void FRTOS1_vApplicationMallocFailedHook(void)
{
 /* Called if a call to pvPortMalloc() fails because there is insufficient
 free memory available in the FreeRTOS heap. pvPortMalloc() is called
 internally by FreeRTOS API functions that create tasks, queues, software
 timers, and semaphores. The size of the FreeRTOS heap is set by the
 configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */
 taskDISABLE_INTERRUPTS();
 /* Write your code here ... */
 for(;;) {}
}
#endif

static void AppTask(void *pvParameters) {
 (void)pvParameters;
 for(;;) {
 LED1_Neg();
 vTaskDelay(pdMS_TO_TICKS(100));
 }
}

/*!
 * @brief Application entry point.
 */

int main(void) {
 /* Init board hardware. */
 BOARD_InitPins();
 BOARD_BootClockRUN();
 BOARD_InitDebugConsole();

 /* init components */
 LED1_Init();
 LED2_Init();
 LED3_Init();

 /* run the code */
#if USE_FREERTOS
 FRTOS1_Init();
 if (xTaskCreate(AppTask, "App", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+1, NULL) != pdPASS) {
 for(;;){} /* error */
 }
 vTaskStartScheduler();
#else
 for(;;) {
#if 0
 LED1_Neg();
 LED2_Neg();
 LED3_Neg();
#else
 LED1_On(); WAIT1_Waitms(500); LED1_Off();
 LED2_On(); WAIT1_Waitms(500); LED2_Off();
 LED3_On(); WAIT1_Waitms(500); LED3_Off();
#endif
 }
#endif

 for(;;) { /* Infinite loop to avoid leaving the main function */
 __asm("NOP"); /* something to use as a breakpoint stop while looping */
 }
}

Compile/build and debug that project, and you should have a blinky with FreeRTOS:

FreeRTOS running on a NXP FRDM-K22F Board

FreeRTOS running on a NXP FRDM-K22F Board

Summary

With this approach I have now an easy way to add FreeRTOS with a Processor Expert component to the Kinetis SDK V2.0. FreeRTOS is already included in the Kinetis SDK, but the Processor Expert component gives me a graphical configuration plus includes all the great extensions e.g. for tickless idle low power mode, Segger SystemView or Percepio Tracealizer.

The project and source files are available on GitHub (see ‘Links’ below).

Happy RTOSing 🙂

Links

Advertisements

14 thoughts on “Tutorial: FreeRTOS with NXP Kinetis SDK V2.0 and Processor Expert

  1. Pingback: Hexiwear: Teardown of the Hackable ‘Do-Anything’ Device | MCU on Eclipse

  2. I’m having issues with the initialization of the debug UART. Everything seems to work fine, except that the task to print to the console runs before the UART can complete it’s set up. The print task appears to run as soon as the task manager start, before the UART finishes. If I add a vTaskDelay(1) to the task everything works fine, but this seems like a band-aid. What am aI doing wrong?

    Like

    • Hi Grant,
      you should do any initialization before you run the tasks. If you want to do the initialization inside a task, then either use a semaphore to hold back any other task using it. Or give the initialization task temporarily a higher priority (so it runs first in a preemptive scheduler). Or you initialize things first in a task, and then create the other tasks from that task.
      There are many ways, but the usual way is to perform any static initialization before running the scheduler. Note that before running the scheduler interrupts are disabled, so if you need to initialize something using interrupts (e.g. an interrupt based driver), then you have to do it from a task context as written above.

      I hope this helps,
      Erich

      Like

      • Initialization the peripherals inside a task worked so I added the other tasks to the end of that init task and everything seems to work well. Thank you Erich. I may have more questions in the future.

        Like

      • Erich,
        I noticed that the registers for the UART and the ADC are not initialized after the return from the RTOS start macro…
        #ifdef PEX_RTOS_START
        PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
        #endif)

        I needed add a vTaskDelay(1) to allow for the initialization to complete. Is this something you’ve run across?

        ~Grant

        Like

      • If you are using an RTOS like FreeRTOS, then PEX_RTOS_START() starts the scheduler, and the scheduler is supposed not to end. Do you terminate/end the scheduler in your application? That sounds like a non-usual use case?
        The UART and ADC shall be intialized inside PE_low_level_init() if you are using components for it.

        Like

      • I moved PEX_RTOS START() into a task, per our earlier conversation, so I disabled the scheduler start in PEX_RTOS_START(). The UART and ADC are being set up in PE_low_level_init, but the registers are not being initialized until later. It looks like the registers are being initialized by calls made in cpu.c Components_Init(void).

        Like

      • PEX_RTOS_START() is a wrapper macro for vTaskStartScheduler() which starts the scheduler. Starting the scheduler in a task is definitely not good idea: why would you want to start the RTOS if it is already started (otherwise your tasks won’t run). Do the vTaskStartScheduler() after you have initialized all the other things.

        Like

  3. I think I’m making this confucing. This is how I’m starting the scheduler in main and the task I’m using to start the RTOS and my other tasks…

    int main(void)
    {
    PE_low_level_init();

    xTaskCreate(init_task, “Init_task”, configMINIMAL_STACK_SIZE, NULL, init_task_PRIORITY, NULL);
    vTaskStartScheduler();
    }

    static void init_task(void *pvParameters)
    {
    for (;;)
    {
    #ifdef PEX_RTOS_START
    PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
    #endif

    vTaskDelay(1); //required to allow peripheral clocks to initialize

    xTaskCreate(hello_task, “Hello_task”, configMINIMAL_STACK_SIZE, ( void * ) 0, hello_task_PRIORITY, NULL);
    xTaskCreate(led_task, “LED_task”, configMINIMAL_STACK_SIZE, NULL, led_task_PRIORITY, NULL);
    vTaskSuspend(NULL);
    }
    }

    From what I’ve been able to track down, it looks like the registers aren’t available until the CLOCK_SYS_EnableAdc_Clock or CLOCK_SYS_EnableUart_Clock run.

    Like

    • Hi Grant,
      not sure if this is causing your problem, but remove that

      #ifdef PEX_RTOS_START
      PEX_RTOS_START(); /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
      #endif

      which is really, really bad and does not make any sense.
      As another comment: you are not checking the return code of xTaskCreate() as it might fail because of not enough heap.

      Erich

      Like

  4. Pingback: Tutorial: Using Eclipse with NXP MCUXpresso SDK v2 and Processor Expert | MCU on Eclipse

  5. Pingback: Recovering and Updating the NXP OpenSDA Bootloader with P&E Multilink and MCUXpresso IDE | MCU on Eclipse

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 )

Google+ photo

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

Connecting to %s