Skip to content

Commit

Permalink
Refactor GpioPort to use the zero-sized GPIO* types directly (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
phil-opp authored Feb 1, 2019
1 parent e237f2c commit a7c30a3
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 163 deletions.
22 changes: 11 additions & 11 deletions src/bin/async-await.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,17 @@ fn run() -> ! {
init::enable_gpio_ports(&mut rcc);
init::enable_syscfg(&mut rcc);

let gpio_a = GpioPort::new_a(&peripherals.GPIOA);
let gpio_b = GpioPort::new_b(&peripherals.GPIOB);
let gpio_c = GpioPort::new(&peripherals.GPIOC);
let gpio_d = GpioPort::new(&peripherals.GPIOD);
let gpio_e = GpioPort::new(&peripherals.GPIOE);
let gpio_f = GpioPort::new(&peripherals.GPIOF);
let gpio_g = GpioPort::new(&peripherals.GPIOG);
let gpio_h = GpioPort::new(&peripherals.GPIOH);
let gpio_i = GpioPort::new(&peripherals.GPIOI);
let gpio_j = GpioPort::new(&peripherals.GPIOJ);
let gpio_k = GpioPort::new(&peripherals.GPIOK);
let gpio_a = GpioPort::new(peripherals.GPIOA);
let gpio_b = GpioPort::new(peripherals.GPIOB);
let gpio_c = GpioPort::new(peripherals.GPIOC);
let gpio_d = GpioPort::new(peripherals.GPIOD);
let gpio_e = GpioPort::new(peripherals.GPIOE);
let gpio_f = GpioPort::new(peripherals.GPIOF);
let gpio_g = GpioPort::new(peripherals.GPIOG);
let gpio_h = GpioPort::new(peripherals.GPIOH);
let gpio_i = GpioPort::new(peripherals.GPIOI);
let gpio_j = GpioPort::new(peripherals.GPIOJ);
let gpio_k = GpioPort::new(peripherals.GPIOK);
let mut pins = init::pins(
gpio_a, gpio_b, gpio_c, gpio_d, gpio_e, gpio_f, gpio_g, gpio_h, gpio_i, gpio_j, gpio_k,
);
Expand Down
22 changes: 11 additions & 11 deletions src/bin/polling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,17 @@ fn main() -> ! {
init::init_system_clock_216mhz(&mut rcc, &mut pwr, &mut flash);
init::enable_gpio_ports(&mut rcc);

let gpio_a = GpioPort::new_a(&peripherals.GPIOA);
let gpio_b = GpioPort::new_b(&peripherals.GPIOB);
let gpio_c = GpioPort::new(&peripherals.GPIOC);
let gpio_d = GpioPort::new(&peripherals.GPIOD);
let gpio_e = GpioPort::new(&peripherals.GPIOE);
let gpio_f = GpioPort::new(&peripherals.GPIOF);
let gpio_g = GpioPort::new(&peripherals.GPIOG);
let gpio_h = GpioPort::new(&peripherals.GPIOH);
let gpio_i = GpioPort::new(&peripherals.GPIOI);
let gpio_j = GpioPort::new(&peripherals.GPIOJ);
let gpio_k = GpioPort::new(&peripherals.GPIOK);
let gpio_a = GpioPort::new(peripherals.GPIOA);
let gpio_b = GpioPort::new(peripherals.GPIOB);
let gpio_c = GpioPort::new(peripherals.GPIOC);
let gpio_d = GpioPort::new(peripherals.GPIOD);
let gpio_e = GpioPort::new(peripherals.GPIOE);
let gpio_f = GpioPort::new(peripherals.GPIOF);
let gpio_g = GpioPort::new(peripherals.GPIOG);
let gpio_h = GpioPort::new(peripherals.GPIOH);
let gpio_i = GpioPort::new(peripherals.GPIOI);
let gpio_j = GpioPort::new(peripherals.GPIOJ);
let gpio_k = GpioPort::new(peripherals.GPIOK);
let mut pins = init::pins(
gpio_a, gpio_b, gpio_c, gpio_d, gpio_e, gpio_f, gpio_g, gpio_h, gpio_i, gpio_j, gpio_k,
);
Expand Down
172 changes: 44 additions & 128 deletions src/gpio/port.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use super::*;
use core::marker::PhantomData;
use stm32f7::stm32f7x6::{gpioa, gpiob, gpiod};
use stm32f7::stm32f7x6::{
gpioa, gpiob, gpiod, GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH, GPIOI, GPIOJ,
GPIOK,
};

/// Abstraction for a GPIO port that allows safe configuration of the port's pins.
pub struct GpioPort<T> {
pub struct GpioPort<T: RegisterBlockTrait> {
pub(super) pin_in_use: [bool; 16],
register_block: T,
}
Expand All @@ -15,124 +18,25 @@ pub enum Error {
PinAlreadyInUse(PinNumber),
}

/// A generic struct representing a hardware GPIO register block.
///
/// This struct is needed because the GPIO A, GPIO B, and the other GPIO ports have slight
/// differences in their reset values so that the SVD file and svd2rust use different types
/// for them.
pub struct RegisterBlock<'a, I: 'a, O: 'a, M: 'a, P: 'a, B: 'a, T: 'a, S: 'a, AH: 'a, AL: 'a> {
idr: &'a I,
odr: &'a O,
moder: &'a M,
pupdr: &'a P,
bsrr: &'a B,
otyper: &'a T,
ospeedr: &'a S,
afrh: &'a AH,
afrl: &'a AL,
}

/// An instantiation of the generic `RegisterBlock` for GPIO port A.
pub type RegisterBlockA<'a> = RegisterBlock<
'a,
gpioa::IDR,
gpioa::ODR,
gpioa::MODER,
gpioa::PUPDR,
gpioa::BSRR,
gpioa::OTYPER,
gpioa::OSPEEDR,
gpioa::AFRH,
gpioa::AFRL,
>;

/// An instantiation of the generic `RegisterBlock` for GPIO port B.
pub type RegisterBlockB<'a> = RegisterBlock<
'a,
gpiob::IDR,
gpiob::ODR,
gpiob::MODER,
gpiob::PUPDR,
gpiob::BSRR,
gpiob::OTYPER,
gpiob::OSPEEDR,
gpiob::AFRH,
gpiob::AFRL,
>;

/// An instantiation of the generic `RegisterBlock` for the remaining GPIO ports.
pub type RegisterBlockD<'a> = RegisterBlock<
'a,
gpiod::IDR,
gpiod::ODR,
gpiod::MODER,
gpiod::PUPDR,
gpiod::BSRR,
gpiod::OTYPER,
gpiod::OSPEEDR,
gpiod::AFRH,
gpiod::AFRL,
>;

macro_rules! new_gpio_port {
($register_block:expr) => {
GpioPort {
pin_in_use: [false; 16],
register_block: RegisterBlock {
idr: &$register_block.idr,
odr: &$register_block.odr,
moder: &$register_block.moder,
pupdr: &$register_block.pupdr,
bsrr: &$register_block.bsrr,
otyper: &$register_block.otyper,
ospeedr: &$register_block.ospeedr,
afrh: &$register_block.afrh,
afrl: &$register_block.afrl,
},
}
};
}

impl<'a> GpioPort<RegisterBlockA<'a>> {
/// Create a new `RegisterBlockA` from the hardware register block.
pub fn new_a(register_block: &'a gpioa::RegisterBlock) -> Self {
new_gpio_port!(register_block)
}
}

impl<'a> GpioPort<RegisterBlockB<'a>> {
/// Create a new `RegisterBlockB` from the hardware register block.
pub fn new_b(register_block: &'a gpiob::RegisterBlock) -> Self {
new_gpio_port!(register_block)
}
}

impl<'a> GpioPort<RegisterBlockD<'a>> {
/// Create a new `RegisterBlockD` from the hardware register block.
pub fn new(register_block: &'a gpiod::RegisterBlock) -> Self {
new_gpio_port!(register_block)
}
}

/// This trait allows generic functions that work on all three register block types.
pub trait RegisterBlockTrait<'a> {
pub trait RegisterBlockTrait {
/// The IDR (input data register) type, returned by the `idr` function.
type Idr: IdrTrait + 'a;
type Idr: IdrTrait + 'static;

/// The ODR (output data register) type, returned by the `odr` function.
type Odr: OdrTrait + 'a;
type Odr: OdrTrait + 'static;

/// The BSRR (bit set and reset register) type, returned by the `bsrr` function.
type Bsrr: BsrrTrait + 'a;
type Bsrr: BsrrTrait + 'static;

/// Returns a reference to the input data register.
fn idr(&self) -> &'a Self::Idr;
/// Returns a static reference to the input data register.
fn idr(&self) -> &'static Self::Idr;

/// Returns a reference to the output data register.
fn odr(&self) -> &'a Self::Odr;
/// Returns a static reference to the output data register.
fn odr(&self) -> &'static Self::Odr;

/// Returns a reference to the bit set and reset register.
fn bsrr(&self) -> &'a Self::Bsrr;
/// Returns a static reference to the bit set and reset register.
fn bsrr(&self) -> &'static Self::Bsrr;

/// Set the mode register for the specified pins to the given `Mode`.
fn set_mode(&mut self, pins: &[PinNumber], mode: Mode);
Expand All @@ -150,13 +54,17 @@ pub trait RegisterBlockTrait<'a> {
fn set_alternate_fn(&mut self, pins: &[PinNumber], alternate_fn: AlternateFunction);
}

impl<'a, T: RegisterBlockTrait<'a>> GpioPort<T> {
impl<T: RegisterBlockTrait> GpioPort<T> {
/// Create a new GPIO port from the passed register block.
pub fn new(register_block: T) -> Self {
Self {
register_block,
pin_in_use: [false; 16],
}
}

/// Initialize the specified pin as an input pin.
pub fn to_input(
&mut self,
pin: PinNumber,
resistor: Resistor,
) -> Result<impl InputPin + 'a, Error> {
pub fn to_input(&mut self, pin: PinNumber, resistor: Resistor) -> Result<impl InputPin, Error> {
self.use_pin(pin)?;

self.register_block.set_mode(&[pin], Mode::Input);
Expand All @@ -175,7 +83,7 @@ impl<'a, T: RegisterBlockTrait<'a>> GpioPort<T> {
out_type: OutputType,
out_speed: OutputSpeed,
resistor: Resistor,
) -> Result<impl OutputPin + 'a, Error> {
) -> Result<impl OutputPin, Error> {
self.use_pin(pin)?;

self.register_block.set_mode(&[pin], Mode::Output);
Expand Down Expand Up @@ -256,21 +164,21 @@ impl<'a, T: RegisterBlockTrait<'a>> GpioPort<T> {

macro_rules! impl_register_block_trait {
($register_block:tt, $gpio:tt) => {
impl<'a> RegisterBlockTrait<'a> for $register_block<'a> {
impl RegisterBlockTrait for $register_block {
type Idr = $gpio::IDR;
type Odr = $gpio::ODR;
type Bsrr = $gpio::BSRR;

fn idr(&self) -> &'a Self::Idr {
self.idr
fn idr(&self) -> &'static Self::Idr {
&unsafe { &*Self::ptr() }.idr
}

fn odr(&self) -> &'a Self::Odr {
self.odr
fn odr(&self) -> &'static Self::Odr {
&unsafe { &*Self::ptr() }.odr
}

fn bsrr(&self) -> &'a Self::Bsrr {
self.bsrr
fn bsrr(&self) -> &'static Self::Bsrr {
&unsafe { &*Self::ptr() }.bsrr
}

fn set_mode(&mut self, pins: &[PinNumber], mode: Mode) {
Expand Down Expand Up @@ -501,6 +409,14 @@ macro_rules! impl_register_block_trait {
};
}

impl_register_block_trait!(RegisterBlockA, gpioa);
impl_register_block_trait!(RegisterBlockB, gpiob);
impl_register_block_trait!(RegisterBlockD, gpiod);
impl_register_block_trait!(GPIOA, gpioa);
impl_register_block_trait!(GPIOB, gpiob);
impl_register_block_trait!(GPIOC, gpiod);
impl_register_block_trait!(GPIOD, gpiod);
impl_register_block_trait!(GPIOE, gpiod);
impl_register_block_trait!(GPIOF, gpiod);
impl_register_block_trait!(GPIOG, gpiod);
impl_register_block_trait!(GPIOH, gpiod);
impl_register_block_trait!(GPIOI, gpiod);
impl_register_block_trait!(GPIOJ, gpiod);
impl_register_block_trait!(GPIOK, gpiod);
28 changes: 15 additions & 13 deletions src/init/pins.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use self::pin_wrapper::PortPins;
use crate::gpio::{
AlternateFunction, GpioPort, InputPin, OutputPin, OutputSpeed, OutputType, RegisterBlockA,
RegisterBlockB, RegisterBlockD, Resistor,
AlternateFunction, GpioPort, InputPin, OutputPin, OutputSpeed, OutputType, Resistor,
};
use stm32f7::stm32f7x6::{
GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH, GPIOI, GPIOJ, GPIOK,
};

/// This struct contains special PIO pins.
Expand Down Expand Up @@ -34,17 +36,17 @@ pub struct Pins<
/// This function uses Rust's ownership mechanism internally to report duplicate mappings
/// at compile time.
pub fn init<'a>(
mut gpio_a: GpioPort<RegisterBlockA<'a>>,
mut gpio_b: GpioPort<RegisterBlockB<'a>>,
mut gpio_c: GpioPort<RegisterBlockD<'a>>,
mut gpio_d: GpioPort<RegisterBlockD<'a>>,
mut gpio_e: GpioPort<RegisterBlockD<'a>>,
mut gpio_f: GpioPort<RegisterBlockD<'a>>,
mut gpio_g: GpioPort<RegisterBlockD<'a>>,
mut gpio_h: GpioPort<RegisterBlockD<'a>>,
mut gpio_i: GpioPort<RegisterBlockD<'a>>,
mut gpio_j: GpioPort<RegisterBlockD<'a>>,
mut gpio_k: GpioPort<RegisterBlockD<'a>>,
mut gpio_a: GpioPort<GPIOA>,
mut gpio_b: GpioPort<GPIOB>,
mut gpio_c: GpioPort<GPIOC>,
mut gpio_d: GpioPort<GPIOD>,
mut gpio_e: GpioPort<GPIOE>,
mut gpio_f: GpioPort<GPIOF>,
mut gpio_g: GpioPort<GPIOG>,
mut gpio_h: GpioPort<GPIOH>,
mut gpio_i: GpioPort<GPIOI>,
mut gpio_j: GpioPort<GPIOJ>,
mut gpio_k: GpioPort<GPIOK>,
) -> Pins<
impl OutputPin + 'a,
impl InputPin + 'a,
Expand Down

0 comments on commit a7c30a3

Please sign in to comment.