Embedded
- Rust course
- Expert
- Lesson 33/46
- 4 min
Program microcontrollers with embedded-hal.
Embedded
Hardware access in embedded Rust is layered: vendor register definitions (PAC), a chip HAL, and on top of those the embedded-hal traits. Drivers (sensors, displays) are written against these traits, so the same driver runs on different microcontrollers:
// embedded-hal
pub trait OutputPin {
type Error;
fn set_high(&mut self) -> Result<(), Self::Error>;
fn set_low(&mut self) -> Result<(), Self::Error>;
}
fn yak_sondur<P: OutputPin>(led: &mut P) -> Result<(), P::Error> {
led.set_high()?;
led.set_low()
}For testing on a desktop, a mock pin implementing the same trait is written.
A mock pin
A mock pin recording state changes verifies driver logic without real hardware:
struct SahtePin {
kayit: String,
}
impl OutputPin for SahtePin {
type Error = core::convert::Infallible;
fn set_high(&mut self) -> Result<(), Self::Error> {
self.kayit.push('H');
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
self.kayit.push('L');
Ok(())
}
}Infallible is an empty error type saying "this operation never fails".
Practice Blink an LED
Write the OutputPin trait above and the SahtePin type. Blink the mock pin three times with fn yak_sondur<P: OutputPin>(led: &mut P) and print the record.
Starter code
fn main() {
// buraya yaz
}Sample solution
pub trait OutputPin {
type Error;
fn set_high(&mut self) -> Result<(), Self::Error>;
fn set_low(&mut self) -> Result<(), Self::Error>;
}
struct SahtePin {
kayit: String,
}
impl OutputPin for SahtePin {
type Error = core::convert::Infallible;
fn set_high(&mut self) -> Result<(), Self::Error> {
self.kayit.push('H');
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
self.kayit.push('L');
Ok(())
}
}
fn yak_sondur<P: OutputPin>(led: &mut P) -> Result<(), P::Error> {
led.set_high()?;
led.set_low()
}
fn main() {
let mut pin = SahtePin { kayit: String::new() };
for _ in 0..3 {
yak_sondur(&mut pin).unwrap();
}
println!("{}", pin.kayit);
}Expected output
HLHLHL
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What is the benefit of writing a driver against a trait instead of a concrete chip type?
- The same driver works on any compatible hardware and in desktop tests Correct answer
- It's faster
- Less memory
- No benefit
Explanation: Since it's generic there's no runtime cost; the compiler generates specialized code for each chip.
2 Never fails
impl OutputPin for SahtePin {
type Error = core::convert::____;
..
}
impl OutputPin for SahtePin {
type Error = core::convert::Infallible;
..
}
Explanation: Infallible is a type with no values, saying failure is impossible.
3 Layer and role
| Term | Meaning |
|---|---|
PAC |
Register definitions |
HAL |
Chip abstraction |
embedded-hal |
Common traits |
Driver |
Written against traits |