Skip to content

kgsinh/FreeRTOSProject

Repository files navigation

FreeRTOS LED Pattern Sequencer

A comprehensive FreeRTOS demonstration project showcasing real-time task management, inter-task communication, and hardware abstraction on the STM32G071RB microcontroller

License Platform RTOS


πŸ“‹ Table of Contents


🎯 Overview

This project demonstrates professional-grade embedded RTOS design patterns using FreeRTOS on an STM32G071RB microcontroller. It bridges the gap between basic "blink" examples and production-ready firmware by implementing:

  • Multi-task coordination with proper priority management
  • ISR-to-task communication using task notifications
  • Inter-task messaging via FreeRTOS queues
  • Hardware abstraction for LEDs, buttons, and PWM control
  • Deterministic timing using vTaskDelayUntil()
  • Pattern-based control with task suspension/resumption

The system orchestrates three LED controllers (blinking and PWM fading) while responding to button press events that trigger predefined LED patterns, all managed by FreeRTOS task scheduler.


✨ Features

  • βœ… 5 Concurrent FreeRTOS Tasks with different priorities
  • βœ… ISR-Safe Communication using task notifications
  • βœ… Queue-Based Messaging for pattern coordination
  • βœ… PWM Control with smooth LED fading (TIM1 Channel 4)
  • βœ… External Interrupt handling (EXTI13) with debouncing
  • βœ… UART Debug Interface (115200 baud) for runtime diagnostics
  • βœ… Modular Code Structure with hardware abstraction layers
  • βœ… Heap 4 Memory Management (6KB heap for dynamic allocation)
  • βœ… Precise Timing Control using FreeRTOS delay functions

πŸ”§ Hardware Requirements

Component Specification
Microcontroller STM32G071RB (Cortex-M0+, 64KB Flash, 36KB RAM)
Development Board STM32 Nucleo-G071RB or compatible
LEDs 3x LEDs (or use onboard LEDs)
Button 1x Push button (or use USER button)
Debug Interface ST-Link V2/V3 (integrated on Nucleo board)
UART Adapter USB-to-UART (optional, for debug output)

Pin Mapping

Peripheral Pin Function Configuration
Green LED PC10 Digital Output Periodic blink (1Hz)
Blue LED PC11 PWM Output (TIM1_CH4) Smooth fading effect
Red LED PC12 Digital Output Blink pattern control
User Button PC13 Digital Input (EXTI13) Interrupt-driven events
UART2 TX PA2 Serial Output Debug logging (115200 baud)
UART2 RX PA3 Serial Input Reserved for future use

πŸ’» Software Prerequisites

Required Tools

  1. STM32CubeIDE (v1.10.0 or later)

  2. STM32CubeMX (optional, for hardware reconfiguration)

    • Project file: 03_FreeRTOSProject.ioc
  3. Serial Terminal (for UART debugging)

    • Examples: PuTTY, Tera Term, CoolTerm, or screen

Dependencies (Included)

  • STM32G0xx HAL Driver (v1.4.x)
  • CMSIS Core (v5.x)
  • FreeRTOS Kernel (v10.3.1)
    • Memory management: heap_4.c
    • Port: ARM Cortex-M0

πŸ“ Project Structure

FreeRTOSProject/
β”‚
β”œβ”€β”€ Core/
β”‚   β”œβ”€β”€ Inc/                        # Header files
β”‚   β”‚   β”œβ”€β”€ main.h                  # Main application header
β”‚   β”‚   β”œβ”€β”€ FreeRTOSConfig.h        # FreeRTOS configuration
β”‚   β”‚   β”œβ”€β”€ led.h                   # LED control interface
β”‚   β”‚   β”œβ”€β”€ button.h                # Button/interrupt interface
β”‚   β”‚   β”œβ”€β”€ pwm.h                   # PWM control interface
β”‚   β”‚   └── stm32g0xx_*.h          # HAL/peripheral headers
β”‚   β”‚
β”‚   β”œβ”€β”€ Src/                        # Source files
β”‚   β”‚   β”œβ”€β”€ main.c                  # Application entry & task definitions
β”‚   β”‚   β”œβ”€β”€ app_freertos.c          # FreeRTOS application code
β”‚   β”‚   β”œβ”€β”€ led.c                   # LED hardware abstraction
β”‚   β”‚   β”œβ”€β”€ button.c                # Button & EXTI interrupt handlers
β”‚   β”‚   β”œβ”€β”€ pwm.c                   # TIM1 PWM configuration
β”‚   β”‚   β”œβ”€β”€ stm32g0xx_it.c         # Interrupt handlers
β”‚   β”‚   └── system_stm32g0xx.c     # System initialization
β”‚   β”‚
β”‚   └── Startup/
β”‚       └── startup_stm32g071r8tx.s # MCU startup assembly
β”‚
β”œβ”€β”€ Drivers/                        # STM32 HAL & CMSIS drivers
β”‚   β”œβ”€β”€ STM32G0xx_HAL_Driver/
β”‚   └── CMSIS/
β”‚
β”œβ”€β”€ Middlewares/                    # Third-party middleware
β”‚   └── Third_Party/
β”‚       └── FreeRTOS/
β”‚           └── Source/             # FreeRTOS kernel source
β”‚
β”œβ”€β”€ STM32G071R8TX_FLASH.ld         # Linker script
β”œβ”€β”€ 03_FreeRTOSProject.ioc         # STM32CubeMX project file
β”œβ”€β”€ README.md                       # This file
└── LICENSE                         # MIT License

