A from-scratch bare-metal firmware project for the STM32F103RB (ARM Cortex-M3) Nucleo board.
This repo shows how to build embedded systems without vendor IDEs or auto-generated HAL code : using only Makefiles, linker scripts, and OpenOCD.
Most STM32 tutorials start with CubeIDE or HAL libraries. Here, everything is done manually:
- Custom startup code (vector table + Reset_Handler).
- Hand-written linker script.
- Minimal Makefile toolchain.
- Direct register access (no HAL, no CMSIS).
- Flash + debug using OpenOCD + GDB.
This repo proves end-to-end understanding of ARM Cortex-M architecture and the firmware build pipeline.
- Target MCU: STM32F103RB (Cortex-M3, ARMv7-M)
- Board: Nucleo-F103RB
- Peripherals Used: GPIO (LED blink on PA5)
- Workflow: GCC ARM toolchain + Make + OpenOCD
- Vector table at
0x08000000
- Reset handler:
.data
copy,.bss
zero, callmain()
- Custom linker script with defined memory regions
- GPIOA clock enable + PA5 LED toggle
- Makefile build system
- Flash/debug with OpenOCD & GDB
- src/ – Application C sources (main.c)
- startup/ – Startup assembly (startup.s)
- include/ – Optional headers
- linker.ld – Custom linker script
- Makefile – Build system
- build/ – Generated build artifacts (.o, .elf, .bin)
- docs/ – In-depth technical explanations
- README.md
- How Cortex-M boots after reset.
- Why startup code matters (stack pointer, Reset_Handler).
- How
.text
,.data
,.bss
, and stack are placed in memory. - How to control peripherals via RCC and GPIO registers.
- How OpenOCD + GDB interact with the MCU via SWD.
arm-none-eabi-gcc
→ compile & linkarm-none-eabi-objcopy
→ ELF → BIN/HEXOpenOCD
→ flash binary & debug bridgeGDB
→ live debugging
Pipeline:
source.c ---> gcc ---> .o ---> ld ---> firmware.elf
---> objcopy ---> firmware.bin ---> OpenOCD ---> MCU
1. Build project
make
Generates build/firmware.elf → ELF executable build/firmware.bin → raw binary for flashing
- Flash to board (via ST-Link)
make flash
- Run + inspect binary size
make run
- Debug with GDB over OpenOCD
bash
make gdb
Opens OpenOCD GDB server.
Launches arm-none-eabi-gdb connected to :3333.
This repo doubles as a learning resource.
- Startup & Reset Flow
- Linker Script Deep Dive
- GPIO & Peripheral Registers
- Toolchain Explained
- ARM Cortex-M3 Architecture Notes
- 🔹 Beginners who want to learn Cortex-M bare metal.
- 🔹 Engineers tired of opaque IDEs/HALs.
- 🔹 Recruiters who want proof of deep embedded expertise.
- Add SysTick timer for delay (instead of busy loops).
- Implement UART driver (printf over USART2).
- Explore interrupts & NVIC.
- Extend docs into a mini Cortex-M bare-metal handbook.
Built with curiosity and first-principles thinking by Ronit.
Always learning, always building.