diff --git a/CHANGELOG.md b/CHANGELOG.md index 5286a830..6df90557 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- `gpio`: port and pin generics first, then mode, `PinMode` for modes instead of pins + ## [v0.9.0] - 2022-03-02 ### Added diff --git a/Cargo.toml b/Cargo.toml index fca57954..40a41eba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,7 @@ [package] +edition = "2021" +rust-version = "1.59" + authors = ["Jorge Aparicio ", "Daniel Egger "] categories = ["embedded", "hardware-support", "no-std"] description = "HAL for the STM32F1xx family of microcontrollers" @@ -8,7 +11,6 @@ name = "stm32f1xx-hal" repository = "https://github.com/stm32-rs/stm32f1xx-hal" documentation = "https://docs.rs/stm32f1xx-hal" readme = "README.md" -edition = "2018" version = "0.9.0" [package.metadata.docs.rs] diff --git a/src/gpio.rs b/src/gpio.rs index 000514df..eb9fee9c 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -78,7 +78,7 @@ use core::marker::PhantomData; use crate::afio; use crate::hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin}; -use crate::pac::{self, EXTI}; +use crate::pac::EXTI; mod partially_erased; pub use partially_erased::{PEPin, PartiallyErasedPin}; @@ -107,8 +107,8 @@ pub trait PinExt { /// Allow setting of the slew rate of an IO pin /// /// Initially all pins are set to the maximum slew rate -pub trait OutputSpeed { - fn set_speed(&mut self, cr: &mut CR, speed: IOPinSpeed); +pub trait OutputSpeed { + fn set_speed(&mut self, cr: &mut Cr, speed: IOPinSpeed); } /// Extension trait to split a GPIO peripheral in independent pins and registers @@ -124,7 +124,7 @@ pub trait GpioExt { pub trait Active {} /// Input mode (type state) -pub struct Input { +pub struct Input { _mode: PhantomData, } impl Active for Input {} @@ -139,7 +139,7 @@ pub struct PullDown; pub struct PullUp; /// Output mode (type state) -pub struct Output { +pub struct Output { _mode: PhantomData, } impl Active for Output {} @@ -154,7 +154,7 @@ pub struct Analog; impl Active for Analog {} /// Alternate function -pub struct Alternate { +pub struct Alternate { _mode: PhantomData, } impl Active for Alternate {} @@ -181,8 +181,10 @@ mod sealed { pub trait Interruptable {} pub trait PinMode { - type CR; - fn set_mode(cr: &mut Self::CR) -> Self; + const CNF: u32; + const MODE: u32; + const PULL: Option = None; + fn new() -> Self; } } use sealed::PinMode; @@ -341,23 +343,22 @@ impl Debugger { macro_rules! gpio { ($GPIOX:ident, $gpiox:ident, $PXx:ident, $port_id:expr, [ - $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty, $CR:ident),)+ + $($PXi:ident: ($pxi:ident, $i:expr, $H:literal, $MODE:ty),)+ ]) => { /// GPIO pub mod $gpiox { - use core::marker::PhantomData; use crate::pac::{$GPIOX, RCC}; use crate::rcc::{Enable, Reset}; - use super::{Active, Floating, GpioExt, Input, PartiallyErasedPin, ErasedPin, Pin, CRL, CRH, Cr}; + use super::{Active, Floating, GpioExt, Input, PartiallyErasedPin, ErasedPin, Pin, Cr}; #[allow(unused)] use super::Debugger; /// GPIO parts pub struct Parts { /// Opaque CRL register - pub crl: Cr, + pub crl: Cr<$port_id, false>, /// Opaque CRH register - pub crh: Cr, + pub crh: Cr<$port_id, true>, $( /// Pin pub $pxi: $PXi<$MODE>, @@ -365,7 +366,7 @@ macro_rules! gpio { } $( - pub type $PXi = Pin; + pub type $PXi = Pin<$port_id, $i, $H, MODE>; )+ impl GpioExt for $GPIOX { @@ -377,8 +378,8 @@ macro_rules! gpio { $GPIOX::reset(rcc); Parts { - crl: Cr:: { _cr: PhantomData }, - crh: Cr:: { _cr: PhantomData }, + crl: Cr::<$port_id, false>(()), + crh: Cr::<$port_id, true>(()), $( $pxi: $PXi::new(<$MODE>::_new()), )+ @@ -386,13 +387,13 @@ macro_rules! gpio { } } - impl PartiallyErasedPin { + impl PartiallyErasedPin<$port_id, MODE> { pub fn erase(self) -> ErasedPin { ErasedPin::$PXx(self) } } - impl Pin + impl Pin<$port_id, N, H, MODE> where MODE: Active, { @@ -412,27 +413,23 @@ macro_rules! gpio { /// Generic pin type /// -/// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). -/// - `CR` represents high or low configuration register (`CRH` or `CRL`). /// - `P` is port name: `A` for GPIOA, `B` for GPIOB, etc. /// - `N` is pin number: from `0` to `15`. -pub struct Pin { +/// - `H` represents high or low configuration register (`true` for high or `false` for low). +/// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). +pub struct Pin> { mode: MODE, - _cr: PhantomData, } -impl Pin { +impl Pin { const OFFSET: u32 = (4 * (N as u32)) % 32; const fn new(mode: MODE) -> Self { - Self { - mode, - _cr: PhantomData, - } + Self { mode } } } -impl PinExt for Pin { +impl PinExt for Pin { type Mode = MODE; #[inline(always)] @@ -445,17 +442,17 @@ impl PinExt for Pin { } } -impl Pin { +impl Pin { /// Put the pin in an active state. The caller /// must enforce that the pin is really in this /// state in the hardware. #[allow(dead_code)] - pub(crate) unsafe fn activate(self) -> Pin, CR, P, N> { + pub(crate) unsafe fn activate(self) -> Pin> { Pin::new(Input::_new()) } } -impl OutputPin for Pin { +impl OutputPin for Pin { type Error = PinModeError; fn set_high(&mut self) -> Result<(), Self::Error> { if self.mode.is_output() { @@ -475,7 +472,7 @@ impl OutputPin for Pin { } } -impl InputPin for Pin { +impl InputPin for Pin { type Error = PinModeError; fn is_high(&self) -> Result { self.is_low().map(|b| !b) @@ -494,7 +491,7 @@ impl InputPin for Pin { // NOTE: The functions in this impl block are "safe", but they // are callable when the pin is in modes where they don't make // sense. -impl Pin { +impl Pin { /** Set the output of the pin regardless of its mode. Primarily used to set the output value of the pin @@ -531,18 +528,18 @@ impl Pin { } } -impl Pin +impl Pin where MODE: Active, { /// Erases the pin number from the type #[inline] - pub fn erase_number(self) -> PartiallyErasedPin { + pub fn erase_number(self) -> PartiallyErasedPin { PartiallyErasedPin::new(N) } } -impl Pin, CR, P, N> { +impl Pin> { #[inline] pub fn set_high(&mut self) { self._set_high() @@ -584,7 +581,7 @@ impl Pin, CR, P, N> { } } -impl OutputPin for Pin, CR, P, N> { +impl OutputPin for Pin> { type Error = Infallible; #[inline] fn set_high(&mut self) -> Result<(), Self::Error> { @@ -598,7 +595,9 @@ impl OutputPin for Pin, CR, P } } -impl StatefulOutputPin for Pin, CR, P, N> { +impl StatefulOutputPin + for Pin> +{ #[inline] fn is_set_high(&self) -> Result { Ok(self.is_set_high()) @@ -609,7 +608,9 @@ impl StatefulOutputPin for Pin ToggleableOutputPin for Pin, CR, P, N> { +impl ToggleableOutputPin + for Pin> +{ type Error = Infallible; #[inline(always)] @@ -619,7 +620,7 @@ impl ToggleableOutputPin for Pin Pin, CR, P, N> { +impl Pin> { #[inline] pub fn is_high(&self) -> bool { !self._is_low() @@ -630,7 +631,7 @@ impl Pin, CR, P, N> { } } -impl InputPin for Pin, CR, P, N> { +impl InputPin for Pin> { type Error = Infallible; #[inline] fn is_high(&self) -> Result { @@ -643,7 +644,7 @@ impl InputPin for Pin, CR, P, } } -impl Pin, CR, P, N> { +impl Pin> { #[inline] pub fn is_high(&self) -> bool { !self._is_low() @@ -654,7 +655,7 @@ impl Pin, CR, P, N> { } } -impl InputPin for Pin, CR, P, N> { +impl InputPin for Pin> { type Error = Infallible; #[inline] fn is_high(&self) -> Result { @@ -668,556 +669,464 @@ impl InputPin for Pin, CR, P, } /// Opaque CR register -pub struct Cr { - _cr: PhantomData, -} - -macro_rules! cr { - ($CR:ident, $cr:ident) => { - #[doc(hidden)] - pub struct $CR { - _0: (), - } - - impl Cr<$CR, P> { - #[allow(dead_code)] - pub(crate) fn cr(&mut self) -> &pac::gpioa::$CR { - unsafe { &(*Gpio::

