mod erased;
mod impl_hal;
mod partially_erased;
use crate::{Steal, afio, pac::EXTI, rcc::Rcc};
use core::marker::PhantomData;
pub use erased::{AnyPin, ErasedPin};
pub use partially_erased::{PEPin, PartiallyErasedPin};
pub enum IOPinSpeed {
Mhz10 = 0b01, Mhz2 = 0b10,
Mhz50 = 0b11,
}
impl From<IOPinSpeed> for Mode {
fn from(value: IOPinSpeed) -> Self {
match value {
IOPinSpeed::Mhz10 => Self::Output,
IOPinSpeed::Mhz2 => Self::Output2,
IOPinSpeed::Mhz50 => Self::Output50,
}
}
}
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, rcc: &mut Rcc) -> Self::Parts;
unsafe fn split_without_reset(self, rcc: &mut Rcc) -> Self::Parts;
}
pub trait Active {}
pub trait UpMode: Clone {}
impl UpMode for Floating {}
impl UpMode for PullUp {}
#[derive(Default, Clone)]
pub struct Input<PULL = Floating>(PhantomData<PULL>);
impl<PULL> Active for Input<PULL> {}
#[derive(Default)]
pub struct Debugger;
#[derive(Default, Clone)]
pub struct Floating;
#[derive(Default)]
pub struct PullDown;
#[derive(Default, Clone)]
pub struct PullUp;
#[derive(Default)]
pub struct Output<Otype = PushPull>(PhantomData<Otype>);
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<Otype = PushPull>(PhantomData<Otype>);
impl<MODE> Active for Alternate<MODE> {}
pub use embedded_hal::digital::PinState;
#[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: super::Cnf;
const MODE: super::Mode;
const PULL: Option<bool> = None;
}
}
use crate::pac::gpioa::crl::{CONFIG as Cnf, MODE as Mode};
use sealed::Interruptable;
pub(crate) use sealed::PinMode;
impl<MODE> Interruptable for Input<MODE> {}
impl Interruptable for Dynamic {}
pub trait ExtiPin {
fn init_external_interrupt(&mut self, edge: Edge, enable: bool, afio: &mut afio::Afio);
fn trigger_on_edge(&mut self, edge: Edge);
fn enable_interrupt(&mut self);
fn disable_interrupt(&mut self);
fn check_and_clear_interrupt(&mut self) -> bool;
fn clear_interrupt_pending_bit(&mut self);
fn check_interrupt(&self) -> bool;
}
impl<PIN> ExtiPin for PIN
where
PIN: PinExt,
PIN::Mode: Interruptable,
{
fn init_external_interrupt(&mut self, edge: Edge, enable: bool, afio: &mut afio::Afio) {
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!(),
}
self.trigger_on_edge(edge);
if enable {
self.enable_interrupt();
} else {
self.disable_interrupt();
}
}
fn trigger_on_edge(&mut self, edge: Edge) {
let exti = unsafe { EXTI::steal() };
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.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::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) {
let exti = unsafe { EXTI::steal() };
exti.imr()
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.pin_id())) });
}
fn disable_interrupt(&mut self) {
let exti = unsafe { EXTI::steal() };
exti.imr()
.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id())) });
}
fn check_and_clear_interrupt(&mut self) -> bool {
if self.check_interrupt() {
self.clear_interrupt_pending_bit();
true
} else {
false
}
}
#[inline]
fn clear_interrupt_pending_bit(&mut self) {
unsafe { EXTI::steal().pr().write(|w| w.bits(1 << self.pin_id())) };
}
#[inline]
fn check_interrupt(&self) -> bool {
unsafe { (EXTI::steal().pr().read().bits() & (1 << self.pin_id())) != 0 }
}
}
#[derive(Default)]
pub enum Dynamic {
#[default]
InputFloating,
InputPullUp,
InputPullDown,
OutputPushPull,
OutputOpenDrain,
}
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;
use crate::rcc::Rcc;
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, rcc: &mut Rcc) -> Parts {
rcc.enable(&self);
rcc.reset(&self);
Parts {
crl: Cr::<$port_id, false>,
crh: Cr::<$port_id, true>,
$(
$pxi: $PXi::new(),
)+
}
}
unsafe fn split_without_reset(self, rcc: &mut Rcc) -> Parts {
rcc.enable(&self);
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,
}
pub trait HL {
type Cr;
fn get_cr() -> Self::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>;
fn get_cr() -> Self::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, 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) {
let gpio = unsafe { &(*gpiox::<P>()) };
gpio.bsrr().write(|w| w.bs(N).set_bit());
}
#[inline(always)]
fn _set_low(&mut self) {
let gpio = unsafe { &(*gpiox::<P>()) };
gpio.bsrr().write(|w| w.br(N).set_bit());
}
#[inline(always)]
fn _is_set_low(&self) -> bool {
let gpio = unsafe { &(*gpiox::<P>()) };
gpio.odr().read().odr(N).bit_is_clear()
}
#[inline(always)]
fn _is_low(&self) -> bool {
let gpio = unsafe { &(*gpiox::<P>()) };
gpio.idr().read().idr(N).bit_is_clear()
}
}
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> 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> 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()
}
}
#[non_exhaustive]
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(self) -> Pin<P, N, Alternate<PushPull>> {
self.into_mode(&mut Self::get_cr())
}
#[inline]
pub fn into_alternate_open_drain(self) -> Pin<P, N, Alternate<OpenDrain>> {
self.into_mode(&mut Self::get_cr())
}
#[inline]
pub fn into_floating_input(self) -> Pin<P, N, Input<Floating>> {
self.into_mode(&mut Self::get_cr())
}
#[inline]
pub fn into_pull_down_input(self) -> Pin<P, N, Input<PullDown>> {
self.into_mode(&mut Self::get_cr())
}
#[inline]
pub fn into_pull_up_input(self) -> Pin<P, N, Input<PullUp>> {
self.into_mode(&mut Self::get_cr())
}
#[inline]
pub fn into_open_drain_output(self) -> Pin<P, N, Output<OpenDrain>> {
self.into_open_drain_output_with_state(PinState::Low)
}
#[inline]
pub fn into_open_drain_output_with_state(
mut self,
initial_state: PinState,
) -> Pin<P, N, Output<OpenDrain>> {
self._set_state(initial_state);
self.into_mode(&mut Self::get_cr())
}
#[inline]
pub fn into_push_pull_output(self) -> Pin<P, N, Output<PushPull>> {
self.into_push_pull_output_with_state(PinState::Low)
}
#[inline]
pub fn into_push_pull_output_with_state(
mut self,
initial_state: PinState,
) -> Pin<P, N, Output<PushPull>> {
self._set_state(initial_state);
self.into_mode(&mut Self::get_cr())
}
#[inline]
pub fn into_push_pull_output_with_current_state(self) -> Pin<P, N, Output<PushPull>> {
self.into_mode(&mut Self::get_cr())
}
#[inline]
pub fn into_analog(self) -> Pin<P, N, Analog> {
self.into_mode(&mut Self::get_cr())
}
#[inline]
pub fn into_dynamic(mut self) -> Pin<P, N, Dynamic> {
self.mode::<Input<Floating>>(&mut Self::get_cr());
Pin::new()
}
}
impl<const P: char, const N: u8, PULL: UpMode> Steal for Pin<P, N, Input<PULL>> {
unsafe fn steal(&self) -> Self {
Pin::<P, N, Input<PULL>> {
mode: self.mode.clone(),
}
}
}
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 _set_speed(&mut self, _cr: &mut <Self as HL>::Cr, speed: IOPinSpeed) {
let gpio = unsafe { &(*gpiox::<P>()) };
match N {
0..=7 => {
gpio.crl().modify(|_, w| w.mode(N).variant(speed.into()));
}
8..=15 => {
gpio.crh()
.modify(|_, w| unsafe { w.mode(N - 8).bits(speed as u8) });
}
_ => unreachable!(),
}
}
}
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 Analog {
const MODE: Mode = Mode::Input;
const CNF: Cnf = Cnf::PushPull;
}
impl PinMode for Input<Floating> {
const MODE: Mode = Mode::Input;
const CNF: Cnf = Cnf::OpenDrain;
}
impl PinMode for Input<PullDown> {
const MODE: Mode = Mode::Input;
const CNF: Cnf = Cnf::AltPushPull;
const PULL: Option<bool> = Some(false);
}
impl PinMode for Input<PullUp> {
const MODE: Mode = Mode::Input;
const CNF: Cnf = Cnf::AltPushPull;
const PULL: Option<bool> = Some(true);
}
impl PinMode for Output<PushPull> {
const MODE: Mode = Mode::Output50;
const CNF: Cnf = Cnf::PushPull;
}
impl PinMode for Output<OpenDrain> {
const MODE: Mode = Mode::Output50;
const CNF: Cnf = Cnf::OpenDrain;
}
impl PinMode for Alternate<PushPull> {
const MODE: Mode = Mode::Output50;
const CNF: Cnf = Cnf::AltPushPull;
}
impl PinMode for Alternate<OpenDrain> {
const MODE: Mode = Mode::Output50;
const CNF: Cnf = Cnf::AltOpenDrain;
}
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 { &(*gpiox::<P>()) };
if let Some(pull) = MODE::PULL {
gpio.bsrr().write(|w| {
if pull {
w.bs(N).set_bit()
} else {
w.br(N).set_bit()
}
});
}
match N {
0..=7 => {
gpio.crl()
.modify(|_, w| w.mode(N).variant(MODE::MODE).cnf(N).variant(MODE::CNF));
}
8..=15 => {
gpio.crh().modify(|_, w| unsafe {
w.mode(N - 8).bits(MODE::MODE as u8);
w.cnf(N - 8).bits(MODE::CNF as u8)
});
}
_ => unreachable!(),
}
}
#[inline]
pub(crate) fn into_mode<MODE: PinMode>(mut self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, MODE> {
self.mode::<MODE>(cr);
Pin::new()
}
}
impl Analog {
pub fn new<const P: char, const N: u8, MODE>(
pin: Pin<P, N, MODE>,
cr: &mut <Pin<P, N, MODE> as HL>::Cr,
) -> Pin<P, N, Self>
where
Pin<P, N, MODE>: HL,
Self: PinMode,
{
pin.into_mode(cr)
}
}
impl<PULL> Input<PULL> {
pub fn new<const P: char, const N: u8, MODE>(
pin: Pin<P, N, MODE>,
cr: &mut <Pin<P, N, MODE> as HL>::Cr,
_pull: PULL,
) -> Pin<P, N, Self>
where
Pin<P, N, MODE>: HL,
Self: PinMode,
{
pin.into_mode(cr)
}
}
impl<Otype> Output<Otype> {
pub fn new<const P: char, const N: u8, MODE>(
mut pin: Pin<P, N, MODE>,
cr: &mut <Pin<P, N, MODE> as HL>::Cr,
state: PinState,
) -> Pin<P, N, Self>
where
Pin<P, N, MODE>: HL,
Self: PinMode,
{
pin._set_state(state);
pin.into_mode(cr)
}
}
impl<Otype> Alternate<Otype> {
pub fn new<const P: char, const N: u8, MODE>(
pin: Pin<P, N, MODE>,
cr: &mut <Pin<P, N, MODE> as HL>::Cr,
) -> Pin<P, N, Self>
where
Pin<P, N, MODE>: HL,
Self: PinMode,
{
pin.into_mode(cr)
}
}
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),
]);
const fn gpiox<const P: char>() -> *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!(),
}
}