πŸ—οΈ System Architecture

Task Hierarchy

Priority 3 (Highest):  [Button Controller Task]
                                |
                                | Task Notification
                                ↓
Priority 2:            [Green LED] [Blue LED PWM] [Red LED]
                                ↑
                                | Queue Message
                                |
Priority 1 (Lowest):   [Pattern Generator Task]

Communication Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Button Press (ISR) β”‚  ← External Interrupt (EXTI13)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚ vTaskNotifyGiveFromISR()
           ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Button Task         β”‚  ← Cycles pattern number (0β†’1β†’2β†’0)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚ xQueueSend()
           ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Pattern Generator   β”‚  ← Receives pattern from queue
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚ vTaskSuspend() β†’ Execute Pattern β†’ vTaskResume()
           ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Green LED β”‚ Blue PWM β”‚ Red LED      β”‚  ← Suspended during pattern
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš€ Getting Started

1. Clone the Repository

git clone https://github.com/kgsinh/FreeRTOSProject.git
cd FreeRTOSProject

2. Open in STM32CubeIDE

  1. Launch STM32CubeIDE
  2. Select File > Open Projects from File System
  3. Navigate to the cloned directory
  4. Click Finish

3. Build the Project

# Using STM32CubeIDE GUI:
Project > Build Project

# Or using command line:
# (Assuming STM32CubeIDE is installed at default location)
cd Debug
make clean
make all

4. Flash to Board

  1. Connect STM32 Nucleo board via USB
  2. Select Run > Debug (F11) or Run > Run (Ctrl+F11)
  3. STM32CubeIDE will automatically flash and start debugging

5. Connect UART Terminal (Optional)

# Linux/Mac
screen /dev/ttyACM0 115200

# Windows (using PuTTY)
# Configure: COM port, 115200 baud, 8N1

πŸ“ Task Description

1. Green LED Controller Task

Priority: 2 | Stack: 128 words

void vGreenLedControllerTask(void *pvParameters)
  • Function: Toggles Green LED at 1 Hz (500ms ON, 500ms OFF)
  • Timing Method: vTaskDelayUntil() for precise periodic execution
  • Hardware: PC10 (GPIO output)

2. Blue LED PWM Controller Task

Priority: 2 | Stack: (128 words)

void vBlueLedControllerTask(void *pvParameters)
  • Function: Smooth PWM fading effect (0% β†’ 100% β†’ 0%)
  • Timing Method: vTaskDelayUntil() at 100ms intervals
  • Hardware: PC11 (TIM1_CH4, PWM output @ 1kHz)
  • Fade Steps: 10% increments/decrements

3. Red LED Controller Task

Priority: 2 | Stack: 128 words

void vRedLedControllerTask(void *pvParameters)
  • Function: Toggles Red LED at 1 Hz (500ms ON, 500ms OFF)
  • Timing Method: vTaskDelayUntil() for consistent timing
  • Hardware: PC12 (GPIO output)

4. Button Controller Task

Priority: 3 (Highest) | Stack: 256 words

void vButtonControllerTask(void *pvParameters)
  • Function: Waits for button press notification from ISR
  • Trigger: External interrupt (EXTI13) on falling edge
  • Action: Cycles through patterns (0 β†’ 1 β†’ 2 β†’ 0) and sends to queue
  • Timeout: 5 second notification timeout for status monitoring

