How to use?

How to configure FreeRTOS without STM32CubeMX2?

To configure and run FreeRTOS without STM32CubeMX2:

  1. Copy FreeRTOS kernel sources into your project (or use as submodule).

  2. Choose one heap implementation (e.g. heap_4.c) and add it to the build.

A clean, manual layout can look like this:

ProjectRoot/
├─ FreeRTOS/
│  ├─ Source/
│  │  ├─ include/
│  │  ├─ portable/
│  │  │  └─ [compiler]/[arch]/
│  │  ├─ tasks.c
│  │  ├─ queue.c
│  │  ├─ timers.c
│  │  ├─ event_groups.c
│  │  ├─ stream_buffer.c
│  │  └─ message_buffer.c
│  └─ portable/
│     └─ MemMang/
│        └─ heap_4.c          # or another heap_x.c
├─ Config/
│  └─ FreeRTOSConfig.h        # your configuration file
└─ Src/ / Inc/
   ├─ main.c
   └─ mx_freertos_app.c       # your tasks, queues, etc.

Key points:

  • All core FreeRTOS sources (tasks.c, queue.c, etc.) are compiled.

  • There is a single FreeRTOSConfig.h reachable via the include path.

  • One heap implementation (heap_x.c) is selected and compiled.

  1. Create Config/FreeRTOSConfig.h and define all required macros manually.

You create and maintain Config/FreeRTOSConfig.h yourself. Start from a known example (e.g. FreeRTOS demo or a previous Cube project) and adapt.

Example (shortened, typical STM32/Cortex-M configuration):

/* Config/FreeRTOSConfig.h */

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#include <stdint.h>

/*-----------------------------------------------------------
 * Scheduler settings
 *----------------------------------------------------------*/
#define configUSE_PREEMPTION                    1
#define configUSE_TIME_SLICING                  1
#define configUSE_TICKLESS_IDLE                 0

#define configTICK_RATE_HZ                      ( ( uint32_t ) 1000 )
#define configMAX_PRIORITIES                    5
#define configMINIMAL_STACK_SIZE                ( ( uint16_t ) 128 )
#define configMAX_TASK_NAME_LEN                 16
#define configUSE_16_BIT_TICKS                  0

/*-----------------------------------------------------------
 * Memory allocation
 *----------------------------------------------------------*/
#define configSUPPORT_STATIC_ALLOCATION         1
#define configSUPPORT_DYNAMIC_ALLOCATION        1
#define configTOTAL_HEAP_SIZE                   ( ( size_t ) ( 10 * 1024 ) )

/*-----------------------------------------------------------
 * Feature inclusion
 *----------------------------------------------------------*/
#define configUSE_MUTEXES                       1
#define configUSE_RECURSIVE_MUTEXES             1
#define configUSE_COUNTING_SEMAPHORES           1
#define configUSE_QUEUE_SETS                    0
#define configUSE_TASK_NOTIFICATIONS            1

#define configUSE_TIMERS                        1
#define configTIMER_TASK_PRIORITY               ( 2 )
#define configTIMER_QUEUE_LENGTH                10
#define configTIMER_TASK_STACK_DEPTH            256

#define configUSE_EVENT_GROUPS                  1

/*-----------------------------------------------------------
 * Hook functions
 *----------------------------------------------------------*/
#define configUSE_IDLE_HOOK                     0
#define configUSE_TICK_HOOK                     0
#define configCHECK_FOR_STACK_OVERFLOW          0
#define configUSE_MALLOC_FAILED_HOOK            1

/*-----------------------------------------------------------
 * Run-time stats / trace
 *----------------------------------------------------------*/
#define configUSE_TRACE_FACILITY                0
#define configGENERATE_RUN_TIME_STATS           0

/*-----------------------------------------------------------
 * Cortex-M specific: interrupt priorities
 * Adjust for your NVIC / library
 *----------------------------------------------------------*/
#define configPRIO_BITS                         4  /* e.g. STM32F4: 4 bits */

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY      0x0F
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

#define configKERNEL_INTERRUPT_PRIORITY \
  ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

#define configMAX_SYSCALL_INTERRUPT_PRIORITY \
  ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

/*-----------------------------------------------------------
 * API functions inclusion
 *----------------------------------------------------------*/
#define INCLUDE_vTaskDelay                      1
#define INCLUDE_vTaskDelete                     1
#define INCLUDE_vTaskSuspend                    1
#define INCLUDE_xTaskGetIdleTaskHandle          1

#endif /* FREERTOS_CONFIG_H */

This file completely replaces any STM32CubeMX2-generated configuration.

  1. Add include paths for:

    • FreeRTOS/Source/include

    • FreeRTOS/Source/portable/[compiler]/[arch]

    • Config (for FreeRTOSConfig.h)

  2. Set preprocessor flags in your build system or IDE:

    • Options: FREERTOS_ENABLE_TRACE, FREERTOS_ENABLE_STACK_CHECK, etc.

  3. In your source files, include FreeRTOS headers:

    #include "FreeRTOS.h"
    #include "task.h"
    #include "queue.h"
    
  4. In main(), initialize the MCU, create at least one task, then start the scheduler:

    vTaskStartScheduler();
    

