123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- //! General Purpose Input / Output
- // TODO the pins here currently correspond to the LQFP-48 package. There should be Cargo features
- // that let you select different microcontroller packages
- use core::marker::PhantomData;
- use rcc::APB2;
- /// Extension trait to split a GPIO peripheral in independent pins and registers
- pub trait GpioExt {
- /// The to split the GPIO into
- type Parts;
- /// Splits the GPIO block into independent pins and registers
- fn split(self, apb2: &mut APB2) -> Self::Parts;
- }
- /// Input mode (type state)
- pub struct Input<MODE> {
- _mode: PhantomData<MODE>,
- }
- /// Floating input (type state)
- pub struct Floating;
- /// Pulled down input (type state)
- pub struct PullDown;
- /// Pulled up input (type state)
- pub struct PullUp;
- /// Output mode (type state)
- pub struct Output<MODE> {
- _mode: PhantomData<MODE>,
- }
- /// Push pull output (type state)
- pub struct PushPull;
- /// Open drain output (type state)
- pub struct OpenDrain;
- /// Analog mode (type state)
- pub struct Analog;
- /// Alternate function
- pub struct Alternate<MODE> {
- _mode: PhantomData<MODE>,
- }
- macro_rules! gpio {
- ($GPIOX:ident, $gpiox:ident, $gpioy:ident, $iopxenr:ident, $iopxrst:ident, $PXx:ident, [
- $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty, $CR:ident),)+
- ]) => {
- /// GPIO
- pub mod $gpiox {
- use core::marker::PhantomData;
- use hal::digital::{InputPin, OutputPin, StatefulOutputPin, toggleable};
- use stm32::{$gpioy, $GPIOX};
- use rcc::APB2;
- use super::{
- Alternate, Floating, GpioExt, Input,
- OpenDrain,
- Output,
- PullDown,
- PullUp,
- PushPull,
- Analog,
- };
- /// GPIO parts
- pub struct Parts {
- /// Opaque CRL register
- pub crl: CRL,
- /// Opaque CRH register
- pub crh: CRH,
- $(
- /// Pin
- pub $pxi: $PXi<$MODE>,
- )+
- }
- impl GpioExt for $GPIOX {
- type Parts = Parts;
- fn split(self, apb2: &mut APB2) -> Parts {
- apb2.enr().modify(|_, w| w.$iopxenr().set_bit());
- apb2.rstr().modify(|_, w| w.$iopxrst().set_bit());
- apb2.rstr().modify(|_, w| w.$iopxrst().clear_bit());
- Parts {
- crl: CRL { _0: () },
- crh: CRH { _0: () },
- $(
- $pxi: $PXi { _mode: PhantomData },
- )+
- }
- }
- }
- /// Opaque CRL register
- pub struct CRL {
- _0: (),
- }
- impl CRL {
- // NOTE(allow) we get a warning on GPIOC because it only has 3 high pins
- #[allow(dead_code)]
- pub(crate) fn cr(&mut self) -> &$gpioy::CRL {
- unsafe { &(*$GPIOX::ptr()).crl }
- }
- }
- /// Opaque CRH register
- pub struct CRH {
- _0: (),
- }
- impl CRH {
- pub(crate) fn cr(&mut self) -> &$gpioy::CRH {
- unsafe { &(*$GPIOX::ptr()).crh }
- }
- }
- /// Partially erased pin
- pub struct $PXx<MODE> {
- i: u8,
- _mode: PhantomData<MODE>,
- }
- impl<MODE> OutputPin for $PXx<Output<MODE>> {
- fn set_high(&mut self) {
- // NOTE(unsafe) atomic write to a stateless register
- unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }
- }
- fn set_low(&mut self) {
- // NOTE(unsafe) atomic write to a stateless register
- unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + self.i))) }
- }
- }
- impl<MODE> InputPin for $PXx<Input<MODE>> {
- fn is_high(&self) -> bool {
- !self.is_low()
- }
- fn is_low(&self) -> bool {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }
- }
- }
- impl <MODE> StatefulOutputPin for $PXx<Output<MODE>> {
- fn is_set_high(&self) -> bool {
- !self.is_set_low()
- }
- fn is_set_low(&self) -> bool {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << self.i) == 0 }
- }
- }
- impl <MODE> toggleable::Default for $PXx<Output<MODE>> {}
- impl InputPin for $PXx<Output<OpenDrain>> {
- fn is_high(&self) -> bool {
- !self.is_low()
- }
- fn is_low(&self) -> bool {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }
- }
- }
- $(
- /// Pin
- pub struct $PXi<MODE> {
- _mode: PhantomData<MODE>,
- }
- impl<MODE> $PXi<MODE> {
- /// Configures the pin to operate as an alternate function push pull output pin
- pub fn into_alternate_push_pull(
- self,
- cr: &mut $CR,
- ) -> $PXi<Alternate<PushPull>> {
- let offset = (4 * $i) % 32;
- // Alternate function output push pull
- let cnf = 0b10;
- // Output mode, max speed 50 MHz
- let mode = 0b11;
- let bits = (cnf << 2) | mode;
- // input mode
- cr
- .cr()
- .modify(|r, w| unsafe {
- w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
- });
- $PXi { _mode: PhantomData }
- }
- pub fn into_alternate_open_drain(
- self,
- cr: &mut $CR,
- ) -> $PXi<Alternate<OpenDrain>> {
- let offset = (4 * $i) % 32;
- // Alternate function output open drain
- let cnf = 0b11;
- // Output mode, max speed 50 MHz
- let mode = 0b11;
- let bits = (cnf << 2) | mode;
- // input mode
- cr
- .cr()
- .modify(|r, w| unsafe {
- w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
- });
- $PXi { _mode: PhantomData }
- }
- /// Configures the pin to operate as a floating input pin
- pub fn into_floating_input(
- self,
- cr: &mut $CR,
- ) -> $PXi<Input<Floating>> {
- let offset = (4 * $i) % 32;
- // Floating input
- let cnf = 0b01;
- // Input mode
- let mode = 0b00;
- let bits = (cnf << 2) | mode;
- // input mode
- cr
- .cr()
- .modify(|r, w| unsafe {
- w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
- });
- $PXi { _mode: PhantomData }
- }
- /// Configures the pin to operate as a pulled down input pin
- pub fn into_pull_down_input(
- self,
- cr: &mut $CR,
- ) -> $PXi<Input<PullDown>> {
- let offset = (4 * $i) % 32;
- // Pull up/down input
- let cnf = 0b10;
- // Input mode
- let mode = 0b00;
- let bits = (cnf << 2) | mode;
- //pull down:
- // NOTE(unsafe) atomic write to a stateless register
- unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + $i))) }
- // input mode
- cr
- .cr()
- .modify(|r, w| unsafe {
- w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
- });
- $PXi { _mode: PhantomData }
- }
- /// Configures the pin to operate as a pulled up input pin
- pub fn into_pull_up_input(
- self,
- cr: &mut $CR,
- ) -> $PXi<Input<PullUp>> {
- let offset = (4 * $i) % 32;
- // Pull up/down input
- let cnf = 0b10;
- // Input mode
- let mode = 0b00;
- let bits = (cnf << 2) | mode;
- //pull up:
- // NOTE(unsafe) atomic write to a stateless register
- unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
- // input mode
- cr
- .cr()
- .modify(|r, w| unsafe {
- w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
- });
- $PXi { _mode: PhantomData }
- }
- /// Configures the pin to operate as an open drain output pin
- pub fn into_open_drain_output(
- self,
- cr: &mut $CR,
- ) -> $PXi<Output<OpenDrain>> {
- let offset = (4 * $i) % 32;
- // General purpose output open-drain
- let cnf = 0b01;
- // Open-Drain Output mode, max speed 50 MHz
- let mode = 0b11;
- let bits = (cnf << 2) | mode;
- cr
- .cr()
- .modify(|r, w| unsafe {
- w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
- });
- $PXi { _mode: PhantomData }
- }
- /// Configures the pin to operate as an push pull output pin
- pub fn into_push_pull_output(
- self,
- cr: &mut $CR,
- ) -> $PXi<Output<PushPull>> {
- let offset = (4 * $i) % 32;
- // General purpose output push-pull
- let cnf = 0b00;
- // Output mode, max speed 50 MHz
- let mode = 0b11;
- let bits = (cnf << 2) | mode;
- cr
- .cr()
- .modify(|r, w| unsafe {
- w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
- });
- $PXi { _mode: PhantomData }
- }
-
- /// Configures the pin to operate as an analog input pin
- pub fn into_analog(self, cr: &mut $CR) -> $PXi<Analog> {
- let offset = (4 * $i) % 32;
- // Analog input
- let cnf = 0b00;
- // Input mode
- let mode = 0b00;
- let bits = (cnf << 2) | mode;
- // analog mode
- cr
- .cr()
- .modify(|r, w| unsafe {
- w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
- });
- $PXi { _mode: PhantomData }
- }
- }
- impl<MODE> $PXi<MODE> {
- /// Erases the pin number from the type
- ///
- /// This is useful when you want to collect the pins into an array where you
- /// need all the elements to have the same type
- pub fn downgrade(self) -> $PXx<MODE> {
- $PXx {
- i: $i,
- _mode: self._mode,
- }
- }
- }
- impl<MODE> OutputPin for $PXi<Output<MODE>> {
- fn set_high(&mut self) {
- // NOTE(unsafe) atomic write to a stateless register
- unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
- }
- fn set_low(&mut self) {
- // NOTE(unsafe) atomic write to a stateless register
- unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + $i))) }
- }
- }
- impl<MODE> StatefulOutputPin for $PXi<Output<MODE>> {
- fn is_set_high(&self) -> bool {
- !self.is_set_low()
- }
- fn is_set_low(&self) -> bool {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 }
- }
- }
- impl<MODE> toggleable::Default for $PXi<Output<MODE>> {}
- impl<MODE> OutputPin for $PXi<Alternate<MODE>> {
- fn set_high(&mut self) {
- // NOTE(unsafe) atomic write to a stateless register
- unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
- }
- fn set_low(&mut self) {
- // NOTE(unsafe) atomic write to a stateless register
- unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + $i))) }
- }
- }
- impl<MODE> StatefulOutputPin for $PXi<Alternate<MODE>> {
- fn is_set_high(&self) -> bool {
- !self.is_set_low()
- }
- fn is_set_low(&self) -> bool {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 }
- }
- }
- impl<MODE> InputPin for $PXi<Input<MODE>> {
- fn is_high(&self) -> bool {
- !self.is_low()
- }
- fn is_low(&self) -> bool {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }
- }
- }
- impl InputPin for $PXi<Output<OpenDrain>> {
- fn is_high(&self) -> bool {
- !self.is_low()
- }
- fn is_low(&self) -> bool {
- // NOTE(unsafe) atomic read with no side effects
- unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }
- }
- }
- )+
- }
- }
- }
- gpio!(GPIOA, gpioa, gpioa, iopaen, ioparst, PAx, [
- PA0: (pa0, 0, Input<Floating>, CRL),
- PA1: (pa1, 1, Input<Floating>, CRL),
- PA2: (pa2, 2, Input<Floating>, CRL),
- PA3: (pa3, 3, Input<Floating>, CRL),
- PA4: (pa4, 4, Input<Floating>, CRL),
- PA5: (pa5, 5, Input<Floating>, CRL),
- PA6: (pa6, 6, Input<Floating>, CRL),
- PA7: (pa7, 7, Input<Floating>, CRL),
- PA8: (pa8, 8, Input<Floating>, CRH),
- PA9: (pa9, 9, Input<Floating>, CRH),
- PA10: (pa10, 10, Input<Floating>, CRH),
- PA11: (pa11, 11, Input<Floating>, CRH),
- PA12: (pa12, 12, Input<Floating>, CRH),
- PA13: (pa13, 13, Input<Floating>, CRH),
- PA14: (pa14, 14, Input<Floating>, CRH),
- PA15: (pa15, 15, Input<Floating>, CRH),
- ]);
- gpio!(GPIOB, gpiob, gpioa, iopben, iopbrst, PBx, [
- PB0: (pb0, 0, Input<Floating>, CRL),
- PB1: (pb1, 1, Input<Floating>, CRL),
- PB2: (pb2, 2, Input<Floating>, CRL),
- PB3: (pb3, 3, Input<Floating>, CRL),
- PB4: (pb4, 4, Input<Floating>, CRL),
- PB5: (pb5, 5, Input<Floating>, CRL),
- PB6: (pb6, 6, Input<Floating>, CRL),
- PB7: (pb7, 7, Input<Floating>, CRL),
- PB8: (pb8, 8, Input<Floating>, CRH),
- PB9: (pb9, 9, Input<Floating>, CRH),
- PB10: (pb10, 10, Input<Floating>, CRH),
- PB11: (pb11, 11, Input<Floating>, CRH),
- PB12: (pb12, 12, Input<Floating>, CRH),
- PB13: (pb13, 13, Input<Floating>, CRH),
- PB14: (pb14, 14, Input<Floating>, CRH),
- PB15: (pb15, 15, Input<Floating>, CRH),
- ]);
- gpio!(GPIOC, gpioc, gpioa, iopcen, iopcrst, PCx, [
- PC13: (pc13, 13, Input<Floating>, CRH),
- PC14: (pc14, 14, Input<Floating>, CRH),
- PC15: (pc15, 15, Input<Floating>, CRH),
- ]);
|