A professional FreeRTOS-based embedded application demonstrating advanced task architecture, thread-safe UART communication, and LED pattern control on STM32F407VG.
π For comprehensive technical documentation, detailed architecture analysis, timing diagrams, and design decisions, see Architecture.md
This project showcases a production-ready FreeRTOS application with an interactive UART menu system for controlling LED patterns. The standout feature is a dedicated print task architecture that eliminates the need for mutex protection by providing exclusive UART TX ownership.
Key Innovation: Instead of using mutexes to protect concurrent UART access (common approach), this implementation uses a dedicated print task with a message queue. This results in cleaner code, better performance, and guaranteed thread safety.
- π¨ 4 LED Patterns: Static ON, Different frequency blinking, Synchronized blinking, OFF
- π¬ Interactive UART Menu: Hierarchical menu system with command processing
- π Thread-Safe Design: Queue-based architecture eliminates race conditions
- β‘ Non-Blocking I/O: Print operations return immediately, no task blocking
- βοΈ Efficient UART RX: Stream Buffer mode with TRUE task blocking (zero CPU waste)
- π Watchdog System: Detects hung or deadlocked tasks automatically
- π Power Efficient: ~98% CPU idle time, WFI sleep mode in idle hook
- π Well Architected: Clean separation of concerns (RX, TX, commands, LEDs)
- π Comprehensive Documentation: Detailed architecture documentation included
Priority 4: Watchdog Task β Monitors task health, detects deadlocks
Priority 3: Print Task β Exclusive UART TX owner
Priority 2: UART Task β Character reception & buffering
Priority 2: Command Handler β Menu state machine & LED control
Priority 2: Timer Service β Software timer callbacks for LED patterns
Priority 0: Idle Task β Power save (WFI instruction)
Problem with Traditional Mutex Approach:
// Multiple tasks competing for UART
xSemaphoreTake(uart_mutex, portMAX_DELAY);
HAL_UART_Transmit(&huart2, data, len, timeout); // Task blocks here
xSemaphoreGive(uart_mutex);Issues: Priority inversion, blocking delays, complex error handling
Our Solution - Dedicated Print Task:
// Any task, anywhere
print_message("Hello World\r\n"); // Returns immediately!
print_char('A'); // Non-blocking echoBenefits:
- β Non-blocking (enqueue ~20-50ΞΌs, return immediately)
- β No priority inversion (queue-based synchronization)
- β Cleaner code (no mutex boilerplate in 10+ locations)
- β FIFO ordering guaranteed
- β Single point of control (easy to extend)
| Component | Size | Utilization |
|---|---|---|
| Total Heap | 75 KB | 17% used |
| Print Queue | ~5.1 KB | 10 messages Γ 512 bytes |
| Task Stacks | ~6.7 KB | 5 tasks |
| Free Memory | ~62 KB | Available for expansion |
Efficient interrupt-driven reception:
UART RX (PA3)
β
RX Interrupt (ISR)
β
Stream Buffer ββ> UART Task (BLOCKED)
(Lock-free) Wakes instantly!
Benefits:
- β TRUE blocking - Task enters BLOCKED state, yields CPU
- β Zero CPU waste - No polling loop
- β Instant wake-up - ISR immediately unblocks task
- β Thread-safe - Lock-free ISR-to-Task communication
All tasks actively monitored:
UART_task, CMD_Handler, Print_Task
β Register & feed every 2 seconds
βββββββββββββββββββ
β Watchdog Task β Checks every 1 second
β (Priority 4) β β If task hasn't fed in 5s β ALERT!
βββββββββββββββββββ
Implementation:
// All three tasks use finite timeouts for watchdog monitoring
void uart_task_handler(void *parameters) {
watchdog_id_t wd_id = watchdog_register("UART_task", 5000);
while(1) {
// Finite 2s timeout (instead of portMAX_DELAY)
xStreamBufferReceive(buffer, &ch, 1, pdMS_TO_TICKS(2000));
watchdog_feed(wd_id); // Prove I'm alive every 2s
}
}Active Monitoring:
- β UART_task - Feeds every 2s (5s timeout)
- β CMD_Handler - Feeds every 2s (5s timeout)
- β Print_Task - Feeds every 2s (5s timeout)
Detects:
- π Hung tasks (stuck in infinite loop)
- π Deadlocked tasks (waiting on mutex forever)
- π Crashed tasks (hard fault before feeding)
- π Starved tasks (priority inversion)
See: WATCHDOG_USAGE.md for complete guide
User Terminal
β
UART RX (PA3) β RX ISR β Stream Buffer β UART Task β Command Queue β Command Handler
(Instant) (BLOCKED) β
LED Effects
β
UART TX (PA2) ββββββββββββ Print Task β Print Queue βββββββββββ Response Messages
β
User Terminal
- Board: STM32F407VG Discovery Board
- Debugger: ST-LINK/V2 (integrated on Discovery board)
- USB-UART Adapter: FTDI FT232RL or similar (3.3V logic level)
- LEDs: On-board LEDs (PD12-Green, PD13-Orange)
ββββββββββββββββββββ
β β
β PC / Laptop β
β β
ββββββββββ¬ββββββββββ
β
ββββββββ΄βββββββββ
β β
USB-A USB Mini-B
β β
β β
β ββββββββΌββββββββββββββββββββββββββββββββββββ
β β STM32F407VG Discovery Board β
β β ββββββββββββββββββββββββββββββββββ β
β β β β β
β β β STM32F407VG MCU β β
β β β (ARM Cortex-M4F) β β
β β β β β
β β β PA2 (UART2 TX) βββββββββ β β
β β β PA3 (UART2 RX) βββββββββΌβββ β β
β β β GND βββββββββββββββββββββΌβββΌββ β β
β β β β β β β β
β β β PD12 β [LED] Green β β β β β β
β β β PD13 β [LED] Orange β β β β β β
β β β β β β β β
β β ββββββββββββββββββββββββββββ β β β β
β β β² β β β β
β β β SWD (Debug/Flash) β β β β
β β ββββββββ΄βββββββ β β β β
β β β ST-LINK/V2 β β β β β
β β β (On-board) β β β β β
β β ββββββββ²βββββββ β β β β
β β β β β β β
β βββββββββββΌββββββββββββββββββββββββΌββΌββΌβββββ
β β β β β
ββββββββββββββββββββ β β β
USB Mini-B (Debug/Flash) β β β
β β β
ββββββββββββββββββββββββββββββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββ
β β ββββββββββββββββββββββββββββββββββββββββ
β β β β
ββββΌβββΌβββΌβββββββ β
β FTDI FT232RL β β
β USB-to-UART β β
β β β
β RX ββββββββββββββββ> PA2 (TX) β
β TX ββββββββββββββββ> PA3 (RX) β
β GND βββββββββββββββββββββββββββββββββββββββββββ
β β
βββββββββ²ββββββββ
β
USB-A to PC
(Serial Terminal)
Connections Summary:
βββββββββββββββββββββ¦βββββββββββββββββββββββββββββββββββββββββββ
β Connection Type β Details β
β ββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββ£
β Debug & Flash β PC USB β STM32 Discovery USB (ST-LINK) β
β Serial Terminal β PC USB β FTDI adapter β STM32 UART2 β
β UART Wiring β FTDI RX β PA2 (TX) β
β β FTDI TX β PA3 (RX) β
β β FTDI GND β STM32 GND β
β LEDs β PD12 (Green), PD13 (Orange) - On-board β
βββββββββββββββββββββ©βββββββββββββββββββββββββββββββββββββββββββ
Power: STM32 powered via USB (ST-LINK connection)
FTDI FT232RL STM32F407VG Discovery
βββββββββββββββ ββββββββββββββββββββ
β β β β
β RX (In) ββββββββ€ PA2 (UART2 TX) β (Yellow wire)
β TX (Out) βββββββΊβ PA3 (UART2 RX) β (Orange wire)
β GND ββββββββ€ GND β (Black wire)
β VCC (3.3V) β β β (Not connected) β (Board self-powered)
β β β β
βββββββββββββββ ββββββββββββββββββββ
β
β USB
βΌ
PC (Serial Terminal: 115200 baud, 8N1)
- IDE: STM32CubeIDE (or command-line ARM GCC)
- Toolchain: ARM GCC (arm-none-eabi)
- RTOS: FreeRTOS v10.x (included)
- HAL: STM32F4 HAL Driver (included)
- Terminal: minicom, screen, PuTTY, or similar (115200 baud, 8N1)
Using STM32CubeIDE:
# Import project into STM32CubeIDE
File β Import β Existing Projects into Workspace
# Select Debug or Release configuration
# Build: Ctrl+B or Project β Build AllUsing Command Line:
cd Debug/
make clean
make -j4# Using ST-LINK utility or STM32CubeIDE
# Flash the generated .elf or .bin file# Linux/macOS
screen /dev/ttyUSB0 115200
# or
screen /dev/tty.usbserial-XXXXX 115200
# Windows
# Use PuTTY: COM port, 115200 baud, 8N1****************************************
* *
* LED Pattern Control Application *
* FreeRTOS UART Interface *
* *
****************************************
========================================
MAIN MENU
========================================
1 - LED Patterns
2 - Exit Application
========================================
Enter selection: 1
========================================
LED Pattern Selection
========================================
0 - Return to main menu
1 - All LEDs ON
2 - Different Frequency Blinking
3 - Same Frequency Blinking
4 - All LEDs OFF
========================================
Enter selection:
rtos-led-control-uart-menu/
βββ includes/
β βββ main.h
β βββ uart_task.h
β βββ print_task.h β Print task API
β βββ command_handler.h
β βββ led_effects.h
β βββ watchdog.h β Watchdog API
βββ src/
β βββ main.c β Initialization & task creation
β βββ uart_task.c β Character RX & buffering
β βββ print_task.c β Print task implementation
β βββ command_handler.c β Menu state machine
β βββ led_effects.c β LED pattern control
β βββ watchdog.c β Watchdog implementation
β βββ stm32f4xx_it.c β Interrupt handlers
β βββ Startup/
β βββ startup_stm32f407vgtx.s
βββ Drivers/ β STM32 HAL & CMSIS
βββ common/ThirdParty/
β βββ FreeRTOS/ β FreeRTOS kernel
β βββ SEGGER/ β SEGGER SystemView (optional)
βββ Debug/ β Build output
βββ Architecture.md β Detailed architecture docs
βββ README.md β This file
βββ STM32F407VGTX_FLASH.ld β Linker script
#define PRINT_MESSAGE_MAX_SIZE 512 // Max message length
#define PRINT_QUEUE_DEPTH 10 // Number of queued messages
#define PRINT_TASK_PRIORITY 3 // Highest app priority
#define PRINT_TASK_STACK_SIZE 512 // Stack in words (2048 bytes)#define configTOTAL_HEAP_SIZE (75 * 1024) // 75 KB heap
#define configTICK_RATE_HZ 1000 // 1ms tick
#define configMAX_PRIORITIES 5 // Priority levels 0-4
#define configUSE_PREEMPTION 1 // Preemptive scheduling
#define configUSE_IDLE_HOOK 1 // Enable WFI sleep
#define configUSE_TIMERS 1 // Software timers
#define configTIMER_TASK_PRIORITY 2 // Timer service priorityβ Character Echo - Immediate feedback, no lag β Menu Navigation - All menus display completely, no truncation β LED Patterns - All 4 patterns work correctly β Thread Safety - No text corruption under rapid input β Error Handling - Buffer overflow and queue full handled gracefully β Backspace - Visual feedback works correctly β Power Efficiency - CPU ~98% idle, WFI sleep active
| Metric | Value |
|---|---|
| Character Echo Latency | ~50-100ΞΌs |
| Command Processing | <6ms |
| CPU Load (Active) | ~2% |
| CPU Load (Idle) | ~98% |
| Average Power | ~22 mA @ 3.3V |
| Heap Utilization | 17% (62 KB free) |
This project demonstrates:
- FreeRTOS Task Design - Multiple cooperating tasks with proper priorities
- Queue-Based Communication - Producer-consumer patterns
- Resource Management - Exclusive ownership vs mutex protection
- State Machines - Menu navigation and command processing
- Software Timers - LED pattern control without blocking
- Power Management - WFI sleep mode in idle task
- Professional Practices - Clean code, documentation, error handling
π Architecture.md - Complete Technical Reference
1000+ lines of comprehensive documentation including:
- Task Architecture - Detailed analysis of all 5 tasks with priorities, stack sizes, responsibilities
- FreeRTOS Objects - Queues, timers, synchronization primitives
- Data Flow Diagrams - Complete system communication paths
- Timing Analysis - Worst-case response times, latency measurements
- Memory Maps - Heap allocation, stack usage, resource utilization
- Interrupt Configuration - UART RX, SysTick, priority levels
- Critical Section Analysis - Thread safety implementation details
- Power Management - WFI sleep mode, power consumption estimates
- Troubleshooting Guide - Common issues and solutions
- Design Decisions - Evolution from mutex to print task architecture
- Testing Verification - Complete test results and validation
- Performance Metrics - CPU load, memory usage, response times
This README provides a quick start guide. For deep technical understanding, refer to Architecture.md.
-
SEGGER RTT Logging
- Add dedicated debug logging via SWD (no UART pins needed)
- SystemView integration for visual task analysis
- Log task states, queue depths, heap usage
-
Advanced Features
- User-configurable LED patterns stored in flash
- Command history with up/down arrow support
- Runtime statistics menu (CPU usage, stack watermarks)
-
Production Hardening
- Watchdog timer integration
- Stack overflow detection hooks
- Comprehensive fault handlers with diagnostics
No output on terminal:
- Check UART connections (TX β RX, RX β TX)
- Verify baud rate: 115200, 8N1
- Press STM32 RESET button after connecting terminal
Text corruption:
- Ensure you flashed the latest firmware
- Print task priority must be 3 (highest)
- Only print task should call HAL_UART_Transmit()
LEDs not blinking:
- Verify
led_effects_init()called before scheduler starts - Check timer priorities (should be 2)
- Ensure patterns 2 or 3 selected (1 is static ON)
This project is for educational and personal use. Feel free to learn from, modify, and extend it.
- STMicroelectronics - STM32 HAL libraries and CMSIS
- FreeRTOS - Real-time operating system kernel
- SEGGER - SystemView debugging tools
For questions or discussions about this project, please refer to the detailed Architecture.md documentation.