Monday, 22 September 2025

FreeRTOS on STM32 - Manual Integration

“Build succeeded” isn’t the finish line. With RTOS work, the real traps are missing configs, handler clashes, and timer conflicts that pass compile but fail on hardware. Here’s a compact, reliable path.

😬 The Trap: “It Compiles!” but Doesn’t Run

  • Missing FreeRTOSConfig.h → silent defaults or hard errors

  • Duplicate exception handlers (SysTick/PendSV/SVC) → link conflicts

  • HAL vs FreeRTOS both using SysTick → time-base collision

  • Undefined shifts/hooks/heap setup → runtime weirdness

⚙️ Two Ways to Add FreeRTOS

  • Manual (portable skill): add kernel sources yourself; you control layout and learn what matters.

  • CubeIDE GUI (fast): Middleware → FreeRTOS (CMSIS-RTOS v1/v2) auto-adds kernel + CMSIS layer.

🛠 Manual, Minimal, Deterministic Setup

  1. Create project in STM32CubeIDE (CubeMX-based).

  2. Add sources under ThirdParty/FreeRTOS/:

    • Copy: License, Source/ (incl. include/) and portable/

    • Keep only portable/GCC/ARM_CM4F for F4 + FPU; delete other compilers/arches

  3. Heap: keep heap_4.c; delete heap_1/2/3/5. Exclude sysmem.c (FreeRTOS provides its own heap mgmt).

  4. Include paths (Project → Properties → C Compiler → Includes):

    • .../FreeRTOS/Source/include

    • .../FreeRTOS/Source/portable/GCC/ARM_CM4F

  5. Add FreeRTOSConfig.h (start from an STM32F407 demo; then tailor). Ensure:

    • extern uint32_t SystemCoreClock; enabled for your compiler (e.g., #if defined(__ICCARM__) || defined(__GNUC__) || defined(__CC_ARM)).

  6. Resolve handler duplicates (in .ioc → System Core → NVIC → Code generation):

    • Uncheck SVC, PendSV, and SysTick handlers (FreeRTOS provides them via macros).

    • Regenerate.

  7. Separate time bases:

    • .iocSYS → HAL Time base source = TIM6 (reserve SysTick for FreeRTOS).

    • NVIC priority grouping 4 bits preemption, 0 bits subpriority.

  8. Start lean: in FreeRTOSConfig.h set initially
    configUSE_TICK_HOOK=0, configUSE_MALLOC_FAILED_HOOK=0, configCHECK_FOR_STACK_OVERFLOW=0 (enable later with proper handlers).

  9. Build → now you’re integrated cleanly.

🖱 CubeIDE One-Click Path (CMSIS-RTOS v2)

  • .iocMiddleware > FreeRTOS → choose CMSIS-RTOS v2; set heap size.

  • Honor the IDE warnings:

    • Change HAL time base to TIM6 (not SysTick).

    • Enable Newlib reentrancy (Advanced settings → USE_NEWLIB_REENTRANT) for thread-safe libc in multitasking.

  • Generate code. You can use CMSIS APIs (e.g., osThreadNew) or native FreeRTOS APIs.

🧊 Myth vs Truth

  • Myth: “If it links, RTOS will run.”

  • Truth: RTOS needs correct handlers, time base, and config. Compile-time success doesn’t prove scheduler health.

🔌 Embedded Relevance

  • Deterministic bring-up removes heisenbugs before they reach hardware.

  • Clear separation of SysTick (RTOS) and HAL time base stabilizes timing.

  • Manual path teaches portable skills you can reuse on any MCU/IDE.

✅ Conclusion

Treat RTOS bring-up as a reliability exercise: one owner for critical handlers, one timer per role, and a known-good FreeRTOSConfig.h. Do that, and your “Hello, World” task isn’t luck—it’s repeatable, predictable, and production-ready.


Written By: Musaab Taha


This article was improved with the assistance of AI.

No comments:

Post a Comment