Peripherals and the Type State Pattern

Why the HAL makes misconfigured pins fail to compile.

Part 2 of 3Updated

Peripherals::take() returns Option and yields None on the second call. That’s a singleton enforced at runtime — there is exactly one set of hardware registers, so exactly one owner.

Then the HAL encodes pin configuration in the type:

let pin: Pin<Output<PushPull>> = gpioa.pa5.into_push_pull_output(&mut gpioa.crl);
pin.set_high();   // exists

let pin: Pin<Input<Floating>> = /* ... */;
pin.set_high();   // does not compile — no such method

This is the type state pattern: calling set_high() on an input pin isn’t a bug you debug with an oscilloscope, it’s a compile error. Embedded Rust’s real pitch isn’t speed — C is already fast — it’s that a whole category of hardware misconfiguration stops being possible.