pub use embedded_hal::digital::PinState;
use crate::{
atomic_register_access::{write_bitmask_clear, write_bitmask_set},
pac,
sio::Sio,
typelevel::{self, Sealed},
};
mod func;
pub(crate) mod pin;
mod pin_group;
mod pull;
pub use func::*;
pub use pin::{DynBankId, DynPinId, PinId};
pub use pin_group::PinGroup;
pub use pull::*;
#[allow(clippy::enum_variant_names)]
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum OutputDriveStrength {
TwoMilliAmps,
FourMilliAmps,
EightMilliAmps,
TwelveMilliAmps,
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum OutputSlewRate {
Slow,
Fast,
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum Interrupt {
LevelLow,
LevelHigh,
EdgeLow,
EdgeHigh,
}
impl Interrupt {
fn mask(&self) -> u32 {
match self {
Interrupt::LevelLow => 0b0001,
Interrupt::LevelHigh => 0b0010,
Interrupt::EdgeLow => 0b0100,
Interrupt::EdgeHigh => 0b1000,
}
}
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum InterruptOverride {
Normal = 0,
Invert = 1,
AlwaysLow = 2,
AlwaysHigh = 3,
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum InputOverride {
Normal = 0,
Invert = 1,
AlwaysLow = 2,
AlwaysHigh = 3,
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum OutputEnableOverride {
Normal = 0,
Invert = 1,
Disable = 2,
Enable = 3,
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum OutputOverride {
DontInvert = 0,
Invert = 1,
AlwaysLow = 2,
AlwaysHigh = 3,
}
#[derive(Debug)]
pub struct Pin<I: PinId, F: func::Function, P: PullType> {
id: I,
function: F,
pull_type: P,
}
pub unsafe fn new_pin(id: DynPinId) -> Pin<DynPinId, DynFunction, DynPullType> {
use pac::io_bank0::gpio::gpio_ctrl::FUNCSEL_A;
use pin::pin_sealed::PinIdOps;
let funcsel = id
.io_ctrl()
.read()
.funcsel()
.variant()
.expect("Invalid funcsel read from register.");
let function = match funcsel {
FUNCSEL_A::JTAG => {
if id.bank == DynBankId::Qspi {
DynFunction::Xip
} else {
DynFunction::Hstx
}
}
FUNCSEL_A::SPI => DynFunction::Spi,
FUNCSEL_A::UART => DynFunction::Uart,
FUNCSEL_A::I2C => DynFunction::I2c,
FUNCSEL_A::PWM => DynFunction::Pwm,
FUNCSEL_A::SIO => {
let mask = id.mask();
let cfg = if id.sio_oe().read().bits() & mask == mask {
DynSioConfig::Output
} else {
DynSioConfig::Input
};
DynFunction::Sio(cfg)
}
FUNCSEL_A::PIO0 => DynFunction::Pio0,
FUNCSEL_A::PIO1 => DynFunction::Pio1,
FUNCSEL_A::PIO2 => DynFunction::Pio2,
FUNCSEL_A::GPCK => DynFunction::Clock,
FUNCSEL_A::USB => DynFunction::Usb,
FUNCSEL_A::UART_AUX => DynFunction::UartAux,
FUNCSEL_A::NULL => DynFunction::Null,
};
let pad = id.pad_ctrl().read();
let pull_type = match (pad.pue().bit_is_set(), pad.pde().bit_is_set()) {
(true, true) => DynPullType::BusKeep,
(true, false) => DynPullType::Up,
(false, true) => DynPullType::Down,
(false, false) => DynPullType::None,
};
Pin {
id,
function,
pull_type,
}
}
impl<I: PinId, F: func::Function, P: PullType> Pin<I, F, P> {
pub fn id(&self) -> DynPinId {
self.id.as_dyn()
}
pub unsafe fn into_unchecked<F2: func::Function, P2: PullType>(self) -> Pin<I, F2, P2> {
Pin {
id: self.id,
function: F2::from(self.function.as_dyn()),
pull_type: P2::from(self.pull_type.as_dyn()),
}
}
pub fn reconfigure<F2, P2>(self) -> Pin<I, F2, P2>
where
F2: func::Function,
P2: PullType,
I: func::ValidFunction<F2>,
{
self.into_function().into_pull_type()
}
#[deprecated(
note = "Misleading name `mode` when it changes the `function`. Please use `into_function` instead.",
since = "0.9.0"
)]
pub fn into_mode<F2>(self) -> Pin<I, F2, P>
where
F2: func::Function,
I: func::ValidFunction<F2>,
{
self.into_function()
}
pub fn into_function<F2>(self) -> Pin<I, F2, P>
where
F2: func::Function,
I: func::ValidFunction<F2>,
{
let prev_function = self.function.as_dyn();
let function = F2::from(prev_function);
let new_function = function.as_dyn();
if prev_function != new_function {
pin::set_function(&self.id, new_function);
}
Pin {
function,
id: self.id,
pull_type: self.pull_type,
}
}
pub fn into_pull_type<M2: PullType>(self) -> Pin<I, F, M2> {
let prev_pull_type = self.pull_type.as_dyn();
let pull_type = M2::from(prev_pull_type);
let new_pull_type = pull_type.as_dyn();
if prev_pull_type != new_pull_type {
pin::set_pull_type(&self.id, new_pull_type);
}
Pin {
pull_type,
id: self.id,
function: self.function,
}
}
pub fn into_dyn_pin(self) -> Pin<DynPinId, F, P> {
Pin {
id: self.id.as_dyn(),
function: self.function,
pull_type: self.pull_type,
}
}
pub fn pull_type(&self) -> DynPullType {
self.pull_type.as_dyn()
}
#[inline]
pub fn into_floating_disabled(self) -> Pin<I, FunctionNull, PullNone>
where
I: ValidFunction<FunctionNull>,
{
self.reconfigure()
}
#[inline]
pub fn into_pull_down_disabled(self) -> Pin<I, FunctionNull, PullDown>
where
I: ValidFunction<FunctionNull>,
{
self.reconfigure()
}
#[inline]
pub fn into_pull_up_disabled(self) -> Pin<I, FunctionNull, PullUp>
where
I: ValidFunction<FunctionNull>,
{
self.reconfigure()
}
#[inline]
pub fn into_floating_input(self) -> Pin<I, FunctionSio<SioInput>, PullNone>
where
I: ValidFunction<FunctionSio<SioInput>>,
{
self.into_function().into_pull_type()
}
#[inline]
pub fn into_pull_down_input(self) -> Pin<I, FunctionSio<SioInput>, PullDown>
where
I: ValidFunction<FunctionSio<SioInput>>,
{
self.into_function().into_pull_type()
}
#[inline]
pub fn into_pull_up_input(self) -> Pin<I, FunctionSio<SioInput>, PullUp>
where
I: ValidFunction<FunctionSio<SioInput>>,
{
self.into_function().into_pull_type()
}
#[inline]
pub fn into_bus_keep_input(self) -> Pin<I, FunctionSio<SioInput>, PullBusKeep>
where
I: ValidFunction<FunctionSio<SioInput>>,
{
self.into_function().into_pull_type()
}
#[inline]
pub fn into_push_pull_output(self) -> Pin<I, FunctionSio<SioOutput>, P>
where
I: ValidFunction<FunctionSio<SioOutput>>,
{
self.into_function()
}
#[inline]
pub fn into_push_pull_output_in_state(
mut self,
state: PinState,
) -> Pin<I, FunctionSio<SioOutput>, P>
where
I: ValidFunction<FunctionSio<SioOutput>>,
{
match state {
PinState::High => self._set_high(),
PinState::Low => self._set_low(),
}
self.into_push_pull_output()
}
#[inline]
#[deprecated(
note = "All gpio are readable, use `.into_push_pull_output()` instead.",
since = "0.9.0"
)]
pub fn into_readable_output(self) -> Pin<I, FunctionSio<SioOutput>, P>
where
I: ValidFunction<FunctionSio<SioOutput>>,
{
self.into_function()
}
#[inline]
#[deprecated(
note = "All gpio are readable, use `.into_push_pull_output_in_state()` instead.",
since = "0.9.0"
)]
pub fn into_readable_output_in_state(self, state: PinState) -> Pin<I, FunctionSio<SioOutput>, P>
where
I: ValidFunction<FunctionSio<SioOutput>>,
{
self.into_push_pull_output_in_state(state)
}
#[inline]
pub fn get_drive_strength(&self) -> OutputDriveStrength {
use pac::pads_bank0::gpio::DRIVE_A;
match self.id.pad_ctrl().read().drive().variant() {
DRIVE_A::_2M_A => OutputDriveStrength::TwoMilliAmps,
DRIVE_A::_4M_A => OutputDriveStrength::FourMilliAmps,
DRIVE_A::_8M_A => OutputDriveStrength::EightMilliAmps,
DRIVE_A::_12M_A => OutputDriveStrength::TwelveMilliAmps,
}
}
#[inline]
pub fn set_drive_strength(&mut self, strength: OutputDriveStrength) {
use pac::pads_bank0::gpio::DRIVE_A;
let variant = match strength {
OutputDriveStrength::TwoMilliAmps => DRIVE_A::_2M_A,
OutputDriveStrength::FourMilliAmps => DRIVE_A::_4M_A,
OutputDriveStrength::EightMilliAmps => DRIVE_A::_8M_A,
OutputDriveStrength::TwelveMilliAmps => DRIVE_A::_12M_A,
};
self.id.pad_ctrl().modify(|_, w| w.drive().variant(variant))
}
#[inline]
pub fn get_slew_rate(&self) -> OutputSlewRate {
if self.id.pad_ctrl().read().slewfast().bit_is_set() {
OutputSlewRate::Fast
} else {
OutputSlewRate::Slow
}
}
#[inline]
pub fn set_slew_rate(&mut self, rate: OutputSlewRate) {
self.id
.pad_ctrl()
.modify(|_, w| w.slewfast().bit(OutputSlewRate::Fast == rate));
}
#[inline]
pub fn get_schmitt_enabled(&self) -> bool {
self.id.pad_ctrl().read().schmitt().bit_is_set()
}
#[inline]
pub fn set_schmitt_enabled(&self, enable: bool) {
self.id.pad_ctrl().modify(|_, w| w.schmitt().bit(enable));
}
#[inline]
pub fn get_output_disable(&mut self) -> bool {
self.id.pad_ctrl().read().od().bit_is_set()
}
#[inline]
pub fn set_output_disable(&mut self, disable: bool) {
self.id.pad_ctrl().modify(|_, w| w.od().bit(disable));
}
#[inline]
pub fn get_input_enable(&mut self) -> bool {
self.id.pad_ctrl().read().ie().bit_is_set()
}
#[inline]
pub fn set_input_enable(&mut self, enable: bool) {
self.id.pad_ctrl().modify(|_, w| w.ie().bit(enable));
}
#[inline]
pub fn get_input_override(&self) -> InputOverride {
use pac::io_bank0::gpio::gpio_ctrl::INOVER_A;
match self.id.io_ctrl().read().inover().variant() {
INOVER_A::NORMAL => InputOverride::Normal,
INOVER_A::INVERT => InputOverride::Invert,
INOVER_A::LOW => InputOverride::AlwaysLow,
INOVER_A::HIGH => InputOverride::AlwaysHigh,
}
}
#[inline]
pub fn set_input_override(&mut self, override_value: InputOverride) {
use pac::io_bank0::gpio::gpio_ctrl::INOVER_A;
let variant = match override_value {
InputOverride::Normal => INOVER_A::NORMAL,
InputOverride::Invert => INOVER_A::INVERT,
InputOverride::AlwaysLow => INOVER_A::LOW,
InputOverride::AlwaysHigh => INOVER_A::HIGH,
};
self.id.io_ctrl().modify(|_, w| w.inover().variant(variant));
}
#[inline]
pub fn get_output_enable_override(&self) -> OutputEnableOverride {
use pac::io_bank0::gpio::gpio_ctrl::OEOVER_A;
match self.id.io_ctrl().read().oeover().variant() {
OEOVER_A::NORMAL => OutputEnableOverride::Normal,
OEOVER_A::INVERT => OutputEnableOverride::Invert,
OEOVER_A::DISABLE => OutputEnableOverride::Disable,
OEOVER_A::ENABLE => OutputEnableOverride::Enable,
}
}
#[inline]
pub fn set_output_enable_override(&mut self, override_value: OutputEnableOverride) {
use pac::io_bank0::gpio::gpio_ctrl::OEOVER_A;
let variant = match override_value {
OutputEnableOverride::Normal => OEOVER_A::NORMAL,
OutputEnableOverride::Invert => OEOVER_A::INVERT,
OutputEnableOverride::Disable => OEOVER_A::DISABLE,
OutputEnableOverride::Enable => OEOVER_A::ENABLE,
};
self.id.io_ctrl().modify(|_, w| w.oeover().variant(variant));
}
#[inline]
pub fn get_output_override(&self) -> OutputOverride {
use pac::io_bank0::gpio::gpio_ctrl::OUTOVER_A;
match self.id.io_ctrl().read().outover().variant() {
OUTOVER_A::NORMAL => OutputOverride::DontInvert,
OUTOVER_A::INVERT => OutputOverride::Invert,
OUTOVER_A::LOW => OutputOverride::AlwaysLow,
OUTOVER_A::HIGH => OutputOverride::AlwaysHigh,
}
}
#[inline]
pub fn set_output_override(&mut self, override_value: OutputOverride) {
use pac::io_bank0::gpio::gpio_ctrl::OUTOVER_A;
let variant = match override_value {
OutputOverride::DontInvert => OUTOVER_A::NORMAL,
OutputOverride::Invert => OUTOVER_A::INVERT,
OutputOverride::AlwaysLow => OUTOVER_A::LOW,
OutputOverride::AlwaysHigh => OUTOVER_A::HIGH,
};
self.id
.io_ctrl()
.modify(|_, w| w.outover().variant(variant));
}
#[inline]
pub fn get_interrupt_override(&self) -> InterruptOverride {
use pac::io_bank0::gpio::gpio_ctrl::IRQOVER_A;
match self.id.io_ctrl().read().irqover().variant() {
IRQOVER_A::NORMAL => InterruptOverride::Normal,
IRQOVER_A::INVERT => InterruptOverride::Invert,
IRQOVER_A::LOW => InterruptOverride::AlwaysLow,
IRQOVER_A::HIGH => InterruptOverride::AlwaysHigh,
}
}
#[inline]
pub fn set_interrupt_override(&mut self, override_value: InterruptOverride) {
use pac::io_bank0::gpio::gpio_ctrl::IRQOVER_A;
let variant = match override_value {
InterruptOverride::Normal => IRQOVER_A::NORMAL,
InterruptOverride::Invert => IRQOVER_A::INVERT,
InterruptOverride::AlwaysLow => IRQOVER_A::LOW,
InterruptOverride::AlwaysHigh => IRQOVER_A::HIGH,
};
self.id
.io_ctrl()
.modify(|_, w| w.irqover().variant(variant));
}
#[inline]
#[allow(clippy::bool_comparison)] pub(crate) fn _is_low(&self) -> bool {
let mask = self.id.mask();
self.id.sio_in().read().bits() & mask == 0
}
#[inline]
#[allow(clippy::bool_comparison)] pub(crate) fn _is_high(&self) -> bool {
!self._is_low()
}
#[inline]
pub(crate) fn _set_low(&mut self) {
let mask = self.id.mask();
self.id.sio_out_clr().write(|w| unsafe { w.bits(mask) });
}
#[inline]
pub(crate) fn _set_high(&mut self) {
let mask = self.id.mask();
self.id.sio_out_set().write(|w| unsafe { w.bits(mask) });
}
#[inline]
pub(crate) fn _toggle(&mut self) {
let mask = self.id.mask();
self.id.sio_out_xor().write(|w| unsafe { w.bits(mask) });
}
#[inline]
pub(crate) fn _is_set_low(&self) -> bool {
let mask = self.id.mask();
self.id.sio_out().read().bits() & mask == 0
}
#[inline]
pub(crate) fn _is_set_high(&self) -> bool {
!self._is_set_low()
}
#[inline]
pub fn clear_interrupt(&mut self, interrupt: Interrupt) {
let (reg, offset) = self.id.intr();
let mask = interrupt.mask();
reg.write(|w| unsafe { w.bits(mask << offset) });
}
#[inline]
pub fn interrupt_status(&self, interrupt: Interrupt) -> bool {
let (reg, offset) = self.id.proc_ints(Sio::core());
let mask = interrupt.mask();
(reg.read().bits() >> offset) & mask == mask
}
#[inline]
pub fn is_interrupt_enabled(&self, interrupt: Interrupt) -> bool {
let (reg, offset) = self.id.proc_inte(Sio::core());
let mask = interrupt.mask();
(reg.read().bits() >> offset) & mask == mask
}
#[inline]
pub fn set_interrupt_enabled(&self, interrupt: Interrupt, enabled: bool) {
let (reg, offset) = self.id.proc_inte(Sio::core());
let mask = interrupt.mask();
unsafe {
if enabled {
write_bitmask_set(reg.as_ptr(), mask << offset);
} else {
write_bitmask_clear(reg.as_ptr(), mask << offset);
}
}
}
#[inline]
pub fn is_interrupt_forced(&self, interrupt: Interrupt) -> bool {
let (reg, offset) = self.id.proc_intf(Sio::core());
let mask = interrupt.mask();
(reg.read().bits() >> offset) & mask == mask
}
#[inline]
pub fn set_interrupt_forced(&self, interrupt: Interrupt, forced: bool) {
let (reg, offset) = self.id.proc_intf(Sio::core());
let mask = interrupt.mask();
unsafe {
if forced {
write_bitmask_set(reg.as_ptr(), mask << offset);
} else {
write_bitmask_clear(reg.as_ptr(), mask << offset);
}
}
}
#[inline]
pub fn dormant_wake_status(&self, interrupt: Interrupt) -> bool {
let (reg, offset) = self.id.dormant_wake_ints();
let mask = interrupt.mask();
(reg.read().bits() >> offset) & mask == mask
}
#[inline]
pub fn is_dormant_wake_enabled(&self, interrupt: Interrupt) -> bool {
let (reg, offset) = self.id.dormant_wake_inte();
let mask = interrupt.mask();
(reg.read().bits() >> offset) & mask == mask
}
#[inline]
pub fn set_dormant_wake_enabled(&self, interrupt: Interrupt, enabled: bool) {
let (reg, offset) = self.id.dormant_wake_inte();
let mask = interrupt.mask();
unsafe {
if enabled {
write_bitmask_set(reg.as_ptr(), mask << offset);
} else {
write_bitmask_clear(reg.as_ptr(), mask << offset);
}
}
}
#[inline]
pub fn is_dormant_wake_forced(&self, interrupt: Interrupt) -> bool {
let (reg, offset) = self.id.dormant_wake_intf();
let mask = interrupt.mask();
(reg.read().bits() >> offset) & mask == mask
}
#[inline]
pub fn set_dormant_wake_forced(&mut self, interrupt: Interrupt, forced: bool) {
let (reg, offset) = self.id.dormant_wake_intf();
let mask = interrupt.mask();
unsafe {
if forced {
write_bitmask_set(reg.as_ptr(), mask << offset);
} else {
write_bitmask_clear(reg.as_ptr(), mask << offset);
}
}
}
pub fn as_input(&self) -> AsInputPin<'_, I, F, P> {
AsInputPin(self)
}
}
impl<I: PinId, C: SioConfig, P: PullType> Pin<I, FunctionSio<C>, P> {
#[inline]
pub fn is_sync_bypass(&self) -> bool {
let mask = self.id.mask();
self.id.proc_in_by_pass().read().bits() & mask == mask
}
#[inline]
pub fn set_sync_bypass(&mut self, bypass: bool) {
let mask = self.id.mask();
let reg = self.id.proc_in_by_pass();
unsafe {
if bypass {
write_bitmask_set(reg.as_ptr(), mask);
} else {
write_bitmask_clear(reg.as_ptr(), mask);
}
}
}
}
impl<F: func::Function, P: PullType> Pin<DynPinId, F, P> {
pub fn try_into_pin<P2: pin::pin_sealed::TypeLevelPinId>(self) -> Result<Pin<P2, F, P>, Self> {
if P2::ID == self.id {
Ok(Pin {
id: P2::new(),
function: self.function,
pull_type: self.pull_type,
})
} else {
Err(self)
}
}
pub fn try_into_function<F2>(self) -> Result<Pin<DynPinId, F2, P>, Pin<DynPinId, F, P>>
where
F2: func::Function,
{
let prev_function = self.function.as_dyn();
let function = F2::from(prev_function);
let function_as_dyn = function.as_dyn();
use func_sealed::Function;
if function_as_dyn.is_valid(&self.id) {
if function_as_dyn != prev_function.as_dyn() {
pin::set_function(&self.id, function_as_dyn);
}
Ok(Pin {
function,
id: self.id,
pull_type: self.pull_type,
})
} else {
Err(self)
}
}
}
impl<I: PinId, P: PullType> Pin<I, DynFunction, P> {
pub fn try_set_function(&mut self, function: DynFunction) -> Result<(), func::InvalidFunction> {
use func_sealed::Function;
if !function.is_valid(&self.id) {
return Err(func::InvalidFunction);
} else if function != self.function.as_dyn() {
pin::set_function(&self.id, function);
self.function = function;
}
Ok(())
}
pub fn function(&self) -> DynFunction {
use func_sealed::Function;
self.function.as_dyn()
}
}
impl<I: PinId, F: func::Function> Pin<I, F, DynPullType> {
pub fn set_pull_type(&mut self, pull_type: DynPullType) {
if pull_type != self.pull_type {
pin::set_pull_type(&self.id, pull_type);
self.pull_type = pull_type;
}
}
}
pub struct AsInputPin<'a, I: PinId, F: func::Function, P: PullType>(&'a Pin<I, F, P>);
pub type Error = core::convert::Infallible;
impl<I, P> embedded_hal_0_2::digital::v2::OutputPin for Pin<I, FunctionSio<SioOutput>, P>
where
I: PinId,
P: PullType,
{
type Error = Error;
fn set_low(&mut self) -> Result<(), Self::Error> {
self._set_low();
Ok(())
}
fn set_high(&mut self) -> Result<(), Self::Error> {
self._set_high();
Ok(())
}
}
impl<I, P> embedded_hal_0_2::digital::v2::InputPin for Pin<I, FunctionSio<SioOutput>, P>
where
I: PinId,
P: PullType,
{
type Error = Error;
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self._is_high())
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self._is_low())
}
}
impl<I: PinId, F: func::Function, P: PullType> embedded_hal_0_2::digital::v2::InputPin
for AsInputPin<'_, I, F, P>
{
type Error = core::convert::Infallible;
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.0._is_high())
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.0._is_low())
}
}
impl<I, P> embedded_hal_0_2::digital::v2::StatefulOutputPin for Pin<I, FunctionSio<SioOutput>, P>
where
I: PinId,
P: PullType,
{
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(self._is_set_high())
}
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(self._is_set_low())
}
}
impl<I, P> embedded_hal_0_2::digital::v2::ToggleableOutputPin for Pin<I, FunctionSio<SioOutput>, P>
where
I: PinId,
P: PullType,
{
type Error = Error;
fn toggle(&mut self) -> Result<(), Self::Error> {
self._toggle();
Ok(())
}
}
impl<I, P> embedded_hal_0_2::digital::v2::InputPin for Pin<I, FunctionSio<SioInput>, P>
where
I: PinId,
P: PullType,
{
type Error = Error;
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self._is_high())
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self._is_low())
}
}
pub trait DefaultTypeState: crate::typelevel::Sealed {
type Function: Function;
type PullType: PullType;
}
macro_rules! reset_ie {
( Bank0, $pads:ident ) => {
for id in (0..=29) {
$pads.gpio(id).modify(|_, w| w.ie().clear_bit());
}
};
( Qspi, $pads:ident ) => {};
}
macro_rules! gpio {
( $bank:ident:$prefix:ident, [ $(($id:expr, $pull_type:ident, $func:ident)),* ] ) => {
paste::paste!{
#[doc = "Pin bank " [<$bank>] ]
pub mod [<$bank:snake>] {
use $crate::pac::{[<IO_ $bank:upper>],[<PADS_ $bank:upper>]};
use crate::sio::[<SioGpio $bank>];
use super::{Pin, pin, pull, func};
$(pub use super::pin::[<$bank:lower>]::[<$prefix $id>];)*
$(
impl super::DefaultTypeState for [<$prefix $id>] {
type Function = super::[<Function $func>];
type PullType = super::[<Pull $pull_type>];
}
)*
gpio!(struct: $bank $prefix $([<$prefix $id>], $id, $func, $pull_type),*);
impl Pins {
pub fn new(io : [<IO_ $bank:upper>], pads: [<PADS_ $bank:upper>], sio: [<SioGpio $bank>], reset : &mut $crate::pac::RESETS) -> Self {
use $crate::resets::SubsystemReset;
pads.reset_bring_down(reset);
io.reset_bring_down(reset);
{
use $crate::gpio::pin::DynBankId;
let sio = unsafe { &*$crate::pac::SIO::PTR };
if DynBankId::$bank == DynBankId::Bank0 {
unsafe {
sio.gpio_oe().reset();
sio.gpio_out().reset();
sio.gpio_hi_oe_clr().write(|w| {
w.bits(0x0000_FFFF);
w
});
sio.gpio_hi_out_clr().write(|w| {
w.bits(0x0000_FFFF);
w
});
}
} else {
unsafe {
sio.gpio_hi_oe_clr().write(|w| {
w.bits(0xFFF0_0000);
w
});
sio.gpio_hi_out_clr().write(|w| {
w.bits(0xFFF0_0000);
w
});
}
}
}
io.reset_bring_up(reset);
pads.reset_bring_up(reset);
reset_ie!($bank, pads);
gpio!(members: io, pads, sio, $(([<$prefix $id>], $func, $pull_type)),+)
}
}
}
}
};
(struct: $bank:ident $prefix:ident $($PXi:ident, $id:expr, $func:ident, $pull_type:ident),*) => {
paste::paste!{
#[derive(Debug)]
pub struct Pins {
_io: [<IO_ $bank:upper>],
_pads: [<PADS_ $bank:upper>],
_sio: [<SioGpio $bank>],
$(
#[doc = "Pin " [<$PXi>] ]
pub [<$PXi:snake>]: Pin<pin::[<$bank:lower>]::[<$prefix $id>] , func::[<Function $func>], pull::[<Pull $pull_type>]>,
)*
}
}
};
(members: $io:ident, $pads:ident, $sio:ident, $(($PXi:ident, $func:ident, $pull_type:ident)),+) => {
paste::paste!{
Self {
_io: $io,
_pads: $pads,
_sio: $sio,
$(
[<$PXi:snake>]: Pin {
id: [<$PXi>] (()),
function: func::[<Function $func>] (()),
pull_type: pull::[<Pull $pull_type>] (())
},
)+
}
}
};
}
gpio!(
Bank0: Gpio,
[
(0, Down, Null),
(1, Down, Null),
(2, Down, Null),
(3, Down, Null),
(4, Down, Null),
(5, Down, Null),
(6, Down, Null),
(7, Down, Null),
(8, Down, Null),
(9, Down, Null),
(10, Down, Null),
(11, Down, Null),
(12, Down, Null),
(13, Down, Null),
(14, Down, Null),
(15, Down, Null),
(16, Down, Null),
(17, Down, Null),
(18, Down, Null),
(19, Down, Null),
(20, Down, Null),
(21, Down, Null),
(22, Down, Null),
(23, Down, Null),
(24, Down, Null),
(25, Down, Null),
(26, Down, Null),
(27, Down, Null),
(28, Down, Null),
(29, Down, Null),
(30, Down, Null),
(31, Down, Null),
(32, Down, Null),
(33, Down, Null),
(34, Down, Null),
(35, Down, Null),
(36, Down, Null),
(37, Down, Null),
(38, Down, Null),
(39, Down, Null),
(40, Down, Null),
(41, Down, Null),
(42, Down, Null),
(43, Down, Null),
(44, Down, Null),
(45, Down, Null),
(46, Down, Null),
(47, Down, Null)
]
);
gpio!(
Qspi: Qspi,
[
(UsbDp, None, Null),
(UsbDm, None, Null),
(Sclk, Down, Null),
(Ss, Up, Null),
(Sd0, None, Null),
(Sd1, None, Null),
(Sd2, None, Null),
(Sd3, None, Null)
]
);
pub use bank0::Pins;
pub trait AnyPin: Sealed
where
Self: typelevel::Sealed,
Self: typelevel::Is<Type = SpecificPin<Self>>,
{
type Id: PinId;
type Function: func::Function;
type Pull: PullType;
}
impl<I, F, P> Sealed for Pin<I, F, P>
where
I: PinId,
F: func::Function,
P: PullType,
{
}
impl<I, F, P> AnyPin for Pin<I, F, P>
where
I: PinId,
F: func::Function,
P: PullType,
{
type Id = I;
type Function = F;
type Pull = P;
}
pub type SpecificPin<P> = Pin<<P as AnyPin>::Id, <P as AnyPin>::Function, <P as AnyPin>::Pull>;
#[macro_export]
macro_rules! bsp_pins {
(
$(
$( #[$id_cfg:meta] )*
$Id:ident {
$( #[$name_doc:meta] )*
name: $name:ident $(,)?
$(
aliases: {
$(
$( #[$alias_cfg:meta] )*
$Function:ty, $PullType: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::DefaultTypeState>::Function,
<$crate::gpio::bank0::$Id as $crate::gpio::DefaultTypeState>::PullType,
>,
)+
}
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 $Function $PullType $Alias )+ )? );
)+
}
};
( @aliases, $( $( $( #[$attr:meta] )* $Id:ident $Function:ident $PullType:ident $Alias:ident )+ )? ) => {
$crate::paste::paste! {
$(
$(
$( #[$attr] )*
pub type $Alias = $crate::gpio::Pin<
$crate::gpio::bank0::$Id,
$crate::gpio::$Function,
$crate::gpio::$PullType
>;
)+
)?
}
};
}
pub struct InOutPin<T: AnyPin> {
inner: Pin<T::Id, FunctionSioOutput, T::Pull>,
}
impl<T: AnyPin> InOutPin<T> {
pub fn new(inner: T) -> InOutPin<T>
where
T::Id: ValidFunction<FunctionSioOutput>,
{
let mut inner = inner.into();
inner.set_output_enable_override(OutputEnableOverride::Disable);
let inner = inner.into_push_pull_output_in_state(PinState::Low);
Self { inner }
}
}
impl<T> InOutPin<T>
where
T: AnyPin,
T::Id: ValidFunction<T::Function>,
{
pub fn release(self) -> T {
let mut inner = self.inner.reconfigure();
inner.set_output_enable_override(OutputEnableOverride::Normal);
T::from(inner)
}
}
impl<T: AnyPin> embedded_hal_0_2::digital::v2::InputPin for InOutPin<T> {
type Error = Error;
fn is_high(&self) -> Result<bool, Error> {
self.inner.is_high()
}
fn is_low(&self) -> Result<bool, Error> {
self.inner.is_low()
}
}
impl<T: AnyPin> embedded_hal_0_2::digital::v2::OutputPin for InOutPin<T> {
type Error = Error;
fn set_low(&mut self) -> Result<(), Error> {
self.inner
.set_output_enable_override(OutputEnableOverride::Enable);
Ok(())
}
fn set_high(&mut self) -> Result<(), Error> {
self.inner
.set_output_enable_override(OutputEnableOverride::Disable);
Ok(())
}
}
mod eh1 {
use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin};
use super::{
func, AnyPin, AsInputPin, Error, FunctionSio, InOutPin, OutputEnableOverride, Pin, PinId,
PullType, SioConfig, SioInput, SioOutput,
};
impl<I, P, S> ErrorType for Pin<I, FunctionSio<S>, P>
where
I: PinId,
P: PullType,
S: SioConfig,
{
type Error = Error;
}
impl<I, P> OutputPin for Pin<I, FunctionSio<SioOutput>, P>
where
I: PinId,
P: PullType,
{
fn set_low(&mut self) -> Result<(), Self::Error> {
self._set_low();
Ok(())
}
fn set_high(&mut self) -> Result<(), Self::Error> {
self._set_high();
Ok(())
}
}
impl<I, P> StatefulOutputPin for Pin<I, FunctionSio<SioOutput>, P>
where
I: PinId,
P: PullType,
{
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Ok(self._is_set_high())
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(self._is_set_low())
}
fn toggle(&mut self) -> Result<(), Self::Error> {
self._toggle();
Ok(())
}
}
impl<I, P> InputPin for Pin<I, FunctionSio<SioInput>, P>
where
I: PinId,
P: PullType,
{
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(self._is_high())
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(self._is_low())
}
}
impl<I, F, P> ErrorType for AsInputPin<'_, I, F, P>
where
I: PinId,
F: func::Function,
P: PullType,
{
type Error = Error;
}
impl<I: PinId, F: func::Function, P: PullType> InputPin for AsInputPin<'_, I, F, P> {
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.0._is_high())
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(self.0._is_low())
}
}
impl<I> ErrorType for InOutPin<I>
where
I: AnyPin,
{
type Error = Error;
}
impl<I> OutputPin for InOutPin<I>
where
I: AnyPin,
{
fn set_low(&mut self) -> Result<(), Self::Error> {
self.inner
.set_output_enable_override(OutputEnableOverride::Enable);
Ok(())
}
fn set_high(&mut self) -> Result<(), Self::Error> {
self.inner
.set_output_enable_override(OutputEnableOverride::Disable);
Ok(())
}
}
impl<I> InputPin for InOutPin<I>
where
I: AnyPin,
{
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.inner._is_high())
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(self.inner._is_low())
}
}
}