Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor GpioPort to use the zero-sized GPIO* types directly #78

Merged
merged 1 commit into from
Feb 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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