embedded-trainings-2020/down-the-stack-book/src/the_hal.md
Jonathan Pallant b7fca7dc70
Update down-the-stack-book/src/the_hal.md
Co-authored-by: Tanks Transfeld <Mirabellensaft@users.noreply.github.com>
2023-03-23 13:54:16 +00:00

2.3 KiB

The Hardware Abstraction Layer


Building a driver

  • Writing to all those registers is tedious
    • You have to get the values right, and the order right
  • Can we wrap it up into a nicer, easier-to-use object?

Typical driver interface

let p = pac::Peripherals.take().unwrap();
let mut uarte0 = hal::uarte::Uarte::new(
    // Our singleton representing exclusive access to
    // the peripheral IP block
    p.UARTE0,
    // Some other settings we might need
    115200,
    hal::uarte::Parity::None,
    hal::uarte::Handshaking::None,
);
// Using the `uarte0` object:
uarte0.write_all(b"Hey, I'm using a UART!").unwrap();

The Hardware Abstraction Layer

  • Contains all the drivers for a chip
  • Often common/shared across chip families
    • e.g. nRF52 HAL for 52832, 52840, etc
  • Usually community developed
  • Often quite different between MCU vendors
    • Different teams came up with different designs!

Kinds of driver

  • PLL / Clock Configuration
  • Reset / Power Control of Peripherals
  • GPIO pins
  • UART
  • SPI
  • I²C
  • ADC
  • Timer/Counters
  • and more!

Handling GPIO pins with code

// Get the singletons
let p = pac::Peripherals.take().unwrap();
// Make a driver for GPIO port P0
let pins = hal::gpio::p0::Parts::new(p.P0);
// Get Pin 13 on port P0 and make it an output
let mut led_pin = pins.p0_13.into_push_pull_output(Level::High);
// Now set the output low
led_pin.set_low();

This differs widely across MCUs (ST, Nordic, Espressif, Atmel, etc). Some MCUs (e.g. Nordic) let you put any function on any pin, and some are much more restrictive!


Correctness by design

  • HALs want to make it hard to do the wrong thing
  • Is a UART driver of any use, if you haven't configured at least one TX pin and one RX pin?
  • Should the UART driver check you've done that?

Giving the pins to the driver

// 'degrade()' converts a P0_08 type into a generic Pin type.
let pins =  hal::uarte::Pins {
    rxd: pins.p0_08.degrade().into_floating_input(),
    txd: pins.p0_06.degrade().into_push_pull_output(Level::High),
    cts: None,
    rts: None,
};

let uarte = hal::uarte::Uarte::new(periph.UARTE1, pins, Parity::EXCLUDED, Baudrate::BAUD115200);

This is an example for the nRF52. We'll use it later in the example.