use core::convert::Infallible;
use core::marker::PhantomData;
use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin};
use crate::pac;
use crate::rcu::{Enable, Rcu, Reset};
enum Ctl {
Input = 0b00,
Output = 0b01,
Af = 0b10,
Analog = 0b11,
}
enum Omode {
PushPull = 0b0,
OpenDrain = 0b1,
}
pub struct Input;
pub struct PushPull;
pub struct OpenDrain;
pub struct Output<OTYPE> {
_otype: PhantomData<OTYPE>,
}
pub struct Analog;
pub struct Alternate<const AF: u8, OTYPE = PushPull> {
_otype: PhantomData<OTYPE>,
}
pub struct Debugger;
pub struct Locked<MODE> {
_mode: PhantomData<MODE>,
}
pub struct Pin<const P: char, const N: u8, MODE> {
_mode: PhantomData<MODE>,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[allow(missing_docs)]
pub enum Port {
A,
B,
#[cfg(pads_ge_48)]
C,
F,
}
impl Port {
#[inline]
const fn from_char(port: char) -> Self {
match port {
'A' => Port::A,
'B' => Port::B,
#[cfg(pads_ge_48)]
'C' => Port::C,
'F' => Port::F,
_ => unreachable!(),
}
}
}
pub struct ErasedPin<MODE> {
port: Port,
number: u8,
_mode: PhantomData<MODE>,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Pull {
Floating = 0b00,
Up = 0b01,
Down = 0b10,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[allow(missing_docs)]
pub enum Speed {
Mhz2 = 0b00,
Mhz10 = 0b01,
Mhz50 = 0b11,
}
pub trait ValidAf<const AF: u8> {}
macro_rules! pin_af {
() => {};
( #[$cfg:meta] $p:literal $n:literal => [ $($af:literal: $fun:literal),* $(,)? ] $(, $($rest:tt)*)? ) => {
$(
#[$cfg]
#[doc = concat!("`AF", stringify!($af), "` — ", $fun, ".")]
impl<MODE> ValidAf<$af> for Pin<$p, $n, MODE> {}
)*
$( pin_af! { $($rest)* } )?
};
( $p:literal $n:literal => [ $($af:literal: $fun:literal),* $(,)? ] $(, $($rest:tt)*)? ) => {
$(
#[doc = concat!("`AF", stringify!($af), "` — ", $fun, ".")]
impl<MODE> ValidAf<$af> for Pin<$p, $n, MODE> {}
)*
$( pin_af! { $($rest)* } )?
};
}
pin_af! {
'A' 0 => [1: "USART0_CTS on x4, USART1_CTS on x6/x8", 7: "CMP_OUT"],
'A' 1 => [0: "EVENTOUT", 1: "USART0_RTS/DE on x4, USART1_RTS/DE on x6/x8"],
'A' 2 => [1: "USART0_TX on x4, USART1_TX on x6/x8"],
'A' 3 => [1: "USART0_RX on x4, USART1_RX on x6/x8"],
'A' 4 => [0: "SPI0_NSS/I2S0_WS", 1: "USART0_CK on x4, USART1_CK on x6/x8", 4: "TIMER13_CH0"],
'A' 5 => [0: "SPI0_SCK/I2S0_CK"],
'A' 6 => [0: "SPI0_MISO", 1: "TIMER2_CH0", 2: "TIMER0_BRKIN", 5: "TIMER15_CH0", 6: "EVENTOUT", 7: "CMP_OUT"],
'A' 7 => [0: "SPI0_MOSI", 1: "TIMER2_CH1", 2: "TIMER0_CH0_ON", 4: "TIMER13_CH0", 5: "TIMER16_CH0", 6: "EVENTOUT"],
#[cfg(pads_ge_24)]
'A' 8 => [0: "CK_OUT", 1: "USART0_CK", 2: "TIMER0_CH0", 3: "EVENTOUT"],
'A' 9 => [1: "USART0_TX", 2: "TIMER0_CH1", 4: "I2C0_SCL", 5: "CK_OUT"],
'A' 10 => [0: "TIMER16_BRKIN", 1: "USART0_RX", 2: "TIMER0_CH2", 4: "I2C0_SDA"],
#[cfg(pads_ge_lqfp32)]
'A' 11 => [0: "EVENTOUT", 1: "USART0_CTS", 2: "TIMER0_CH3", 4: "I2C0_SMBA", 7: "CMP_OUT"],
#[cfg(pads_ge_lqfp32)]
'A' 12 => [0: "EVENTOUT", 1: "USART0_RTS/DE", 2: "TIMER0_ETI", 4: "I2C0_TXFRAME"],
'A' 13 => [0: "SWDIO", 1: "IFRP_OUT"],
'A' 14 => [0: "SWCLK", 1: "USART0_TX on x4, USART1_TX on x6/x8"],
#[cfg(pads_ge_28)]
'A' 15 => [0: "SPI0_NSS/I2S0_WS", 1: "USART0_RX on x4, USART1_RX on x6/x8", 3: "EVENTOUT"],
#[cfg(pads_ge_24)]
'B' 0 => [0: "EVENTOUT", 1: "TIMER2_CH2", 2: "TIMER0_CH1_ON"],
'B' 1 => [1: "TIMER2_CH3", 2: "TIMER13_CH0", 3: "TIMER0_CH2_ON"],
#[cfg(pads_ge_qfn32)]
'B' 2 => [1: "TIMER2_ETI"],
#[cfg(pads_ge_28)]
'B' 3 => [0: "SPI0_SCK/I2S0_CK", 1: "EVENTOUT"],
#[cfg(pads_ge_28)]
'B' 4 => [0: "SPI0_MISO", 1: "TIMER2_CH0", 2: "EVENTOUT", 4: "I2C0_TXFRAME", 6: "TIMER16_BRKIN"],
#[cfg(pads_ge_28)]
'B' 5 => [0: "SPI0_MOSI", 1: "TIMER2_CH1", 2: "I2C0_SMBA", 3: "TIMER15_BRKIN"],
#[cfg(pads_ge_24)]
'B' 6 => [0: "USART0_TX", 1: "I2C0_SCL", 2: "TIMER15_CH0_ON"],
#[cfg(pads_ge_24)]
'B' 7 => [0: "USART0_RX", 1: "I2C0_SDA", 2: "TIMER16_CH0_ON"],
#[cfg(pads_ge_qfn32)]
'B' 8 => [1: "I2C0_SCL", 2: "TIMER15_CH0"],
#[cfg(pads_ge_48)]
'B' 9 => [0: "IFRP_OUT", 1: "I2C0_SDA", 2: "TIMER16_CH0", 3: "EVENTOUT", 5: "I2S0_MCK"],
#[cfg(pads_ge_48)]
'B' 11 => [0: "EVENTOUT"],
#[cfg(pads_ge_48)]
'B' 12 => [1: "EVENTOUT", 2: "TIMER0_BRKIN"],
#[cfg(pads_ge_48)]
'B' 13 => [2: "TIMER0_CH0_ON"],
#[cfg(pads_ge_48)]
'B' 14 => [2: "TIMER0_CH1_ON"],
#[cfg(pads_ge_48)]
'B' 15 => [2: "TIMER0_CH2_ON"],
'F' 0 => [1: "I2C0_SDA"],
'F' 1 => [1: "I2C0_SCL"],
}
#[cfg(chip_x4)]
pin_af! {
#[cfg(pads_ge_48)]
'B' 10 => [1: "I2C0_SCL"],
#[cfg(pads_ge_48)]
'B' 11 => [1: "I2C0_SDA"],
#[cfg(pads_ge_48)]
'B' 12 => [0: "SPI0_NSS"],
#[cfg(pads_ge_48)]
'B' 13 => [0: "SPI0_SCK"],
#[cfg(pads_ge_48)]
'B' 14 => [0: "SPI0_MISO"],
#[cfg(pads_ge_48)]
'B' 15 => [0: "SPI0_MOSI"],
#[cfg(pads_ge_48)]
'F' 6 => [0: "I2C0_SCL"],
#[cfg(pads_ge_48)]
'F' 7 => [0: "I2C0_SDA"],
}
#[cfg(any(chip_x6, chip_x8))]
pin_af! {
#[cfg(pads_ge_24)]
'A' 8 => [4: "USART1_TX"],
#[cfg(pads_ge_24)]
'B' 0 => [4: "USART1_RX"],
}
#[cfg(chip_x8)]
pin_af! {
'A' 0 => [4: "I2C1_SCL"],
'A' 1 => [4: "I2C1_SDA", 5: "TIMER14_CH0_ON"],
'A' 2 => [0: "TIMER14_CH0"],
'A' 3 => [0: "TIMER14_CH1"],
'A' 4 => [6: "SPI1_NSS"],
'A' 9 => [0: "TIMER14_BRKIN"],
#[cfg(pads_ge_lqfp32)]
'A' 11 => [5: "I2C1_SCL", 6: "SPI1_IO2"],
#[cfg(pads_ge_lqfp32)]
'A' 12 => [5: "I2C1_SDA", 6: "SPI1_IO3"],
'A' 13 => [6: "SPI1_MISO"],
'A' 14 => [6: "SPI1_MOSI"],
#[cfg(pads_ge_28)]
'A' 15 => [6: "SPI1_NSS"],
'B' 1 => [6: "SPI1_SCK"],
#[cfg(pads_ge_48)]
'B' 9 => [7: "SPI1_NSS"],
#[cfg(pads_ge_48)]
'B' 10 => [1: "I2C1_SCL", 6: "SPI1_IO2", 7: "SPI1_SCK"],
#[cfg(pads_ge_48)]
'B' 11 => [1: "I2C1_SDA", 6: "SPI1_IO3"],
#[cfg(pads_ge_48)]
'B' 12 => [0: "SPI1_NSS", 4: "I2C1_SMBA"],
#[cfg(pads_ge_48)]
'B' 13 => [0: "SPI1_SCK", 1: "I2C1_TXFRAME", 5: "I2C1_SCL"],
#[cfg(pads_ge_48)]
'B' 14 => [0: "SPI1_MISO", 1: "TIMER14_CH0", 5: "I2C1_SDA"],
#[cfg(pads_ge_48)]
'B' 15 => [0: "SPI1_MOSI", 1: "TIMER14_CH1", 3: "TIMER14_CH0_ON"],
#[cfg(pads_ge_48)]
'F' 6 => [0: "I2C1_SCL"],
#[cfg(pads_ge_48)]
'F' 7 => [0: "I2C1_SDA"],
}
pub trait Active {}
impl Active for Input {}
impl Active for Analog {}
impl<const AF: u8, OTYPE> Active for Alternate<AF, OTYPE> {}
impl<OTYPE> Active for Output<OTYPE> {}
pub trait HasLock {}
impl<const N: u8, MODE> HasLock for Pin<'A', N, MODE> {}
impl<const N: u8, MODE> HasLock for Pin<'B', N, MODE> {}
impl<const P: char, const N: u8> Pin<P, N, Debugger> {
pub fn activate_into_input(mut self) -> Pin<P, N, Input> {
self.set_mode(Ctl::Input);
Pin { _mode: PhantomData }
}
pub fn activate(self) -> Pin<P, N, Input> {
self.activate_into_input()
}
pub fn activate_into_push_pull_output(mut self) -> Pin<P, N, Output<PushPull>> {
self.set_mode(Ctl::Output);
self.set_omode(Omode::PushPull);
Pin { _mode: PhantomData }
}
pub fn activate_into_open_drain_output(mut self) -> Pin<P, N, Output<OpenDrain>> {
self.set_mode(Ctl::Output);
self.set_omode(Omode::OpenDrain);
Pin { _mode: PhantomData }
}
pub fn activate_into_output(self) -> Pin<P, N, Output<PushPull>> {
self.activate_into_push_pull_output()
}
pub fn activate_into_analog(mut self) -> Pin<P, N, Analog> {
self.set_mode(Ctl::Analog);
Pin { _mode: PhantomData }
}
pub fn activate_into_alternate<const AF: u8>(mut self) -> Pin<P, N, Alternate<AF>>
where
Self: ValidAf<AF>,
{
self.set_alternate(AF as u32, Omode::PushPull);
Pin { _mode: PhantomData }
}
pub fn activate_into_alternate_open_drain<const AF: u8>(
mut self,
) -> Pin<P, N, Alternate<AF, OpenDrain>>
where
Self: ValidAf<AF>,
{
self.set_alternate(AF as u32, Omode::OpenDrain);
Pin { _mode: PhantomData }
}
}
#[inline]
const fn reg(port: Port) -> &'static pac::gpioa::RegisterBlock {
let ptr = match port {
Port::A => pac::Gpioa::ptr(),
Port::B => pac::Gpiob::ptr().cast(),
#[cfg(pads_ge_48)]
Port::C => pac::Gpioc::ptr().cast(),
Port::F => pac::Gpiof::ptr().cast(),
};
unsafe { &*ptr }
}
#[inline]
fn read_pin(port: Port, number: u8) -> bool {
let bits = reg(port).istat().read().bits();
((bits >> number) & 0b1) == 0b1
}
#[inline]
fn read_octl(port: Port, number: u8) -> bool {
let bits = reg(port).octl().read().bits();
((bits >> number) & 0b1) == 0b1
}
#[inline]
fn set_bop(port: Port, number: u8) {
reg(port).bop().write(|w| unsafe { w.bits(1 << number) });
}
#[inline]
fn set_bc(port: Port, number: u8) {
reg(port).bc().write(|w| unsafe { w.bits(1 << number) });
}
#[inline]
fn set_tg(port: Port, number: u8) {
reg(port).tg().write(|w| unsafe { w.bits(1 << number) });
}
#[allow(clippy::unused_self)]
impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
fn reg(&self) -> &'static pac::gpioa::RegisterBlock {
reg(Port::from_char(P))
}
fn read_pin(&self) -> bool {
read_pin(Port::from_char(P), N)
}
fn read_octl(&self) -> bool {
read_octl(Port::from_char(P), N)
}
fn set_bop(&mut self) {
set_bop(Port::from_char(P), N);
}
fn set_bc(&mut self) {
set_bc(Port::from_char(P), N);
}
fn set_tg(&mut self) {
set_tg(Port::from_char(P), N);
}
}
impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
fn set_mode(&mut self, mode: Ctl) {
let offset = N * 2;
self.reg().ctl().modify(|r, w| unsafe {
w.bits((r.bits() & !(0b11 << offset)) | ((mode as u32) << offset))
});
}
fn set_af(&mut self, af: u32) {
let is_afsel0 = N < 8;
let offset = (N % 8) * 4;
if is_afsel0 {
self.reg().afsel0().modify(|r, w| unsafe {
w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
});
} else {
self.reg().afsel1().modify(|r, w| unsafe {
w.bits((r.bits() & !(0b1111 << offset)) | (af << offset))
});
}
}
fn set_pud(&mut self, bits: u32) {
let offset = N * 2;
self.reg()
.pud()
.modify(|r, w| unsafe { w.bits((r.bits() & !(0b11 << offset)) | (bits << offset)) });
}
fn set_ospd(&mut self, bits: u32) {
let offset = N * 2;
self.reg()
.ospd()
.modify(|r, w| unsafe { w.bits((r.bits() & !(0b11 << offset)) | (bits << offset)) });
}
fn set_omode(&mut self, omode: Omode) {
let offset = N;
self.reg().omode().modify(|r, w| unsafe {
w.bits((r.bits() & !(0b1 << offset)) | ((omode as u32) << offset))
});
}
fn set_alternate(&mut self, af: u32, omode: Omode) {
self.set_mode(Ctl::Af);
self.set_af(af);
self.set_omode(omode);
}
fn set_lk(&mut self, lkk: bool) {
self.reg().lock().modify(|_, w| {
let w = match N {
0 => w.lk0().locked(),
1 => w.lk1().locked(),
2 => w.lk2().locked(),
3 => w.lk3().locked(),
4 => w.lk4().locked(),
5 => w.lk5().locked(),
6 => w.lk6().locked(),
7 => w.lk7().locked(),
8 => w.lk8().locked(),
9 => w.lk9().locked(),
10 => w.lk10().locked(),
11 => w.lk11().locked(),
12 => w.lk12().locked(),
13 => w.lk13().locked(),
14 => w.lk14().locked(),
15 => w.lk15().locked(),
_ => unreachable!(),
};
if lkk {
w.lkk().active()
} else {
w.lkk().not_active()
}
});
}
}
#[cfg(not(pads_ge_lqfp32))]
impl<const P: char, const N: u8> Pin<P, N, Input> {
pub(crate) fn take_as_input() -> Self {
let mut pin = Pin { _mode: PhantomData };
pin.set_mode(Ctl::Input);
pin
}
}
impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
where
MODE: Active,
{
pub fn into_input(mut self) -> Pin<P, N, Input> {
self.set_mode(Ctl::Input);
Pin { _mode: PhantomData }
}
pub fn into_push_pull_output(mut self) -> Pin<P, N, Output<PushPull>> {
self.set_mode(Ctl::Output);
self.set_omode(Omode::PushPull);
Pin { _mode: PhantomData }
}
pub fn into_open_drain_output(mut self) -> Pin<P, N, Output<OpenDrain>> {
self.set_mode(Ctl::Output);
self.set_omode(Omode::OpenDrain);
Pin { _mode: PhantomData }
}
pub fn into_output(self) -> Pin<P, N, Output<PushPull>> {
self.into_push_pull_output()
}
pub fn into_analog(mut self) -> Pin<P, N, Analog> {
self.set_mode(Ctl::Analog);
Pin { _mode: PhantomData }
}
pub fn into_alternate<const AF: u8>(mut self) -> Pin<P, N, Alternate<AF>>
where
Self: ValidAf<AF>,
{
self.set_alternate(AF as u32, Omode::PushPull);
Pin { _mode: PhantomData }
}
pub fn into_alternate_open_drain<const AF: u8>(mut self) -> Pin<P, N, Alternate<AF, OpenDrain>>
where
Self: ValidAf<AF>,
{
self.set_alternate(AF as u32, Omode::OpenDrain);
Pin { _mode: PhantomData }
}
pub fn lock(mut self) -> Pin<P, N, Locked<MODE>>
where
Self: HasLock,
{
self.set_lk(true);
self.set_lk(false);
self.set_lk(true);
for _ in 0..2 {
self.reg().lock().read();
}
Pin { _mode: PhantomData }
}
pub fn erase(self) -> ErasedPin<MODE> {
ErasedPin {
port: Port::from_char(P),
number: N,
_mode: PhantomData,
}
}
pub fn set_pull(&mut self, p: Pull) {
self.set_pud(p as u32);
}
pub fn set_speed(&mut self, s: Speed) {
self.set_ospd(s as u32);
}
}
impl<const P: char, const N: u8, OTYPE> Pin<P, N, Output<OTYPE>> {
pub fn set_high(&mut self) {
self.set_bop();
}
pub fn set_low(&mut self) {
self.set_bc();
}
pub fn toggle(&mut self) {
self.set_tg();
}
pub fn is_set_high(&self) -> bool {
self.read_octl()
}
pub fn is_set_low(&self) -> bool {
!self.read_octl()
}
}
impl<const P: char, const N: u8> Pin<P, N, Input> {
pub fn is_high(&self) -> bool {
self.read_pin()
}
pub fn is_low(&self) -> bool {
!self.read_pin()
}
}
impl<const P: char, const N: u8> Pin<P, N, Output<OpenDrain>> {
pub fn is_high(&self) -> bool {
self.read_pin()
}
pub fn is_low(&self) -> bool {
!self.read_pin()
}
}
impl<MODE> ErasedPin<MODE> {
pub fn port(&self) -> Port {
self.port
}
pub fn number(&self) -> u8 {
self.number
}
}
impl<OTYPE> ErasedPin<Output<OTYPE>> {
pub fn set_high(&mut self) {
set_bop(self.port, self.number);
}
pub fn set_low(&mut self) {
set_bc(self.port, self.number);
}
pub fn toggle(&mut self) {
set_tg(self.port, self.number);
}
pub fn is_set_high(&self) -> bool {
read_octl(self.port, self.number)
}
pub fn is_set_low(&self) -> bool {
!read_octl(self.port, self.number)
}
}
impl ErasedPin<Input> {
pub fn is_high(&self) -> bool {
read_pin(self.port, self.number)
}
pub fn is_low(&self) -> bool {
!read_pin(self.port, self.number)
}
}
impl ErasedPin<Output<OpenDrain>> {
pub fn is_high(&self) -> bool {
read_pin(self.port, self.number)
}
pub fn is_low(&self) -> bool {
!read_pin(self.port, self.number)
}
}
impl<const P: char, const N: u8, OTYPE> ErrorType for Pin<P, N, Output<OTYPE>> {
type Error = Infallible;
}
impl<const P: char, const N: u8, OTYPE> OutputPin for Pin<P, N, Output<OTYPE>> {
fn set_high(&mut self) -> Result<(), Self::Error> {
self.set_bop();
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
self.set_bc();
Ok(())
}
}
impl<const P: char, const N: u8, OTYPE> StatefulOutputPin for Pin<P, N, Output<OTYPE>> {
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.read_octl())
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(!self.read_octl())
}
fn toggle(&mut self) -> Result<(), Self::Error> {
self.set_tg();
Ok(())
}
}
impl<const P: char, const N: u8> ErrorType for Pin<P, N, Input> {
type Error = Infallible;
}
impl<const P: char, const N: u8> InputPin for Pin<P, N, Input> {
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.read_pin())
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(!self.read_pin())
}
}
impl<const P: char, const N: u8> InputPin for Pin<P, N, Output<OpenDrain>> {
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.read_pin())
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(!self.read_pin())
}
}
impl<OTYPE> ErrorType for ErasedPin<Output<OTYPE>> {
type Error = Infallible;
}
impl<OTYPE> OutputPin for ErasedPin<Output<OTYPE>> {
fn set_high(&mut self) -> Result<(), Self::Error> {
set_bop(self.port, self.number);
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
set_bc(self.port, self.number);
Ok(())
}
}
impl<OTYPE> StatefulOutputPin for ErasedPin<Output<OTYPE>> {
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Ok(read_octl(self.port, self.number))
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(!read_octl(self.port, self.number))
}
fn toggle(&mut self) -> Result<(), Self::Error> {
set_tg(self.port, self.number);
Ok(())
}
}
impl ErrorType for ErasedPin<Input> {
type Error = Infallible;
}
impl InputPin for ErasedPin<Input> {
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(read_pin(self.port, self.number))
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(!read_pin(self.port, self.number))
}
}
impl InputPin for ErasedPin<Output<OpenDrain>> {
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(read_pin(self.port, self.number))
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(!read_pin(self.port, self.number))
}
}
impl<const P: char, const N: u8, MODE> Pin<P, N, Locked<MODE>>
where
Pin<P, N, MODE>: OutputPin,
{
pub fn set_high(&mut self) {
self.set_bop();
}
pub fn set_low(&mut self) {
self.set_bc();
}
}
impl<const P: char, const N: u8, MODE> Pin<P, N, Locked<MODE>>
where
Pin<P, N, MODE>: StatefulOutputPin,
{
pub fn toggle(&mut self) {
self.set_tg();
}
pub fn is_set_high(&self) -> bool {
self.read_octl()
}
pub fn is_set_low(&self) -> bool {
!self.read_octl()
}
}
impl<const P: char, const N: u8, MODE> Pin<P, N, Locked<MODE>>
where
Pin<P, N, MODE>: InputPin,
{
pub fn is_high(&self) -> bool {
self.read_pin()
}
pub fn is_low(&self) -> bool {
!self.read_pin()
}
}
impl<const P: char, const N: u8, MODE> ErrorType for Pin<P, N, Locked<MODE>> {
type Error = Infallible;
}
impl<const P: char, const N: u8, MODE> OutputPin for Pin<P, N, Locked<MODE>>
where
Pin<P, N, MODE>: OutputPin,
{
fn set_high(&mut self) -> Result<(), Self::Error> {
self.set_bop();
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
self.set_bc();
Ok(())
}
}
impl<const P: char, const N: u8, MODE> StatefulOutputPin for Pin<P, N, Locked<MODE>>
where
Pin<P, N, MODE>: StatefulOutputPin,
{
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.read_octl())
}
fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(!self.read_octl())
}
fn toggle(&mut self) -> Result<(), Self::Error> {
self.set_tg();
Ok(())
}
}
impl<const P: char, const N: u8, MODE> InputPin for Pin<P, N, Locked<MODE>>
where
Pin<P, N, MODE>: InputPin,
{
fn is_high(&mut self) -> Result<bool, Self::Error> {
Ok(self.read_pin())
}
fn is_low(&mut self) -> Result<bool, Self::Error> {
Ok(!self.read_pin())
}
}
pub trait GpioExt {
type Parts;
fn split(self, rcu: &mut Rcu) -> Self::Parts;
}
macro_rules! gpio {
($Parts:ident, $Gpio:ty, $P:literal, [
$( $(#[$cfg:meta])? $name:ident : $num:literal : $mode:ty ),+ $(,)?
]) => {
#[allow(missing_docs)]
pub struct $Parts {
$(
$(#[$cfg])?
pub $name: Pin<$P, $num, $mode>,
)+
}
impl GpioExt for $Gpio {
type Parts = $Parts;
fn split(self, rcu: &mut Rcu) -> Self::Parts {
<$Gpio as Enable>::enable(rcu);
<$Gpio as Reset>::reset(rcu);
$Parts {
$(
$(#[$cfg])?
$name: Pin::<$P, $num, $mode> { _mode: PhantomData },
)+
}
}
}
};
}
gpio!(PartsA, pac::Gpioa, 'A', [
pa0:0:Input,
pa1:1:Input,
pa2:2:Input,
pa3:3:Input,
pa4:4:Input,
pa5:5:Input,
pa6:6:Input,
pa7:7:Input,
#[cfg(pads_ge_24)] pa8:8:Input,
pa9:9:Input,
pa10:10:Input,
#[cfg(pads_ge_lqfp32)] pa11:11:Input,
#[cfg(pads_ge_lqfp32)] pa12:12:Input,
pa13:13:Debugger,
pa14:14:Debugger,
#[cfg(pads_ge_28)] pa15:15:Input,
]);
gpio!(PartsB, pac::Gpiob, 'B', [
#[cfg(pads_ge_24)] pb0:0:Input,
pb1:1:Input,
#[cfg(pads_ge_qfn32)] pb2:2:Input,
#[cfg(pads_ge_28)] pb3:3:Input,
#[cfg(pads_ge_28)] pb4:4:Input,
#[cfg(pads_ge_28)] pb5:5:Input,
#[cfg(pads_ge_24)] pb6:6:Input,
#[cfg(pads_ge_24)] pb7:7:Input,
#[cfg(pads_ge_qfn32)] pb8:8:Input,
#[cfg(pads_ge_48)] pb9:9:Input,
#[cfg(pads_ge_48)] pb10:10:Input,
#[cfg(pads_ge_48)] pb11:11:Input,
#[cfg(pads_ge_48)] pb12:12:Input,
#[cfg(pads_ge_48)] pb13:13:Input,
#[cfg(pads_ge_48)] pb14:14:Input,
#[cfg(pads_ge_48)] pb15:15:Input,
]);
#[cfg(pads_ge_48)]
gpio!(PartsC, pac::Gpioc, 'C', [
pc13:13:Input,
pc14:14:Input,
pc15:15:Input,
]);
gpio!(PartsF, pac::Gpiof, 'F', [
pf0:0:Input,
pf1:1:Input,
#[cfg(pads_ge_48)] pf6:6:Input,
#[cfg(pads_ge_48)] pf7:7:Input,
]);