use core::{convert::Infallible, marker::PhantomData};
pub struct Disconnected;
pub struct Input<MODE> {
_mode: PhantomData<MODE>,
}
pub struct Floating;
pub struct PullDown;
pub struct PullUp;
pub struct Output<MODE> {
_mode: PhantomData<MODE>,
}
pub struct PushPull;
pub struct OpenDrain;
pub struct OpenDrainIO;
#[derive(Debug, Eq, PartialEq)]
pub enum Level {
Low,
High,
}
#[derive(Debug, Eq, PartialEq)]
pub enum Port {
Port0,
#[cfg(any(feature = "5340-app"))]
Port0Secure,
#[cfg(any(feature = "52833", feature = "52840", feature = "5340-net"))]
Port1,
}
pub struct Pin<MODE> {
pin_port: u8,
_mode: PhantomData<MODE>,
}
#[cfg(feature = "51")]
use crate::pac::{gpio, GPIO as P0};
#[cfg(any(feature = "5340-app", feature = "5340-net", feature = "9160"))]
use crate::pac::{p0_ns as gpio, P0_NS as P0};
#[cfg(feature = "5340-app")]
use crate::pac::P0_S;
#[cfg(not(any(
feature = "9160",
feature = "5340-app",
feature = "5340-net",
feature = "51"
)))]
use crate::pac::{p0 as gpio, P0};
#[cfg(any(feature = "52833", feature = "52840"))]
use crate::pac::P1;
#[cfg(feature = "5340-net")]
use crate::pac::P1_NS as P1;
use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin};
impl<MODE> Pin<MODE> {
fn new(port: Port, pin: u8) -> Self {
let port_bits = match port {
Port::Port0 => 0x00,
#[cfg(any(feature = "5340-app"))]
Port::Port0Secure => 0x20,
#[cfg(any(feature = "52833", feature = "52840", feature = "5340-net"))]
Port::Port1 => 0x20,
};
Self {
pin_port: pin | port_bits,
_mode: PhantomData,
}
}
pub unsafe fn from_psel_bits(psel_bits: u32) -> Self {
Self {
pin_port: psel_bits as u8,
_mode: PhantomData,
}
}
#[inline]
pub fn pin(&self) -> u8 {
#[cfg(any(
feature = "52833",
feature = "52840",
feature = "5340-app",
feature = "5340-net"
))]
{
self.pin_port & 0x1f
}
#[cfg(not(any(
feature = "52833",
feature = "52840",
feature = "5340-app",
feature = "5340-net"
)))]
{
self.pin_port
}
}
#[inline]
pub fn port(&self) -> Port {
#[cfg(any(feature = "52833", feature = "52840", feature = "5340-net"))]
{
if self.pin_port & 0x20 == 0 {
Port::Port0
} else {
Port::Port1
}
}
#[cfg(any(feature = "5340-app"))]
{
if self.pin_port & 0x20 == 0 {
Port::Port0
} else {
Port::Port0Secure
}
}
#[cfg(not(any(
feature = "52833",
feature = "52840",
feature = "5340-app",
feature = "5340-net"
)))]
{
Port::Port0
}
}
#[inline]
pub fn psel_bits(&self) -> u32 {
self.pin_port as u32
}
fn block(&self) -> &gpio::RegisterBlock {
let ptr = match self.port() {
Port::Port0 => P0::ptr(),
#[cfg(feature = "5340-app")]
Port::Port0Secure => P0_S::ptr(),
#[cfg(any(feature = "52833", feature = "52840", feature = "5340-net"))]
Port::Port1 => P1::ptr(),
};
unsafe { &*ptr }
}
pub(crate) fn conf(&self) -> &gpio::PIN_CNF {
&self.block().pin_cnf[self.pin() as usize]
}
pub fn into_floating_input(self) -> Pin<Input<Floating>> {
self.conf().write(|w| {
w.dir().input();
w.input().connect();
w.pull().disabled();
w.drive().s0s1();
w.sense().disabled();
w
});
Pin {
_mode: PhantomData,
pin_port: self.pin_port,
}
}
pub fn into_pullup_input(self) -> Pin<Input<PullUp>> {
self.conf().write(|w| {
w.dir().input();
w.input().connect();
w.pull().pullup();
w.drive().s0s1();
w.sense().disabled();
w
});
Pin {
_mode: PhantomData,
pin_port: self.pin_port,
}
}
pub fn into_pulldown_input(self) -> Pin<Input<PullDown>> {
self.conf().write(|w| {
w.dir().input();
w.input().connect();
w.pull().pulldown();
w.drive().s0s1();
w.sense().disabled();
w
});
Pin {
_mode: PhantomData,
pin_port: self.pin_port,
}
}
pub fn into_push_pull_output_drive(
self,
initial_output: Level,
drive: DriveConfig,
) -> Pin<Output<PushPull>> {
let mut pin = Pin {
_mode: PhantomData,
pin_port: self.pin_port,
};
match initial_output {
Level::Low => pin.set_low().unwrap(),
Level::High => pin.set_high().unwrap(),
}
self.conf().write(|w| {
w.dir().output();
w.input().connect(); w.pull().disabled();
match drive {
DriveConfig::Standard0Standard1 => w.drive().s0s1(),
DriveConfig::Standard0HighDrive1 => w.drive().s0h1(),
DriveConfig::HighDrive0Standard1 => w.drive().h0s1(),
DriveConfig::HighDrive0HighDrive1 => w.drive().h0h1(),
};
w.sense().disabled();
w
});
pin
}
pub fn into_push_pull_output(self, initial_output: Level) -> Pin<Output<PushPull>> {
self.into_push_pull_output_drive(initial_output, DriveConfig::Standard0Standard1)
}
pub fn into_open_drain_output(
self,
config: OpenDrainConfig,
initial_output: Level,
) -> Pin<Output<OpenDrain>> {
let mut pin = Pin {
_mode: PhantomData,
pin_port: self.pin_port,
};
match initial_output {
Level::Low => pin.set_low().unwrap(),
Level::High => pin.set_high().unwrap(),
}
self.conf().write(|w| {
w.dir().output();
w.input().disconnect();
w.pull().disabled();
w.drive().variant(config.variant());
w.sense().disabled();
w
});
pin
}
pub fn into_open_drain_input_output(
self,
config: OpenDrainConfig,
initial_output: Level,
) -> Pin<Output<OpenDrainIO>> {
let mut pin = Pin {
_mode: PhantomData,
pin_port: self.pin_port,
};
match initial_output {
Level::Low => pin.set_low().unwrap(),
Level::High => pin.set_high().unwrap(),
}
self.conf().write(|w| {
w.dir().output();
w.input().connect();
w.pull().disabled();
w.drive().variant(config.variant());
w.sense().disabled();
w
});
pin
}
pub fn into_disconnected(self) -> Pin<Disconnected> {
self.conf().reset();
Pin {
_mode: PhantomData,
pin_port: self.pin_port,
}
}
}
impl<MODE> ErrorType for Pin<MODE> {
type Error = Infallible;
}
impl<MODE> InputPin for Pin<Input<MODE>> {
fn is_high(&mut self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v)
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(self.block().in_.read().bits() & (1 << self.pin()) == 0)
}
}
impl InputPin for Pin<Output<OpenDrainIO>> {
fn is_high(&mut self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v)
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(self.block().in_.read().bits() & (1 << self.pin()) == 0)
}
}
impl<MODE> OutputPin for Pin<Output<MODE>> {
fn set_high(&mut self) -> Result<(), Self::Error> {
unsafe {
self.block().outset.write(|w| w.bits(1u32 << self.pin()));
}
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
unsafe {
self.block().outclr.write(|w| w.bits(1u32 << self.pin()));
}
Ok(())
}
}
impl<MODE> StatefulOutputPin for Pin<Output<MODE>> {
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
self.is_set_low().map(|v| !v)
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(self.block().out.read().bits() & (1 << self.pin()) == 0)
}
}
#[cfg(feature = "embedded-hal-02")]
impl<MODE> embedded_hal_02::digital::v2::InputPin for Pin<Input<MODE>> {
type Error = void::Void;
fn is_high(&self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v)
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.block().in_.read().bits() & (1 << self.pin()) == 0)
}
}
#[cfg(feature = "embedded-hal-02")]
impl embedded_hal_02::digital::v2::InputPin for Pin<Output<OpenDrainIO>> {
type Error = void::Void;
fn is_high(&self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v)
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.block().in_.read().bits() & (1 << self.pin()) == 0)
}
}
#[cfg(feature = "embedded-hal-02")]
impl<MODE> embedded_hal_02::digital::v2::OutputPin for Pin<Output<MODE>> {
type Error = void::Void;
fn set_high(&mut self) -> Result<(), Self::Error> {
unsafe {
self.block().outset.write(|w| w.bits(1u32 << self.pin()));
}
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
unsafe {
self.block().outclr.write(|w| w.bits(1u32 << self.pin()));
}
Ok(())
}
}
#[cfg(feature = "embedded-hal-02")]
impl<MODE> embedded_hal_02::digital::v2::StatefulOutputPin for Pin<Output<MODE>> {
fn is_set_high(&self) -> Result<bool, Self::Error> {
self.is_set_low().map(|v| !v)
}
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(self.block().out.read().bits() & (1 << self.pin()) == 0)
}
}
pub enum OpenDrainConfig {
Disconnect0Standard1,
Disconnect0HighDrive1,
Standard0Disconnect1,
HighDrive0Disconnect1,
}
pub enum DriveConfig {
Standard0Standard1,
Standard0HighDrive1,
HighDrive0Standard1,
HighDrive0HighDrive1,
}
#[cfg(feature = "51")]
use crate::pac::gpio::pin_cnf;
#[cfg(any(feature = "5340-app", feature = "5340-net", feature = "9160"))]
use crate::pac::p0_ns::pin_cnf;
#[cfg(not(any(
feature = "9160",
feature = "5340-app",
feature = "5340-net",
feature = "51"
)))]
use crate::pac::p0::pin_cnf;
impl OpenDrainConfig {
fn variant(self) -> pin_cnf::DRIVE_A {
use self::OpenDrainConfig::*;
match self {
Disconnect0Standard1 => pin_cnf::DRIVE_A::D0S1,
Disconnect0HighDrive1 => pin_cnf::DRIVE_A::D0H1,
Standard0Disconnect1 => pin_cnf::DRIVE_A::S0D1,
HighDrive0Disconnect1 => pin_cnf::DRIVE_A::H0D1,
}
}
}
macro_rules! gpio {
(
$PX:ident, $pxsvd:ident, $px:ident, $port_value:expr, [
$($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+
]
) => {
pub mod $px {
use super::{
Pin,
Port,
Floating,
Disconnected,
DriveConfig,
Input,
Level,
OpenDrain,
OpenDrainConfig,
Output,
PullDown,
PullUp,
PushPull,
OpenDrainIO,
PhantomData,
$PX
};
use core::convert::Infallible;
use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin};
pub struct Parts {
$(
pub $pxi: $PXi<$MODE>,
)+
}
impl Parts {
pub fn new(_gpio: $PX) -> Self {
Self {
$(
$pxi: $PXi {
_mode: PhantomData,
},
)+
}
}
}
$(
pub struct $PXi<MODE> {
_mode: PhantomData<MODE>,
}
impl<MODE> $PXi<MODE> {
pub fn into_floating_input(self) -> $PXi<Input<Floating>> {
unsafe { &(*$PX::ptr()).pin_cnf[$i] }.write(|w| {
w.dir().input();
w.input().connect();
w.pull().disabled();
w.drive().s0s1();
w.sense().disabled();
w
});
$PXi {
_mode: PhantomData,
}
}
pub fn into_pulldown_input(self) -> $PXi<Input<PullDown>> {
unsafe { &(*$PX::ptr()).pin_cnf[$i] }.write(|w| {
w.dir().input();
w.input().connect();
w.pull().pulldown();
w.drive().s0s1();
w.sense().disabled();
w
});
$PXi {
_mode: PhantomData,
}
}
pub fn into_pullup_input(self) -> $PXi<Input<PullUp>> {
unsafe { &(*$PX::ptr()).pin_cnf[$i] }.write(|w| {
w.dir().input();
w.input().connect();
w.pull().pullup();
w.drive().s0s1();
w.sense().disabled();
w
});
$PXi {
_mode: PhantomData,
}
}
pub fn into_push_pull_output_drive(self, initial_output: Level, drive: DriveConfig)
-> $PXi<Output<PushPull>>
{
let mut pin = $PXi {
_mode: PhantomData,
};
match initial_output {
Level::Low => pin.set_low().unwrap(),
Level::High => pin.set_high().unwrap(),
}
unsafe { &(*$PX::ptr()).pin_cnf[$i] }.write(|w| {
w.dir().output();
w.input().disconnect();
w.pull().disabled();
match drive {
DriveConfig::Standard0Standard1 => w.drive().s0s1(),
DriveConfig::Standard0HighDrive1 => w.drive().s0h1(),
DriveConfig::HighDrive0Standard1 => w.drive().h0s1(),
DriveConfig::HighDrive0HighDrive1 => w.drive().h0h1(),
};
w.sense().disabled();
w
});
pin
}
pub fn into_push_pull_output(self, initial_output: Level)
-> $PXi<Output<PushPull>>
{
self.into_push_pull_output_drive(initial_output, DriveConfig::Standard0Standard1)
}
pub fn into_open_drain_output(self,
config: OpenDrainConfig,
initial_output: Level,
)
-> $PXi<Output<OpenDrain>>
{
let mut pin = $PXi {
_mode: PhantomData,
};
match initial_output {
Level::Low => pin.set_low().unwrap(),
Level::High => pin.set_high().unwrap(),
}
let pin_cnf = unsafe {
&(*$PX::ptr()).pin_cnf[$i]
};
pin_cnf.write(|w| {
w.dir().output();
w.input().disconnect();
w.pull().disabled();
w.drive().variant(config.variant());
w.sense().disabled();
w
});
pin
}
pub fn into_open_drain_input_output(self,
config: OpenDrainConfig,
initial_output: Level,
)
-> $PXi<Output<OpenDrainIO>>
{
let mut pin = $PXi {
_mode: PhantomData,
};
match initial_output {
Level::Low => pin.set_low().unwrap(),
Level::High => pin.set_high().unwrap(),
}
let pin_cnf = unsafe {
&(*$PX::ptr()).pin_cnf[$i]
};
pin_cnf.write(|w| {
w.dir().output();
w.input().connect();
w.pull().disabled();
w.drive().variant(config.variant());
w.sense().disabled();
w
});
pin
}
pub fn into_disconnected(self) -> $PXi<Disconnected> {
unsafe { &(*$PX::ptr()).pin_cnf[$i] }.reset();
$PXi {
_mode: PhantomData,
}
}
pub fn degrade(self) -> Pin<MODE> {
Pin::new($port_value, $i)
}
}
impl<MODE> ErrorType for $PXi<MODE> {
type Error = Infallible;
}
impl<MODE> InputPin for $PXi<Input<MODE>> {
fn is_high(&mut self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v)
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(unsafe { ((*$PX::ptr()).in_.read().bits() & (1 << $i)) == 0 })
}
}
impl InputPin for $PXi<Output<OpenDrainIO>> {
fn is_high(&mut self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v)
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(unsafe { ((*$PX::ptr()).in_.read().bits() & (1 << $i)) == 0 })
}
}
impl<MODE> OutputPin for $PXi<Output<MODE>> {
fn set_high(&mut self) -> Result<(), Self::Error> {
unsafe { (*$PX::ptr()).outset.write(|w| w.bits(1u32 << $i)); }
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
unsafe { (*$PX::ptr()).outclr.write(|w| w.bits(1u32 << $i)); }
Ok(())
}
}
impl<MODE> StatefulOutputPin for $PXi<Output<MODE>> {
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
self.is_set_low().map(|v| !v)
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(unsafe { ((*$PX::ptr()).out.read().bits() & (1 << $i)) == 0 })
}
}
#[cfg(feature = "embedded-hal-02")]
impl<MODE> embedded_hal_02::digital::v2::InputPin for $PXi<Input<MODE>> {
type Error = void::Void;
fn is_high(&self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v)
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(unsafe { ((*$PX::ptr()).in_.read().bits() & (1 << $i)) == 0 })
}
}
#[cfg(feature = "embedded-hal-02")]
impl embedded_hal_02::digital::v2::InputPin for $PXi<Output<OpenDrainIO>> {
type Error = void::Void;
fn is_high(&self) -> Result<bool, Self::Error> {
self.is_low().map(|v| !v)
}
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(unsafe { ((*$PX::ptr()).in_.read().bits() & (1 << $i)) == 0 })
}
}
impl<MODE> From<$PXi<MODE>> for Pin<MODE> {
fn from(value: $PXi<MODE>) -> Self {
value.degrade()
}
}
#[cfg(feature = "embedded-hal-02")]
impl<MODE> embedded_hal_02::digital::v2::OutputPin for $PXi<Output<MODE>> {
type Error = void::Void;
fn set_high(&mut self) -> Result<(), Self::Error> {
unsafe { (*$PX::ptr()).outset.write(|w| w.bits(1u32 << $i)); }
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
unsafe { (*$PX::ptr()).outclr.write(|w| w.bits(1u32 << $i)); }
Ok(())
}
}
#[cfg(feature = "embedded-hal-02")]
impl<MODE> embedded_hal_02::digital::v2::StatefulOutputPin for $PXi<Output<MODE>> {
fn is_set_high(&self) -> Result<bool, Self::Error> {
self.is_set_low().map(|v| !v)
}
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(unsafe { ((*$PX::ptr()).out.read().bits() & (1 << $i)) == 0 })
}
}
)+
}
}
}
gpio!(P0, p0, p0, Port::Port0, [
P0_00: (p0_00, 0, Disconnected),
P0_01: (p0_01, 1, Disconnected),
P0_02: (p0_02, 2, Disconnected),
P0_03: (p0_03, 3, Disconnected),
P0_04: (p0_04, 4, Disconnected),
P0_05: (p0_05, 5, Disconnected),
P0_06: (p0_06, 6, Disconnected),
P0_07: (p0_07, 7, Disconnected),
P0_08: (p0_08, 8, Disconnected),
P0_09: (p0_09, 9, Disconnected),
P0_10: (p0_10, 10, Disconnected),
P0_11: (p0_11, 11, Disconnected),
P0_12: (p0_12, 12, Disconnected),
P0_13: (p0_13, 13, Disconnected),
P0_14: (p0_14, 14, Disconnected),
P0_15: (p0_15, 15, Disconnected),
P0_16: (p0_16, 16, Disconnected),
P0_17: (p0_17, 17, Disconnected),
P0_18: (p0_18, 18, Disconnected),
P0_19: (p0_19, 19, Disconnected),
P0_20: (p0_20, 20, Disconnected),
P0_21: (p0_21, 21, Disconnected),
P0_22: (p0_22, 22, Disconnected),
P0_23: (p0_23, 23, Disconnected),
P0_24: (p0_24, 24, Disconnected),
P0_25: (p0_25, 25, Disconnected),
P0_26: (p0_26, 26, Disconnected),
P0_27: (p0_27, 27, Disconnected),
P0_28: (p0_28, 28, Disconnected),
P0_29: (p0_29, 29, Disconnected),
P0_30: (p0_30, 30, Disconnected),
P0_31: (p0_31, 31, Disconnected),
]);
#[cfg(any(feature = "52833", feature = "52840", feature = "5340-net"))]
gpio!(P1, p0, p1, Port::Port1, [
P1_00: (p1_00, 0, Disconnected),
P1_01: (p1_01, 1, Disconnected),
P1_02: (p1_02, 2, Disconnected),
P1_03: (p1_03, 3, Disconnected),
P1_04: (p1_04, 4, Disconnected),
P1_05: (p1_05, 5, Disconnected),
P1_06: (p1_06, 6, Disconnected),
P1_07: (p1_07, 7, Disconnected),
P1_08: (p1_08, 8, Disconnected),
P1_09: (p1_09, 9, Disconnected),
P1_10: (p1_10, 10, Disconnected),
P1_11: (p1_11, 11, Disconnected),
P1_12: (p1_12, 12, Disconnected),
P1_13: (p1_13, 13, Disconnected),
P1_14: (p1_14, 14, Disconnected),
P1_15: (p1_15, 15, Disconnected),
]);
#[cfg(feature = "5340-app")]
gpio!(P0_S, p0, p0_s, Port::Port0Secure, [
P0_00: (p0_00, 0, Disconnected),
P0_01: (p0_01, 1, Disconnected),
P0_02: (p0_02, 2, Disconnected),
P0_03: (p0_03, 3, Disconnected),
P0_04: (p0_04, 4, Disconnected),
P0_05: (p0_05, 5, Disconnected),
P0_06: (p0_06, 6, Disconnected),
P0_07: (p0_07, 7, Disconnected),
P0_08: (p0_08, 8, Disconnected),
P0_09: (p0_09, 9, Disconnected),
P0_10: (p0_10, 10, Disconnected),
P0_11: (p0_11, 11, Disconnected),
P0_12: (p0_12, 12, Disconnected),
P0_13: (p0_13, 13, Disconnected),
P0_14: (p0_14, 14, Disconnected),
P0_15: (p0_15, 15, Disconnected),
P0_16: (p0_16, 16, Disconnected),
P0_17: (p0_17, 17, Disconnected),
P0_18: (p0_18, 18, Disconnected),
P0_19: (p0_19, 19, Disconnected),
P0_20: (p0_20, 20, Disconnected),
P0_21: (p0_21, 21, Disconnected),
P0_22: (p0_22, 22, Disconnected),
P0_23: (p0_23, 23, Disconnected),
P0_24: (p0_24, 24, Disconnected),
P0_25: (p0_25, 25, Disconnected),
P0_26: (p0_26, 26, Disconnected),
P0_27: (p0_27, 27, Disconnected),
P0_28: (p0_28, 28, Disconnected),
P0_29: (p0_29, 29, Disconnected),
P0_30: (p0_30, 30, Disconnected),
P0_31: (p0_31, 31, Disconnected),
]);