Tutorial: Adding FreeRTOS to where there is no FreeRTOS

FreeRTOS is pretty much everywhere because it is so simple and universal, and it runs from the smallest to the biggest systems. But it still might be that for the microcontroller device you have selected there is no example or SDK support for it from your vendor of choice. In that case: no problem: I show how you could easily add FreeRTOS plus many more goodies to it.

Binky on NXP LPC845-BRK Board

Binky on NXP LPC845-BRK Board

Outline

FreeRTOS requires only few resources, and I have it running in projects on microcontrollers with as less as 1 KByte RAM and 16 KByte FLASH. Of course more leg room is better. The advantage of FreeRTOS is that it is very generic and not really microcontroller specific, except the ‘port’ part. But that port part is generic for Cortex-M0/M0+, M4 o M7 too, so basically you only need a port for your architecture and your are ready to go. At the university we are using FreeRTOS in many projects, and to simplify things even further across all Cortex-M cores of all the different vendors you can imagine, we are using a ‘McuLib’ which includes a unified and extended FreeRTOS port to cover all the architectures we are using. This makes using FreeRTOS for us even easier and simpler, and that port is available as open source on GitHub.

In this tutorial I show how to add FreeRTOS to a ‘bare metal’ project using the NXP LPC845 and the Eclipse based NXP MCUXpresso IDE with the NXP MCUXpresso SDK. The process itself is generic too, so you could use that for your IDE of choice too.

Base project

First you need to have (of course) the bare metal project ready. I recommend to start with a working example where you can add FreeRTOS.

initial bare metal project

initial bare metal project

Adding McuLib

Next, add the McuLib. One easy way is to download the repository .zip file https://github.com/ErichStyger/McuOnEclipseLibrary.git.

McuLib Zip File

McuLib Zip File

One way would be using just FreeRTOS, but to keep things simple we just add the full library to the project (don’t worry: what is not used won’t add to the code/data size). What we need is that ‘lib’ folder from above zip. Copy that into the project root folder and rename it as ‘McuLib’ (we will use that folder name later on).

McuLib in the project

McuLib in the project

By default in Eclipse, added folders won’t be added to the build. So go to the folder properties and have it included into the build. The Eclipse Icon Decorator shall show that blue ‘c’.

Included into build

Included into build

Selecting FreeRTOS Port

The McuLib contains multiple FreeRTOS ports. The folder ‘McuLib\FreeRTOS\Source\portable\GCC\ARM_CM4F’ has the ports for Cortex-M0/M4/M7 in it.

Disable the other ports (Cortex-M33 and RISC-V): set the folder properties to ‘Exclude resource from Build’:

Other FreeRTOS ports excluded from Build

Other FreeRTOS ports excluded from Build

Configure the McuLib

The library uses a flexible way to configure it (see “Different Ways of Software Configuration“). The library comes with a default configuration header file. Copy the template header file into your sources folder and rename it:

copied and renamed template configuration

copied and renamed template configuration

This header file will configure the library, and for this we add it to the ‘-include’ gcc compiler option:

"${ProjDirPath}/source/IncludeMcuLibConfig.h"

Add this to the project settings for the compiler:

-include compiler setting

-include compiler setting

The same time we can tell the compiler about the where to find all the header files. An easy way is to copy the list below and paste it into the ‘Include Paths’ dialog:

../McuLib
../McuLib/config
../McuLib/config/fonts
../McuLib/fonts
../McuLib/src
../McuLib/FreeRTOS/Source/include
../McuLib/FreeRTOS/Source/portable/GCC/ARM_CM4F
../McuLib/SEGGER_RTT
../McuLib/SEGGER_Sysview
../McuLib/TraceRecorder/config
../McuLib/TraceRecorder/include
../McuLib/TraceRecorder/streamports/Jlink_RTT/include
../McuLib/HD44780
../McuLib/FatFS
../McuLib/FatFS/source
Pasted Include paths

Pasted Include paths

HardFault Handler

If your SDK comes with a hard fault handler: you can remove it as the McuLib comes with its own (and probably better) handler. Remove an existing handler otherwise you might face a linker error:

Remove existing hardfault handler

Remove existing hardfault handler

Optional: Disabling other Middleware

The McuLib comes with extra middleware like a GUI, FatFS or Trace libraries. If rebuilding the project that middleware gets recompiled too (but won’t add to the code size). If not used, the extra middleware folders can be deleted. Or what I recommend: simply exclude them from the build so they can be easily added later on if needed:

Disabled not needed middleware

Disabled not needed middleware

This completes the setup, and the project shall compile without errors.

Running FreeRTOS

Now it is time to test it and run a first FreeRTOS task. For this I initialize the middleware (needed in case I want to use things like FreeRTOS Trace), create a task and start the scheduler:

#include <stdio.h>
#include "board.h"
#include "peripherals.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "LPC845.h"
#include "fsl_debug_console.h"

#include "McuRTOS.h" /* access to all FreeRTOS API functions */

static void MyTask(void *pv) { /* simple task */
  for(;;) {
    vTaskDelay(pdMS_TO_TICKS(100));
  }
}

