← Back to Projects
Embedded SystemsBare-Metal ProgrammingAArch64ARM AssemblyGPIOInterruptsUARTLow-Level Systems

Raspberry Pi Bare-Metal Systems Programming (AArch64)

Bare-metal Raspberry Pi programs in C and AArch64 assembly: boot/runtime init, GPIO control, interrupts, timers, and serial UART debugging without an operating system.

Overview

A collection of bare-metal Raspberry Pi programs that boot directly on hardware with no OS. Implemented (and extended) startup/runtime code, controlled GPIO, handled interrupts via exception vectors, and built small demos (LED patterns, input handling, timer-driven behaviors) with UART-based debugging.

Build practical intuition for hardware–software interaction by programming the Pi at the register level: initialization, exception vectors, device I/O, timing, and debugging without OS tooling.

Your Role

What I Built

  • Bare-metal boot and runtime initialization (provided starter + custom extensions)
  • GPIO control for LED output and input devices
  • Interrupt handling via exception vector setup and ISRs
  • Timer-driven and interrupt-driven demos (patterns, state changes, input response)
  • Serial UART output for debugging and observability

What I Owned End-to-End

  • AArch64 + C integration for low-level runtime behavior and device control
  • Memory-mapped I/O register configuration for GPIO/UART
  • Interrupt service routines (ISRs) and state-machine style control flow
  • UART-based debugging workflow for bare-metal development

Technical Highlights

Architecture Decisions

  • Bare-metal execution: no OS, minimal runtime, direct hardware control
  • Memory-mapped I/O for GPIO and UART
  • Interrupt-driven control flow using exception vectors (plus timer-based behaviors)
  • State-machine logic to coordinate LED/input behaviors deterministically

Algorithms / Protocols / Constraints

  • Interrupt-driven state transitions from input events
  • Timer-based scheduling for periodic behaviors
  • Deterministic sequencing for patterns and timing

Failure Handling

  • Interrupt masking/unmasking to avoid unsafe re-entrancy
  • Careful state transitions to avoid undefined hardware behavior

Optimization Strategies

  • Interrupt-driven design to avoid constant polling where appropriate
  • Small footprint and low overhead by staying bare-metal

Tech Stack

CAArch64 AssemblyRaspberry PiCross-Compilation Toolchain

Results / Learnings

What Worked

  • Booted and ran custom bare-metal code on Raspberry Pi hardware
  • Implemented GPIO control and interrupt-driven input handling without an OS
  • Used UART for practical debugging/visibility in a constrained bare-metal environment

What I Learned

  • How exception vectors, ISRs, and device registers interact at the CPU level
  • Bare-metal timing/debugging requires building your own observability primitives
  • Low-level work demands strict discipline around state, timing, and side effects

Tradeoffs Considered

  • Optimized for learning and control over portability
  • Accepted higher development overhead in exchange for full-stack hardware visibility
  • Kept demos small and deterministic rather than building complex drivers/abstractions