Skip to content
All projects
FirmwareCompleted2025

STM32 Bare-Metal Peripheral Driver Library

Register-level UART / I²C / SPI drivers for STM32F4, no HAL

Core

ARM Cortex-M4 (STM32F4)

UART

115200 baud · IRQ RX

I²C

400 kHz Fast Mode

Sensor

BMP280 ±0.5 °C / ±1 hPa

01Overview

A from-scratch peripheral driver library for the STM32F4, written in C with no HAL abstractions. Drivers for UART, I²C, and SPI are built by configuring RCC, GPIO, and the peripheral registers directly, giving full control over clocking, pin alternate functions, and peripheral behavior.

The library is validated against a real sensor, a Bosch BMP280 over SPI, with register-level initialization, burst reads, and the manufacturer compensation formulas applied to produce calibrated measurements.

02Problem Statement

HAL libraries are convenient but opaque; they hide the register-level reality that embedded engineers are expected to understand and debug.

Building drivers directly on the registers forces a correct mental model of clock trees, GPIO alternate functions, peripheral configuration, and interrupt handling.

03Architecture

Each driver (UART, I²C, SPI) owns its peripheral end to end: enabling the clock through RCC, configuring the GPIO alternate functions, and setting up the peripheral registers for the target mode and speed.

UART runs at 115200 baud with an interrupt-driven receive path backed by an ISR-based 64-byte circular buffer, enabling non-blocking real-time serial communication. I²C is configured for 400 kHz Fast Mode.

A BMP280 sensor is integrated over SPI with register-level initialization, burst-read routines, and the compensation formulas needed to convert raw readings into calibrated temperature and pressure.

04Technical Challenges

Driving peripherals from raw registers

Without HAL, every detail is manual: enabling peripheral clocks via RCC, selecting GPIO alternate functions, and configuring peripheral control registers correctly for the chosen mode and baud/clock rate. Getting clocking and pin configuration exactly right is the difference between a working bus and silence.

Non-blocking serial under interrupts

A blocking UART stalls the application. An interrupt-driven receive path with an ISR-based 64-byte circular buffer lets the firmware accept bytes asynchronously and process them when ready, keeping serial communication real-time and non-blocking.

Calibrated sensor output

Raw BMP280 readings are meaningless without the compensation formulas. Applying them correctly, on top of register-level init and burst reads, is what yields validated accuracy of ±0.5 °C and ±1 hPa.

05Implementation Details

UART / I²C / SPI from RCC + GPIO up

Implemented UART, I²C, and SPI drivers by directly configuring RCC, GPIO, and peripheral registers, deliberately avoiding HAL abstractions. UART targets 115200 baud; I²C targets 400 kHz Fast Mode.

BMP280 over SPI

Integrated a BMP280 sensor over SPI with register-level initialization, burst-read routines, and the compensation formulas, validating accuracy to ±0.5 °C and ±1 hPa.

Interrupt-driven UART receive

Built an interrupt-driven UART receive path with configured NVIC priorities and an ISR-based 64-byte circular buffer, enabling non-blocking real-time serial communication.

06Key Engineering Decisions

No HAL, on purpose

Avoiding HAL was the entire point. The library exists to demonstrate and exercise register-level control of the STM32F4, the skill that distinguishes firmware engineers from API consumers.

Circular buffer for RX

A fixed 64-byte ISR-fed circular buffer decouples byte arrival from processing, the standard pattern for robust, non-blocking serial input on a microcontroller.

Validate against a real sensor

Targeting a real BMP280 and checking against datasheet accuracy turns the library from an exercise into something provably correct.

07Future Improvements

  • Add DMA paths for UART/SPI to further reduce CPU involvement.
  • Generalize the driver interfaces into a small reusable HAL-free framework.
  • Add unit-test harnesses and on-target self-tests for each peripheral.
  • Extend sensor support beyond the BMP280 family.

08Media & Documentation

Visual documentation for this project. Placeholders below are reserved for assets being produced during development.

Firmware diagramRCC → GPIO → peripheral init flow
Asset pending
Logic analyzerUART 115200 baud framing capture
Asset pending
Scope captureI²C Fast Mode (400 kHz) waveform
Asset pending

Open to opportunities

Seeking Fall 2026 embedded / firmware / hardware co-op.

If you're hiring for embedded, firmware, or hardware roles, I'd be glad to talk through my projects and how I work. The fastest way to reach me is email.