int main(void) {
  	/* Init board hardware. */
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    BOARD_InitBootPeripherals();
  	/* Init FSL debug console. */
    BOARD_InitDebugConsole();

    McuRTOS_Init(); /* initialize FreeRTOS middleware */
    if (xTaskCreate(  /* create task */
        MyTask,  /* pointer to the task */
        "App", /* task name for kernel awareness debugging */
        200/sizeof(StackType_t), /* task stack size */
        (void*)NULL, /* optional task startup argument */
        tskIDLE_PRIORITY+2,  /* initial priority */
        (TaskHandle_t*)NULL /* optional task handle to create */
      ) != pdPASS) {
       for(;;){} /* error! probably out of memory */
    }
    vTaskStartScheduler(); /* start RTOS scheduler */
    return 0 ;
}

Build and Debug:

Debugging with FreeRTOS

Debugging with FreeRTOS

Summary

Because FreeRTOS is very generic for ARM Cortex, it is possible to add it to any Cortex-M microcontroller. The McuLib includes an even more generic port plus it is implemented and configured to work with extra middleware like USB stacks, FatFS, RTT, SystemViewer or Percepio trace.

Happy FreeRTOSing 🙂

Links

13 thoughts on “Tutorial: Adding FreeRTOS to where there is no FreeRTOS

  1. Thank you, Erich, for great article again!
    It works fine with BM project on K60F12 under MCUXpresso 11.1.1 and SDK 2.7.

    Now I’m trying to select configUSE_HEAP_SCHEME=6 for NewLib and getting “undefined reference to __heap_size and __HeapLimit”.
    I tried to follow the path of MCUXpresso from your 2017 article “Using FreeRTOS with newlib and newlib-nano” but didn’t succeed. Maybe due to new ver of MCUXpresso.
    What is the best way to deal with Linker Script under MCUXpresso 11.1.1 (preferably with “Managed Linker Script” option enabled) ?

    Like

    • Hi Slava,
      are you using the FreeRTOS of the MCUXpresso SDK or the one from the McuLib?
      I ask because the one of the SDK does not (yet) implement the Heap Scheme 6, so you should go ahead and use the FreeRTOS port of the McuLib.

      I hope this helps,
      Erich

      Like

    • Add the following to your IncludeMcuLibConfig.h

      #define configLINKER_HEAP_BASE_SYMBOL _pvHeapStart
      /*!< Linker symbol used to denote the base address of the heap, used for heap memory scheme 6 (newlib). (KDS: __HeapBase, MCUXpresso: _pvHeapStart) */
      #define configLINKER_HEAP_LIMIT_SYMBOL _pvHeapLimit
      /*!< Linker symbol used to denote the limit address of the heap, used for heap memory scheme 6 (newlib). (KDS: __HeapLimit, MCUXpresso: _pvHeapLimit) */
      #define configLINKER_HEAP_SIZE_SYMBOL _HeapSize
      /*!< Linker symbol used to denote the size of the heap, used for heap memory scheme 6 (newlib). (KDS: __heap_size, MCUXpresso: _HeapSize) */

      The reason is that the linker symbol is different for the MCUXpresso IDE. I see if I can automatically detect if it is the MCUXpresso or not.

      Like

    • Eventually, I found in McuRTOSconfig.h :

      #ifndef configLINKER_HEAP_BASE_SYMBOL
      #define configLINKER_HEAP_BASE_SYMBOL _pvHeapStart //__HeapBase
      /*!< Linker symbol used to denote the base address of the heap, used for heap memory scheme 6 (newlib). (KDS: __HeapBase, MCUXpresso: _pvHeapStart) */
      #endif

      Now I can compile with MCUXpresso and heap scheme=6 !

      Like

      • Moving forward now.
        Freertos tasks hangs in printf(). Without them tasks running ok. I know you don’t like them. But I do. Will investigate further.
        Whole this exercise I’m doing because K60F12 is not supported by SDK. When I ported NXP SDK Freertos example from K64F12 to K60F12 it doesn’t start. Your McuLib Freertos works fine on the top of BM.

        Like

        • Thank you Erich again.
          Yes it was a stack size in tasks.
          I like printf because my C code looks the same , is it a windows console app or embedded code. Nowdays uControllers almost capable to provide me the feeling that I m programming on PC. Every year it even more true. People program uControllers in C++! Why should I care about printf and use a cripple one instead of standard? If there is a mem limitation or cost sensitive app, then yes, I agree.
          Bottom line you freertos runs perfectly now on my non standard K60F12 board.

          Do you have option/example how to configure USB CDC VCOM for stdin and stdout ?
          I can see some definitions in SDK but not sure NXP supports it yet.

          Like

        • Hi Slava,
          I understand your motivation about printf(), but keep in mind that the implementation on the host might be different than the one on the embedded side (available formatting options, etc). If you stick to the most used ones, you are probably fine.
          C++: that would be yet again a different discussion, but it all depends on which features you would use.

          Stdin/stdout with USB CDC: I do this with my ‘shell’ implementation, but again not with the library stdin/stdout. But the MCUXpresso SDK examples/projects come with an option at project creation time where it provides all the hooks to redirect printf() style to VCOM.

          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 )

Google photo

You are commenting using your Google 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.