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

23 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

  2. I’m trying to cut down FreeRTOS to the minimum (to fit on the LPC804 along with my actual application). I want to use only static allocation for FreeRTOS. That way I don’t need a heap or supporting functions. But I can’t undefine configUSE_HEAP_SCHEME b/c freertos_task_c_additions.h and FreeRTOSConfig.h set it to a default if undefined. And McuRTOS.c breaks if it’s not defined.
    How can I remove the heap? Thanks!

    Liked by 1 person

  3. Hi Erich,
    Great tutorial. I followed it trough it all steps and just needed to add one additional step for my project to work. I had to go to the McuLibconfig.h that i copied into my src folder and modify line 80
    #define McuLib_CONFIG_SDK_USE_FREERTOS (0)
    to #define McuLib_CONFIG_SDK_USE_FREERTOS (1)
    Is that the right way or I’m missing some compliler option that makes this automatically ? As i said i modified 0 to 1 and project compiled just fine
    Thanks!

    Im using MCUXpresso IDE v11.3.1 [Build 5262] [2021-04-02] and SDK_2.9.0_LPC845BREAKOUT SDK for my LPC845-BRK

    Liked by 1 person

  4. Your FreeRTOS port is working great so far for me with MCUxpresso SDK on LPC804. Nice and modular.
    But would you show us how to enable low power sleep during idle? (I used to hook into something in Events.c with PE. ) I’m guessing something to do with configUSE_IDLE_HOOK?

    Liked by 1 person

    • The hooks (or events file is in McuLib/FreeRTOS/FreeRTOShooks.c with the latest version of the library. That file provides default/empty hooks for most things. I recommend to make a copy of that one into your sources folder and ‘exclucde from build’ the default template one. There you find the McuRTOS_vApplicationIdleHook() which can be used to enter low power mode.

      Last but not least, I recommend that you turn on tickless idle: how it works is described here: https://mcuoneclipse.com/2013/07/06/low-power-with-freertos-tickless-idle-mode/ . You turn this one on with configUSE_TICKLESS_IDLE

      I hope this helps as a starter?

      Like

What do you think?

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