use {
core::marker::PhantomData,
embedded_hal::digital::v2::{
InputPin,
OutputPin,
},
};
#[cfg(feature = "atsam4e")]
use {
crate::pac::{
PIOA, pioa,
PIOB, piob,
PIOC, pioc,
PIOD, piod,
PIOE, pioe,
},
crate::clock::{
ParallelIOControllerAClock,
ParallelIOControllerBClock,
ParallelIOControllerCClock,
ParallelIOControllerDClock,
ParallelIOControllerEClock,
Enabled,
},
};
#[cfg(feature = "atsam4s")]
use {
crate::pac::{
PIOA, pioa,
PIOB, piob,
PIOC, pioc,
},
crate::clock::{
ParallelIOControllerAClock,
ParallelIOControllerBClock,
ParallelIOControllerCClock,
Enabled,
},
};
pub trait GpioExt {
type Parts;
fn split(self) -> Self::Parts;
}
pub struct Ports {
pioa: PhantomData<PIOA>,
pioa_clock: PhantomData<ParallelIOControllerAClock<Enabled>>,
piob: PhantomData<PIOB>,
piob_clock: PhantomData<ParallelIOControllerBClock<Enabled>>,
pioc: PhantomData<PIOC>,
pioc_clock: PhantomData<ParallelIOControllerCClock<Enabled>>,
#[cfg(feature = "atsam4e")]
piod: PhantomData<PIOD>,
#[cfg(feature = "atsam4e")]
piod_clock: PhantomData<ParallelIOControllerDClock<Enabled>>,
#[cfg(feature = "atsam4e")]
pioe: PhantomData<PIOE>,
#[cfg(feature = "atsam4e")]
pioe_clock: PhantomData<ParallelIOControllerEClock<Enabled>>,
}
impl Ports {
pub fn new(_pioa: PIOA,
_pioa_clock: ParallelIOControllerAClock<Enabled>,
_piob: PIOB,
_piob_clock: ParallelIOControllerBClock<Enabled>,
_pioc: PIOC,
_pioc_clock: ParallelIOControllerCClock<Enabled>,
#[cfg(feature = "atsam4e")]
_piod: PIOD,
#[cfg(feature = "atsam4e")]
_piod_clock: ParallelIOControllerDClock<Enabled>,
#[cfg(feature = "atsam4e")]
_pioe: PIOE,
#[cfg(feature = "atsam4e")]
_pioe_clock: ParallelIOControllerEClock<Enabled>,
) -> Self {
Ports {
pioa: PhantomData,
pioa_clock: PhantomData,
piob: PhantomData,
piob_clock: PhantomData,
pioc: PhantomData,
pioc_clock: PhantomData,
#[cfg(feature = "atsam4e")]
piod: PhantomData,
#[cfg(feature = "atsam4e")]
piod_clock: PhantomData,
#[cfg(feature = "atsam4e")]
pioe: PhantomData,
#[cfg(feature = "atsam4e")]
pioe_clock: PhantomData,
}
}
}
pub struct Input<MODE> {
_mode: PhantomData<MODE>,
}
pub struct Output<MODE> {
_mode: PhantomData<MODE>,
}
pub struct PfA;
pub struct PfB;
pub struct PfC;
pub struct PfD;
pub struct Floating;
pub struct PullDown;
pub struct PullUp;
pub struct PushPull;
pub struct OpenDrain;
macro_rules! pins {
([
$($PinTypeA:ident: ($pin_identA:ident, $pin_noA:expr),)+
],[
$($PinTypeB:ident: ($pin_identB:ident, $pin_noB:expr),)+
],[
$($PinTypeC:ident: ($pin_identC:ident, $pin_noC:expr),)+
],[
$($PinTypeD:ident: ($pin_identD:ident, $pin_noD:expr),)+
],[
$($PinTypeE:ident: ($pin_identE:ident, $pin_noE:expr),)+
]) => {
pub struct Pins {
$(
pub $pin_identA: $PinTypeA<Input<Floating>>,
)+
$(
pub $pin_identB: $PinTypeB<Input<Floating>>,
)+
$(
pub $pin_identC: $PinTypeC<Input<Floating>>,
)+
$(
#[cfg(feature = "atsam4e")]
pub $pin_identD: $PinTypeD<Input<Floating>>,
)+
$(
#[cfg(feature = "atsam4e")]
pub $pin_identE: $PinTypeE<Input<Floating>>,
)+
}
impl GpioExt for Ports {
type Parts = Pins;
fn split(self) -> Pins {
Pins {
$(
$pin_identA: $PinTypeA { _mode: PhantomData },
)+
$(
$pin_identB: $PinTypeB { _mode: PhantomData },
)+
$(
$pin_identC: $PinTypeC { _mode: PhantomData },
)+
$(
#[cfg(feature = "atsam4e")]
$pin_identD: $PinTypeD { _mode: PhantomData },
)+
$(
#[cfg(feature = "atsam4e")]
$pin_identE: $PinTypeE { _mode: PhantomData },
)+
}
}
}
$(
pin!($PinTypeA, $pin_identA, $pin_noA, PIOA, pioa);
)+
$(
pin!($PinTypeB, $pin_identB, $pin_noB, PIOB, piob);
)+
$(
pin!($PinTypeC, $pin_identC, $pin_noC, PIOC, pioc);
)+
$(
#[cfg(feature = "atsam4e")]
pin!($PinTypeD, $pin_identD, $pin_noD, PIOD, piod);
)+
$(
#[cfg(feature = "atsam4e")]
pin!($PinTypeE, $pin_identE, $pin_noE, PIOE, pioe);
)+
};
}
macro_rules! pin {
(
$PinType:ident,
$pin_ident:ident,
$i:expr,
$PIO:ident,
$pio:ident
) => {
pub struct $PinType<MODE> {
_mode: PhantomData<MODE>,
}
impl<MODE> $PinType<MODE> {
pub(crate) fn puer(&mut self) -> &$pio::PUER {
unsafe { &(*$PIO::ptr()).puer }
}
pub(crate) fn pudr(&mut self) -> &$pio::PUDR {
unsafe { &(*$PIO::ptr()).pudr }
}
pub(crate) fn _ier(&mut self) -> &$pio::IER {
unsafe { &(*$PIO::ptr()).ier }
}
pub(crate) fn idr(&mut self) -> &$pio::IDR {
unsafe { &(*$PIO::ptr()).idr }
}
pub(crate) fn ppder(&mut self) -> &$pio::PPDER {
unsafe { &(*$PIO::ptr()).ppder }
}
pub(crate) fn ppddr(&mut self) -> &$pio::PPDDR {
unsafe { &(*$PIO::ptr()).ppddr }
}
pub(crate) fn abcdsr1(&mut self) -> &$pio::ABCDSR {
unsafe { &(*$PIO::ptr()).abcdsr[0] }
}
pub(crate) fn abcdsr2(&mut self) -> &$pio::ABCDSR {
unsafe { &(*$PIO::ptr()).abcdsr[1] }
}
pub(crate) fn mder(&mut self) -> &$pio::MDER {
unsafe { &(*$PIO::ptr()).mder }
}
pub(crate) fn mddr(&mut self) -> &$pio::MDDR {
unsafe { &(*$PIO::ptr()).mddr }
}
pub(crate) fn oer(&mut self) -> &$pio::OER {
unsafe { &(*$PIO::ptr()).oer }
}
pub(crate) fn odr(&mut self) -> &$pio::ODR {
unsafe { &(*$PIO::ptr()).odr }
}
pub(crate) fn per(&mut self) -> &$pio::PER {
unsafe { &(*$PIO::ptr()).per }
}
pub(crate) fn pdr(&mut self) -> &$pio::PDR {
unsafe { &(*$PIO::ptr()).pdr }
}
pub(crate) fn sodr(&mut self) -> &$pio::SODR {
unsafe { &(*$PIO::ptr()).sodr }
}
pub(crate) fn codr(&mut self) -> &$pio::CODR {
unsafe { &(*$PIO::ptr()).codr }
}
pub(crate) fn ifscdr(&mut self) -> &$pio::IFSCDR {
unsafe { &(*$PIO::ptr()).ifscdr }
}
fn enable_pin(&mut self) {
self.per().write_with_zero(|w| unsafe { w.bits(1 << $i) });
}
fn disable_pin(&mut self) {
self.pdr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
}
fn _enable_pin_interrupt(&mut self) {
self._ier().write_with_zero(|w| unsafe { w.bits(1 << $i) });
}
fn disable_pin_interrupt(&mut self) {
self.idr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
}
fn prepare_pin_for_function_use(&mut self) {
self.pudr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.ppddr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.mddr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.ifscdr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
}
fn prepare_pin_for_input_use(&mut self) {
self.disable_pin_interrupt();
self.mddr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.odr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
}
pub fn into_peripheral_function_a(mut self) -> $PinType<PfA> {
self.prepare_pin_for_function_use();
self.abcdsr1().modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) });
self.abcdsr2().modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) });
self.disable_pin();
$PinType { _mode: PhantomData }
}
pub fn into_peripheral_function_b(mut self) -> $PinType<PfB> {
self.prepare_pin_for_function_use();
self.abcdsr1().modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) });
self.abcdsr2().modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) });
self.disable_pin();
$PinType { _mode: PhantomData }
}
pub fn into_peripheral_function_c(mut self) -> $PinType<PfC> {
self.prepare_pin_for_function_use();
self.abcdsr1().modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) });
self.abcdsr2().modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) });
self.disable_pin();
$PinType { _mode: PhantomData }
}
pub fn into_peripheral_function_d(mut self) -> $PinType<PfD> {
self.prepare_pin_for_function_use();
self.abcdsr1().modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) });
self.abcdsr2().modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) });
self.disable_pin();
$PinType { _mode: PhantomData }
}
pub fn into_floating_input(mut self) -> $PinType<Input<Floating>> {
self.prepare_pin_for_input_use();
self.pudr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.ppddr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.enable_pin();
$PinType { _mode: PhantomData }
}
pub fn into_pull_down_input(mut self) -> $PinType<Input<PullDown>> {
self.prepare_pin_for_input_use();
self.pudr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.ppder().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.enable_pin();
$PinType { _mode: PhantomData }
}
pub fn into_pull_up_input(mut self) -> $PinType<Input<PullUp>> {
self.prepare_pin_for_input_use();
self.ppddr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.puer().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.enable_pin();
$PinType { _mode: PhantomData }
}
pub fn into_open_drain_output(mut self) -> $PinType<Output<OpenDrain>> {
self.disable_pin_interrupt();
self.mder().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.oer().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.enable_pin();
$PinType { _mode: PhantomData }
}
pub fn into_push_pull_output(mut self) -> $PinType<Output<PushPull>> {
self.disable_pin_interrupt();
self.mddr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.oer().write_with_zero(|w| unsafe { w.bits(1 << $i) });
self.per().write_with_zero(|w| unsafe { w.bits(1 << $i) });
$PinType { _mode: PhantomData }
}
}
impl<MODE> InputPin for $PinType<Input<MODE>> {
type Error = ();
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(false)
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(false)
}
}
impl<MODE> OutputPin for $PinType<Output<MODE>> {
type Error = ();
fn set_high(&mut self) -> Result<(), Self::Error> {
self.sodr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
self.codr().write_with_zero(|w| unsafe { w.bits(1 << $i) });
Ok(())
}
}
};
}
pins!([
Pa0: (pa0, 0),
Pa1: (pa1, 1),
Pa2: (pa2, 2),
Pa3: (pa3, 3),
Pa4: (pa4, 4),
Pa5: (pa5, 5),
Pa6: (pa6, 6),
Pa7: (pa7, 7),
Pa8: (pa8, 8),
Pa9: (pa9, 9),
Pa10: (pa10, 10),
Pa11: (pa11, 11),
Pa12: (pa12, 12),
Pa13: (pa13, 13),
Pa14: (pa14, 14),
Pa15: (pa15, 15),
Pa16: (pa16, 16),
Pa17: (pa17, 17),
Pa18: (pa18, 18),
Pa19: (pa19, 19),
Pa20: (pa20, 20),
Pa21: (pa21, 21),
Pa22: (pa22, 22),
Pa23: (pa23, 23),
Pa24: (pa24, 24),
Pa25: (pa25, 25),
Pa26: (pa26, 26),
Pa27: (pa27, 27),
Pa28: (pa28, 28),
Pa29: (pa29, 29),
Pa30: (pa30, 30),
Pa31: (pa31, 31),
],[
Pb0: (pb0, 0),
Pb1: (pb1, 1),
Pb2: (pb2, 2),
Pb3: (pb3, 3),
Pb4: (pb4, 4),
Pb5: (pb5, 5),
Pb6: (pb6, 6),
Pb7: (pb7, 7),
Pb8: (pb8, 8),
Pb9: (pb9, 9),
Pb10: (pb10, 10),
Pb11: (pb11, 11),
Pb12: (pb12, 12),
Pb13: (pb13, 13),
Pb14: (pb14, 14),
],
[
Pc0: (pc0, 0),
Pc1: (pc1, 1),
Pc2: (pc2, 2),
Pc3: (pc3, 3),
Pc4: (pc4, 4),
Pc5: (pc5, 5),
Pc6: (pc6, 6),
Pc7: (pc7, 7),
Pc8: (pc8, 8),
Pc9: (pc9, 9),
Pc10: (pc10, 10),
Pc11: (pc11, 11),
Pc12: (pc12, 12),
Pc13: (pc13, 13),
Pc14: (pc14, 14),
Pc15: (pc15, 15),
Pc16: (pc16, 16),
Pc17: (pc17, 17),
Pc18: (pc18, 18),
Pc19: (pc19, 19),
Pc20: (pc20, 20),
Pc21: (pc21, 21),
Pc22: (pc22, 22),
Pc23: (pc23, 23),
Pc24: (pc24, 24),
Pc25: (pc25, 25),
Pc26: (pc26, 26),
Pc27: (pc27, 27),
Pc28: (pc28, 28),
Pc29: (pc29, 29),
Pc30: (pc30, 30),
Pc31: (pc31, 31),
],
[
Pd0: (pd0, 0),
Pd1: (pd1, 1),
Pd2: (pd2, 2),
Pd3: (pd3, 3),
Pd4: (pd4, 4),
Pd5: (pd5, 5),
Pd6: (pd6, 6),
Pd7: (pd7, 7),
Pd8: (pd8, 8),
Pd9: (pd9, 9),
Pd10: (pd10, 10),
Pd11: (pd11, 11),
Pd12: (pd12, 12),
Pd13: (pd13, 13),
Pd14: (pd14, 14),
Pd15: (pd15, 15),
Pd16: (pd16, 16),
Pd17: (pd17, 17),
Pd18: (pd18, 18),
Pd19: (pd19, 19),
Pd20: (pd20, 20),
Pd21: (pd21, 21),
Pd22: (pd22, 22),
Pd23: (pd23, 23),
Pd24: (pd24, 24),
Pd25: (pd25, 25),
Pd26: (pd26, 26),
Pd27: (pd27, 27),
Pd28: (pd28, 28),
Pd29: (pd29, 29),
Pd30: (pd30, 30),
Pd31: (pd31, 31),
],
[
Pe0: (pe0, 0),
Pe1: (pe1, 1),
Pe2: (pe2, 2),
Pe3: (pe3, 3),
Pe4: (pe4, 4),
Pe5: (pe5, 5),
]);
#[macro_export]
macro_rules! define_pin_map {
($(#[$topattr:meta])* struct $Type:ident,
$( $(#[$attr:meta])* pin $name:ident = $pin_ident:ident<$pin_type:ty, $into_method:ident>),+ , ) => {
paste! {
$(#[$topattr])*
pub struct $Type {
$(
$(#[$attr])*
pub $name: [<P $pin_ident>]<$pin_type>
),+
}
}
impl $Type {
paste! {
pub fn new(ports: Ports) -> Self {
let pins = ports.split();
$(
let [<new_pin $pin_ident>] = pins.[<p $pin_ident>].$into_method();
)+
$Type {
$(
$name: [<new_pin $pin_ident>]
),+
}
}
}
}
}
}