In modern embedded systems, doing one thing at a time is rarely enough. We need to read sensors, update displays, and control actuators all "at the same time." This project demonstrates how to implement a Real-Time Operating System (FreeRTOS) on the RT-Thread RT-Spark (STM32F407) development board to manage four distinct tasks simultaneously:
- Display temperature on LCD
- Adjust RGB LED brightness via potentiometer
- Show incrementing counter on LCD
- Blink status LED
During development, I encountered a critical hardware conflict. The RT-Spark board has an onboard 19-LED WS2812B matrix hardwired to pin PA7.
I initially attempted to use PA7 to drive the Green channel of my external RGB LED. Even though I programmatically disabled the onboard matrix power (Pin PF2), the matrix continued to flicker wildly whenever the Green LED was active.
The Diagnosis: This was a classic case of "Phantom Power." The PWM signal sent to PA7 was leaking through the data input of the onboard LEDs, energizing their internal logic circuits even without the main VCC connected.
The Solution : I completely isolated the external hardware from the onboard peripherals by:
- Hardware Isolation: Moving all RGB control lines to Timer 1 (Port E) and Timer 3 (Port A), avoiding the conflict pins entirely.
- Software "Kill Switch": Writing a specific function
Kill_Onboard_Hardware()that runs at startup to aggressively drive the conflict pins (PF2 and PF12) to a safe state, ensuring the onboard components remain silent.
- RT-Thread RT-Spark Board (STM32F407ZGT6)
- External RGB LED (4-Pin, Common Cathode)
- Potentiometer (10kΩ or similar)
- Resistors (220Ω - 330Ω x3 for LED protection)
- Breadboard & Jumper Wires
This is the final, conflict-free wiring configuration used in the project.
To replicate this project, configure your .ioc file as follows:
1.Timers (PWM Generation):
- TIM3: Channel 1 & Channel 2 enabled. (Prescaler: 15, Period: 999).
- TIM1: Channel 3 enabled. (Prescaler: 15, Period: 999).
- Why? This gives a 1kHz PWM frequency, perfect for flicker-free LED control.
2.Analog (ADC):
- ADC1: IN1 (Single-ended mode).
3.Connectivity (FSMC):
- Enabled for the onboard ST7789 LCD.
- Crucial Setting: Set "Write Operation" to Enabled.
4.Middleware:
- FreeRTOS: Interface set to CMSIS_V2.
The core logic is handled in main.c. We define four tasks and one Mutex.
This function runs immediately after initialization to ensure the onboard matrix and Red LED do not interfere with our external components.
This task reads the potentiometer and updates the brightness. It features hysteresis (ignoring noise < 20) and a deadzone (forcing 0 at low values) to prevent flickering.
This task blinks the onboard Yellow LED (PF11) to show the RTOS is alive. Crucially, it also reinforces the "Safety Kill" on the Red LED (PF12). Since the FSMC peripheral shares a pin with the Red LED, it occasionally tries to toggle it. This task forces it back OFF every cycle.
4. The Counter Task (UI Update)
This task demonstrates simple periodic updates. It increments a number and updates the display every 500ms. Note the use of LCD_ShowString with spaces to clear the previous number before drawing the new one.
Reads data from the AHT21 sensor and updates the display.
When the system boots up:
1.Startup: The Onboard Matrix stays dark (success!). The external RGB LED stays off until the potentiometer is moved.
2.LCD Display:
- Temp: Shows real-time temperature in Red.
- Hum: Shows humidity in Blue.
- Counter: Increments every 500ms.
- LED Brightness: Shows 0-100% based on the knob position.
3.Visuals:
- The Yellow onboard LED blinks steadily (indicating the RTOS heartbeat is alive).
- Turning the potentiometer smoothly fades the external RGB LED from Off -> White -> Bright White.
Video link: https://drive.google.com/file/d/1W_uP7u19ETCzEoCuDDwYHd4BvZ-pWlWk/view?usp=sharing














Comments