stm32l4xx_hal/
gpio.rs

1//! General Purpose Input / Output
2
3pub use crate::hal::digital::v2::PinState;
4use crate::hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin};
5use core::convert::Infallible;
6use core::marker::PhantomData;
7
8use crate::pac::{self, EXTI, SYSCFG};
9use crate::rcc::{Enable, AHB2, APB2};
10
11mod convert;
12
13mod partially_erased;
14pub use partially_erased::{PEPin, PartiallyErasedPin};
15mod erased;
16pub use erased::{EPin, ErasedPin};
17
18/// Extension trait to split a GPIO peripheral in independent pins and registers
19pub trait GpioExt {
20    /// The to split the GPIO into
21    type Parts;
22
23    /// Splits the GPIO block into independent pins and registers
24    fn split(self, ahb: &mut AHB2) -> Self::Parts;
25}
26
27/// Input mode (type state)
28pub struct Input<IOCONF> {
29    _mode: PhantomData<IOCONF>,
30}
31
32/// Floating input (type state)
33pub struct Floating;
34/// Pulled down input (type state)
35pub struct PullDown;
36/// Pulled up input (type state)
37pub struct PullUp;
38
39/// Output mode (type state)
40pub struct Output<OTYPE> {
41    _mode: PhantomData<OTYPE>,
42}
43
44/// Push pull output (type state)
45pub struct PushPull;
46/// Open drain output (type state)
47pub struct OpenDrain;
48
49/// Analog mode (type state)
50pub struct Analog;
51
52pub type Debugger = Alternate<PushPull, 0>;
53
54/// GPIO Pin speed selection
55pub enum Speed {
56    Low = 0,
57    Medium = 1,
58    High = 2,
59    VeryHigh = 3,
60}
61
62pub trait PinExt {
63    type Mode;
64    /// Return pin number
65    fn pin_id(&self) -> u8;
66    /// Return port number
67    fn port_id(&self) -> u8;
68}
69
70/// Alternate mode (type state)
71pub struct Alternate<MODE, const A: u8> {
72    _mode: PhantomData<MODE>,
73}
74
75#[derive(Debug, PartialEq)]
76pub enum Edge {
77    Rising,
78    Falling,
79    RisingFalling,
80}
81
82mod sealed {
83    /// Marker trait that show if `ExtiPin` can be implemented
84    pub trait Interruptable {}
85}
86
87use sealed::Interruptable;
88impl<MODE> Interruptable for Output<MODE> {}
89impl<MODE> Interruptable for Input<MODE> {}
90
91/// External Interrupt Pin
92pub trait ExtiPin {
93    fn make_interrupt_source(&mut self, syscfg: &mut SYSCFG, apb2: &mut APB2);
94    fn trigger_on_edge(&mut self, exti: &mut EXTI, level: Edge);
95    fn enable_interrupt(&mut self, exti: &mut EXTI);
96    fn disable_interrupt(&mut self, exti: &mut EXTI);
97    fn clear_interrupt_pending_bit(&mut self);
98    fn check_interrupt(&self) -> bool;
99}
100
101impl<PIN> ExtiPin for PIN
102where
103    PIN: PinExt,
104    PIN::Mode: Interruptable,
105{
106    /// Make corresponding EXTI line sensitive to this pin
107    #[inline(always)]
108    fn make_interrupt_source(&mut self, syscfg: &mut SYSCFG, apb2: &mut APB2) {
109        // SYSCFG clock must be enabled in order to do register writes
110        SYSCFG::enable(apb2);
111
112        let i = self.pin_id();
113        let port = self.port_id() as u32;
114        let offset = 4 * (i % 4);
115        match i {
116            0..=3 => {
117                syscfg.exticr1.modify(|r, w| unsafe {
118                    w.bits((r.bits() & !(0xf << offset)) | (port << offset))
119                });
120            }
121            4..=7 => {
122                syscfg.exticr2.modify(|r, w| unsafe {
123                    w.bits((r.bits() & !(0xf << offset)) | (port << offset))
124                });
125            }
126            8..=11 => {
127                syscfg.exticr3.modify(|r, w| unsafe {
128                    w.bits((r.bits() & !(0xf << offset)) | (port << offset))
129                });
130            }
131            12..=15 => {
132                syscfg.exticr4.modify(|r, w| unsafe {
133                    w.bits((r.bits() & !(0xf << offset)) | (port << offset))
134                });
135            }
136            _ => unreachable!(),
137        }
138    }
139
140    /// Generate interrupt on rising edge, falling edge or both
141    #[inline(always)]
142    fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: Edge) {
143        let i = self.pin_id();
144        match edge {
145            Edge::Rising => {
146                exti.rtsr1
147                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
148                exti.ftsr1
149                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
150            }
151            Edge::Falling => {
152                exti.ftsr1
153                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
154                exti.rtsr1
155                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
156            }
157            Edge::RisingFalling => {
158                exti.rtsr1
159                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
160                exti.ftsr1
161                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
162            }
163        }
164    }
165
166    /// Enable external interrupts from this pin.
167    #[inline(always)]
168    fn enable_interrupt(&mut self, exti: &mut EXTI) {
169        exti.imr1
170            .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.pin_id())) });
171    }
172
173    /// Disable external interrupts from this pin
174    #[inline(always)]
175    fn disable_interrupt(&mut self, exti: &mut EXTI) {
176        exti.imr1
177            .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id())) });
178    }
179
180    /// Clear the interrupt pending bit for this pin
181    #[inline(always)]
182    fn clear_interrupt_pending_bit(&mut self) {
183        unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << self.pin_id())) };
184    }
185
186    /// Reads the interrupt pending bit for this pin
187    #[inline(always)]
188    fn check_interrupt(&self) -> bool {
189        unsafe { ((*EXTI::ptr()).pr1.read().bits() & (1 << self.pin_id())) != 0 }
190    }
191}
192
193/// Opaque MODER register
194pub struct MODER<const P: char> {
195    _0: (),
196}
197
198impl<const P: char> MODER<P> {
199    pub(crate) fn new() -> Self {
200        Self { _0: () }
201    }
202}
203
204/// Opaque OTYPER register
205pub struct OTYPER<const P: char> {
206    _0: (),
207}
208
209impl<const P: char> OTYPER<P> {
210    pub(crate) fn new() -> Self {
211        Self { _0: () }
212    }
213}
214
215/// Opaque OSPEEDR register
216pub struct OSPEEDR<const P: char> {
217    _0: (),
218}
219impl<const P: char> OSPEEDR<P> {
220    pub(crate) fn new() -> Self {
221        Self { _0: () }
222    }
223}
224
225/// Opaque PUPDR register
226pub struct PUPDR<const P: char> {
227    _0: (),
228}
229
230impl<const P: char> PUPDR<P> {
231    pub(crate) fn new() -> Self {
232        Self { _0: () }
233    }
234}
235
236macro_rules! gpio {
237    ($GPIOX:ident, $gpiox:ident, $PXx:ident, $port_id:literal, $extigpionr:expr, $({ $pwrenable:expr },)? [
238        $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty, $HL:ident, $exticri:ident),)+
239    ]) => {
240        /// GPIO
241        pub mod $gpiox {
242            use crate::stm32::$GPIOX;
243
244            use crate::rcc::{AHB2, Enable, Reset};
245            use super::{Afr, Analog, GpioExt, Pin, H8, L8, MODER, OTYPER, OSPEEDR, PUPDR};
246
247            /// GPIO parts
248            pub struct Parts {
249                /// Opaque AFRH register
250                pub afrh: Afr<H8, $port_id>,
251                /// Opaque AFRL register
252                pub afrl: Afr<L8, $port_id>,
253                /// Opaque MODER register
254                pub moder: MODER<$port_id>,
255                /// Opaque OTYPER register
256                pub otyper: OTYPER<$port_id>,
257                /// Opaque OSPEEDR register
258                pub ospeedr: OSPEEDR<$port_id>,
259                /// Opaque PUPDR register
260                pub pupdr: PUPDR<$port_id>,
261                $(
262                    /// Pin
263                    pub $pxi: $PXi<$MODE>,
264                )+
265            }
266
267            $(
268                pub type $PXi<MODE> = Pin<MODE, $HL, $port_id, $i>;
269            )+
270
271            impl GpioExt for $GPIOX {
272                type Parts = Parts;
273
274                fn split(self, ahb: &mut AHB2) -> Parts {
275                    <$GPIOX>::enable(ahb);
276                    <$GPIOX>::reset(ahb);
277                    $($pwrenable)?
278
279                    Parts {
280                        afrh: Afr::new(),
281                        afrl: Afr::new(),
282                        moder: MODER::new(),
283                        otyper: OTYPER::new(),
284                        ospeedr: OSPEEDR::new(),
285                        pupdr: PUPDR::new(),
286                        $(
287                            $pxi: $PXi::new(),
288                        )+
289                    }
290                }
291            }
292        }
293
294        pub use $gpiox::{
295            $($PXi,)*
296        };
297    }
298}
299
300/// Generic pin type
301///
302/// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section).
303/// - `HL` represents high 8 or low 8 pin.
304/// - `P` is port name: `A` for GPIOA, `B` for GPIOB, etc.
305/// - `N` is pin number: from `0` to `15`.
306pub struct Pin<MODE, HL, const P: char, const N: u8> {
307    _mode: PhantomData<(MODE, HL)>,
308}
309
310impl<MODE, HL, const P: char, const N: u8> Pin<MODE, HL, P, N> {
311    const fn new() -> Self {
312        Self { _mode: PhantomData }
313    }
314}
315
316impl<MODE, HL, const P: char, const N: u8> PinExt for Pin<MODE, HL, P, N> {
317    type Mode = MODE;
318
319    #[inline(always)]
320    fn pin_id(&self) -> u8 {
321        N
322    }
323    #[inline(always)]
324    fn port_id(&self) -> u8 {
325        P as u8 - b'A'
326    }
327}
328
329impl<MODE, HL, const P: char, const N: u8> Pin<Output<MODE>, HL, P, N> {
330    /// Set pin speed
331    pub fn set_speed(self, speed: Speed) -> Self {
332        let offset = 2 * { N };
333
334        unsafe {
335            (*Gpio::<P>::ptr())
336                .ospeedr
337                .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | ((speed as u32) << offset)))
338        };
339
340        self
341    }
342}
343
344impl<HL, const P: char, const N: u8> Pin<Output<OpenDrain>, HL, P, N> {
345    /// Enables / disables the internal pull up
346    pub fn internal_pull_up(&mut self, _pupdr: &mut PUPDR<P>, on: bool) {
347        let offset = 2 * { N };
348        let value = if on { 0b01 } else { 0b00 };
349        unsafe {
350            (*Gpio::<P>::ptr())
351                .pupdr
352                .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (value << offset)))
353        };
354    }
355}
356
357impl<MODE, HL, const P: char, const N: u8, const A: u8> Pin<Alternate<MODE, A>, HL, P, N> {
358    /// Set pin speed
359    pub fn set_speed(self, speed: Speed) -> Self {
360        let offset = 2 * { N };
361
362        unsafe {
363            (*Gpio::<P>::ptr())
364                .ospeedr
365                .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | ((speed as u32) << offset)))
366        };
367
368        self
369    }
370
371    /// Enables / disables the internal pull up
372    pub fn internal_pull_up(&mut self, _pupdr: &mut PUPDR<P>, on: bool) {
373        let offset = 2 * { N };
374        let value = if on { 0b01 } else { 0b00 };
375        unsafe {
376            (*Gpio::<P>::ptr())
377                .pupdr
378                .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (value << offset)))
379        };
380    }
381}
382
383impl<HL, const P: char, const N: u8, const A: u8> Pin<Alternate<PushPull, A>, HL, P, N> {
384    /// Turns pin alternate configuration pin into open drain
385    pub fn set_open_drain(self) -> Pin<Alternate<OpenDrain, A>, HL, P, N> {
386        let offset = { N };
387        unsafe {
388            (*Gpio::<P>::ptr())
389                .otyper
390                .modify(|r, w| w.bits(r.bits() | (1 << offset)))
391        };
392
393        Pin::new()
394    }
395}
396
397impl<MODE, HL, const P: char, const N: u8> Pin<MODE, HL, P, N> {
398    /// Erases the pin number from the type
399    ///
400    /// This is useful when you want to collect the pins into an array where you
401    /// need all the elements to have the same type
402    pub fn erase_number(self) -> PEPin<MODE, P> {
403        PEPin::new(N)
404    }
405
406    /// Erases the pin number and the port from the type
407    ///
408    /// This is useful when you want to collect the pins into an array where you
409    /// need all the elements to have the same type
410    pub fn erase(self) -> EPin<MODE> {
411        EPin::new(P as u8 - b'A', N)
412    }
413}
414
415// Internal helper functions
416//
417// NOTE: The functions in this impl block are "safe", but they
418// are callable when the pin is in modes where they don't make
419// sense.
420impl<MODE, HL, const P: char, const N: u8> Pin<MODE, HL, P, N> {
421    /// Set the output of the pin regardless of its mode.
422    /// Primarily used to set the output value of the pin
423    /// before changing its mode to an output to avoid
424    /// a short spike of an incorrect value
425    #[inline(always)]
426    fn _set_state(&mut self, state: PinState) {
427        match state {
428            PinState::High => self._set_high(),
429            PinState::Low => self._set_low(),
430        }
431    }
432    #[inline(always)]
433    fn _set_high(&mut self) {
434        // NOTE(unsafe) atomic write to a stateless register
435        unsafe { (*Gpio::<P>::ptr()).bsrr.write(|w| w.bits(1 << N)) }
436    }
437    #[inline(always)]
438    fn _set_low(&mut self) {
439        // NOTE(unsafe) atomic write to a stateless register
440        unsafe { (*Gpio::<P>::ptr()).bsrr.write(|w| w.bits(1 << (16 + N))) }
441    }
442
443    #[inline(always)]
444    fn _is_set_low(&self) -> bool {
445        // NOTE(unsafe) atomic read with no side effects
446        unsafe { (*Gpio::<P>::ptr()).odr.read().bits() & (1 << N) == 0 }
447    }
448    #[inline(always)]
449    fn _is_low(&self) -> bool {
450        // NOTE(unsafe) atomic read with no side effects
451        unsafe { (*Gpio::<P>::ptr()).idr.read().bits() & (1 << N) == 0 }
452    }
453}
454
455impl<MODE, HL, const P: char, const N: u8> Pin<Output<MODE>, HL, P, N> {
456    #[inline]
457    pub fn set_high(&mut self) {
458        self._set_high()
459    }
460    #[inline]
461    pub fn set_low(&mut self) {
462        self._set_low()
463    }
464    #[inline(always)]
465    pub fn get_state(&self) -> PinState {
466        if self._is_set_low() {
467            PinState::Low
468        } else {
469            PinState::High
470        }
471    }
472    #[inline(always)]
473    pub fn set_state(&mut self, state: PinState) {
474        match state {
475            PinState::Low => self._set_low(),
476            PinState::High => self._set_high(),
477        }
478    }
479    #[inline]
480    pub fn is_set_high(&self) -> bool {
481        !self._is_set_low()
482    }
483    #[inline]
484    pub fn is_set_low(&self) -> bool {
485        self._is_set_low()
486    }
487    #[inline]
488    pub fn toggle(&mut self) {
489        if self._is_set_low() {
490            self._set_high()
491        } else {
492            self._set_low()
493        }
494    }
495}
496
497impl<MODE, HL, const P: char, const N: u8> OutputPin for Pin<Output<MODE>, HL, P, N> {
498    type Error = Infallible;
499    #[inline]
500    fn set_high(&mut self) -> Result<(), Self::Error> {
501        self.set_high();
502        Ok(())
503    }
504    #[inline]
505    fn set_low(&mut self) -> Result<(), Self::Error> {
506        self.set_low();
507        Ok(())
508    }
509}
510
511impl<MODE, HL, const P: char, const N: u8> StatefulOutputPin for Pin<Output<MODE>, HL, P, N> {
512    #[inline]
513    fn is_set_high(&self) -> Result<bool, Self::Error> {
514        Ok(self.is_set_high())
515    }
516    #[inline]
517    fn is_set_low(&self) -> Result<bool, Self::Error> {
518        Ok(self.is_set_low())
519    }
520}
521
522impl<MODE, HL, const P: char, const N: u8> ToggleableOutputPin for Pin<Output<MODE>, HL, P, N> {
523    type Error = Infallible;
524
525    #[inline(always)]
526    fn toggle(&mut self) -> Result<(), Self::Error> {
527        self.toggle();
528        Ok(())
529    }
530}
531
532impl<MODE, HL, const P: char, const N: u8> Pin<Input<MODE>, HL, P, N> {
533    #[inline]
534    pub fn is_high(&self) -> bool {
535        !self._is_low()
536    }
537    #[inline]
538    pub fn is_low(&self) -> bool {
539        self._is_low()
540    }
541}
542
543impl<MODE, HL, const P: char, const N: u8> InputPin for Pin<Input<MODE>, HL, P, N> {
544    type Error = Infallible;
545    #[inline]
546    fn is_high(&self) -> Result<bool, Self::Error> {
547        Ok(self.is_high())
548    }
549
550    #[inline]
551    fn is_low(&self) -> Result<bool, Self::Error> {
552        Ok(self.is_low())
553    }
554}
555
556impl<HL, const P: char, const N: u8> Pin<Output<OpenDrain>, HL, P, N> {
557    #[inline]
558    pub fn is_high(&self) -> bool {
559        !self._is_low()
560    }
561    #[inline]
562    pub fn is_low(&self) -> bool {
563        self._is_low()
564    }
565}
566
567impl<HL, const P: char, const N: u8> InputPin for Pin<Output<OpenDrain>, HL, P, N> {
568    type Error = Infallible;
569    #[inline]
570    fn is_high(&self) -> Result<bool, Self::Error> {
571        Ok(self.is_high())
572    }
573
574    #[inline]
575    fn is_low(&self) -> Result<bool, Self::Error> {
576        Ok(self.is_low())
577    }
578}
579
580/// Opaque AFR register
581pub struct Afr<HL, const P: char> {
582    _afr: PhantomData<HL>,
583}
584
585impl<HL, const P: char> Afr<HL, P> {
586    pub(crate) fn new() -> Self {
587        Self { _afr: PhantomData }
588    }
589}
590
591macro_rules! af {
592    ($HL:ident, $AFR:ident, $afr:ident) => {
593        #[doc(hidden)]
594        pub struct $HL {
595            _0: (),
596        }
597
598        impl<const P: char> Afr<$HL, P> {
599            #[allow(dead_code)]
600            pub(crate) fn afr(&mut self) -> &pac::gpioa::$AFR {
601                unsafe { &(*Gpio::<P>::ptr()).$afr }
602            }
603        }
604    };
605}
606
607af!(H8, AFRH, afrh);
608af!(L8, AFRL, afrl);
609
610gpio!(GPIOA, gpioa, PAx, 'A', 0, [
611    PA0: (pa0, 0, Analog, L8, exticr1),
612    PA1: (pa1, 1, Analog, L8, exticr1),
613    PA2: (pa2, 2, Analog, L8, exticr1),
614    PA3: (pa3, 3, Analog, L8, exticr1),
615    PA4: (pa4, 4, Analog, L8, exticr2),
616    PA5: (pa5, 5, Analog, L8, exticr2),
617    PA6: (pa6, 6, Analog, L8, exticr2),
618    PA7: (pa7, 7, Analog, L8, exticr2),
619    PA8: (pa8, 8, Analog, H8, exticr3),
620    PA9: (pa9, 9, Analog, H8, exticr3),
621    PA10: (pa10, 10, Analog, H8, exticr3),
622    PA11: (pa11, 11, Analog, H8, exticr3),
623    PA12: (pa12, 12, Analog, H8, exticr4),
624    PA13: (pa13, 13, super::Debugger, H8, exticr4), // SWDIO, PullUp VeryHigh speed
625    PA14: (pa14, 14, super::Debugger, H8, exticr4), // SWCLK, PullDown
626    PA15: (pa15, 15, super::Debugger, H8, exticr4), // JTDI, PullUp
627]);
628
629gpio!(GPIOB, gpiob, PBx, 'B', 1, [
630    PB0: (pb0, 0, Analog, L8, exticr1),
631    PB1: (pb1, 1, Analog, L8, exticr1),
632    PB2: (pb2, 2, Analog, L8, exticr1),
633    PB3: (pb3, 3, super::Debugger, L8, exticr1), // SWO
634    PB4: (pb4, 4, super::Debugger, L8, exticr2), // JTRST, PullUp
635    PB5: (pb5, 5, Analog, L8, exticr2),
636    PB6: (pb6, 6, Analog, L8, exticr2),
637    PB7: (pb7, 7, Analog, L8, exticr2),
638    PB8: (pb8, 8, Analog, H8, exticr3),
639    PB9: (pb9, 9, Analog, H8, exticr3),
640    PB10: (pb10, 10, Analog, H8, exticr3),
641    PB11: (pb11, 11, Analog, H8, exticr3),
642    PB12: (pb12, 12, Analog, H8, exticr4),
643    PB13: (pb13, 13, Analog, H8, exticr4),
644    PB14: (pb14, 14, Analog, H8, exticr4),
645    PB15: (pb15, 15, Analog, H8, exticr4),
646]);
647
648gpio!(GPIOC, gpioc, PCx, 'C', 2, [
649    PC0: (pc0, 0, Analog, L8, exticr1),
650    PC1: (pc1, 1, Analog, L8, exticr1),
651    PC2: (pc2, 2, Analog, L8, exticr1),
652    PC3: (pc3, 3, Analog, L8, exticr1),
653    PC4: (pc4, 4, Analog, L8, exticr2),
654    PC5: (pc5, 5, Analog, L8, exticr2),
655    PC6: (pc6, 6, Analog, L8, exticr2),
656    PC7: (pc7, 7, Analog, L8, exticr2),
657    PC8: (pc8, 8, Analog, H8, exticr3),
658    PC9: (pc9, 9, Analog, H8, exticr3),
659    PC10: (pc10, 10, Analog, H8, exticr3),
660    PC11: (pc11, 11, Analog, H8, exticr3),
661    PC12: (pc12, 12, Analog, H8, exticr4),
662    PC13: (pc13, 13, Analog, H8, exticr4),
663    PC14: (pc14, 14, Analog, H8, exticr4),
664    PC15: (pc15, 15, Analog, H8, exticr4),
665]);
666
667gpio!(GPIOD, gpiod, PDx, 'D', 3, [
668    PD0: (pd0, 0, Analog, L8, exticr1),
669    PD1: (pd1, 1, Analog, L8, exticr1),
670    PD2: (pd2, 2, Analog, L8, exticr1),
671    PD3: (pd3, 3, Analog, L8, exticr1),
672    PD4: (pd4, 4, Analog, L8, exticr2),
673    PD5: (pd5, 5, Analog, L8, exticr2),
674    PD6: (pd6, 6, Analog, L8, exticr2),
675    PD7: (pd7, 7, Analog, L8, exticr2),
676    PD8: (pd8, 8, Analog, H8, exticr3),
677    PD9: (pd9, 9, Analog, H8, exticr3),
678    PD10: (pd10, 10, Analog, H8, exticr3),
679    PD11: (pd11, 11, Analog, H8, exticr3),
680    PD12: (pd12, 12, Analog, H8, exticr4),
681    PD13: (pd13, 13, Analog, H8, exticr4),
682    PD14: (pd14, 14, Analog, H8, exticr4),
683    PD15: (pd15, 15, Analog, H8, exticr4),
684]);
685
686gpio!(GPIOE, gpioe, PEx, 'E', 4, [
687    PE0: (pe0, 0, Analog, L8, exticr1),
688    PE1: (pe1, 1, Analog, L8, exticr1),
689    PE2: (pe2, 2, Analog, L8, exticr1),
690    PE3: (pe3, 3, Analog, L8, exticr1),
691    PE4: (pe4, 4, Analog, L8, exticr2),
692    PE5: (pe5, 5, Analog, L8, exticr2),
693    PE6: (pe6, 6, Analog, L8, exticr2),
694    PE7: (pe7, 7, Analog, L8, exticr2),
695    PE8: (pe8, 8, Analog, H8, exticr3),
696    PE9: (pe9, 9, Analog, H8, exticr3),
697    PE10: (pe10, 10, Analog, H8, exticr3),
698    PE11: (pe11, 11, Analog, H8, exticr3),
699    PE12: (pe12, 12, Analog, H8, exticr4),
700    PE13: (pe13, 13, Analog, H8, exticr4),
701    PE14: (pe14, 14, Analog, H8, exticr4),
702    PE15: (pe15, 15, Analog, H8, exticr4),
703]);
704
705#[cfg(any(
706    // feature = "stm32l471",  // missing PAC support for Port G
707    feature = "stm32l475",
708    feature = "stm32l476",
709    feature = "stm32l485",
710    feature = "stm32l486",
711    feature = "stm32l496",
712    feature = "stm32l4a6",
713    // feature = "stm32l4p5",
714    // feature = "stm32l4q5",
715    // feature = "stm32l4r5",
716    // feature = "stm32l4s5",
717    // feature = "stm32l4r7",
718    // feature = "stm32l4s7",
719    feature = "stm32l4r9",
720    feature = "stm32l4s9",
721))]
722gpio!(GPIOF, gpiof, PFx, 'F', 5, [
723    PF0: (pf0, 0, Analog, L8, exticr1),
724    PF1: (pf1, 1, Analog, L8, exticr1),
725    PF2: (pf2, 2, Analog, L8, exticr1),
726    PF3: (pf3, 3, Analog, L8, exticr1),
727    PF4: (pf4, 4, Analog, L8, exticr2),
728    PF5: (pf5, 5, Analog, L8, exticr2),
729    PF6: (pf6, 6, Analog, L8, exticr2),
730    PF7: (pf7, 7, Analog, L8, exticr2),
731    PF8: (pf8, 8, Analog, H8, exticr3),
732    PF9: (pf9, 9, Analog, H8, exticr3),
733    PF10: (pf10, 10, Analog, H8, exticr3),
734    PF11: (pf11, 11, Analog, H8, exticr3),
735    PF12: (pf12, 12, Analog, H8, exticr4),
736    PF13: (pf13, 13, Analog, H8, exticr4),
737    PF14: (pf14, 14, Analog, H8, exticr4),
738    PF15: (pf15, 15, Analog, H8, exticr4),
739]);
740#[cfg(any(
741    // feature = "stm32l471",  // missing PAC support for Port G
742    feature = "stm32l475",
743    feature = "stm32l476",
744    feature = "stm32l485",
745    feature = "stm32l486",
746    feature = "stm32l496",
747    feature = "stm32l4a6",
748    // feature = "stm32l4p5",
749    // feature = "stm32l4q5",
750    // feature = "stm32l4r5",
751    // feature = "stm32l4s5",
752    // feature = "stm32l4r7",
753    // feature = "stm32l4s7",
754    feature = "stm32l4r9",
755    feature = "stm32l4s9",
756))]
757gpio!(GPIOG, gpiog, PGx, 'G', 6,
758    { unsafe { (*crate::pac::PWR::ptr()).cr2.modify(|_,w| w.iosv().set_bit()); } },
759[
760    PG0: (pg0, 0, Analog, L8, exticr1),
761    PG1: (pg1, 1, Analog, L8, exticr1),
762    PG2: (pg2, 2, Analog, L8, exticr1),
763    PG3: (pg3, 3, Analog, L8, exticr1),
764    PG4: (pg4, 4, Analog, L8, exticr2),
765    PG5: (pg5, 5, Analog, L8, exticr2),
766    PG6: (pg6, 6, Analog, L8, exticr2),
767    PG7: (pg7, 7, Analog, L8, exticr2),
768    PG8: (pg8, 8, Analog, H8, exticr3),
769    PG9: (pg9, 9, Analog, H8, exticr3),
770    PG10: (pg10, 10, Analog, H8, exticr3),
771    PG11: (pg11, 11, Analog, H8, exticr3),
772    PG12: (pg12, 12, Analog, H8, exticr4),
773    PG13: (pg13, 13, Analog, H8, exticr4),
774    PG14: (pg14, 14, Analog, H8, exticr4),
775    PG15: (pg15, 15, Analog, H8, exticr4),
776]);
777
778struct Gpio<const P: char>;
779impl<const P: char> Gpio<P> {
780    const fn ptr() -> *const crate::pac::gpioa::RegisterBlock {
781        match P {
782            'A' => crate::pac::GPIOA::ptr(),
783            'B' => crate::pac::GPIOB::ptr() as _,
784            'C' => crate::pac::GPIOC::ptr() as _,
785            'D' => crate::pac::GPIOD::ptr() as _,
786            'E' => crate::pac::GPIOE::ptr() as _,
787            #[cfg(any(
788                // feature = "stm32l471",  // missing PAC support for Port F
789                feature = "stm32l475",
790                feature = "stm32l476",
791                feature = "stm32l485",
792                feature = "stm32l486",
793                feature = "stm32l496",
794                feature = "stm32l4a6",
795                // feature = "stm32l4p5",
796                // feature = "stm32l4q5",
797                // feature = "stm32l4r5",
798                // feature = "stm32l4s5",
799                // feature = "stm32l4r7",
800                // feature = "stm32l4s7",
801                feature = "stm32l4r9",
802                feature = "stm32l4s9",
803            ))]
804            'F' => crate::pac::GPIOF::ptr() as _,
805            #[cfg(any(
806                // feature = "stm32l471",  // missing PAC support for Port G
807                feature = "stm32l475",
808                feature = "stm32l476",
809                feature = "stm32l485",
810                feature = "stm32l486",
811                feature = "stm32l496",
812                feature = "stm32l4a6",
813                // feature = "stm32l4p5",
814                // feature = "stm32l4q5",
815                // feature = "stm32l4r5",
816                // feature = "stm32l4s5",
817                // feature = "stm32l4r7",
818                // feature = "stm32l4s7",
819                feature = "stm32l4r9",
820                feature = "stm32l4s9",
821            ))]
822            'G' => crate::pac::GPIOG::ptr() as _,
823            _ => crate::pac::GPIOA::ptr(),
824        }
825    }
826}