5. Pattern Generator Task

Priority: 1 (Lowest) | Stack: 256 words

void vPatternGeneratorTask(void *pvParameters)
  • Function: Executes LED patterns based on queue messages
  • Blocking: Waits indefinitely on queue (portMAX_DELAY)
  • Coordination: Suspends all LED tasks during pattern execution

Pattern Definitions

Pattern Description LED(s) Used Duration
0 Blink Green 3 times Green (PC10) ~1.8s
1 Fade Blue LED in/out Blue (PC11) ~2.0s
2 Blink Red 5 times Red (PC12) ~2.0s

πŸŽ“ RTOS Concepts Demonstrated

This project serves as a comprehensive learning resource for embedded RTOS development:

1. Task Management

  • Creation: xTaskCreate() with configurable priorities and stack sizes
  • Scheduling: Preemptive priority-based scheduler
  • Suspension: vTaskSuspend() / vTaskResume() for coordinated control
  • Handles: Task handles for inter-task references

2. Timing & Synchronization

  • Periodic Tasks: vTaskDelayUntil() for drift-free periodic execution
  • Delay: vTaskDelay() for relative delays
  • Tick Configuration: 1ms tick rate (configTICK_RATE_HZ = 1000)

3. Inter-Task Communication

  • Task Notifications: Lightweight, ISR-safe signaling
    • vTaskNotifyGiveFromISR() from interrupt context
    • ulTaskNotifyTake() in task context
  • Queues: Type-safe message passing
    • xQueueCreate() for queue creation
    • xQueueSend() / xQueueReceive() for messaging

4. Interrupt Handling

  • NVIC Priority: Interrupt priority 5 (compatible with FreeRTOS)
  • ISR Safety: Using FromISR() API variants
  • Context Switch: portYIELD_FROM_ISR() for immediate task switching

5. Memory Management

  • Heap Scheme: heap_4.c (coalescence algorithm)
  • Total Heap: 6144 bytes (6 KB)
  • Allocation: Dynamic task and queue creation

βš™οΈ Hardware Configuration

GPIO Configuration

LED Outputs (GPIOC)

// PC10, PC11, PC12 - Output mode, high speed
GPIOC->MODER |= (1U << (2*10));   // PC10: Green LED
GPIOC->MODER |= (2U << (2*11));   // PC11: Blue LED (AF mode)
GPIOC->MODER |= (1U << (2*12));   // PC12: Red LED

Button Input (PC13)

// PC13 - Input mode with pull-up
GPIOC->MODER &= ~(3U << (2*13));  // Input mode
GPIOC->PUPDR |= (1U << (2*13));   // Pull-up enabled

TIM1 PWM Configuration (Blue LED)

Parameter Value Description
Timer Clock 16 MHz System clock (HSI)
Prescaler (PSC) 79 Timer clock = 200 kHz
Auto-Reload (ARR) 999 PWM frequency = 200 Hz
Channel 4 (PC11) TIM1_CH4
Mode PWM Mode 1 Active high
Output Main output enabled BDTR_MOE set

PWM Frequency Calculation:

f_PWM = f_timer / (ARR + 1)
      = 200 kHz / 1000
      = 200 Hz

EXTI Configuration (Button)

// EXTI13 - Falling edge trigger
EXTI->EXTICR[3] |= (2U << 8);    // Connect to Port C
EXTI->IMR1 |= (1U << 13);         // Unmask interrupt
EXTI->FTSR1 |= (1U << 13);        // Falling edge trigger
NVIC_SetPriority(EXTI4_15_IRQn, 5);
NVIC_EnableIRQ(EXTI4_15_IRQn);

UART2 Configuration

// 115200 baud, 8N1, no flow control
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;

πŸ”„ Operation Flow

Normal Operation (LED Controllers Active)

1. System starts β†’ FreeRTOS scheduler begins
2. All 5 tasks enter their while(1) loops
3. LED controller tasks run independently:
   - Green LED: Toggle every 500ms
   - Blue LED: Fade PWM duty cycle (0-100-0%)
   - Red LED: Toggle every 500ms
4. Button task waits for notification (5s timeout)
5. Pattern generator waits on queue (indefinite block)

Pattern Execution Sequence

1. User presses button (PC13 pulled low)
   ↓
2. EXTI13 interrupt fires β†’ EXTI4_15_IRQHandler()
   ↓
3. ISR sends notification β†’ vTaskNotifyGiveFromISR()
   ↓