This setup completely avoids STM32CubeMX2 and still provides a flexible configuration mechanism using ``FreeRTOSConfig.h`` + preprocessor flags .

Important

Configuration of TIM6 as HAL Time Base:

When using FreeRTOS, the SysTick timer is typically used by the FreeRTOS kernel to generate the RTOS tick. In this case, SysTick should not be used by the STM32 HAL as its time base.

To avoid conflicts, the HAL time base (used by functions such as HAL_Delay() and internal timeout handling) is moved from SysTick to a general-purpose timer, for example TIM6 .

How to configure FreeRTOS with STM32CubeMX2?

This section explains how to configure FreeRTOS using STM32CubeMX2 and the FreeRTOS pack.

It covers:

  • Project setup with STM32CubeMX2 and FreeRTOS pack

  • FreeRTOS configuration (FreeRTOSConfig.h) through STM32CubeMX2

  • Time base configuration (SysTick vs TIM6)

Prerequisites and Project Creation

  1. Install ** STM32CubeMX2 tool**

  2. Create a new STM32 project:

    • Select your MCU or Discovery/Nucleo board.

    • Configure system clock (RCC) as usual.

Add FreeRTOS pack in STM32CubeMX2

  1. In the configuration tree, go to Middleware:

    • Select the FreeRTOS pack from Middlewware list, see following figures

    • Activate FreeRTOS from the FreeRTOS pack.

middleware selection

FreeRTOS middleware selection

  1. Once activated, you should see a FreeRTOS interface with the following configuration layout:

FreeRTOS interface

FreeRTOS interface

FreeRTOS Kernel Configuration in STM32CubeMX2

Most options that are normally defined in FreeRTOSConfig.h are instead configured through the STM32CubeMX2 GUI.

Core menu

FreeRTOS Core menu interface

  • Scheduler and priorities

    The FreeRTOS Kernel menu is as shown in the following figure:

kernel menu

FreeRTOS kernel menu interface

In the FreeRTOS / Core/Kernel panel, configure:

  • Task scheduling mode:

    • Enable preemptive scheduling (typical RTOS usage).

    • Maps to configUSE_PREEMPTION.

  • Maximum priorities:

    • Set the number of task priority levels (for example 5).

    • Maps to configMAX_PRIORITIES.

  • Time slicing:

    • Enable/disable round-robin among tasks with the same priority.

    • Maps to configUSE_TIME_SLICING.

- System configuration

The FreeRTOS system menu is as shown in the following figure:

system menu

FreeRTOS System menu interface

  • Library maximum syscall interrupt priority:

    • Any interrupt that calls FreeRTOS FromISR APIs has a priority numerically equal to or lower than configMAX_SYSCALL_INTERRUPT_PRIORITY.

  • RTOS tick frequency:

    • Common values: 1000 Hz (1 ms).

    • Maps to configTICK_RATE_HZ.

  • Memory allocation

    As shown in the following figure, the memory management menu:

memory management

FreeRTOS memory management menu interface

  • Memory management menu

    Choose allocation model:

    • Dynamic allocation only, or * Static + dynamic (recommended for more flexibility).

    • STM32CubeMX2 should set configSUPPORT_DYNAMIC_ALLOCATION and optionally``configSUPPORT_STATIC_ALLOCATION``.

    • Select one of the heap_x.c implementations (often heap_4.c).

    • Configure Total heap size:

    • Maps to configTOTAL_HEAP_SIZE in the generated configuration.

  • Optional kernel features

    Enable/disable according to your needs:

    • Mutexes: maps to configUSE_MUTEXES.

    • Recursive mutexes: maps to configUSE_RECURSIVE_MUTEXES.

    • Counting semaphores: maps to configUSE_COUNTING_SEMAPHORES.

    • Event groups: maps to configUSE_EVENT_GROUPS.

    • Software timers:

      • Enabled/disabled via configUSE_TIMERS.

      • Timer service task settings:

        • configTIMER_TASK_PRIORITY

        • configTIMER_QUEUE_LENGTH

        • configTIMER_TASK_STACK_DEPTH

  • Time Base: SysTick vs TIM6

    By default, the STM32 HAL uses the SysTick timer as its time base (for HAL_Delay() and internal timeouts). FreeRTOS also uses SysTick for the kernel tick. To avoid conflicts:

    • Reserve SysTick for FreeRTOS kernel tick.

    • Configure a general-purpose timer (for example TIM6) as the HAL time base.

hal tim selection

HAL timebase selection interface

In STM32CubeMX2:

  1. Open Project Settings → HAL common definitions → HAL timebase.

  2. Look for Timebase Source:

  • Change from SysTick to TIM6 (or another appropriate timer).

  1. Activalte TIM6:

Note

With this setup, SysTick is used exclusively by the FreeRTOS kernel, while TIM6 provides the time base for HAL functions such as HAL_Delay().

How to initialize FreeRTOS without STM32CubeMX2?

After configuration, verify:

  • Include paths

Your compiler must see:

  • The generated configuration and application files:

  • FreeRTOS kernel headers:

    • FreeRTOS/Source/include.

  • FreeRTOS port headers:

    • FreeRTOS/Source/portable/[compiler]/[arch] (e.g. GCC/ARM_CM33_NTZ, IAR/ARM_CM33_NTZ).

  • Source files to compile

Ensure your build includes:

  • FreeRTOS kernel sources:

    • tasks.c

    • queue.c

    • timers.c

    • event_groups.c

    • stream_buffer.c

    • message_buffer.c

  • Port layer: port.c (specific to CPU/toolchain, e.g. portable/GCC/ARM_CM33_NTZ/port.c).

  • Memory management: One heap_x.c (often heap_4.c) from portable/MemMang/.

  • Application glue: mx_freertos_app.c (from the project Src/ folder).

  • FreeRTOS usage

In user code, include FreeRTOS headers normally:

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

Then:

  • Initialize hardware (HAL, clocks, peripherals).

  • Create tasks using FreeRTOS APIs (in mx_freertos_app.c or your own files).

    Once the FreeRTOS kernel, system, and memory management are configured, the next step is to set up FreeRTOS objects according to the final application:

Tasks

  • Define each task’s role, priority, stack size, and whether it is created statically or dynamically.

Queues

  • Used for data exchange between tasks (producer/consumer).

  • Configure queue length and item size.

Semaphores / Mutexes

  • Binary semaphores: task/ISR synchronization.

  • Counting semaphores: multiple identical resources or event counting.

  • Mutexes: protect shared resources, with priority inheritance.

Event Groups

  • Manage multiple status flags and more complex synchronization (one task waiting on several events).

Software Timers

  • Periodic or one-shot actions without a dedicated task (timeouts, housekeeping, etc.).

Stream Buffers

  • For continuous data streams or variable-length messages.

  • Call vTaskStartScheduler() to start the RTOS.

How to initialize FreeRTOS with STM32CubeMX2?

Once the FreeRTOS kernel, system, and memory management are configured, the next step is to configure the FreeRTOS objects according to the final application’s needs.

hal tim selection

FreeRTOS application layout

Typical FreeRTOS objects to plan and configure are:

Tasks

  • Define application tasks and their responsibilities (e.g., communication, control loop, UI, logging).

  • Set priorities based on timing and criticality.

  • Assign appropriate stack sizes.

  • Decide creation time: at startup (static/dynamic) or created on demand.

hal tim selection

FreeRTOS tasks layout

Queues

  • Identify data flows between tasks (e.g., sensor → processing → communication).

  • For each flow, define:

    • Queue length.

    • Item size (structure vs. primitive).

    • Producer/consumer priorities and expected throughput.

    • Decide if queues are used for: - Command passing - Event notification - Data buffering

queue_layout

FreeRTOS queue layout

Semaphores and Mutexes

  • Binary semaphores: For task synchronization with ISRs (e.g., “data ready” from an interrupt).

  • Counting semaphores: For resource pools or counting events.

  • Mutexes: For protecting shared resources (peripherals, global variables, drivers). Use priority inheritance to limit priority inversion.

semaphore_layout

FreeRTOS semaphore layout

counting_semaphore_layout

FreeRTOS counting semaphore layout

Freertos_mutex_layout

FreeRTOS mutex layout

Event Groups

  • For managing multiple event flags and complex synchronization cases:

    • One task waiting on several conditions.

    • System state flags (e.g., “network up”, “storage ready”, “config loaded”).

Freertos_events_layout

FreeRTOS events layout

Timers (Software Timers)

  • For periodic or one-shot actions that don’t need a full task:

    • Housekeeping, timeouts, watchdog kicks, statistics.

    • Choose:

      • Period

      • Auto-reload vs one-shot

      • Callback function context (fast, non-blocking).

soft_timer_layout

FreeRTOS software timer layout

Stream Buffers / Message Buffers

  • For variable-sized or continuous data:

    • UART streams, audio samples, logging.

  • Decide:

    • Buffer size in bytes.

    • Whether to use stream buffer (unstructured stream) or message buffer (framed messages).

stream_buffer_layout

FreeRTOS stream buffer layout

In Project Settings menu, configure the IDE, folders and then generate the project.

IDE_layout

FreeRTOS Project generation

After project generation, the mx_freertos_app.c file should be updated to add the user application code for each entry_function and/or callback functions. The user should also add the following API in main.c file:

  • int32_t app_synctasks_init(void) to call the FreeRTOS initialisation code

  • vTaskStartScheduler() to start the FreeRTOS scheduler

  • add #include "mx_freertos_app.h"