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

98 lines
2.3 KiB
Markdown

# 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
```rust
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
```rust
// 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
```rust
// '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.