A hands-on FreeRTOS learning project for the STM32F407G-DISC1 (Cortex-M4F, 168 MHz), covering fundamental RTOS concepts through progressively more complex examples. Each project is self-contained and demonstrates a specific FreeRTOS feature, with SEGGER SystemView integration for real-time task scheduling visualization and debugging.
- Six self-contained example projects covering core FreeRTOS concepts
- Shared CMake modules — add FreeRTOS or FreeRTOS + SEGGER to any project in two lines
- SEGGER SystemView tracing with two recording modes: single-shot (no extra hardware) and UART streaming (real-time)
- Supports both CLion and STM32CubeIDE
- FreeRTOS-Kernel as a Git submodule (easy version pinning and upgrades)
- Strict compiler warnings on kernel code (
-Wall -Wextra -Wpedantic -Werror -Wconversion)
Each numbered directory is an independent project. They build on each other conceptually:
| # | Project | FreeRTOS Concept |
|---|---|---|
| 001 | 001_Tasks |
Task creation and preemptive scheduling |
| 002 | 002_LED_Tasks |
Multiple concurrent tasks controlling LEDs |
| 003 | 003_ISR_Notify |
Task notification from an interrupt (vTaskNotifyGiveFromISR) |
| 004 | 004_Queue_RTC_LED |
Inter-task communication with queues, RTC timestamps, and LED effects |
| 005 | 005_Binary_Semaphore_Tasks |
Producer/consumer synchronization with binary semaphores |
| 006 | 006_Mutex |
Shared resource protection with mutexes (race condition prevention) |
| Tool | Version | Purpose |
|---|---|---|
| arm-none-eabi-gcc | GCC 11+ | ARM cross-compiler |
| CMake | 3.22+ | Build system |
| Ninja | Any | Build generator (used by presets) |
| CLion or STM32CubeIDE | — | IDE (either works) |
| SEGGER SystemView | — | Trace analysis (optional) |
git clone git@github.com:hugo-juarez/FreeRTOS-Projects.git
cd FreeRTOS-Projects
git submodule update --init --recursive # pulls FreeRTOS-KernelThe FreeRTOS-Kernel submodule must be initialized before any project will build.
Each project lives in its own directory. Navigate into a project before building.
Open a project directory (e.g. 001_Tasks/) as a CMake project. CLion will automatically pick up CMakePresets.json and configure the ARM toolchain — no manual setup needed.
cd 001_Tasks
cmake --preset Debug # configure (outputs to build/Debug/)
cmake --build --preset Debug # compileUse --preset Release for an optimized build (-Os).
- Open STM32CubeIDE and set up a workspace
- File > Open Projects from File System — set the project path (e.g.
001_Tasks/) as source - Set
<project>/build-cubeideas the build directory
FreeRTOS/
├── 001_Tasks/ # Self-contained project
│ ├── Core/
│ │ ├── Inc/ # FreeRTOSConfig.h, main.h, HAL config
│ │ └── Src/ # main.c, syscalls.c, interrupt handlers
│ ├── Drivers/ # STM32 HAL + CMSIS (per-project copy)
│ ├── cmake/
│ │ ├── stm32cubemx/ # CubeMX-generated CMake (HAL sources, flags)
│ │ ├── gcc-arm-none-eabi.cmake # GCC cross-compiler toolchain
│ │ └── starm-clang.cmake # Clang cross-compiler toolchain (alternative)
│ ├── CMakeLists.txt
│ ├── CMakePresets.json # Debug / Release presets (Ninja)
│ ├── STM32F407XX_FLASH.ld # Linker script
│ └── startup_stm32f407xx.s # Startup assembly
├── cmake/
│ ├── freertos.cmake # FreeRTOS-only CMake module
│ └── segger.cmake # FreeRTOS + SEGGER CMake module
└── ThirdParty/
├── FreeRTOS-Kernel/ # Git submodule (port: GCC_ARM_CM4F, heap: 4)
└── SEGGER/ # RTT + SystemView sources (not a submodule)
- Create a project directory following the structure above (copy an existing project as a template)
- Add
FreeRTOSConfig.htoCore/Inc/— use a template from the official FreeRTOS demos - Add to the end of your
CMakeLists.txt:
Without SEGGER:
include(${CMAKE_SOURCE_DIR}/../cmake/freertos.cmake)
add_freertos_library(${CMAKE_PROJECT_NAME} ${CMAKE_SOURCE_DIR}/Core/Inc)With SEGGER (replaces the above — not additive):
include(${CMAKE_SOURCE_DIR}/../cmake/segger.cmake)
add_freertos_segger_library(${CMAKE_PROJECT_NAME} ${CMAKE_SOURCE_DIR}/Core/Inc)- Update
FREERTOS_PORTincmake/freertos.cmake(e.g.GCC_ARM_CM3,GCC_ARM_CM0) - Update
TARGET_FLAGSincmake/gcc-arm-none-eabi.cmakefor your CPU/FPU - Replace the linker script and startup file
cd ThirdParty/FreeRTOS-Kernel
git fetch && git checkout <desired-tag>
cd ../..
git add ThirdParty/FreeRTOS-Kernel
git commit -m "Update FreeRTOS-Kernel to <version>"SEGGER SystemView lets you visualize FreeRTOS task scheduling, CPU load, and inter-task events in real time. RTT and SystemView sources are included in ThirdParty/SEGGER/.
Add these macros:
#define configUSE_TRACE_FACILITY 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_pxTaskGetStackStart 1At the bottom of the file:
#include "SEGGER_SYSVIEW_FreeRTOS.h"// After SystemClock_Config() — enables cycle counter required by SystemView
DWT->CTRL |= (1 << 0);
// Before creating any tasks
SEGGER_SYSVIEW_Conf();
SEGGER_SYSVIEW_Start();In HAL_MspInit():
NVIC_SetPriorityGrouping(0);Interrupt priorities: ISRs that call FreeRTOS API must have priority ≥
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY(5).
Captures a trace buffer snapshot after a debug session. No extra hardware required.
- Pause execution in the debugger
- Evaluate
_SEGGER_RTT.aUp[1].pBuffer(buffer address) and_SEGGER_RTT.aUp[1].WrOff(byte count) - Open the Memory Browser, export that range as a raw binary file with a
.SVdatextension - In SystemView: File > Load Data
Streams trace data live over USART2 (PA2/TX, PA3/RX). Requires a USB-to-UART adapter.
Note:
ThirdParty/SEGGER/Rec/segger_uart.cis STM32F407-specific (USART2 on APB1 at 42 MHz). Modify it for other MCUs.
CMakeLists.txt — add before include(segger.cmake):
set(SEGGER_UART_REC 1)
include(${CMAKE_SOURCE_DIR}/../cmake/segger.cmake)
add_freertos_segger_library(${CMAKE_PROJECT_NAME} ${CMAKE_SOURCE_DIR}/Core/Inc)main.c — replace SEGGER_SYSVIEW_Start() with:
extern void SEGGER_UART_init(U32 baud);
SEGGER_UART_init(500000);
SEGGER_SYSVIEW_Conf();
// Do NOT call SEGGER_SYSVIEW_Start() — the host triggers itHost: In SystemView go to Target > Recorder Configuration > UART, set the baud rate, then click Start Recording.
The UART IRQ runs at priority 6 — below
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY(5) — so it does not interfere with FreeRTOS. Single-shot and UART recording are mutually exclusive.
When segger_rtt_syscalls is linked (the default with add_freertos_segger_library), printf() is routed to SEGGER RTT — nothing appears on SWO.
| Mode | How to use |
|---|---|
| SEGGER RTT | SEGGER_SYSVIEW_PrintfTarget("msg") (visible in SystemView), or J-Link RTT Viewer for raw printf |
| SWO | Remove segger_rtt_syscalls from link libraries in cmake/segger.cmake |
- FreeRTOS Documentation
- FreeRTOS-Kernel on GitHub
- SEGGER SystemView Download
- SEGGER SystemView on GitHub
- SEGGER RTT on GitHub
- STM32F407G-DISC1 Product Page
The original source code in this repository (project Core/ directories and cmake/ modules) is licensed under the MIT License.
Third-party components retain their own licenses:
| Component | License | Location |
|---|---|---|
| FreeRTOS-Kernel | MIT | ThirdParty/FreeRTOS-Kernel/LICENSE.md |
| CMSIS | Apache 2.0 | Drivers/CMSIS/LICENSE.txt |
| STM32 HAL Driver | BSD-3-Clause | Drivers/STM32F4xx_HAL_Driver/LICENSE.txt |
| SEGGER RTT / SystemView | BSD-1-Clause | File headers in ThirdParty/SEGGER/ |