A deterministic, multi-tasking firmware built for the STM32F103C8T6 (Blue Pill) microcontroller using FreeRTOS. The system continuously reads simulated sensor telemetry (temperature, vibration) and streams structured log data over USART1 in real time.
Since physical hardware was not available during development, the complete firmware — including FreeRTOS kernel scheduling, interrupt handling, and USART output — was fully validated using the Renode hardware emulation framework, with zero changes required between simulation and real deployment.
- ✅ Multi-task FreeRTOS architecture with priority-based preemptive scheduling
- ✅ Deterministic interrupt vector mapping (
SVC,PendSV,SysTick) — no hardfaults - ✅ Real-time telemetry streaming via USART1 at 115200 baud
- ✅ Fully emulated on Renode — no physical hardware required
- ✅ Clean, portable codebase generated via STM32CubeMX + STM32CubeIDE
[STM32 Boot]
│
▼
[HAL & Clock Init] ──► USART1 @ 115200 baud
│ TIM1 Base Timer
▼
[FreeRTOS Kernel Start]
│
├──► [Task: Telemetry Logger] (High Priority)
│ └── Reads sensor data → formats log → sends to USART pipeline
│
└──► [Task: System Heartbeat] (Low Priority)
└── Periodic system status broadcast
The most critical configuration step — required to prevent the firmware from freezing at [DEBUG] Before Kernel Start... — is correctly mapping FreeRTOS kernel handlers to the STM32 HAL vector names inside Core/Inc/FreeRTOSConfig.h:
/* FreeRTOS Handler Remapping — STM32 Compatibility Fix */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_HandlerIn Core/Src/stm32f1xx_it.c, the default-generated native handler stubs for SVC_Handler, PendSV_Handler, and SysTick_Handler are removed. This avoids duplicate symbol conflicts and hands full deterministic control to the FreeRTOS kernel loop.
This project was developed and tested entirely on Renode v1.16.1 — an open-source hardware emulation framework that creates an accurate virtual ARM Cortex-M3 environment.
| Tool | Version |
|---|---|
| Renode | v1.16.1+ |
| STM32CubeIDE | 1.14.x |
| GNU Arm Embedded Toolchain | 10.3-2021.10+ |
Step 1: Open the Renode Monitor (terminal or GUI).
Step 2: Load the project deployment script:
include @C:\STM\STM32_Projects\SensorTelemetry\run.rescStep 3: Start emulation:
startStep 4: Open the USART1 virtual console window to observe live telemetry output.
Once the FreeRTOS scheduler is running, the following telemetry stream appears on the USART1 virtual console at 115200 baud:
[SYSTEM] STM32 Hardware initialized successfully!
[DEBUG] Before Kernel Start...
[TELEMETRY] Temp: 25 C | Vibration: Normal | Status: All Systems GO!
[TELEMETRY] Temp: 26 C | Vibration: Normal | Status: All Systems GO!
[TELEMETRY] Temp: 27 C | Vibration: Normal | Status: All Systems GO!
[TELEMETRY] Temp: 25 C | Vibration: Normal | Status: All Systems GO!
Troubleshooting: If output stops at
[DEBUG] Before Kernel Start..., verify that the FreeRTOS interrupt vectors are correctly remapped inFreeRTOSConfig.has shown above. This is the most common cause of kernel startup failure on STM32.
SensorTelemetry/
├── Core/
│ ├── Inc/
│ │ ├── FreeRTOSConfig.h # FreeRTOS kernel config & vector remapping
│ │ ├── main.h
│ │ └── stm32f1xx_it.h
│ └── Src/
│ ├── main.c # HAL init, task creation, scheduler launch
│ ├── stm32f1xx_it.c # Interrupt handlers (native stubs removed)
│ └── freertos.c # Task definitions & telemetry logic
├── Drivers/
│ ├── CMSIS/ # ARM Cortex-M3 core support files
│ └── STM32F1xx_HAL_Driver/ # STM32 HAL peripheral drivers
├── Middlewares/
│ └── FreeRTOS/ # FreeRTOS kernel source
├── run.resc # Renode emulation script
└── README.md
| Category | Tool / Technology |
|---|---|
| Microcontroller | STM32F103C8T6 (ARM Cortex-M3) |
| Real-Time OS | FreeRTOS Kernel |
| Emulation Platform | Renode v1.16.1 |
| IDE | STM32CubeIDE |
| Code Generator | STM32CubeMX |
| Toolchain | GNU Arm Embedded Toolchain |
| Language | Embedded C |
- Understood FreeRTOS task lifecycle, preemptive scheduling, and priority inversion pitfalls
- Debugged hardfault root causes from misconfigured interrupt vector tables
- Gained hands-on experience with hardware-in-the-loop emulation using Renode as a physical hardware substitute
- Practiced clean firmware architecture separation (HAL init → RTOS → Application layer)
This project is licensed under the MIT License — free to use, modify, and distribute for educational and personal projects.
Built with ☕ and way too many hardfault debugging sessions — Sugavanam