What Is a BSP?

~5 min slides

The Top of the Stack

A Board Support Package encapsulates board-specific knowledge — pin assignments, peripheral configuration, and hardware defaults.

BSP allows us to skip the configure step. Pattern becomes Instantiate → Control.

Same idea as HAL with PAC — BSP takes PAC singletons as input to create HAL instances and use them.

Without BSP (raw HAL)

#![allow(unused)]
fn main() {
// Instantiate
let peripherals = esp_hal::init(Config::default());

// Configure
let led = Output::new(
    peripherals.GPIO5,
    Level::Low,
    OutputConfig::default(),
);

// Control
led.set_high();
}

With BSP

#![allow(unused)]
fn main() {
// Instantiate (BSP takes HAL peripherals as input)
let peripherals = esp_hal::init(Config::default());
let mut uferris = uferris_init(peripherals).unwrap();

// Control — no configure step needed
uferris.led1_on();
}

The BSP still requires instantiation — you pass the HAL peripherals into uferris_init(). But the board-specific configuration (which pin, what drive strength, which pull resistor) is all handled internally. You go straight from Instantiate to Control.

It's Not Magic

The BSP is just Rust code that does exactly what you've been doing — but packages it up with meaningful names. Open the source and you'll see Output::new(), I2c::new(), and all the same patterns.

The value is:

  • No pin lookup errors — the board knows its own pin assignments
  • Sensible defaults — configurations chosen for the specific board's hardware
  • Convenience — less boilerplate for common setups

When to Use a BSP vs. Raw HAL

Use BSP WhenUse Raw HAL When
Quick prototypingYou need non-default configurations
Your board has a BSPYou're using custom hardware
You don't need fine controlYou want to learn the lower layers

In a workshop about ecosystem navigation, understanding the raw HAL is essential. The BSP is the reward: once you understand the layers underneath, you can appreciate what the BSP does for you.