4. Button task wakes up β†’ ulTaskNotifyTake() returns
   ↓
5. Button task cycles pattern: (N + 1) % 3
   ↓
6. Pattern sent to queue β†’ xQueueSend()
   ↓
7. Pattern generator wakes up β†’ xQueueReceive() returns
   ↓
8. Suspend all LED tasks β†’ vTaskSuspend() Γ— 3
   ↓
9. Turn off all LEDs (clean slate)
   ↓
10. Execute selected pattern (0, 1, or 2)
   ↓
11. Resume all LED tasks β†’ vTaskResume() Γ— 3
   ↓
12. Return to normal operation

πŸ’‘ Code Examples

Task Notification Pattern (ISR β†’ Task)

// In ISR context (button.c)
void EXTI4_15_IRQHandler(void)
{
    if(EXTI->FPR1 & (1U << 13))
    {
        EXTI->FPR1 |= (1U << 13);  // Clear flag
        
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        vTaskNotifyGiveFromISR(xButtonTaskHandle, &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

// In task context (main.c)
void vButtonControllerTask(void *pvParameters)
{
    while(1)
    {
        uint32_t notification = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(5000));
        
        if(notification > 0)
        {
            pattern = (pattern + 1) % 3;
            xQueueSend(xPatternQueue, &pattern, portMAX_DELAY);
        }
    }
}

Queue Communication Pattern

// Create queue in main()
xPatternQueue = xQueueCreate(5, sizeof(uint8_t));

// Producer (Button Task)
uint8_t pattern = 2;
xQueueSend(xPatternQueue, &pattern, portMAX_DELAY);

// Consumer (Pattern Generator Task)
uint8_t receivedPattern;
if(xQueueReceive(xPatternQueue, &receivedPattern, portMAX_DELAY) == pdPASS)
{
    // Process pattern
}

Precise Periodic Timing

void vGreenLedControllerTask(void *pvParameters)
{
    TickType_t xLastWakeTime = xTaskGetTickCount();
    const TickType_t xFrequency = pdMS_TO_TICKS(500);
    
    while(1)
    {
        led_on(10);
        vTaskDelayUntil(&xLastWakeTime, xFrequency);
        led_off(10);
        vTaskDelayUntil(&xLastWakeTime, xFrequency);
    }
}

PWM Duty Cycle Control

void set_pwm_duty_cycle(uint8_t duty_percent)
{
    if(duty_percent > 100)
        duty_percent = 100;
    
    TIM1->CCR4 = (TIM1->ARR + 1) * duty_percent / 100;
}

// Smooth fading (in Blue LED task)
void pwm_fade(void)
{
    static uint16_t brightness = 0;
    static uint8_t direction = 1;
    
    if(direction) {
        brightness += 10;
        if(brightness >= 999) direction = 0;
    } else {
        brightness -= 10;
        if(brightness <= 0) direction = 1;
    }
    
    TIM1->CCR4 = brightness;
}

πŸ“‘ UART Debug Output

The system provides real-time debug information via UART2 (115200 baud):

Example Console Output

=== BUTTON TASK STARTED ===
Pattern 0 sent to Pattern Generator Task
Pattern Generator Task received pattern: 0
Executing Pattern 0: Blink Green LED 3 times
Resumed LED controller tasks after pattern execution

Pattern 1 sent to Pattern Generator Task
Pattern Generator Task received pattern: 1
Executing Pattern 1: Fade Blue LED in and out
Resumed LED controller tasks after pattern execution

Pattern 2 sent to Pattern Generator Task
Pattern Generator Task received pattern: 2
Executing Pattern 2: Blink Red LED 5 times
Resumed LED controller tasks after pattern execution

UART Redirect (printf Support)

int __io_putchar(int ch)
{
    HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}

All printf() calls are automatically redirected to UART2.


βš™οΈ Configuration

FreeRTOS Configuration Highlights

File: Core/Inc/FreeRTOSConfig.h

Parameter Value Description
configUSE_PREEMPTION 1 Preemptive scheduling enabled
configCPU_CLOCK_HZ 16000000 16 MHz (HSI oscillator)
configTICK_RATE_HZ 1000 1 ms tick resolution
configMAX_PRIORITIES 56 Maximum priority levels
configMINIMAL_STACK_SIZE 128 Minimum stack (words)
configTOTAL_HEAP_SIZE 6144 Total heap size (bytes)
configUSE_TASK_NOTIFICATIONS 1 Task notifications enabled
configUSE_MUTEXES 1 Mutex support enabled
configUSE_TIMERS 1 Software timers enabled

Clock Configuration

  • System Clock: 16 MHz (HSI - High-Speed Internal oscillator)
  • AHB Prescaler: 1 (HCLK = 16 MHz)
  • APB Prescaler: 1 (PCLK = 16 MHz)
  • Timer Clock: 16 MHz (no prescaler on APB)

πŸ› οΈ Troubleshooting

Issue: LEDs not blinking

Possible Causes:

  1. βœ“ Check power supply and LED connections
  2. βœ“ Verify GPIO initialization (led_gpio_init() called)
  3. βœ“ Confirm FreeRTOS scheduler started (vTaskStartScheduler())
  4. βœ“ Check task creation was successful (handle != NULL)

Debug Steps:

// Add to main.c before while(1)
if(xGreenTaskHandle == NULL) {
    printf("ERROR: Green task creation failed!\n\r");
}

Issue: Button press not working

Possible Causes:

  1. βœ“ Interrupt not enabled (button_enable_interrupt() called)
  2. βœ“ Task handle not set (xButtonTaskHandle is NULL)
  3. βœ“ EXTI configuration error (check pin mapping)

Debug Steps:

// Add to EXTI interrupt handler
printf("Button ISR triggered!\n\r");

Issue: PWM not working on Blue LED

Possible Causes:

  1. βœ“ TIM1 not initialized (pwm_init() called)
  2. βœ“ GPIO alternate function not set (AF2 for PC11)
  3. βœ“ Main output not enabled (BDTR_MOE bit)

Verification:

// Check CCR4 register value
printf("TIM1->CCR4 = %lu\n\r", TIM1->CCR4);

Issue: System hangs or Hard Fault

Possible Causes:

  1. βœ“ Stack overflow (increase configMINIMAL_STACK_SIZE)
  2. βœ“ Heap exhausted (increase configTOTAL_HEAP_SIZE)
  3. βœ“ ISR priority too high (use 5 or higher for FreeRTOS compatibility)
  4. βœ“ configASSERT() triggered

Debug Steps:

  • Enable FreeRTOS stack overflow checking:
#define configCHECK_FOR_STACK_OVERFLOW 2
  • Monitor heap usage:
size_t freeHeap = xPortGetFreeHeapSize();
printf("Free heap: %u bytes\n\r", freeHeap);

Issue: UART output not visible

Possible Causes:

  1. βœ“ Incorrect baud rate (ensure 115200)
  2. βœ“ Wrong COM port selected
  3. βœ“ UART not initialized (MX_USART2_UART_Init() called)

Verification:

  • Check UART settings: 115200 baud, 8 data bits, no parity, 1 stop bit (8N1)
  • Verify TX pin (PA2) is properly connected

πŸš€ Future Enhancements

Recommended Improvements

  1. Event Groups for Synchronization

    • Replace vTaskSuspend() / vTaskResume() with Event Groups
    • More scalable and cleaner synchronization mechanism
  2. UART Command Interface

    • Implement pattern selection via serial commands
    • Add runtime configuration (LED brightness, timing)
  3. Software Timers

    • Button debouncing using FreeRTOS timers
    • Automatic pattern timeout/reset
  4. Runtime Statistics

    • Enable configGENERATE_RUN_TIME_STATS
    • Monitor task execution time and CPU usage
  5. Low Power Modes

    • Implement tickless idle mode
    • Use STM32 low-power modes during idle
  6. Enhanced Patterns

    • Music-like rhythm sequencing
    • User-configurable pattern library
    • Pattern chaining and loops
  7. Error Handling

    • Add comprehensive error detection
    • Implement recovery mechanisms
    • LED error indication codes
  8. Unit Testing

    • Add unit tests for peripheral drivers
    • Mock HAL for host-based testing

Coding Standards

  • Follow existing code style and indentation
  • Add comments for complex logic
  • Update documentation for API changes
  • Test on hardware before submitting PR

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

Third-Party Components

  • FreeRTOS Kernel: MIT License (Amazon FreeRTOS)
  • STM32 HAL Driver: BSD-3-Clause (STMicroelectronics)
  • CMSIS: Apache-2.0 (ARM Limited)

πŸ“š References

Official Documentation

Learning Resources


πŸ‘€ Author

kgsinh

About

FreeRTOS with STM32

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages