use core::convert::Infallible;
use core::marker::PhantomData;
use crate::afio;
use crate::hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin};
use crate::pac::EXTI;
mod partially_erased;
pub use partially_erased::{PEPin, PartiallyErasedPin};
mod erased;
pub use erased::{EPin, ErasedPin};
pub enum IOPinSpeed {
Mhz10 = 0b01, Mhz2 = 0b10,
Mhz50 = 0b11,
}
pub trait PinExt {
type Mode;
fn pin_id(&self) -> u8;
fn port_id(&self) -> u8;
}
pub trait OutputSpeed: HL {
fn set_speed(&mut self, cr: &mut Self::Cr, speed: IOPinSpeed);
}
pub trait GpioExt {
type Parts;
fn split(self) -> Self::Parts;
}
pub trait Active {}
#[derive(Default)]
pub struct Input<MODE = Floating> {
_mode: PhantomData<MODE>,
}
impl<MODE> Active for Input<MODE> {}
#[derive(Default)]
pub struct Debugger;
#[derive(Default)]
pub struct Floating;
#[derive(Default)]
pub struct PullDown;
#[derive(Default)]
pub struct PullUp;
#[derive(Default)]
pub struct Output<MODE = PushPull> {
_mode: PhantomData<MODE>,
}
impl<MODE> Active for Output<MODE> {}
#[derive(Default)]
pub struct PushPull;
#[derive(Default)]
pub struct OpenDrain;
#[derive(Default)]
pub struct Analog;
impl Active for Analog {}
#[derive(Default)]
pub struct Alternate<MODE = PushPull> {
_mode: PhantomData<MODE>,
}
impl<MODE> Active for Alternate<MODE> {}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PinState {
High,
Low,
}
#[allow(non_camel_case_types)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Edge {
Rising,
Falling,
RisingFalling,
}
mod sealed {
pub trait Interruptable {}
pub trait PinMode: Default {
const CNF: u32;
const MODE: u32;
const PULL: Option<bool> = None;
}
}
use sealed::Interruptable;
use sealed::PinMode;
impl<MODE> Interruptable for Input<MODE> {}
impl Interruptable for Dynamic {}
pub trait ExtiPin {
fn make_interrupt_source(&mut self, afio: &mut afio::Parts);
fn trigger_on_edge(&mut self, exti: &mut EXTI, level: Edge);
fn enable_interrupt(&mut self, exti: &mut EXTI);
fn disable_interrupt(&mut self, exti: &mut EXTI);
fn clear_interrupt_pending_bit(&mut self);
fn check_interrupt(&self) -> bool;
}
impl<PIN> ExtiPin for PIN
where
PIN: PinExt,
PIN::Mode: Interruptable,
{
fn make_interrupt_source(&mut self, afio: &mut afio::Parts) {
let pin_number = self.pin_id();
let port = self.port_id() as u32;
let offset = 4 * (pin_number % 4);
match pin_number {
0..=3 => {
afio.exticr1.exticr1().modify(|r, w| unsafe {
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
});
}
4..=7 => {
afio.exticr2.exticr2().modify(|r, w| unsafe {
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
});
}
8..=11 => {
afio.exticr3.exticr3().modify(|r, w| unsafe {
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
});
}
12..=15 => {
afio.exticr4.exticr4().modify(|r, w| unsafe {
w.bits((r.bits() & !(0xf << offset)) | (port << offset))
});
}
_ => unreachable!(),
}
}
fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: Edge) {
let pin_number = self.pin_id();
match edge {
Edge::Rising => {
exti.rtsr
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << pin_number)) });
exti.ftsr
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << pin_number)) });
}
Edge::Falling => {
exti.ftsr
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << pin_number)) });
exti.rtsr
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << pin_number)) });
}
Edge::RisingFalling => {
exti.rtsr
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << pin_number)) });
exti.ftsr
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << pin_number)) });
}
}
}
fn enable_interrupt(&mut self, exti: &mut EXTI) {
exti.imr
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.pin_id())) });
}
fn disable_interrupt(&mut self, exti: &mut EXTI) {
exti.imr
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id())) });
}
fn clear_interrupt_pending_bit(&mut self) {
unsafe { (*EXTI::ptr()).pr.write(|w| w.bits(1 << self.pin_id())) };
}
fn check_interrupt(&self) -> bool {
unsafe { ((*EXTI::ptr()).pr.read().bits() & (1 << self.pin_id())) != 0 }
}
}
pub enum Dynamic {
InputFloating,
InputPullUp,
InputPullDown,
OutputPushPull,
OutputOpenDrain,
}
impl Default for Dynamic {
fn default() -> Self {
Dynamic::InputFloating
}
}
impl Active for Dynamic {}
#[derive(Debug, PartialEq, Eq)]
pub enum PinModeError {
IncorrectMode,
}
impl Dynamic {
fn is_input(&self) -> bool {
use Dynamic::*;
match self {
InputFloating | InputPullUp | InputPullDown | OutputOpenDrain => true,
OutputPushPull => false,
}
}
fn is_output(&self) -> bool {
use Dynamic::*;
match self {
InputFloating | InputPullUp | InputPullDown => false,
OutputPushPull | OutputOpenDrain => true,
}
}
}
macro_rules! gpio {
($GPIOX:ident, $gpiox:ident, $PXx:ident, $port_id:expr, [
$($PXi:ident: ($pxi:ident, $pin_number:expr $(, $MODE:ty)?),)+
]) => {
pub mod $gpiox {
use crate::pac::{$GPIOX, RCC};
use crate::rcc::{Enable, Reset};
use super::{Active, Floating, GpioExt, Input, PartiallyErasedPin, ErasedPin, Pin, Cr};
#[allow(unused)]
use super::Debugger;
pub struct Parts {
pub crl: Cr<$port_id, false>,
pub crh: Cr<$port_id, true>,
$(
pub $pxi: $PXi $(<$MODE>)?,
)+
}
$(
pub type $PXi<MODE = Input<Floating>> = Pin<$port_id, $pin_number, MODE>;
)+
impl GpioExt for $GPIOX {
type Parts = Parts;
fn split(self) -> Parts {
let rcc = unsafe { &(*RCC::ptr()) };
$GPIOX::enable(rcc);
$GPIOX::reset(rcc);
Parts {
crl: Cr::<$port_id, false>(()),
crh: Cr::<$port_id, true>(()),
$(
$pxi: $PXi::new(),
)+
}
}
}
impl<MODE> PartiallyErasedPin<$port_id, MODE> {
pub fn erase(self) -> ErasedPin<MODE> {
ErasedPin::$PXx(self)
}
}
impl<const N: u8, MODE> Pin<$port_id, N, MODE>
where
MODE: Active,
{
pub fn erase(self) -> ErasedPin<MODE> {
self.erase_number().erase()
}
}
}
pub use $gpiox::{ $($PXi,)+ };
}
}
pub struct Pin<const P: char, const N: u8, MODE = Input<Floating>> {
mode: MODE,
}
impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
const OFFSET: u32 = (4 * (N as u32)) % 32;
}
pub trait HL {
type Cr;
}
macro_rules! cr {
($cr_is_h:literal: [$($pin_number:literal),+]) => {
$(
impl<const P: char, MODE> HL for Pin<P, $pin_number, MODE> {
type Cr = Cr<P, $cr_is_h>;
}
)+
}
}
cr!(false: [0, 1, 2, 3, 4, 5, 6, 7]);
cr!(true: [8, 9, 10, 11, 12, 13, 14, 15]);
impl<const P: char, const N: u8, MODE: Default> Pin<P, N, MODE> {
fn new() -> Self {
Self {
mode: Default::default(),
}
}
}
impl<const P: char, const N: u8, MODE> PinExt for Pin<P, N, MODE> {
type Mode = MODE;
#[inline(always)]
fn pin_id(&self) -> u8 {
N
}
#[inline(always)]
fn port_id(&self) -> u8 {
P as u8 - b'A'
}
}
impl<const P: char, const N: u8> Pin<P, N, Debugger> {
#[allow(dead_code)]
pub(crate) unsafe fn activate(self) -> Pin<P, N, Input<Floating>> {
Pin::new()
}
}
impl<const P: char, const N: u8> OutputPin for Pin<P, N, Dynamic> {
type Error = PinModeError;
fn set_high(&mut self) -> Result<(), Self::Error> {
if self.mode.is_output() {
self._set_high();
Ok(())
} else {
Err(PinModeError::IncorrectMode)
}
}
fn set_low(&mut self) -> Result<(), Self::Error> {
if self.mode.is_output() {
self._set_low();
Ok(())
} else {
Err(PinModeError::IncorrectMode)
}
}
}
impl<const P: char, const N: u8> InputPin for Pin<P, N, Dynamic> {
type Error = PinModeError;
fn is_high(&self) -> Result<bool, Self::Error> {
self.is_low().map(|b| !b)
}
fn is_low(&self) -> Result<bool, Self::Error> {
if self.mode.is_input() {
Ok(self._is_low())
} else {
Err(PinModeError::IncorrectMode)
}
}
}
impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
#[inline(always)]
fn _set_state(&mut self, state: PinState) {
match state {
PinState::High => self._set_high(),
PinState::Low => self._set_low(),
}
}
#[inline(always)]
fn _set_high(&mut self) {
unsafe { (*Gpio::<P>::ptr()).bsrr.write(|w| w.bits(1 << N)) }
}
#[inline(always)]
fn _set_low(&mut self) {
unsafe { (*Gpio::<P>::ptr()).bsrr.write(|w| w.bits(1 << (16 + N))) }
}
#[inline(always)]
fn _is_set_low(&self) -> bool {
unsafe { (*Gpio::<P>::ptr()).odr.read().bits() & (1 << N) == 0 }
}
#[inline(always)]
fn _is_low(&self) -> bool {
unsafe { (*Gpio::<P>::ptr()).idr.read().bits() & (1 << N) == 0 }
}
}
impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
where
MODE: Active,
{
#[inline]
pub fn erase_number(self) -> PartiallyErasedPin<P, MODE> {
PartiallyErasedPin::new(N)
}
}
impl<const P: char, const N: u8, MODE> Pin<P, N, Output<MODE>> {
#[inline]
pub fn set_high(&mut self) {
self._set_high()
}
#[inline]
pub fn set_low(&mut self) {
self._set_low()
}
#[inline(always)]
pub fn get_state(&self) -> PinState {
if self._is_set_low() {
PinState::Low
} else {
PinState::High
}
}
#[inline(always)]
pub fn set_state(&mut self, state: PinState) {
self._set_state(state)
}
#[inline]
pub fn is_set_high(&self) -> bool {
!self._is_set_low()
}
#[inline]
pub fn is_set_low(&self) -> bool {
self._is_set_low()
}
#[inline]
pub fn toggle(&mut self) {
if self._is_set_low() {
self._set_high()
} else {
self._set_low()
}
}
}
impl<const P: char, const N: u8, MODE> OutputPin for Pin<P, N, Output<MODE>> {
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<const P: char, const N: u8, MODE> StatefulOutputPin for Pin<P, N, Output<MODE>> {
#[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())
}
}
impl<const P: char, const N: u8, MODE> ToggleableOutputPin for Pin<P, N, Output<MODE>> {
type Error = Infallible;
#[inline(always)]
fn toggle(&mut self) -> Result<(), Self::Error> {
self.toggle();
Ok(())
}
}
impl<const P: char, const N: u8, MODE> Pin<P, N, Input<MODE>> {
#[inline]
pub fn is_high(&self) -> bool {
!self._is_low()
}
#[inline]
pub fn is_low(&self) -> bool {
self._is_low()
}
}
impl<const P: char, const N: u8, MODE> InputPin for Pin<P, N, Input<MODE>> {
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<const P: char, const N: u8> Pin<P, N, Output<OpenDrain>> {
#[inline]
pub fn is_high(&self) -> bool {
!self._is_low()
}
#[inline]
pub fn is_low(&self) -> bool {
self._is_low()
}
}
impl<const P: char, const N: u8> InputPin for Pin<P, N, Output<OpenDrain>> {
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())
}
}
pub struct Cr<const P: char, const H: bool>(());
impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
where
MODE: Active,
Self: HL,
{
#[inline]
pub fn into_alternate_push_pull(
mut self,
cr: &mut <Self as HL>::Cr,
) -> Pin<P, N, Alternate<PushPull>> {
self.mode::<Alternate<PushPull>>(cr);
Pin::new()
}
#[inline]
pub fn into_alternate_open_drain(
mut self,
cr: &mut <Self as HL>::Cr,
) -> Pin<P, N, Alternate<OpenDrain>> {
self.mode::<Alternate<OpenDrain>>(cr);
Pin::new()
}
#[inline]
pub fn into_floating_input(mut self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Input<Floating>> {
self.mode::<Input<Floating>>(cr);
Pin::new()
}
#[inline]
pub fn into_pull_down_input(mut self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Input<PullDown>> {
self.mode::<Input<PullDown>>(cr);
Pin::new()
}
#[inline]
pub fn into_pull_up_input(mut self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Input<PullUp>> {
self.mode::<Input<PullUp>>(cr);
Pin::new()
}
#[inline]
pub fn into_open_drain_output(self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Output<OpenDrain>> {
self.into_open_drain_output_with_state(cr, PinState::Low)
}
#[inline]
pub fn into_open_drain_output_with_state(
mut self,
cr: &mut <Self as HL>::Cr,
initial_state: PinState,
) -> Pin<P, N, Output<OpenDrain>> {
self._set_state(initial_state);
self.mode::<Output<OpenDrain>>(cr);
Pin::new()
}
#[inline]
pub fn into_push_pull_output(self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Output<PushPull>> {
self.into_push_pull_output_with_state(cr, PinState::Low)
}
#[inline]
pub fn into_push_pull_output_with_state(
mut self,
cr: &mut <Self as HL>::Cr,
initial_state: PinState,
) -> Pin<P, N, Output<PushPull>> {
self._set_state(initial_state);
self.mode::<Output<PushPull>>(cr);
Pin::new()
}
#[inline]
pub fn into_analog(mut self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Analog> {
self.mode::<Analog>(cr);
Pin::new()
}
#[inline]
pub fn into_dynamic(mut self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Dynamic> {
self.mode::<Input<Floating>>(cr);
Pin::new()
}
}
macro_rules! impl_temp_output {
($fn_name:ident, $stateful_fn_name:ident, $mode:ty) => {
#[inline]
pub fn $fn_name(
&mut self,
cr: &mut <Self as HL>::Cr,
mut f: impl FnMut(&mut Pin<P, N, $mode>),
) {
self.mode::<$mode>(cr);
let mut temp = Pin::<P, N, $mode>::new();
f(&mut temp);
self.mode::<$mode>(cr);
Self::new();
}
#[inline]
pub fn $stateful_fn_name(
&mut self,
cr: &mut <Self as HL>::Cr,
state: PinState,
mut f: impl FnMut(&mut Pin<P, N, $mode>),
) {
self._set_state(state);
self.mode::<$mode>(cr);
let mut temp = Pin::<P, N, $mode>::new();
f(&mut temp);
self.mode::<$mode>(cr);
Self::new();
}
};
}
macro_rules! impl_temp_input {
($fn_name:ident, $mode:ty) => {
#[inline]
pub fn $fn_name(
&mut self,
cr: &mut <Self as HL>::Cr,
mut f: impl FnMut(&mut Pin<P, N, $mode>),
) {
self.mode::<$mode>(cr);
let mut temp = Pin::<P, N, $mode>::new();
f(&mut temp);
self.mode::<$mode>(cr);
Self::new();
}
};
}
impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
where
MODE: Active + PinMode,
Self: HL,
{
impl_temp_output!(
as_push_pull_output,
as_push_pull_output_with_state,
Output<PushPull>
);
impl_temp_output!(
as_open_drain_output,
as_open_drain_output_with_state,
Output<OpenDrain>
);
impl_temp_input!(as_floating_input, Input<Floating>);
impl_temp_input!(as_pull_up_input, Input<PullUp>);
impl_temp_input!(as_pull_down_input, Input<PullDown>);
}
impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
where
Self: HL,
{
#[inline(always)]
fn cr_modify(&mut self, _cr: &mut <Self as HL>::Cr, f: impl FnOnce(u32) -> u32) {
let gpio = unsafe { &(*Gpio::<P>::ptr()) };
match N {
0..=7 => {
gpio.crl.modify(|r, w| unsafe { w.bits(f(r.bits())) });
}
8..=15 => {
gpio.crh.modify(|r, w| unsafe { w.bits(f(r.bits())) });
}
_ => unreachable!(),
}
}
#[inline(always)]
fn _set_speed(&mut self, cr: &mut <Self as HL>::Cr, speed: IOPinSpeed) {
self.cr_modify(cr, |r_bits| {
(r_bits & !(0b11 << Self::OFFSET)) | ((speed as u32) << Self::OFFSET)
});
}
}
impl<const P: char, const N: u8, MODE> OutputSpeed for Pin<P, N, Output<MODE>>
where
Self: HL,
{
fn set_speed(&mut self, cr: &mut <Self as HL>::Cr, speed: IOPinSpeed) {
self._set_speed(cr, speed)
}
}
impl<const P: char, const N: u8> OutputSpeed for Pin<P, N, Alternate<PushPull>>
where
Self: HL,
{
fn set_speed(&mut self, cr: &mut <Self as HL>::Cr, speed: IOPinSpeed) {
self._set_speed(cr, speed)
}
}
impl<const P: char, const N: u8> Pin<P, N, Dynamic>
where
Self: HL,
{
#[inline]
pub fn make_pull_up_input(&mut self, cr: &mut <Self as HL>::Cr) {
self.mode::<Input<PullUp>>(cr);
self.mode = Dynamic::InputPullUp;
}
#[inline]
pub fn make_pull_down_input(&mut self, cr: &mut <Self as HL>::Cr) {
self.mode::<Input<PullDown>>(cr);
self.mode = Dynamic::InputPullDown;
}
#[inline]
pub fn make_floating_input(&mut self, cr: &mut <Self as HL>::Cr) {
self.mode::<Input<Floating>>(cr);
self.mode = Dynamic::InputFloating;
}
#[inline]
pub fn make_push_pull_output(&mut self, cr: &mut <Self as HL>::Cr) {
self.mode::<Output<PushPull>>(cr);
self.mode = Dynamic::OutputPushPull;
}
#[inline]
pub fn make_open_drain_output(&mut self, cr: &mut <Self as HL>::Cr) {
self.mode::<Output<OpenDrain>>(cr);
self.mode = Dynamic::OutputOpenDrain;
}
}
impl PinMode for Input<Floating> {
const CNF: u32 = 0b01;
const MODE: u32 = 0b00;
}
impl PinMode for Input<PullDown> {
const CNF: u32 = 0b10;
const MODE: u32 = 0b00;
const PULL: Option<bool> = Some(false);
}
impl PinMode for Input<PullUp> {
const CNF: u32 = 0b10;
const MODE: u32 = 0b00;
const PULL: Option<bool> = Some(true);
}
impl PinMode for Output<OpenDrain> {
const CNF: u32 = 0b01;
const MODE: u32 = 0b11;
}
impl PinMode for Output<PushPull> {
const CNF: u32 = 0b00;
const MODE: u32 = 0b11;
}
impl PinMode for Analog {
const CNF: u32 = 0b00;
const MODE: u32 = 0b00;
}
impl PinMode for Alternate<PushPull> {
const CNF: u32 = 0b10;
const MODE: u32 = 0b11;
}
impl PinMode for Alternate<OpenDrain> {
const CNF: u32 = 0b11;
const MODE: u32 = 0b11;
}
impl<const P: char, const N: u8, M> Pin<P, N, M>
where
Self: HL,
{
fn mode<MODE: PinMode>(&mut self, cr: &mut <Self as HL>::Cr) {
let gpio = unsafe { &(*Gpio::<P>::ptr()) };
if let Some(pull) = MODE::PULL {
if pull {
gpio.bsrr.write(|w| unsafe { w.bits(1 << N) });
} else {
gpio.bsrr.write(|w| unsafe { w.bits(1 << (16 + N)) });
}
}
let bits = (MODE::CNF << 2) | MODE::MODE;
self.cr_modify(cr, |r_bits| {
(r_bits & !(0b1111 << Self::OFFSET)) | (bits << Self::OFFSET)
});
}
}
gpio!(GPIOA, gpioa, PAx, 'A', [
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, Debugger),
PA14: (pa14, 14, Debugger),
PA15: (pa15, 15, Debugger),
]);
gpio!(GPIOB, gpiob, PBx, 'B', [
PB0: (pb0, 0),
PB1: (pb1, 1),
PB2: (pb2, 2),
PB3: (pb3, 3, Debugger),
PB4: (pb4, 4, Debugger),
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),
PB15: (pb15, 15),
]);
gpio!(GPIOC, gpioc, PCx, 'C', [
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),
]);
gpio!(GPIOD, gpiod, PDx, 'D', [
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),
]);
gpio!(GPIOE, gpioe, PEx, 'E', [
PE0: (pe0, 0),
PE1: (pe1, 1),
PE2: (pe2, 2),
PE3: (pe3, 3),
PE4: (pe4, 4),
PE5: (pe5, 5),
PE6: (pe6, 6),
PE7: (pe7, 7),
PE8: (pe8, 8),
PE9: (pe9, 9),
PE10: (pe10, 10),
PE11: (pe11, 11),
PE12: (pe12, 12),
PE13: (pe13, 13),
PE14: (pe14, 14),
PE15: (pe15, 15),
]);
#[cfg(any(feature = "xl", feature = "high"))]
gpio!(GPIOF, gpiof, PFx, 'F', [
PF0: (pf0, 0),
PF1: (pf1, 1),
PF2: (pf2, 2),
PF3: (pf3, 3),
PF4: (pf4, 4),
PF5: (pf5, 5),
PF6: (pf6, 6),
PF7: (pf7, 7),
PF8: (pf8, 8),
PF9: (pf9, 9),
PF10: (pf10, 10),
PF11: (pf11, 11),
PF12: (pf12, 12),
PF13: (pf13, 13),
PF14: (pf14, 14),
PF15: (pf15, 15),
]);
#[cfg(any(feature = "xl", feature = "high"))]
gpio!(GPIOG, gpiog, PGx, 'G', [
PG0: (pg0, 0),
PG1: (pg1, 1),
PG2: (pg2, 2),
PG3: (pg3, 3),
PG4: (pg4, 4),
PG5: (pg5, 5),
PG6: (pg6, 6),
PG7: (pg7, 7),
PG8: (pg8, 8),
PG9: (pg9, 9),
PG10: (pg10, 10),
PG11: (pg11, 11),
PG12: (pg12, 12),
PG13: (pg13, 13),
PG14: (pg14, 14),
PG15: (pg15, 15),
]);
struct Gpio<const P: char>;
impl<const P: char> Gpio<P> {
const fn ptr() -> *const crate::pac::gpioa::RegisterBlock {
match P {
'A' => crate::pac::GPIOA::ptr(),
'B' => crate::pac::GPIOB::ptr() as _,
'C' => crate::pac::GPIOC::ptr() as _,
'D' => crate::pac::GPIOD::ptr() as _,
'E' => crate::pac::GPIOE::ptr() as _,
#[cfg(any(feature = "xl", feature = "high"))]
'F' => crate::pac::GPIOF::ptr() as _,
#[cfg(any(feature = "xl", feature = "high"))]
'G' => crate::pac::GPIOG::ptr() as _,
_ => unreachable!(),
}
}
}