::ptr()).$cr } - } - } - - impl Pin - where - MODE: Active, - { - /// Configures the pin to operate as an alternate function push-pull output - /// pin. - #[inline] - pub fn into_alternate_push_pull( - self, - cr: &mut Cr<$CR, P>, - ) -> Pin, $CR, P, N> { - Pin::, $CR, P, N>::set_mode(cr) - } - - /// Configures the pin to operate as an alternate function open-drain output - /// pin. - #[inline] - pub fn into_alternate_open_drain( - self, - cr: &mut Cr<$CR, P>, - ) -> Pin, $CR, P, N> { - Pin::, $CR, P, N>::set_mode(cr) - } +pub struct Cr(()); - /// Configures the pin to operate as a floating input pin - #[inline] - pub fn into_floating_input( - self, - cr: &mut Cr<$CR, P>, - ) -> Pin, $CR, P, N> { - Pin::, $CR, P, N>::set_mode(cr) - } - - /// Configures the pin to operate as a pulled down input pin - #[inline] - pub fn into_pull_down_input( - self, - cr: &mut Cr<$CR, P>, - ) -> Pin, $CR, P, N> { - Pin::, $CR, P, N>::set_mode(cr) - } - - /// Configures the pin to operate as a pulled up input pin - #[inline] - pub fn into_pull_up_input(self, cr: &mut Cr<$CR, P>) -> Pin, $CR, P, N> { - Pin::, $CR, P, N>::set_mode(cr) - } +impl Pin +where + MODE: Active, +{ + /// Configures the pin to operate as an alternate function push-pull output + /// pin. + #[inline] + pub fn into_alternate_push_pull(self, cr: &mut Cr) -> Pin> { + Pin::>::set_mode(cr) + } - /// Configures the pin to operate as an open-drain output pin. - /// Initial state will be low. - #[inline] - pub fn into_open_drain_output( - self, - cr: &mut Cr<$CR, P>, - ) -> Pin, $CR, P, N> { - self.into_open_drain_output_with_state(cr, PinState::Low) - } + /// Configures the pin to operate as an alternate function open-drain output + /// pin. + #[inline] + pub fn into_alternate_open_drain( + self, + cr: &mut Cr, + ) -> Pin> { + Pin::>::set_mode(cr) + } - /// Configures the pin to operate as an open-drain output pin. - /// `initial_state` specifies whether the pin should be initially high or low. - #[inline] - pub fn into_open_drain_output_with_state( - mut self, - cr: &mut Cr<$CR, P>, - initial_state: PinState, - ) -> Pin, $CR, P, N> { - self._set_state(initial_state); - Pin::, $CR, P, N>::set_mode(cr) - } - /// Configures the pin to operate as an push-pull output pin. - /// Initial state will be low. - #[inline] - pub fn into_push_pull_output( - self, - cr: &mut Cr<$CR, P>, - ) -> Pin, $CR, P, N> { - self.into_push_pull_output_with_state(cr, PinState::Low) - } + /// Configures the pin to operate as a floating input pin + #[inline] + pub fn into_floating_input(self, cr: &mut Cr) -> Pin> { + Pin::>::set_mode(cr) + } - /// Configures the pin to operate as an push-pull output pin. - /// `initial_state` specifies whether the pin should be initially high or low. - #[inline] - pub fn into_push_pull_output_with_state( - mut self, - cr: &mut Cr<$CR, P>, - initial_state: PinState, - ) -> Pin, $CR, P, N> { - self._set_state(initial_state); - Pin::, $CR, P, N>::set_mode(cr) - } + /// Configures the pin to operate as a pulled down input pin + #[inline] + pub fn into_pull_down_input(self, cr: &mut Cr) -> Pin> { + Pin::>::set_mode(cr) + } - /// Configures the pin to operate as an analog input pin - #[inline] - pub fn into_analog(self, cr: &mut Cr<$CR, P>) -> Pin { - Pin::::set_mode(cr) - } + /// Configures the pin to operate as a pulled up input pin + #[inline] + pub fn into_pull_up_input(self, cr: &mut Cr) -> Pin> { + Pin::>::set_mode(cr) + } - /// Configures the pin as a pin that can change between input - /// and output without changing the type. It starts out - /// as a floating input - #[inline] - pub fn into_dynamic(self, cr: &mut Cr<$CR, P>) -> Pin { - self.into_floating_input(cr); - Pin::new(Dynamic::InputFloating) - } - } + /// Configures the pin to operate as an open-drain output pin. + /// Initial state will be low. + #[inline] + pub fn into_open_drain_output(self, cr: &mut Cr) -> Pin> { + self.into_open_drain_output_with_state(cr, PinState::Low) + } - // These macros are defined here instead of at the top level in order - // to be able to refer to macro variables from the outer layers. - macro_rules! impl_temp_output { - ($fn_name:ident, $stateful_fn_name:ident, $mode:ty) => { - /// Temporarily change the mode of the pin. - /// - /// The value of the pin after conversion is undefined. If you - /// want to control it, use `$stateful_fn_name` - #[inline] - pub fn $fn_name( - &mut self, - cr: &mut Cr<$CR, P>, - mut f: impl FnMut(&mut Pin<$mode, $CR, P, N>), - ) { - let mut temp = Pin::<$mode, $CR, P, N>::set_mode(cr); - f(&mut temp); - Self::set_mode(cr); - } + /// Configures the pin to operate as an open-drain output pin. + /// `initial_state` specifies whether the pin should be initially high or low. + #[inline] + pub fn into_open_drain_output_with_state( + mut self, + cr: &mut Cr, + initial_state: PinState, + ) -> Pin> { + self._set_state(initial_state); + Pin::>::set_mode(cr) + } + /// Configures the pin to operate as an push-pull output pin. + /// Initial state will be low. + #[inline] + pub fn into_push_pull_output(self, cr: &mut Cr) -> Pin> { + self.into_push_pull_output_with_state(cr, PinState::Low) + } - /// Temporarily change the mode of the pin. - /// - /// Note that the new state is set slightly before conversion - /// happens. This can cause a short output glitch if switching - /// between output modes - #[inline] - pub fn $stateful_fn_name( - &mut self, - cr: &mut Cr<$CR, P>, - state: PinState, - mut f: impl FnMut(&mut Pin<$mode, $CR, P, N>), - ) { - self._set_state(state); - let mut temp = Pin::<$mode, $CR, P, N>::set_mode(cr); - f(&mut temp); - Self::set_mode(cr); - } - }; - } - macro_rules! impl_temp_input { - ($fn_name:ident, $mode:ty) => { - /// Temporarily change the mode of the pin. - #[inline] - pub fn $fn_name( - &mut self, - cr: &mut Cr<$CR, P>, - mut f: impl FnMut(&mut Pin<$mode, $CR, P, N>), - ) { - let mut temp = Pin::<$mode, $CR, P, N>::set_mode(cr); - f(&mut temp); - Self::set_mode(cr); - } - }; - } + /// Configures the pin to operate as an push-pull output pin. + /// `initial_state` specifies whether the pin should be initially high or low. + #[inline] + pub fn into_push_pull_output_with_state( + mut self, + cr: &mut Cr, + initial_state: PinState, + ) -> Pin> { + self._set_state(initial_state); + Pin::>::set_mode(cr) + } - impl Pin - where - MODE: Active, - Self: PinMode>, - { - impl_temp_output!( - as_push_pull_output, - as_push_pull_output_with_state, - Output - ); - impl_temp_output!( - as_open_drain_output, - as_open_drain_output_with_state, - Output - ); - impl_temp_input!(as_floating_input, Input); - impl_temp_input!(as_pull_up_input, Input); - impl_temp_input!(as_pull_down_input, Input); - } + /// Configures the pin to operate as an analog input pin + #[inline] + pub fn into_analog(self, cr: &mut Cr) -> Pin { + Pin::::set_mode(cr) + } - impl OutputSpeed> - for Pin, $CR, P, N> - { - fn set_speed(&mut self, cr: &mut Cr<$CR, P>, speed: IOPinSpeed) { - cr.cr().modify(|r, w| unsafe { - w.bits((r.bits() & !(0b11 << Self::OFFSET)) | ((speed as u32) << Self::OFFSET)) - }); - } - } + /// Configures the pin as a pin that can change between input + /// and output without changing the type. It starts out + /// as a floating input + #[inline] + pub fn into_dynamic(self, cr: &mut Cr) -> Pin { + self.into_floating_input(cr); + Pin::new(Dynamic::InputFloating) + } +} - impl OutputSpeed> - for Pin, $CR, P, N> - { - fn set_speed(&mut self, cr: &mut Cr<$CR, P>, speed: IOPinSpeed) { - cr.cr().modify(|r, w| unsafe { - w.bits((r.bits() & !(0b11 << Self::OFFSET)) | ((speed as u32) << Self::OFFSET)) - }); - } +// These macros are defined here instead of at the top level in order +// to be able to refer to macro variables from the outer layers. +macro_rules! impl_temp_output { + ($fn_name:ident, $stateful_fn_name:ident, $mode:ty) => { + /// Temporarily change the mode of the pin. + /// + /// The value of the pin after conversion is undefined. If you + /// want to control it, use `$stateful_fn_name` + #[inline] + pub fn $fn_name(&mut self, cr: &mut Cr, mut f: impl FnMut(&mut Pin)) { + let mut temp = Pin::::set_mode(cr); + f(&mut temp); + Self::set_mode(cr); } - // Dynamic pin - - impl Pin { - #[inline] - pub fn make_pull_up_input(&mut self, cr: &mut Cr<$CR, P>) { - // NOTE(unsafe), we have a mutable reference to the current pin - Pin::, $CR, P, N>::set_mode(cr); - self.mode = Dynamic::InputPullUp; - } - #[inline] - pub fn make_pull_down_input(&mut self, cr: &mut Cr<$CR, P>) { - // NOTE(unsafe), we have a mutable reference to the current pin - Pin::, $CR, P, N>::set_mode(cr); - self.mode = Dynamic::InputPullDown; - } - #[inline] - pub fn make_floating_input(&mut self, cr: &mut Cr<$CR, P>) { - // NOTE(unsafe), we have a mutable reference to the current pin - Pin::, $CR, P, N>::set_mode(cr); - self.mode = Dynamic::InputFloating; - } - #[inline] - pub fn make_push_pull_output(&mut self, cr: &mut Cr<$CR, P>) { - // NOTE(unsafe), we have a mutable reference to the current pin - Pin::, $CR, P, N>::set_mode(cr); - self.mode = Dynamic::OutputPushPull; - } - #[inline] - pub fn make_open_drain_output(&mut self, cr: &mut Cr<$CR, P>) { - // NOTE(unsafe), we have a mutable reference to the current pin - Pin::, $CR, P, N>::set_mode(cr); - self.mode = Dynamic::OutputOpenDrain; - } + /// Temporarily change the mode of the pin. + /// + /// Note that the new state is set slightly before conversion + /// happens. This can cause a short output glitch if switching + /// between output modes + #[inline] + pub fn $stateful_fn_name( + &mut self, + cr: &mut Cr, + state: PinState, + mut f: impl FnMut(&mut Pin), + ) { + self._set_state(state); + let mut temp = Pin::::set_mode(cr); + f(&mut temp); + Self::set_mode(cr); } - - impl PinMode for Pin, $CR, P, N> { - type CR = Cr<$CR, P>; - - fn set_mode(cr: &mut Self::CR) -> Self { - // Floating input - const CNF: u32 = 0b01; - // Input mode - const MODE: u32 = 0b00; - const BITS: u32 = (CNF << 2) | MODE; - - // input mode - cr.cr().modify(|r, w| unsafe { - w.bits((r.bits() & !(0b1111 << Self::OFFSET)) | (BITS << Self::OFFSET)) - }); - - Self::new(Input::_new()) - } + }; +} +macro_rules! impl_temp_input { + ($fn_name:ident, $mode:ty) => { + /// Temporarily change the mode of the pin. + #[inline] + pub fn $fn_name(&mut self, cr: &mut Cr, mut f: impl FnMut(&mut Pin)) { + let mut temp = Pin::::set_mode(cr); + f(&mut temp); + Self::set_mode(cr); } + }; +} - impl PinMode for Pin, $CR, P, N> { - type CR = Cr<$CR, P>; - - fn set_mode(cr: &mut Self::CR) -> Self { - // Pull up/down input - const CNF: u32 = 0b10; - // Input mode - const MODE: u32 = 0b00; - const BITS: u32 = (CNF << 2) | MODE; - - //pull down: - // NOTE(unsafe) atomic write to a stateless register - unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(1 << (16 + N))) }; - - // input mode - cr.cr().modify(|r, w| unsafe { - w.bits((r.bits() & !(0b1111 << Self::OFFSET)) | (BITS << Self::OFFSET)) - }); +impl Pin +where + MODE: Active + PinMode, +{ + impl_temp_output!( + as_push_pull_output, + as_push_pull_output_with_state, + Output + ); + impl_temp_output!( + as_open_drain_output, + as_open_drain_output_with_state, + Output + ); + impl_temp_input!(as_floating_input, Input); + impl_temp_input!(as_pull_up_input, Input); + impl_temp_input!(as_pull_down_input, Input); +} - Self::new(Input::_new()) - } +impl OutputSpeed + for Pin> +{ + fn set_speed(&mut self, _cr: &mut Cr, speed: IOPinSpeed) { + let gpio = unsafe { &(*Gpio::

::ptr()) }; + if H { + gpio.crh.modify(|r, w| unsafe { + w.bits((r.bits() & !(0b11 << Self::OFFSET)) | ((speed as u32) << Self::OFFSET)) + }); + } else { + gpio.crl.modify(|r, w| unsafe { + w.bits((r.bits() & !(0b11 << Self::OFFSET)) | ((speed as u32) << Self::OFFSET)) + }); } + } +} - impl PinMode for Pin, $CR, P, N> { - type CR = Cr<$CR, P>; - - fn set_mode(cr: &mut Self::CR) -> Self { - // Pull up/down input - const CNF: u32 = 0b10; - // Input mode - const MODE: u32 = 0b00; - const BITS: u32 = (CNF << 2) | MODE; - - //pull up: - // NOTE(unsafe) atomic write to a stateless register - unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(1 << N)) }; - - // input mode - cr.cr().modify(|r, w| unsafe { - w.bits((r.bits() & !(0b1111 << Self::OFFSET)) | (BITS << Self::OFFSET)) - }); - - Self::new(Input::_new()) - } +impl OutputSpeed + for Pin> +{ + fn set_speed(&mut self, _cr: &mut Cr, speed: IOPinSpeed) { + let gpio = unsafe { &(*Gpio::

::ptr()) }; + if H { + gpio.crh.modify(|r, w| unsafe { + w.bits((r.bits() & !(0b11 << Self::OFFSET)) | ((speed as u32) << Self::OFFSET)) + }); + } else { + gpio.crl.modify(|r, w| unsafe { + w.bits((r.bits() & !(0b11 << Self::OFFSET)) | ((speed as u32) << Self::OFFSET)) + }); } + } +} - impl PinMode for Pin, $CR, P, N> { - type CR = Cr<$CR, P>; - - fn set_mode(cr: &mut Self::CR) -> Self { - // General purpose output open-drain - const CNF: u32 = 0b01; - // Open-Drain Output mode, max speed 50 MHz - const MODE: u32 = 0b11; - const BITS: u32 = (CNF << 2) | MODE; +// Dynamic pin - cr.cr().modify(|r, w| unsafe { - w.bits((r.bits() & !(0b1111 << Self::OFFSET)) | (BITS << Self::OFFSET)) - }); +impl Pin { + #[inline] + pub fn make_pull_up_input(&mut self, cr: &mut Cr) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::>::set_mode(cr); + self.mode = Dynamic::InputPullUp; + } + #[inline] + pub fn make_pull_down_input(&mut self, cr: &mut Cr) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::>::set_mode(cr); + self.mode = Dynamic::InputPullDown; + } + #[inline] + pub fn make_floating_input(&mut self, cr: &mut Cr) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::>::set_mode(cr); + self.mode = Dynamic::InputFloating; + } + #[inline] + pub fn make_push_pull_output(&mut self, cr: &mut Cr) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::>::set_mode(cr); + self.mode = Dynamic::OutputPushPull; + } + #[inline] + pub fn make_open_drain_output(&mut self, cr: &mut Cr) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::>::set_mode(cr); + self.mode = Dynamic::OutputOpenDrain; + } +} - Self::new(Output::_new()) - } - } +impl PinMode for Input { + const CNF: u32 = 0b01; + const MODE: u32 = 0b00; + fn new() -> Self { + Self::_new() + } +} - impl PinMode for Pin, $CR, P, N> { - type CR = Cr<$CR, P>; +impl PinMode for Input { + const CNF: u32 = 0b10; + const MODE: u32 = 0b00; + const PULL: Option = Some(false); + fn new() -> Self { + Self::_new() + } +} - fn set_mode(cr: &mut Self::CR) -> Self { - // General purpose output push-pull - const CNF: u32 = 0b00; - // Output mode, max speed 50 MHz - const MODE: u32 = 0b11; - const BITS: u32 = (CNF << 2) | MODE; +impl PinMode for Input { + const CNF: u32 = 0b10; + const MODE: u32 = 0b00; + const PULL: Option = Some(true); + fn new() -> Self { + Self::_new() + } +} - cr.cr().modify(|r, w| unsafe { - w.bits((r.bits() & !(0b1111 << Self::OFFSET)) | (BITS << Self::OFFSET)) - }); +impl PinMode for Output { + const CNF: u32 = 0b01; + const MODE: u32 = 0b11; + fn new() -> Self { + Self::_new() + } +} - Self::new(Output::_new()) - } - } +impl PinMode for Output { + const CNF: u32 = 0b00; + const MODE: u32 = 0b11; + fn new() -> Self { + Self::_new() + } +} - impl PinMode for Pin { - type CR = Cr<$CR, P>; +impl PinMode for Analog { + const CNF: u32 = 0b00; + const MODE: u32 = 0b00; + fn new() -> Self { + Self {} + } +} - fn set_mode(cr: &mut Self::CR) -> Self { - // Analog input - const CNF: u32 = 0b00; - // Input mode - const MODE: u32 = 0b00; - const BITS: u32 = (CNF << 2) | MODE; +impl PinMode for Alternate { + const CNF: u32 = 0b10; + const MODE: u32 = 0b11; + fn new() -> Self { + Self::_new() + } +} - // analog mode - cr.cr().modify(|r, w| unsafe { - w.bits((r.bits() & !(0b1111 << Self::OFFSET)) | (BITS << Self::OFFSET)) - }); +impl PinMode for Alternate { + const CNF: u32 = 0b11; + const MODE: u32 = 0b11; + fn new() -> Self { + Self::_new() + } +} - Self::new(Analog {}) +impl Pin +where + MODE: PinMode, +{ + fn set_mode(_cr: &mut Cr) -> Self { + // input mode + let gpio = unsafe { &(*Gpio::

::ptr()) }; + if let Some(pull) = MODE::PULL { + if pull { + gpio.bsrr.write(|w| unsafe { w.bits(1 << N) }); + } else { + gpio.bsrr.write(|w| unsafe { w.bits(1 << (16 + N)) }); } } - impl PinMode for Pin, $CR, P, N> { - type CR = Cr<$CR, P>; + let bits = (MODE::CNF << 2) | MODE::MODE; - fn set_mode(cr: &mut Self::CR) -> Self { - // Alternate function output push pull - const CNF: u32 = 0b10; - // Output mode, max speed 50 MHz - const MODE: u32 = 0b11; - const BITS: u32 = (CNF << 2) | MODE; - - // input mode - cr.cr().modify(|r, w| unsafe { - w.bits((r.bits() & !(0b1111 << Self::OFFSET)) | (BITS << Self::OFFSET)) - }); - - Pin::new(Alternate::_new()) - } + if H { + gpio.crh.modify(|r, w| unsafe { + w.bits((r.bits() & !(0b1111 << Self::OFFSET)) | (bits << Self::OFFSET)) + }); + } else { + gpio.crl.modify(|r, w| unsafe { + w.bits((r.bits() & !(0b1111 << Self::OFFSET)) | (bits << Self::OFFSET)) + }); } - impl PinMode for Pin, $CR, P, N> { - type CR = Cr<$CR, P>; - - fn set_mode(cr: &mut Self::CR) -> Self { - // Alternate function output open drain - const CNF: u32 = 0b11; - // Output mode, max speed 50 MHz - const MODE: u32 = 0b11; - const BITS: u32 = (CNF << 2) | MODE; - - // input mode - cr.cr().modify(|r, w| unsafe { - w.bits((r.bits() & !(0b1111 << Self::OFFSET)) | (BITS << Self::OFFSET)) - }); - - Pin::new(Alternate::_new()) - } - } - }; + Pin::new(MODE::new()) + } } -cr!(CRH, crh); -cr!(CRL, crl); - gpio!(GPIOA, gpioa, PAx, 'A', [ - PA0: (pa0, 0, Input, CRL), - PA1: (pa1, 1, Input, CRL), - PA2: (pa2, 2, Input, CRL), - PA3: (pa3, 3, Input, CRL), - PA4: (pa4, 4, Input, CRL), - PA5: (pa5, 5, Input, CRL), - PA6: (pa6, 6, Input, CRL), - PA7: (pa7, 7, Input, CRL), - PA8: (pa8, 8, Input, CRH), - PA9: (pa9, 9, Input, CRH), - PA10: (pa10, 10, Input, CRH), - PA11: (pa11, 11, Input, CRH), - PA12: (pa12, 12, Input, CRH), - PA13: (pa13, 13, Debugger, CRH), - PA14: (pa14, 14, Debugger, CRH), - PA15: (pa15, 15, Debugger, CRH), + PA0: (pa0, 0, false, Input), + PA1: (pa1, 1, false, Input), + PA2: (pa2, 2, false, Input), + PA3: (pa3, 3, false, Input), + PA4: (pa4, 4, false, Input), + PA5: (pa5, 5, false, Input), + PA6: (pa6, 6, false, Input), + PA7: (pa7, 7, false, Input), + PA8: (pa8, 8, true, Input), + PA9: (pa9, 9, true, Input), + PA10: (pa10, 10, true, Input), + PA11: (pa11, 11, true, Input), + PA12: (pa12, 12, true, Input), + PA13: (pa13, 13, true, Debugger), + PA14: (pa14, 14, true, Debugger), + PA15: (pa15, 15, true, Debugger), ]); gpio!(GPIOB, gpiob, PBx, 'B', [ - PB0: (pb0, 0, Input, CRL), - PB1: (pb1, 1, Input, CRL), - PB2: (pb2, 2, Input, CRL), - PB3: (pb3, 3, Debugger, CRL), - PB4: (pb4, 4, Debugger, CRL), - PB5: (pb5, 5, Input, CRL), - PB6: (pb6, 6, Input, CRL), - PB7: (pb7, 7, Input, CRL), - PB8: (pb8, 8, Input, CRH), - PB9: (pb9, 9, Input, CRH), - PB10: (pb10, 10, Input, CRH), - PB11: (pb11, 11, Input, CRH), - PB12: (pb12, 12, Input, CRH), - PB13: (pb13, 13, Input, CRH), - PB14: (pb14, 14, Input, CRH), - PB15: (pb15, 15, Input, CRH), + PB0: (pb0, 0, false, Input), + PB1: (pb1, 1, false, Input), + PB2: (pb2, 2, false, Input), + PB3: (pb3, 3, false, Debugger), + PB4: (pb4, 4, false, Debugger), + PB5: (pb5, 5, false, Input), + PB6: (pb6, 6, false, Input), + PB7: (pb7, 7, false, Input), + PB8: (pb8, 8, true, Input), + PB9: (pb9, 9, true, Input), + PB10: (pb10, 10, true, Input), + PB11: (pb11, 11, true, Input), + PB12: (pb12, 12, true, Input), + PB13: (pb13, 13, true, Input), + PB14: (pb14, 14, true, Input), + PB15: (pb15, 15, true, Input), ]); gpio!(GPIOC, gpioc, PCx, 'C', [ - PC0: (pc0, 0, Input, CRL), - PC1: (pc1, 1, Input, CRL), - PC2: (pc2, 2, Input, CRL), - PC3: (pc3, 3, Input, CRL), - PC4: (pc4, 4, Input, CRL), - PC5: (pc5, 5, Input, CRL), - PC6: (pc6, 6, Input, CRL), - PC7: (pc7, 7, Input, CRL), - PC8: (pc8, 8, Input, CRH), - PC9: (pc9, 9, Input, CRH), - PC10: (pc10, 10, Input, CRH), - PC11: (pc11, 11, Input, CRH), - PC12: (pc12, 12, Input, CRH), - PC13: (pc13, 13, Input, CRH), - PC14: (pc14, 14, Input, CRH), - PC15: (pc15, 15, Input, CRH), + PC0: (pc0, 0, false, Input), + PC1: (pc1, 1, false, Input), + PC2: (pc2, 2, false, Input), + PC3: (pc3, 3, false, Input), + PC4: (pc4, 4, false, Input), + PC5: (pc5, 5, false, Input), + PC6: (pc6, 6, false, Input), + PC7: (pc7, 7, false, Input), + PC8: (pc8, 8, true, Input), + PC9: (pc9, 9, true, Input), + PC10: (pc10, 10, true, Input), + PC11: (pc11, 11, true, Input), + PC12: (pc12, 12, true, Input), + PC13: (pc13, 13, true, Input), + PC14: (pc14, 14, true, Input), + PC15: (pc15, 15, true, Input), ]); gpio!(GPIOD, gpiod, PDx, 'D', [ - PD0: (pd0, 0, Input, CRL), - PD1: (pd1, 1, Input, CRL), - PD2: (pd2, 2, Input, CRL), - PD3: (pd3, 3, Input, CRL), - PD4: (pd4, 4, Input, CRL), - PD5: (pd5, 5, Input, CRL), - PD6: (pd6, 6, Input, CRL), - PD7: (pd7, 7, Input, CRL), - PD8: (pd8, 8, Input, CRH), - PD9: (pd9, 9, Input, CRH), - PD10: (pd10, 10, Input, CRH), - PD11: (pd11, 11, Input, CRH), - PD12: (pd12, 12, Input, CRH), - PD13: (pd13, 13, Input, CRH), - PD14: (pd14, 14, Input, CRH), - PD15: (pd15, 15, Input, CRH), + PD0: (pd0, 0, false, Input), + PD1: (pd1, 1, false, Input), + PD2: (pd2, 2, false, Input), + PD3: (pd3, 3, false, Input), + PD4: (pd4, 4, false, Input), + PD5: (pd5, 5, false, Input), + PD6: (pd6, 6, false, Input), + PD7: (pd7, 7, false, Input), + PD8: (pd8, 8, true, Input), + PD9: (pd9, 9, true, Input), + PD10: (pd10, 10, true, Input), + PD11: (pd11, 11, true, Input), + PD12: (pd12, 12, true, Input), + PD13: (pd13, 13, true, Input), + PD14: (pd14, 14, true, Input), + PD15: (pd15, 15, true, Input), ]); gpio!(GPIOE, gpioe, PEx, 'E', [ - PE0: (pe0, 0, Input, CRL), - PE1: (pe1, 1, Input, CRL), - PE2: (pe2, 2, Input, CRL), - PE3: (pe3, 3, Input, CRL), - PE4: (pe4, 4, Input, CRL), - PE5: (pe5, 5, Input, CRL), - PE6: (pe6, 6, Input, CRL), - PE7: (pe7, 7, Input, CRL), - PE8: (pe8, 8, Input, CRH), - PE9: (pe9, 9, Input, CRH), - PE10: (pe10, 10, Input, CRH), - PE11: (pe11, 11, Input, CRH), - PE12: (pe12, 12, Input, CRH), - PE13: (pe13, 13, Input, CRH), - PE14: (pe14, 14, Input, CRH), - PE15: (pe15, 15, Input, CRH), + PE0: (pe0, 0, false, Input), + PE1: (pe1, 1, false, Input), + PE2: (pe2, 2, false, Input), + PE3: (pe3, 3, false, Input), + PE4: (pe4, 4, false, Input), + PE5: (pe5, 5, false, Input), + PE6: (pe6, 6, false, Input), + PE7: (pe7, 7, false, Input), + PE8: (pe8, 8, true, Input), + PE9: (pe9, 9, true, Input), + PE10: (pe10, 10, true, Input), + PE11: (pe11, 11, true, Input), + PE12: (pe12, 12, true, Input), + PE13: (pe13, 13, true, Input), + PE14: (pe14, 14, true, Input), + PE15: (pe15, 15, true, Input), ]); #[cfg(any(feature = "xl", feature = "high"))] gpio!(GPIOF, gpiof, PFx, 'F', [ - PF0: (pf0, 0, Input, CRL), - PF1: (pf1, 1, Input, CRL), - PF2: (pf2, 2, Input, CRL), - PF3: (pf3, 3, Input, CRL), - PF4: (pf4, 4, Input, CRL), - PF5: (pf5, 5, Input, CRL), - PF6: (pf6, 6, Input, CRL), - PF7: (pf7, 7, Input, CRL), - PF8: (pf8, 8, Input, CRH), - PF9: (pf9, 9, Input, CRH), - PF10: (pf10, 10, Input, CRH), - PF11: (pf11, 11, Input, CRH), - PF12: (pf12, 12, Input, CRH), - PF13: (pf13, 13, Input, CRH), - PF14: (pf14, 14, Input, CRH), - PF15: (pf15, 15, Input, CRH), + PF0: (pf0, 0, false, Input), + PF1: (pf1, 1, false, Input), + PF2: (pf2, 2, false, Input), + PF3: (pf3, 3, false, Input), + PF4: (pf4, 4, false, Input), + PF5: (pf5, 5, false, Input), + PF6: (pf6, 6, false, Input), + PF7: (pf7, 7, false, Input), + PF8: (pf8, 8, true, Input), + PF9: (pf9, 9, true, Input), + PF10: (pf10, 10, true, Input), + PF11: (pf11, 11, true, Input), + PF12: (pf12, 12, true, Input), + PF13: (pf13, 13, true, Input), + PF14: (pf14, 14, true, Input), + PF15: (pf15, 15, true, Input), ]); #[cfg(any(feature = "xl", feature = "high"))] gpio!(GPIOG, gpiog, PGx, 'G', [ - PG0: (pg0, 0, Input, CRL), - PG1: (pg1, 1, Input, CRL), - PG2: (pg2, 2, Input, CRL), - PG3: (pg3, 3, Input, CRL), - PG4: (pg4, 4, Input, CRL), - PG5: (pg5, 5, Input, CRL), - PG6: (pg6, 6, Input, CRL), - PG7: (pg7, 7, Input, CRL), - PG8: (pg8, 8, Input, CRH), - PG9: (pg9, 9, Input, CRH), - PG10: (pg10, 10, Input, CRH), - PG11: (pg11, 11, Input, CRH), - PG12: (pg12, 12, Input, CRH), - PG13: (pg13, 13, Input, CRH), - PG14: (pg14, 14, Input, CRH), - PG15: (pg15, 15, Input, CRH), + PG0: (pg0, 0, false, Input), + PG1: (pg1, 1, false, Input), + PG2: (pg2, 2, false, Input), + PG3: (pg3, 3, false, Input), + PG4: (pg4, 4, false, Input), + PG5: (pg5, 5, false, Input), + PG6: (pg6, 6, false, Input), + PG7: (pg7, 7, false, Input), + PG8: (pg8, 8, true, Input), + PG9: (pg9, 9, true, Input), + PG10: (pg10, 10, true, Input), + PG11: (pg11, 11, true, Input), + PG12: (pg12, 12, true, Input), + PG13: (pg13, 13, true, Input), + PG14: (pg14, 14, true, Input), + PG15: (pg15, 15, true, Input), ]); struct Gpio; diff --git a/src/gpio/erased.rs b/src/gpio/erased.rs index 2dd9673d..7846cee8 100644 --- a/src/gpio/erased.rs +++ b/src/gpio/erased.rs @@ -9,7 +9,7 @@ macro_rules! impl_pxx { /// `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). pub enum ErasedPin { $( - $pin(PartiallyErasedPin) + $pin(PartiallyErasedPin<$port_id, MODE>) ),* } diff --git a/src/gpio/partially_erased.rs b/src/gpio/partially_erased.rs index d963fa16..82d2a242 100644 --- a/src/gpio/partially_erased.rs +++ b/src/gpio/partially_erased.rs @@ -1,17 +1,17 @@ use super::*; -pub type PEPin = PartiallyErasedPin; +pub type PEPin = PartiallyErasedPin; /// Partially erased pin /// /// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). /// - `P` is port name: `A` for GPIOA, `B` for GPIOB, etc. -pub struct PartiallyErasedPin { +pub struct PartiallyErasedPin { i: u8, _mode: PhantomData, } -impl PartiallyErasedPin { +impl PartiallyErasedPin { pub(crate) fn new(i: u8) -> Self { Self { i, @@ -20,7 +20,7 @@ impl PartiallyErasedPin { } } -impl PinExt for PartiallyErasedPin { +impl PinExt for PartiallyErasedPin { type Mode = MODE; #[inline(always)] @@ -33,7 +33,7 @@ impl PinExt for PartiallyErasedPin { } } -impl PartiallyErasedPin, P> { +impl PartiallyErasedPin> { #[inline(always)] pub fn set_high(&mut self) { // NOTE(unsafe) atomic write to a stateless register @@ -88,7 +88,7 @@ impl PartiallyErasedPin, P> { } } -impl OutputPin for PartiallyErasedPin, P> { +impl OutputPin for PartiallyErasedPin> { type Error = Infallible; #[inline(always)] @@ -104,7 +104,7 @@ impl OutputPin for PartiallyErasedPin, P> { } } -impl StatefulOutputPin for PartiallyErasedPin, P> { +impl StatefulOutputPin for PartiallyErasedPin> { #[inline(always)] fn is_set_high(&self) -> Result { Ok(self.is_set_high()) @@ -116,7 +116,7 @@ impl StatefulOutputPin for PartiallyErasedPin, } } -impl ToggleableOutputPin for PartiallyErasedPin, P> { +impl ToggleableOutputPin for PartiallyErasedPin> { type Error = Infallible; #[inline(always)] @@ -126,7 +126,7 @@ impl ToggleableOutputPin for PartiallyErasedPin PartiallyErasedPin, P> { +impl PartiallyErasedPin> { #[inline(always)] pub fn is_high(&self) -> bool { !self.is_low() @@ -139,7 +139,7 @@ impl PartiallyErasedPin, P> { } } -impl InputPin for PartiallyErasedPin, P> { +impl InputPin for PartiallyErasedPin> { type Error = Infallible; #[inline(always)] @@ -153,7 +153,7 @@ impl InputPin for PartiallyErasedPin, P> { } } -impl PartiallyErasedPin, P> { +impl PartiallyErasedPin> { #[inline(always)] pub fn is_high(&self) -> bool { !self.is_low() @@ -166,7 +166,7 @@ impl PartiallyErasedPin, P> { } } -impl InputPin for PartiallyErasedPin, P> { +impl InputPin for PartiallyErasedPin> { type Error = Infallible; #[inline(always)]