Embedded Abstractions — The Layer Cake

~15 min

Embedded Rust is built in layers. Understanding these layers is the single most important thing you'll learn today — because once you see the pattern, you can navigate any crate in the ecosystem.

The Five Layers

From lowest (closest to hardware) to highest (most convenient):

┌─────────────────────────────────┐
│         BSP                     │  Board Support Package
│   (board-specific config)       │  e.g., uferris-bsp
├─────────────────────────────────┤
│       Driver Crates             │  Hardware-agnostic drivers
│   (sensor/device drivers)       │  e.g., icm42670, bmp180
├─────────────────────────────────┤
│     embedded-hal Traits         │  The portable interface
│    (the "contract")             │  e.g., InputPin, I2c
├─────────────────────────────────┤
│         HAL                     │  Hardware Abstraction Layer
│   (chip-specific safe API)      │  e.g., esp-hal
├─────────────────────────────────┤
│         PAC                     │  Peripheral Access Crate
│   (raw register access)         │  e.g., esp32c3 (auto-generated)
└─────────────────────────────────┘
        ↓ Hardware ↓

PAC — Peripheral Access Crate

The lowest layer. Auto-generated from SVD (System View Description) files — basically, a Rust representation of every register in the chip. You can use it directly, but you almost never need to.

#![allow(unused)]
fn main() {
// PAC-level: writing directly to a register
// You don't want to do this. But it's good to know it exists.
peripherals.GPIO.out_w1ts.write(|w| unsafe { w.bits(1 << 5) });
}

HAL — Hardware Abstraction Layer

This is where we'll spend most of our time. The HAL provides safe, ergonomic Rust APIs on top of the PAC. For ESP32 chips, this is esp-hal.

#![allow(unused)]
fn main() {
// HAL-level: safe, readable, type-checked
let mut led = Output::new(peripherals.GPIO5, Level::Low, OutputConfig::default());
led.set_high();
}

embedded-hal Traits

The key to portability. These traits define a contract — a standard interface that any HAL can implement. If your code uses embedded_hal::digital::OutputPin instead of esp_hal::gpio::Output directly, it can work on any chip.

#![allow(unused)]
fn main() {
// This function works on ANY microcontroller that implements OutputPin
fn blink(pin: &mut impl OutputPin, delay: &mut impl DelayNs) {
    pin.set_high().unwrap();
    delay.delay_ms(500);
    pin.set_low().unwrap();
    delay.delay_ms(500);
}
}

Driver Crates

Built on top of embedded-hal traits. A driver crate provides a high-level API for a specific sensor or device — and it works on any chip because it only depends on the traits, not on any specific HAL.

#![allow(unused)]
fn main() {
// This driver doesn't know about ESP32. It just needs something that implements I2c.
let mut imu = Icm42670::new(i2c, Address::Primary);
let accel = imu.accel_norm().unwrap();
}

BSP — Board Support Package

The highest layer. A BSP pre-configures everything for a specific board — pin assignments, peripheral setup, default configurations. Instead of remembering pin numbers, you use meaningful names.

#![allow(unused)]
fn main() {
// Without BSP: which pin is the LED again?
let led = Output::new(peripherals.GPIO5, Level::Low, OutputConfig::default());

// With BSP: the board knows
let led = board.led();
}
When you're reading documentation, knowing which layer you're looking at tells you *what kind of information to expect*. HAL docs show chip-specific APIs. Driver crate docs show device-specific APIs. embedded-hal docs show the contract between them.

How the Layers Connect

The power of this architecture:

  1. esp-hal implements embedded-hal traits for ESP32-C3 hardware
  2. Driver crates are written against embedded-hal traits
  3. So any driver crate works with any HAL — no glue code needed

This is why you can take an IMU driver written by someone who's never touched an ESP32, plug it into esp-hal's I2C, and it just works. The traits are the contract that makes this possible.

In the next section, we'll see how this maps to a pattern you'll use for every peripheral.