From c7751d926d9951ed1eb4bdc9d14b6a622398a469 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Fri, 1 Feb 2019 11:55:56 +0100 Subject: [PATCH] Refactor GpioPort to use the zero-sized GPIO* types directly cc https://github.com/embed-rs/stm32f7-discovery/issues/72 --- src/bin/async-await.rs | 22 +++--- src/bin/polling.rs | 22 +++--- src/gpio/port.rs | 172 +++++++++++------------------------------ src/init/pins.rs | 28 +++---- 4 files changed, 81 insertions(+), 163 deletions(-) diff --git a/src/bin/async-await.rs b/src/bin/async-await.rs index f48c83ed..5d2dd59c 100644 --- a/src/bin/async-await.rs +++ b/src/bin/async-await.rs @@ -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, ); diff --git a/src/bin/polling.rs b/src/bin/polling.rs index 673f298d..c5afa1a1 100644 --- a/src/bin/polling.rs +++ b/src/bin/polling.rs @@ -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, ); diff --git a/src/gpio/port.rs b/src/gpio/port.rs index de864515..31199022 100644 --- a/src/gpio/port.rs +++ b/src/gpio/port.rs @@ -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 { +pub struct GpioPort { pub(super) pin_in_use: [bool; 16], register_block: T, } @@ -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> { - /// 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> { - /// 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> { - /// 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); @@ -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 { +impl GpioPort { + /// 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 { + pub fn to_input(&mut self, pin: PinNumber, resistor: Resistor) -> Result { self.use_pin(pin)?; self.register_block.set_mode(&[pin], Mode::Input); @@ -175,7 +83,7 @@ impl<'a, T: RegisterBlockTrait<'a>> GpioPort { out_type: OutputType, out_speed: OutputSpeed, resistor: Resistor, - ) -> Result { + ) -> Result { self.use_pin(pin)?; self.register_block.set_mode(&[pin], Mode::Output); @@ -256,21 +164,21 @@ impl<'a, T: RegisterBlockTrait<'a>> GpioPort { 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) { @@ -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); diff --git a/src/init/pins.rs b/src/init/pins.rs index 66f84fe3..c9d9f220 100644 --- a/src/init/pins.rs +++ b/src/init/pins.rs @@ -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. @@ -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>, - mut gpio_b: GpioPort>, - mut gpio_c: GpioPort>, - mut gpio_d: GpioPort>, - mut gpio_e: GpioPort>, - mut gpio_f: GpioPort>, - mut gpio_g: GpioPort>, - mut gpio_h: GpioPort>, - mut gpio_i: GpioPort>, - mut gpio_j: GpioPort>, - mut gpio_k: GpioPort>, + mut gpio_a: GpioPort, + mut gpio_b: GpioPort, + mut gpio_c: GpioPort, + mut gpio_d: GpioPort, + mut gpio_e: GpioPort, + mut gpio_f: GpioPort, + mut gpio_g: GpioPort, + mut gpio_h: GpioPort, + mut gpio_i: GpioPort, + mut gpio_j: GpioPort, + mut gpio_k: GpioPort, ) -> Pins< impl OutputPin + 'a, impl InputPin + 'a,