use super::dynpin::{DynDisabled, DynInput, DynOutput, DynPinId, DynPinMode};
use super::{
InputOverride, Interrupt, InterruptOverride, OutputDriveStrength, OutputEnableOverride,
OutputOverride, OutputSlewRate,
};
use crate::gpio::reg::RegisterInterface;
use crate::typelevel::{Is, NoneT, Sealed};
use core::convert::Infallible;
use core::marker::PhantomData;
use crate::gpio::dynpin::DynFunction;
#[cfg(feature = "eh1_0_alpha")]
use eh1_0_alpha::digital as eh1;
pub use embedded_hal::digital::v2::PinState;
use hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin};
use core::mem::transmute;
pub trait ValidPinMode<I: PinId>: Sealed {}
pub trait DisabledConfig: Sealed {
const DYN: DynDisabled;
}
pub enum Floating {}
pub enum PullDown {}
pub enum PullUp {}
pub enum BusKeep {}
impl Sealed for Floating {}
impl Sealed for PullDown {}
impl Sealed for PullUp {}
impl Sealed for BusKeep {}
impl DisabledConfig for Floating {
const DYN: DynDisabled = DynDisabled::Floating;
}
impl DisabledConfig for PullDown {
const DYN: DynDisabled = DynDisabled::PullDown;
}
impl DisabledConfig for PullUp {
const DYN: DynDisabled = DynDisabled::PullUp;
}
impl DisabledConfig for BusKeep {
const DYN: DynDisabled = DynDisabled::BusKeep;
}
pub struct Disabled<C: DisabledConfig> {
cfg: PhantomData<C>,
}
impl<C: DisabledConfig> Sealed for Disabled<C> {}
pub type FloatingDisabled = Disabled<Floating>;
pub type PullDownDisabled = Disabled<PullDown>;
pub type PullUpDisabled = Disabled<PullUp>;
pub type BusKeepDisabled = Disabled<BusKeep>;
impl<I: PinId, C: DisabledConfig> ValidPinMode<I> for Disabled<C> {}
pub trait InputConfig: Sealed {
const DYN: DynInput;
}
impl InputConfig for Floating {
const DYN: DynInput = DynInput::Floating;
}
impl InputConfig for PullDown {
const DYN: DynInput = DynInput::PullDown;
}
impl InputConfig for PullUp {
const DYN: DynInput = DynInput::PullUp;
}
impl InputConfig for BusKeep {
const DYN: DynInput = DynInput::BusKeep;
}
pub struct Input<C: InputConfig> {
cfg: PhantomData<C>,
}
impl<C: InputConfig> Sealed for Input<C> {}
pub type FloatingInput = Input<Floating>;
pub type PullDownInput = Input<PullDown>;
pub type PullUpInput = Input<PullUp>;
pub type BusKeepInput = Input<BusKeep>;
impl<I: PinId, C: InputConfig> ValidPinMode<I> for Input<C> {}
pub trait OutputConfig: Sealed {
const DYN: DynOutput;
}
pub enum PushPull {}
pub enum Readable {}
impl Sealed for PushPull {}
impl Sealed for Readable {}
impl OutputConfig for PushPull {
const DYN: DynOutput = DynOutput::PushPull;
}
impl OutputConfig for Readable {
const DYN: DynOutput = DynOutput::Readable;
}
pub struct Output<C: OutputConfig> {
cfg: PhantomData<C>,
}
impl<C: OutputConfig> Sealed for Output<C> {}
pub type PushPullOutput = Output<PushPull>;
pub type ReadableOutput = Output<Readable>;
impl<I: PinId, C: OutputConfig> ValidPinMode<I> for Output<C> {}
pub struct Function<C: FunctionConfig> {
cfg: PhantomData<C>,
}
impl<C: FunctionConfig> Sealed for Function<C> {}
pub trait FunctionConfig: Sealed {
const DYN: DynFunction;
}
macro_rules! function {
(
$(
$Func:ident
),+
) => {
$crate::paste::paste! {
$(
#[
doc = "Type-level variant of [`FunctionConfig`] for \
alternate peripheral function " $Func
]
pub enum $Func {}
impl Sealed for $Func {}
impl FunctionConfig for $Func {
const DYN: DynFunction = DynFunction::$Func;
}
#[
doc = "Type-level variant of [`PinMode`] for alternate \
peripheral function [`" $Func "`]"
]
pub type [<Function $Func>] = Function<$Func>;
)+
}
};
}
function!(Spi, Xip, Uart, I2C, Pwm, Clock, UsbAux);
impl Sealed for pac::PIO0 {}
impl FunctionConfig for pac::PIO0 {
const DYN: DynFunction = DynFunction::Pio0;
}
pub type FunctionPio0 = Function<pac::PIO0>;
impl Sealed for pac::PIO1 {}
impl FunctionConfig for pac::PIO1 {
const DYN: DynFunction = DynFunction::Pio1;
}
pub type FunctionPio1 = Function<pac::PIO1>;
pub trait PinMode: Sealed + Sized {
const DYN: DynPinMode;
}
impl<C: DisabledConfig> PinMode for Disabled<C> {
const DYN: DynPinMode = DynPinMode::Disabled(C::DYN);
}
impl<C: InputConfig> PinMode for Input<C> {
const DYN: DynPinMode = DynPinMode::Input(C::DYN);
}
impl<C: OutputConfig> PinMode for Output<C> {
const DYN: DynPinMode = DynPinMode::Output(C::DYN);
}
impl<C: FunctionConfig> PinMode for Function<C> {
const DYN: DynPinMode = DynPinMode::Function(C::DYN);
}
pub trait PinId: Sealed {
const DYN: DynPinId;
type Reset;
}
macro_rules! pin_id {
($Group:ident, $Id:ident, $NUM:literal, $reset : ident) => {
#[doc = "Pin ID representing pin "]
pub enum $Id {}
impl Sealed for $Id {}
impl PinId for $Id {
type Reset = $reset;
const DYN: DynPinId = DynPinId {
group: DynGroup::$Group,
num: $NUM,
};
}
};
}
pub trait OptionalPinId: Sealed {}
impl OptionalPinId for NoneT {}
impl<I: PinId> OptionalPinId for I {}
pub trait SomePinId: OptionalPinId + PinId + Sealed {}
impl<I: PinId> SomePinId for I {}
struct Registers<I: PinId> {
id: PhantomData<I>,
}
unsafe impl<I: PinId> RegisterInterface for Registers<I> {
#[inline]
fn id(&self) -> DynPinId {
I::DYN
}
}
impl<I: PinId> Registers<I> {
#[inline]
unsafe fn new() -> Self {
Registers { id: PhantomData }
}
#[inline]
fn change_mode<M: PinMode + ValidPinMode<I>>(&mut self) {
RegisterInterface::do_change_mode(self, M::DYN);
}
}
pub struct Pin<I, M>
where
I: PinId,
M: PinMode + ValidPinMode<I>,
{
regs: Registers<I>,
mode: PhantomData<M>,
}
impl<I, M> Pin<I, M>
where
I: PinId,
M: PinMode + ValidPinMode<I>,
{
#[inline]
pub(crate) unsafe fn new() -> Pin<I, M> {
Pin {
regs: Registers::new(),
mode: PhantomData,
}
}
#[inline]
pub fn id(&self) -> DynPinId {
I::DYN
}
#[inline]
pub fn into_mode<N: PinMode + ValidPinMode<I>>(mut self) -> Pin<I, N> {
if N::DYN != M::DYN {
self.regs.change_mode::<N>();
}
unsafe { Pin::new() }
}
#[inline]
pub fn into_floating_disabled(self) -> Pin<I, FloatingDisabled> {
self.into_mode()
}
#[inline]
pub fn into_pull_down_disabled(self) -> Pin<I, PullDownDisabled> {
self.into_mode()
}
#[inline]
pub fn into_pull_up_disabled(self) -> Pin<I, PullUpDisabled> {
self.into_mode()
}
#[inline]
pub fn into_floating_input(self) -> Pin<I, FloatingInput> {
self.into_mode()
}
#[inline]
pub fn into_pull_down_input(self) -> Pin<I, PullDownInput> {
self.into_mode()
}
#[inline]
pub fn into_pull_up_input(self) -> Pin<I, PullUpInput> {
self.into_mode()
}
#[inline]
pub fn into_bus_keep_input(self) -> Pin<I, BusKeepInput> {
self.into_mode()
}
#[inline]
pub fn into_push_pull_output(self) -> Pin<I, PushPullOutput> {
self.into_mode()
}
#[inline]
pub fn into_push_pull_output_in_state(mut self, state: PinState) -> Pin<I, PushPullOutput> {
match state {
PinState::High => self._set_high(),
PinState::Low => self._set_low(),
}
self.into_mode()
}
#[inline]
pub fn into_readable_output(self) -> Pin<I, ReadableOutput> {
self.into_mode()
}
#[inline]
pub fn into_readable_output_in_state(mut self, state: PinState) -> Pin<I, ReadableOutput> {
match state {
PinState::High => self._set_high(),
PinState::Low => self._set_low(),
}
self.into_mode()
}
#[inline]
pub fn get_drive_strength(&self) -> OutputDriveStrength {
self.regs.read_drive_strength()
}
#[inline]
pub fn set_drive_strength(&mut self, strength: OutputDriveStrength) {
self.regs.write_drive_strength(strength);
}
#[inline]
pub fn get_slew_rate(&self) -> OutputSlewRate {
self.regs.read_slew_rate()
}
#[inline]
pub fn set_slew_rate(&mut self, rate: OutputSlewRate) {
self.regs.write_slew_rate(rate)
}
#[inline]
pub fn clear_interrupt(&mut self, interrupt: Interrupt) {
self.regs.clear_interrupt(interrupt);
}
#[inline]
pub fn interrupt_status(&self, interrupt: Interrupt) -> bool {
self.regs.interrupt_status(interrupt)
}
#[inline]
pub fn is_interrupt_enabled(&self, interrupt: Interrupt) -> bool {
self.regs.is_interrupt_enabled(interrupt)
}
#[inline]
pub fn set_interrupt_enabled(&self, interrupt: Interrupt, enabled: bool) {
self.regs.set_interrupt_enabled(interrupt, enabled);
}
#[inline]
pub fn is_interrupt_forced(&self, interrupt: Interrupt) -> bool {
self.regs.is_interrupt_forced(interrupt)
}
#[inline]
pub fn set_interrupt_forced(&self, interrupt: Interrupt, forced: bool) {
self.regs.set_interrupt_forced(interrupt, forced);
}
#[inline]
pub fn set_interrupt_override(&mut self, override_value: InterruptOverride) {
self.regs.set_interrupt_override(override_value);
}
#[inline]
pub fn set_input_override(&mut self, override_value: InputOverride) {
self.regs.set_input_override(override_value);
}
#[inline]
pub fn set_output_enable_override(&mut self, override_value: OutputEnableOverride) {
self.regs.set_output_enable_override(override_value);
}
#[inline]
pub fn set_output_override(&mut self, override_value: OutputOverride) {
self.regs.set_output_override(override_value);
}
#[inline]
#[allow(clippy::bool_comparison)] pub(crate) fn _is_low(&self) -> bool {
self.regs.read_pin() == false
}
#[inline]
#[allow(clippy::bool_comparison)] pub(crate) fn _is_high(&self) -> bool {
self.regs.read_pin() == true
}
#[inline]
pub(crate) fn _set_low(&mut self) {
self.regs.write_pin(false);
}
#[inline]
pub(crate) fn _set_high(&mut self) {
self.regs.write_pin(true);
}
#[inline]
pub(crate) fn _toggle(&mut self) {
self.regs.toggle_pin();
}
#[inline]
#[allow(clippy::bool_comparison)] pub(crate) fn _is_set_low(&self) -> bool {
self.regs.read_out_pin() == false
}
#[inline]
#[allow(clippy::bool_comparison)] pub(crate) fn _is_set_high(&self) -> bool {
self.regs.read_out_pin() == true
}
}
pub trait AnyPin
where
Self: Sealed,
Self: Is<Type = SpecificPin<Self>>,
<Self as AnyPin>::Mode: ValidPinMode<<Self as AnyPin>::Id>,
{
type Id: PinId;
type Mode: PinMode;
}
impl<I, M> Sealed for Pin<I, M>
where
I: PinId,
M: PinMode + ValidPinMode<I>,
{
}
impl<I, M> AnyPin for Pin<I, M>
where
I: PinId,
M: PinMode + ValidPinMode<I>,
{
type Id = I;
type Mode = M;
}
pub type SpecificPin<P> = Pin<<P as AnyPin>::Id, <P as AnyPin>::Mode>;
impl<P: AnyPin> AsRef<P> for SpecificPin<P> {
#[inline]
fn as_ref(&self) -> &P {
unsafe { transmute(self) }
}
}
impl<P: AnyPin> AsMut<P> for SpecificPin<P> {
#[inline]
fn as_mut(&mut self) -> &mut P {
unsafe { transmute(self) }
}
}
pub trait OptionalPin: Sealed {
#[allow(missing_docs)]
type Id: OptionalPinId;
}
impl OptionalPin for NoneT {
type Id = NoneT;
}
impl<P: AnyPin> OptionalPin for P {
type Id = P::Id;
}
pub trait SomePin: AnyPin + Sealed {}
impl<P: AnyPin> SomePin for P {}
impl<I, C> OutputPin for Pin<I, Output<C>>
where
I: PinId,
C: OutputConfig,
{
type Error = Infallible;
#[inline]
fn set_high(&mut self) -> Result<(), Self::Error> {
self._set_high();
Ok(())
}
#[inline]
fn set_low(&mut self) -> Result<(), Self::Error> {
self._set_low();
Ok(())
}
}
impl<I> InputPin for Pin<I, ReadableOutput>
where
I: PinId,
{
type Error = Infallible;
#[inline]
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self._is_high())
}
#[inline]
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self._is_low())
}
}
impl<I, C> InputPin for Pin<I, Input<C>>
where
I: PinId,
C: InputConfig,
{
type Error = Infallible;
#[inline]
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self._is_high())
}
#[inline]
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self._is_low())
}
}
impl<I, C> ToggleableOutputPin for Pin<I, Output<C>>
where
I: PinId,
C: OutputConfig,
{
type Error = Infallible;
#[inline]
fn toggle(&mut self) -> Result<(), Self::Error> {
self._toggle();
Ok(())
}
}
impl<I, C> StatefulOutputPin for Pin<I, Output<C>>
where
I: PinId,
C: OutputConfig,
{
#[inline]
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(self._is_set_high())
}
#[inline]
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(self._is_set_low())
}
}
#[cfg(feature = "eh1_0_alpha")]
impl<I, C> eh1::ErrorType for Pin<I, Output<C>>
where
I: PinId,
C: OutputConfig,
{
type Error = Infallible;
}
#[cfg(feature = "eh1_0_alpha")]
impl<I, C> eh1::OutputPin for Pin<I, Output<C>>
where
I: PinId,
C: OutputConfig,
{
#[inline]
fn set_high(&mut self) -> Result<(), Self::Error> {
self._set_high();
Ok(())
}
#[inline]
fn set_low(&mut self) -> Result<(), Self::Error> {
self._set_low();
Ok(())
}
}
#[cfg(feature = "eh1_0_alpha")]
impl<I> eh1::InputPin for Pin<I, ReadableOutput>
where
I: PinId,
{
#[inline]
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self._is_high())
}
#[inline]
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self._is_low())
}
}
#[cfg(feature = "eh1_0_alpha")]
impl<I, C> eh1::ErrorType for Pin<I, Input<C>>
where
I: PinId,
C: InputConfig,
{
type Error = Infallible;
}
#[cfg(feature = "eh1_0_alpha")]
impl<I, C> eh1::InputPin for Pin<I, Input<C>>
where
I: PinId,
C: InputConfig,
{
#[inline]
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self._is_high())
}
#[inline]
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self._is_low())
}
}
#[cfg(feature = "eh1_0_alpha")]
impl<I, C> eh1::ToggleableOutputPin for Pin<I, Output<C>>
where
I: PinId,
C: OutputConfig,
{
#[inline]
fn toggle(&mut self) -> Result<(), Self::Error> {
self._toggle();
Ok(())
}
}
#[cfg(feature = "eh1_0_alpha")]
impl<I, C> eh1::StatefulOutputPin for Pin<I, Output<C>>
where
I: PinId,
C: OutputConfig,
{
#[inline]
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(self._is_set_high())
}
#[inline]
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(self._is_set_low())
}
}
macro_rules! gpio {
($Group:ident, [ $($Func:ident),+ ], [
$($PXi:ident: ($i:expr, $is:expr, $reset:ident $(, [ $($PinFunc:ident),+ ])? )),+
]) => {
$crate::paste::paste! {
#[doc = "GPIO Pins for " $Group]
pub mod [<$Group:lower>] {
use crate::sio::[<SioGpio $Group>];
use pac::{[<IO_ $Group:upper>],[<PADS_ $Group:upper>]};
pub trait BankPinId {}
use crate::typelevel::Sealed;
use crate::gpio::dynpin::{DynGroup,DynPinId};
#[allow(unused_imports)]
use super::{PullDownDisabled,PullUpDisabled,FloatingDisabled,BusKeepDisabled};
use super::{Pin,PinId};
use crate::resets::SubsystemReset;
$(
pin_id!($Group, $PXi, $i, $reset);
impl BankPinId for $PXi {}
$( $(impl super::ValidPinMode<$PXi> for super::Function<super::$PinFunc> {})+ )*
)+
pub struct Pins {
_io: [<IO_ $Group:upper>],
_pads: [<PADS_ $Group:upper>],
_sio: [<SioGpio $Group>],
$(
#[doc = "Pin " $PXi]
pub [<$PXi:lower>] : Pin<$PXi,<$PXi as PinId>::Reset>,
)+
}
impl Pins {
pub fn new(io : [<IO_ $Group:upper>], pads: [<PADS_ $Group:upper>], sio: [<SioGpio $Group>], reset : &mut pac::RESETS) -> Self {
pads.reset_bring_down(reset);
io.reset_bring_down(reset);
io.reset_bring_up(reset);
pads.reset_bring_up(reset);
unsafe {
Self {
_io: io,
_pads: pads,
_sio: sio,
$(
[<$PXi:lower>]: Pin::new(),
)+
}
}
}
}
$( impl<I: PinId + BankPinId> super::ValidPinMode<I> for super::[<Function $Func>] {} )+
}
}
}
}
gpio!(
Bank0, [ Spi, Uart, I2C, Pwm, Pio0, Pio1, UsbAux ], [
Gpio0: (0, "0", PullDownDisabled),
Gpio1: (1, "1", PullDownDisabled),
Gpio2: (2, "2", PullDownDisabled),
Gpio3: (3, "3", PullDownDisabled),
Gpio4: (4, "4", PullDownDisabled),
Gpio5: (5, "5", PullDownDisabled),
Gpio6: (6, "6", PullDownDisabled),
Gpio7: (7, "7", PullDownDisabled),
Gpio8: (8, "8", PullDownDisabled),
Gpio9: (9, "9", PullDownDisabled),
Gpio10: (10, "10", PullDownDisabled),
Gpio11: (11, "11", PullDownDisabled),
Gpio12: (12, "12", PullDownDisabled),
Gpio13: (13, "13", PullDownDisabled),
Gpio14: (14, "14", PullDownDisabled),
Gpio15: (15, "15", PullDownDisabled),
Gpio16: (16, "16", PullDownDisabled),
Gpio17: (17, "17", PullDownDisabled),
Gpio18: (18, "18", PullDownDisabled),
Gpio19: (19, "19", PullDownDisabled),
Gpio20: (20, "20", PullDownDisabled, [Clock]),
Gpio21: (21, "21", PullDownDisabled, [Clock]),
Gpio22: (22, "22", PullDownDisabled, [Clock]),
Gpio23: (23, "23", PullDownDisabled, [Clock]),
Gpio24: (24, "24", PullDownDisabled, [Clock]),
Gpio25: (25, "25", PullDownDisabled, [Clock]),
Gpio26: (26, "26", PullDownDisabled),
Gpio27: (27, "27", PullDownDisabled),
Gpio28: (28, "28", PullDownDisabled),
Gpio29: (29, "29", PullDownDisabled)
]
);
pub use bank0::Pins;
gpio!(
Qspi, [ Xip ], [
Sck: (0, "sck", PullDownDisabled),
Cs: (1, "cs", PullUpDisabled),
Sd0: (2, "sd0", FloatingDisabled),
Sd1: (3, "sd1", FloatingDisabled),
Sd2: (4, "sd2", FloatingDisabled),
Sd3: (5, "sd3", FloatingDisabled)
]
);
#[macro_export]
macro_rules! bsp_pins {
(
$(
$( #[$id_cfg:meta] )*
$Id:ident {
$( #[$name_doc:meta] )*
name: $name:ident $(,)?
$(
aliases: {
$(
$( #[$alias_cfg:meta] )*
$Mode:ident: $Alias:ident
),+
}
)?
} $(,)?
)+
) => {
$crate::paste::paste! {
pub struct Pins {
$(
$( #[$id_cfg] )*
$( #[$name_doc] )*
pub $name: $crate::gpio::Pin<
$crate::gpio::bank0::$Id,
<$crate::gpio::bank0::$Id as $crate::gpio::PinId>::Reset
>,
)+
}
impl Pins {
#[inline]
pub fn new(io : $crate::pac::IO_BANK0, pads: $crate::pac::PADS_BANK0, sio: $crate::sio::SioGpioBank0, reset : &mut $crate::pac::RESETS) -> Self {
let mut pins = $crate::gpio::Pins::new(io,pads,sio,reset);
Self {
$(
$( #[$id_cfg] )*
$name: pins.[<$Id:lower>],
)+
}
}
}
$(
$( #[$id_cfg] )*
$crate::bsp_pins!(@aliases, $( $( $( #[$alias_cfg] )* $Id $Mode $Alias )+ )? );
)+
}
};
( @aliases, $( $( $( #[$attr:meta] )* $Id:ident $Mode:ident $Alias:ident )+ )? ) => {
$crate::paste::paste! {
$(
$(
$( #[$attr] )*
pub type $Alias = $crate::gpio::Pin<
$crate::gpio::bank0::$Id,
$crate::gpio::$Mode
>;
$( #[$attr] )*
#[doc = "[DynPinId](rp2040_hal::gpio::DynPinId) "]
#[doc = "for the `" $Alias "` alias."]
pub const [<$Alias:snake:upper _ID>]: $crate::gpio::DynPinId =
<$crate::gpio::bank0::$Id as $crate::gpio::PinId>::DYN;
$( #[$attr] )*
#[doc = "[DynPinMode](rp2040_hal::gpio::DynPinMode) "]
#[doc = "for the `" $Alias "` alias."]
pub const [<$Alias:snake:upper _MODE>]: $crate::gpio::DynPinMode =
<$crate::gpio::$Mode as $crate::gpio::PinMode>::DYN;
)+
)?
}
};
}