//! General Purpose Input / Output use core::marker::PhantomData; /// Extension trait to split a GPIO peripheral in independent pins and registers pub trait GpioExt { /// The parts to split the GPIO into type Parts; /// Splits the GPIO block into independent pins and registers fn split(self) -> Self::Parts; } pub struct AF0; pub struct AF1; pub struct AF2; pub struct AF3; pub struct AF4; pub struct AF5; pub struct AF6; pub struct AF7; pub struct AF8; pub struct AF9; pub struct AF10; pub struct AF11; pub struct AF12; pub struct AF13; pub struct AF14; pub struct AF15; pub struct Alternate { _mode: PhantomData, } /// Input mode (type state) pub struct Input { _mode: PhantomData, } /// Floating input (type state) pub struct Floating; /// Pulled down input (type state) pub struct PullDown; /// Pulled up input (type state) pub struct PullUp; /// Open drain input or output (type state) pub struct OpenDrain; /// Output mode (type state) pub struct Output { _mode: PhantomData, } /// Push pull output (type state) pub struct PushPull; macro_rules! gpio { ($GPIOX:ident, $gpiox:ident, $iopxenr:ident, $PXx:ident, [ $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+ ]) => { /// GPIO pub mod $gpiox { use core::marker::PhantomData; use hal::digital::{InputPin, OutputPin}; use stm32f7::stm32f7x7::$GPIOX; use stm32f7::stm32f7x7::RCC; use super::{ Alternate, Floating, GpioExt, Input, OpenDrain, Output, PullDown, PullUp, PushPull, AF0, AF1, AF2, AF3, AF4, AF5, AF6, AF7, AF8, AF9, AF10, AF11, AF12, AF13, AF14, AF15 }; /// GPIO parts pub struct Parts { $( /// Pin pub $pxi: $PXi<$MODE>, )+ } impl GpioExt for $GPIOX { type Parts = Parts; fn split(self) -> Parts { // NOTE(unsafe) This executes only during initialisation let rcc = unsafe { &(*RCC::ptr()) }; rcc.ahb1enr.modify(|_, w| w.$iopxenr().set_bit()); Parts { $( $pxi: $PXi { _mode: PhantomData }, )+ } } } /// Partially erased pin pub struct $PXx { i: u8, _mode: PhantomData, } impl OutputPin for $PXx> { 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 << (self.i + 16))) } } } impl InputPin for $PXx> { 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 } } } fn _set_alternate_mode (index:usize, mode: u32) { let offset = 2 * index; let offset2 = 4 * index; unsafe { &(*$GPIOX::ptr()).moder.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset)) }); if offset2 < 32 { &(*$GPIOX::ptr()).afrl.modify(|r, w| { w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2)) }); } else { let offset2 = offset2 - 32; &(*$GPIOX::ptr()).afrh.modify(|r, w| { w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2)) }); } } } $( /// Pin pub struct $PXi { _mode: PhantomData, } impl $PXi { /// Configures the pin to operate in AF0 mode pub fn into_alternate_af0( self, ) -> $PXi> { _set_alternate_mode($i, 0); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF1 mode pub fn into_alternate_af1( self, ) -> $PXi> { _set_alternate_mode($i, 1); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF2 mode pub fn into_alternate_af2( self, ) -> $PXi> { _set_alternate_mode($i, 2); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF3 mode pub fn into_alternate_af3( self, ) -> $PXi> { _set_alternate_mode($i, 3); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF4 mode pub fn into_alternate_af4( self, ) -> $PXi> { _set_alternate_mode($i, 4); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF5 mode pub fn into_alternate_af5( self, ) -> $PXi> { _set_alternate_mode($i, 5); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF6 mode pub fn into_alternate_af6( self, ) -> $PXi> { _set_alternate_mode($i, 6); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF7 mode pub fn into_alternate_af7( self, ) -> $PXi> { _set_alternate_mode($i, 7); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF8 mode pub fn into_alternate_af8( self, ) -> $PXi> { _set_alternate_mode($i, 8); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF9 mode pub fn into_alternate_af9( self, ) -> $PXi> { _set_alternate_mode($i, 9); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF10 mode pub fn into_alternate_af10( self, ) -> $PXi> { _set_alternate_mode($i, 10); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF11 mode pub fn into_alternate_af11( self, ) -> $PXi> { _set_alternate_mode($i, 11); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF12 mode pub fn into_alternate_af12( self, ) -> $PXi> { _set_alternate_mode($i, 12); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF13 mode pub fn into_alternate_af13( self, ) -> $PXi> { _set_alternate_mode($i, 13); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF14 mode pub fn into_alternate_af14( self, ) -> $PXi> { _set_alternate_mode($i, 14); $PXi { _mode: PhantomData } } /// Configures the pin to operate in AF15 mode pub fn into_alternate_af15( self, ) -> $PXi> { _set_alternate_mode($i, 15); $PXi { _mode: PhantomData } } /// Configures the pin to operate as a floating input pin pub fn into_floating_input( self, ) -> $PXi> { let offset = 2 * $i; unsafe { &(*$GPIOX::ptr()).moder.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset)) }); &(*$GPIOX::ptr()).pupdr.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset)) })}; $PXi { _mode: PhantomData } } /// Configures the pin to operate as a pulled down input pin pub fn into_pull_down_input( self, ) -> $PXi> { let offset = 2 * $i; unsafe { &(*$GPIOX::ptr()).moder.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset)) }); &(*$GPIOX::ptr()).pupdr.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset)) })}; $PXi { _mode: PhantomData } } /// Configures the pin to operate as a pulled up input pin pub fn into_pull_up_input( self, ) -> $PXi> { let offset = 2 * $i; unsafe { &(*$GPIOX::ptr()).moder.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset)) }); &(*$GPIOX::ptr()).pupdr.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset)) })}; $PXi { _mode: PhantomData } } /// Configures the pin to operate as an open drain output pin pub fn into_open_drain_output( self, ) -> $PXi> { let offset = 2 * $i; unsafe { &(*$GPIOX::ptr()).moder.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset)) }); &(*$GPIOX::ptr()).pupdr.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset)) }); &(*$GPIOX::ptr()).otyper.modify(|r, w| { w.bits(r.bits() | (0b1 << $i)) })}; $PXi { _mode: PhantomData } } /// Configures the pin to operate as an push pull output pin pub fn into_push_pull_output( self, ) -> $PXi> { let offset = 2 * $i; unsafe { &(*$GPIOX::ptr()).moder.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset)) }); &(*$GPIOX::ptr()).pupdr.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset)) }); &(*$GPIOX::ptr()).otyper.modify(|r, w| { w.bits(r.bits() & !(0b1 << $i)) })}; $PXi { _mode: PhantomData } } } impl $PXi> { /// Enables / disables the internal pull up pub fn internal_pull_up(&mut self, on: bool) { let offset = 2 * $i; let value = if on { 0b01 } else { 0b00 }; unsafe { &(*$GPIOX::ptr()).pupdr.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (value << offset)) })}; } } impl $PXi> { /// Enables / disables the internal pull up pub fn internal_pull_up(self, on: bool) -> Self { let offset = 2 * $i; let value = if on { 0b01 } else { 0b00 }; unsafe { &(*$GPIOX::ptr()).pupdr.modify(|r, w| { w.bits((r.bits() & !(0b11 << offset)) | (value << offset)) })}; self } } impl $PXi> { /// Turns pin alternate configuration pin into open drain pub fn set_open_drain(self) -> Self { let offset = $i; unsafe { &(*$GPIOX::ptr()).otyper.modify(|r, w| { w.bits(r.bits() & (1 << offset)) })}; self } } impl $PXi> { /// 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> { $PXx { i: $i, _mode: self._mode, } } } impl OutputPin for $PXi> { 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 << ($i + 16))) } } } impl $PXi> { /// 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> { $PXx { i: $i, _mode: self._mode, } } } impl InputPin for $PXi> { 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 $PXx { pub fn get_id (&self) -> u8 { self.i } } } } } gpio!(GPIOA, gpioa, gpioaen, PA, [ PA0: (pa0, 0, Input), PA1: (pa1, 1, Input), PA2: (pa2, 2, Input), PA3: (pa3, 3, Input), PA4: (pa4, 4, Input), PA5: (pa5, 5, Input), PA6: (pa6, 6, Input), PA7: (pa7, 7, Input), PA8: (pa8, 8, Input), PA9: (pa9, 9, Input), PA10: (pa10, 10, Input), PA11: (pa11, 11, Input), PA12: (pa12, 12, Input), PA13: (pa13, 13, Input), PA14: (pa14, 14, Input), PA15: (pa15, 15, Input), ]); gpio!(GPIOB, gpiob, gpioben, PB, [ PB0: (pb0, 0, Input), PB1: (pb1, 1, Input), PB2: (pb2, 2, Input), PB3: (pb3, 3, Input), PB4: (pb4, 4, Input), PB5: (pb5, 5, Input), PB6: (pb6, 6, Input), PB7: (pb7, 7, Input), PB8: (pb8, 8, Input), PB9: (pb9, 9, Input), PB10: (pb10, 10, Input), PB11: (pb11, 11, Input), PB12: (pb12, 12, Input), PB13: (pb13, 13, Input), PB14: (pb14, 14, Input), PB15: (pb15, 15, Input), ]); gpio!(GPIOC, gpioc, gpiocen, PC, [ PC0: (pc0, 0, Input), PC1: (pc1, 1, Input), PC2: (pc2, 2, Input), PC3: (pc3, 3, Input), PC4: (pc4, 4, Input), PC5: (pc5, 5, Input), PC6: (pc6, 6, Input), PC7: (pc7, 7, Input), PC8: (pc8, 8, Input), PC9: (pc9, 9, Input), PC10: (pc10, 10, Input), PC11: (pc11, 11, Input), PC12: (pc12, 12, Input), PC13: (pc13, 13, Input), PC14: (pc14, 14, Input), PC15: (pc15, 15, Input), ]); gpio!(GPIOD, gpiod, gpioden, pd, [ PD0: (pd0, 0, Input), PD1: (pd1, 1, Input), PD2: (pd2, 2, Input), PD3: (pd3, 3, Input), PD4: (pd4, 4, Input), PD5: (pd5, 5, Input), PD6: (pd6, 6, Input), PD7: (pd7, 7, Input), PD8: (pd8, 8, Input), PD9: (pd9, 9, Input), PD10: (pd10, 10, Input), PD11: (pd11, 11, Input), PD12: (pd12, 12, Input), PD13: (pd13, 13, Input), PD14: (pd14, 14, Input), PD15: (pd15, 15, Input), ]); gpio!(GPIOE, gpioe, gpioeen, PE, [ PE0: (pe0, 0, Input), PE1: (pe1, 1, Input), PE2: (pe2, 2, Input), PE3: (pe3, 3, Input), PE4: (pe4, 4, Input), PE5: (pe5, 5, Input), PE6: (pe6, 6, Input), PE7: (pe7, 7, Input), PE8: (pe8, 8, Input), PE9: (pe9, 9, Input), PE10: (pe10, 10, Input), PE11: (pe11, 11, Input), PE12: (pe12, 12, Input), PE13: (pe13, 13, Input), PE14: (pe14, 14, Input), PE15: (pe15, 15, Input), ]); gpio!(GPIOF, gpiof, gpiofen, PF, [ PF0: (pf0, 0, Input), PF1: (pf1, 1, Input), PF2: (pf2, 2, Input), PF3: (pf3, 3, Input), PF4: (pf4, 4, Input), PF5: (pf5, 5, Input), PF6: (pf6, 6, Input), PF7: (pf7, 7, Input), PF8: (pf8, 8, Input), PF9: (pf9, 9, Input), PF10: (pf10, 10, Input), PF11: (pf11, 11, Input), PF12: (pf12, 12, Input), PF13: (pf13, 13, Input), PF14: (pf14, 14, Input), PF15: (pf15, 15, Input), ]); gpio!(GPIOG, gpiog, gpiogen, PG, [ PG0: (pg0, 0, Input), PG1: (pg1, 1, Input), PG2: (pg2, 2, Input), PG3: (pg3, 3, Input), PG4: (pg4, 4, Input), PG5: (pg5, 5, Input), PG6: (pg6, 6, Input), PG7: (pg7, 7, Input), PG8: (pg8, 8, Input), PG9: (pg9, 9, Input), PG10: (pg10, 10, Input), PG11: (pg11, 11, Input), PG12: (pg12, 12, Input), PG13: (pg13, 13, Input), PG14: (pg14, 14, Input), PG15: (pg15, 15, Input), ]); gpio!(GPIOH, gpioh, gpiohen, PH, [ PH0: (ph0, 0, Input), PH1: (ph1, 1, Input), PH2: (ph2, 2, Input), PH3: (ph3, 3, Input), PH4: (ph4, 4, Input), PH5: (ph5, 5, Input), PH6: (ph6, 6, Input), PH7: (ph7, 7, Input), PH8: (ph8, 8, Input), PH9: (ph9, 9, Input), PH10: (ph10, 10, Input), PH11: (ph11, 11, Input), PH12: (ph12, 12, Input), PH13: (ph13, 13, Input), PH14: (ph14, 14, Input), PH15: (ph15, 15, Input), ]); gpio!(GPIOI, gpioi, gpioien, PI, [ PI0: (pi0, 0, Input), PI1: (pi1, 1, Input), PI2: (pi2, 2, Input), PI3: (pi3, 3, Input), PI4: (pi4, 4, Input), PI5: (pi5, 5, Input), PI6: (pi6, 6, Input), PI7: (pi7, 7, Input), PI8: (pi8, 8, Input), PI9: (pi9, 9, Input), PI10: (pi10, 10, Input), PI11: (pi11, 11, Input), PI12: (pi12, 12, Input), PI13: (pi13, 13, Input), PI14: (pi14, 14, Input), PI15: (pi15, 15, Input), ]); gpio!(GPIOJ, gpioj, gpiojen, PJ, [ PJ0: (pj0, 0, Input), PJ1: (pj1, 1, Input), PJ2: (pj2, 2, Input), PJ3: (pj3, 3, Input), PJ4: (pj4, 4, Input), PJ5: (pj5, 5, Input), PJ6: (pj6, 6, Input), PJ7: (pj7, 7, Input), PJ8: (pj8, 8, Input), PJ9: (pj9, 9, Input), PJ10: (pj10, 10, Input), PJ11: (pj11, 11, Input), PJ12: (pj12, 12, Input), PJ13: (pj13, 13, Input), PJ14: (pj14, 14, Input), PJ15: (pj15, 15, Input), ]); gpio!(GPIOK, gpiok, gpioken, PK, [ PK0: (pk0, 0, Input), PK1: (pk1, 1, Input), PK2: (pk2, 2, Input), PK3: (pk3, 3, Input), PK4: (pk4, 4, Input), PK5: (pk5, 5, Input), PK6: (pk6, 6, Input), PK7: (pk7, 7, Input), ]);