stm32f1_hal/gpio/
mod.rs

1//! # General Purpose I/Os
2//!
3//! The GPIO pins are organised into groups of 16 pins which can be accessed through the
4//! `gpioa`, `gpiob`... modules. To get access to the pins, you first need to convert them into a
5//! HAL designed struct from the `pac` struct using the [split](trait.GpioExt.html#tymethod.split) function.
6//! ```rust
7//! // Acquire the GPIOC peripheral
8//! // NOTE: `dp` is the device peripherals from the `PAC` crate
9//! let mut gpioa = dp.GPIOA.split();
10//! ```
11//!
12//! This gives you a struct containing two control registers `crl` and `crh`, and all the pins
13//! `px0..px15`. These structs are what you use to interract with the pins to change their modes,
14//! or their inputs or outputs. For example, to set `pa5` high, you would call
15//!
16//! ```rust
17//! let output = gpioa.pa5.into_push_pull_output(&mut gpioa.crl);
18//! output.set_high();
19//! ```
20//!
21//! ## Modes
22//!
23//! Each GPIO pin can be set to various modes:
24//!
25//! - **Alternate**: Pin mode required when the pin is driven by other peripherals
26//! - **Dynamic**: Pin mode is selected at runtime. See changing configurations for more details
27//! - Input
28//!     - **PullUp**: Input connected to high with a weak pull-up resistor. Will be high when nothing
29//!       is connected
30//!     - **PullDown**: Input connected to ground with a weak pull-down resistor. Will be low when nothing
31//!       is connected
32//!     - **Floating**: Input not pulled to high or low. Will be undefined when nothing is connected
33//! - Output
34//!     - **PushPull**: Output which either drives the pin high or low
35//!     - **OpenDrain**: Output which leaves the gate floating, or pulls it to ground in drain
36//!       mode. Can be used as an input in the `open` configuration
37//! - **Debugger**: Some pins start out being used by the debugger. A pin in this mode can only be
38//!   used if the [JTAG peripheral has been turned off](#accessing-pa15-pb3-and-pb14).
39//!
40//! ## Changing modes
41//! The simplest way to change the pin mode is to use the `into_<mode>` functions. These return a
42//! new struct with the correct mode that you can use the input or output functions on.
43//!
44//! If you need a more temporary mode change, and can not use the `into_<mode>` functions for
45//! ownership reasons, you can use the `as_<mode>` functions to temporarily change the pin type, do
46//! some output or input, and then have it change back once done.
47//!
48//! ### Dynamic Mode Change
49//! The above mode change methods guarantee that you can only call input functions when the pin is
50//! in input mode, and output when in output modes, but can lead to some issues. Therefore, there
51//! is also a mode where the state is kept track of at runtime, allowing you to change the mode
52//! often, and without problems with ownership, or references, at the cost of some performance and
53//! the risk of runtime errors.
54//!
55//! To make a pin dynamic, use the `into_dynamic` function, and then use the `make_<mode>` functions to
56//! change the mode
57//!
58//! ## Accessing PA15, PB3, and PB14
59//!
60//! These pins are used by the JTAG peripheral by default. To use them in your program, you need to
61//! disable that peripheral. This is done using the [afio::MAPR::disable_jtag](../afio/struct.MAPR.html#method.disable_jtag) function
62//!
63//! # Interfacing with v1 traits
64//!
65//! `embedded-hal` has two versions of the digital traits, `v2` which is used by this crate and
66//! `v1` which is deprecated but still used by a lot of drivers.  If you want to use such a driver
67//! with this crate, you need to convert the digital pins to the `v1` type.
68//!
69//! This is done using `embedded-hal::digital::v1_compat::OldOutputPin`. For example:
70//!
71//! ```rust
72//! let nss = gpioa.pa4.into_push_pull_output(&mut gpioa.crl);
73//! let mut mfrc522 = Mfrc522::new(spi, OldOutputPin::from(nss)).unwrap();
74//! ```
75
76use core::marker::PhantomData;
77
78use crate::afio;
79use crate::pac::{EXTI, RCC};
80
81mod partially_erased;
82pub use partially_erased::{PEPin, PartiallyErasedPin};
83mod erased;
84pub use erased::{AnyPin, ErasedPin};
85
86mod impl_hal;
87
88/// Slew rates available for Output and relevant AlternateMode Pins
89///
90/// See Table 21 "Output MODE bits" in the reference
91pub enum IOPinSpeed {
92    /// Slew at 10Mhz
93    Mhz10 = 0b01, // (yes, this one is "less" then 2Mhz)
94    /// Slew at 2Mhz
95    Mhz2 = 0b10,
96    /// Slew at 50Mhz
97    Mhz50 = 0b11,
98}
99
100impl From<IOPinSpeed> for Mode {
101    fn from(value: IOPinSpeed) -> Self {
102        match value {
103            IOPinSpeed::Mhz10 => Self::Output,
104            IOPinSpeed::Mhz2 => Self::Output2,
105            IOPinSpeed::Mhz50 => Self::Output50,
106        }
107    }
108}
109
110pub trait PinExt {
111    type Mode;
112
113    /// Return pin number
114    fn pin_id(&self) -> u8;
115
116    /// Return port number
117    fn port_id(&self) -> u8;
118}
119
120/// Allow setting of the slew rate of an IO pin
121///
122/// Initially all pins are set to the maximum slew rate
123pub trait OutputSpeed: HL {
124    fn set_speed(&mut self, cr: &mut Self::Cr, speed: IOPinSpeed);
125}
126
127/// Extension trait to split a GPIO peripheral in independent pins and registers
128pub trait GpioExt {
129    /// The to split the GPIO into
130    type Parts;
131
132    /// Splits the GPIO block into independent pins and registers.
133    ///
134    /// This resets the state of the GPIO block.
135    fn split(self, rcc: &mut RCC) -> Self::Parts;
136
137    /// Splits the GPIO block into independent pins and registers without resetting its state.
138    ///
139    /// # Safety
140    /// Make sure that all pins modes are set in reset state.
141    unsafe fn split_without_reset(self, rcc: &mut RCC) -> Self::Parts;
142}
143
144/// Marker trait for active states.
145pub trait Active {}
146
147/// Marker trait for Floating or PullUp inputs
148pub trait UpMode {}
149impl UpMode for Floating {}
150impl UpMode for PullUp {}
151
152/// Input mode (type state)
153#[derive(Default)]
154pub struct Input<PULL = Floating>(PhantomData<PULL>);
155
156impl<PULL> Active for Input<PULL> {}
157
158/// Used by the debugger (type state)
159#[derive(Default)]
160pub struct Debugger;
161
162/// Floating input (type state)
163#[derive(Default)]
164pub struct Floating;
165
166/// Pulled down input (type state)
167#[derive(Default)]
168pub struct PullDown;
169
170/// Pulled up input (type state)
171#[derive(Default)]
172pub struct PullUp;
173
174/// Output mode (type state)
175#[derive(Default)]
176pub struct Output<Otype = PushPull>(PhantomData<Otype>);
177
178impl<MODE> Active for Output<MODE> {}
179
180/// Push pull output (type state)
181#[derive(Default)]
182pub struct PushPull;
183
184/// Open drain output (type state)
185#[derive(Default)]
186pub struct OpenDrain;
187
188/// Analog mode (type state)
189#[derive(Default)]
190pub struct Analog;
191
192impl Active for Analog {}
193
194/// Alternate function
195#[derive(Default)]
196pub struct Alternate<Otype = PushPull>(PhantomData<Otype>);
197
198impl<MODE> Active for Alternate<MODE> {}
199
200/// Digital output pin state
201pub use embedded_hal::digital::PinState;
202
203// Using SCREAMING_SNAKE_CASE to be consistent with other HALs
204// see 59b2740 and #125 for motivation
205#[allow(non_camel_case_types)]
206#[derive(Debug, PartialEq, Eq, Clone, Copy)]
207pub enum Edge {
208    Rising,
209    Falling,
210    RisingFalling,
211}
212
213mod sealed {
214    /// Marker trait that show if `ExtiPin` can be implemented
215    pub trait Interruptable {}
216
217    pub trait PinMode: Default {
218        const CNF: super::Cnf;
219        const MODE: super::Mode;
220        const PULL: Option<bool> = None;
221    }
222}
223
224use crate::pac::gpioa::crl::{CONFIG as Cnf, MODE as Mode};
225
226use sealed::Interruptable;
227pub(crate) use sealed::PinMode;
228
229impl<MODE> Interruptable for Input<MODE> {}
230impl Interruptable for Dynamic {}
231
232/// External Interrupt Pin
233pub trait ExtiPin {
234    fn make_interrupt_source(&mut self, afio: &mut afio::Afio);
235    fn trigger_on_edge(&mut self, exti: &mut EXTI, level: Edge);
236    fn enable_interrupt(&mut self, exti: &mut EXTI);
237    fn disable_interrupt(&mut self, exti: &mut EXTI);
238    fn clear_interrupt_pending_bit(&mut self);
239    fn check_interrupt(&self) -> bool;
240}
241
242impl<PIN> ExtiPin for PIN
243where
244    PIN: PinExt,
245    PIN::Mode: Interruptable,
246{
247    /// Make corresponding EXTI line sensitive to this pin
248    fn make_interrupt_source(&mut self, afio: &mut afio::Afio) {
249        let pin_number = self.pin_id();
250        let port = self.port_id() as u32;
251        let offset = 4 * (pin_number % 4);
252        match pin_number {
253            0..=3 => {
254                afio.exticr1.exticr1().modify(|r, w| unsafe {
255                    w.bits((r.bits() & !(0xf << offset)) | (port << offset))
256                });
257            }
258            4..=7 => {
259                afio.exticr2.exticr2().modify(|r, w| unsafe {
260                    w.bits((r.bits() & !(0xf << offset)) | (port << offset))
261                });
262            }
263            8..=11 => {
264                afio.exticr3.exticr3().modify(|r, w| unsafe {
265                    w.bits((r.bits() & !(0xf << offset)) | (port << offset))
266                });
267            }
268            12..=15 => {
269                afio.exticr4.exticr4().modify(|r, w| unsafe {
270                    w.bits((r.bits() & !(0xf << offset)) | (port << offset))
271                });
272            }
273            _ => unreachable!(),
274        }
275    }
276
277    /// Generate interrupt on rising edge, falling edge or both
278    fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: Edge) {
279        let pin_number = self.pin_id();
280        match edge {
281            Edge::Rising => {
282                exti.rtsr()
283                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << pin_number)) });
284                exti.ftsr()
285                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << pin_number)) });
286            }
287            Edge::Falling => {
288                exti.rtsr()
289                    .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << pin_number)) });
290                exti.ftsr()
291                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << pin_number)) });
292            }
293            Edge::RisingFalling => {
294                exti.rtsr()
295                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << pin_number)) });
296                exti.ftsr()
297                    .modify(|r, w| unsafe { w.bits(r.bits() | (1 << pin_number)) });
298            }
299        }
300    }
301
302    /// Enable external interrupts from this pin.
303    fn enable_interrupt(&mut self, exti: &mut EXTI) {
304        exti.imr()
305            .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.pin_id())) });
306    }
307
308    /// Disable external interrupts from this pin
309    fn disable_interrupt(&mut self, exti: &mut EXTI) {
310        exti.imr()
311            .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id())) });
312    }
313
314    /// Clear the interrupt pending bit for this pin
315    fn clear_interrupt_pending_bit(&mut self) {
316        unsafe { (*EXTI::ptr()).pr().write(|w| w.bits(1 << self.pin_id())) };
317    }
318
319    /// Reads the interrupt pending bit for this pin
320    fn check_interrupt(&self) -> bool {
321        unsafe { ((*EXTI::ptr()).pr().read().bits() & (1 << self.pin_id())) != 0 }
322    }
323}
324
325/// Tracks the current pin state for dynamic pins
326pub enum Dynamic {
327    InputFloating,
328    InputPullUp,
329    InputPullDown,
330    OutputPushPull,
331    OutputOpenDrain,
332}
333
334impl Default for Dynamic {
335    fn default() -> Self {
336        Dynamic::InputFloating
337    }
338}
339
340impl Active for Dynamic {}
341
342#[derive(Debug, PartialEq, Eq)]
343pub enum PinModeError {
344    IncorrectMode,
345}
346
347impl Dynamic {
348    fn is_input(&self) -> bool {
349        use Dynamic::*;
350        match self {
351            InputFloating | InputPullUp | InputPullDown | OutputOpenDrain => true,
352            OutputPushPull => false,
353        }
354    }
355
356    fn is_output(&self) -> bool {
357        use Dynamic::*;
358        match self {
359            InputFloating | InputPullUp | InputPullDown => false,
360            OutputPushPull | OutputOpenDrain => true,
361        }
362    }
363}
364
365macro_rules! gpio {
366    ($GPIOX:ident, $gpiox:ident, $PXx:ident, $port_id:expr, [
367        $($PXi:ident: ($pxi:ident, $pin_number:expr $(, $MODE:ty)?),)+
368    ]) => {
369        /// GPIO
370        pub mod $gpiox {
371            use crate::pac::{$GPIOX, RCC};
372            use crate::rcc::{Enable, Reset};
373            use super::{Active, Floating, GpioExt, Input, PartiallyErasedPin, ErasedPin, Pin, Cr};
374            #[allow(unused)]
375            use super::Debugger;
376
377            /// GPIO parts
378            pub struct Parts {
379                /// Opaque CRL register
380                pub crl: Cr<$port_id, false>,
381                /// Opaque CRH register
382                pub crh: Cr<$port_id, true>,
383                $(
384                    /// Pin
385                    pub $pxi: $PXi $(<$MODE>)?,
386                )+
387            }
388
389            $(
390                pub type $PXi<MODE = Input<Floating>> = Pin<$port_id, $pin_number, MODE>;
391            )+
392
393            impl GpioExt for $GPIOX {
394                type Parts = Parts;
395
396                fn split(self, rcc: &mut RCC) -> Parts {
397                        $GPIOX::enable(rcc);
398                        $GPIOX::reset(rcc);
399
400                    Parts {
401                        crl: Cr::<$port_id, false>,
402                        crh: Cr::<$port_id, true>,
403                        $(
404                            $pxi: $PXi::new(),
405                        )+
406                    }
407                }
408
409                unsafe fn split_without_reset(self, rcc: &mut RCC) -> Parts {
410                        $GPIOX::enable(rcc);
411
412                    Parts {
413                        crl: Cr::<$port_id, false>,
414                        crh: Cr::<$port_id, true>,
415                        $(
416                            $pxi: $PXi::new(),
417                        )+
418                    }
419                }
420            }
421
422            impl<MODE> PartiallyErasedPin<$port_id, MODE> {
423                pub fn erase(self) -> ErasedPin<MODE> {
424                    ErasedPin::$PXx(self)
425                }
426            }
427
428            impl<const N: u8, MODE> Pin<$port_id, N, MODE>
429            where
430                MODE: Active,
431            {
432                /// Erases the pin number and port from the type
433                ///
434                /// This is useful when you want to collect the pins into an array where you
435                /// need all the elements to have the same type
436                pub fn erase(self) -> ErasedPin<MODE> {
437                    self.erase_number().erase()
438                }
439            }
440        }
441
442        pub use $gpiox::{ $($PXi,)+ };
443    }
444}
445
446/// Generic pin type
447///
448/// - `P` is port name: `A` for GPIOA, `B` for GPIOB, etc.
449/// - `N` is pin number: from `0` to `15`.
450/// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section).
451pub struct Pin<const P: char, const N: u8, MODE = Input<Floating>> {
452    mode: MODE,
453}
454
455/// Represents high or low configuration register
456pub trait HL {
457    /// Configuration register associated to pin
458    type Cr;
459}
460
461macro_rules! cr {
462    ($cr_is_h:literal: [$($pin_number:literal),+]) => {
463        $(
464            impl<const P: char, MODE> HL for Pin<P, $pin_number, MODE> {
465                type Cr = Cr<P, $cr_is_h>;
466            }
467        )+
468    }
469}
470
471cr!(false: [0, 1, 2, 3, 4, 5, 6, 7]);
472cr!(true: [8, 9, 10, 11, 12, 13, 14, 15]);
473
474impl<const P: char, const N: u8, MODE: Default> Pin<P, N, MODE> {
475    fn new() -> Self {
476        Self {
477            mode: Default::default(),
478        }
479    }
480}
481
482impl<const P: char, const N: u8, MODE> PinExt for Pin<P, N, MODE> {
483    type Mode = MODE;
484
485    #[inline(always)]
486    fn pin_id(&self) -> u8 {
487        N
488    }
489
490    #[inline(always)]
491    fn port_id(&self) -> u8 {
492        P as u8 - b'A'
493    }
494}
495
496impl<const P: char, const N: u8> Pin<P, N, Debugger> {
497    /// Put the pin in an active state. The caller
498    /// must enforce that the pin is really in this
499    /// state in the hardware.
500    #[allow(dead_code)]
501    pub(crate) unsafe fn activate(self) -> Pin<P, N, Input<Floating>> {
502        Pin::new()
503    }
504}
505
506// Internal helper functions
507
508// NOTE: The functions in this impl block are "safe", but they
509// are callable when the pin is in modes where they don't make
510// sense.
511impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
512    /**
513      Set the output of the pin regardless of its mode.
514      Primarily used to set the output value of the pin
515      before changing its mode to an output to avoid
516      a short spike of an incorrect value
517    */
518    #[inline(always)]
519    fn _set_state(&mut self, state: PinState) {
520        match state {
521            PinState::High => self._set_high(),
522            PinState::Low => self._set_low(),
523        }
524    }
525
526    #[inline(always)]
527    fn _set_high(&mut self) {
528        // NOTE(unsafe) atomic write to a stateless register
529        let gpio = unsafe { &(*gpiox::<P>()) };
530        gpio.bsrr().write(|w| w.bs(N).set_bit());
531    }
532
533    #[inline(always)]
534    fn _set_low(&mut self) {
535        // NOTE(unsafe) atomic write to a stateless register
536        let gpio = unsafe { &(*gpiox::<P>()) };
537        gpio.bsrr().write(|w| w.br(N).set_bit());
538    }
539
540    #[inline(always)]
541    fn _is_set_low(&self) -> bool {
542        // NOTE(unsafe) atomic read with no side effects
543        let gpio = unsafe { &(*gpiox::<P>()) };
544        gpio.odr().read().odr(N).bit_is_clear()
545    }
546
547    #[inline(always)]
548    fn _is_low(&self) -> bool {
549        // NOTE(unsafe) atomic read with no side effects
550        let gpio = unsafe { &(*gpiox::<P>()) };
551        gpio.idr().read().idr(N).bit_is_clear()
552    }
553}
554
555impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
556where
557    MODE: Active,
558{
559    /// Erases the pin number from the type
560    #[inline]
561    pub fn erase_number(self) -> PartiallyErasedPin<P, MODE> {
562        PartiallyErasedPin::new(N)
563    }
564}
565
566impl<const P: char, const N: u8, MODE> Pin<P, N, Output<MODE>> {
567    #[inline]
568    pub fn set_high(&mut self) {
569        self._set_high()
570    }
571
572    #[inline]
573    pub fn set_low(&mut self) {
574        self._set_low()
575    }
576
577    #[inline(always)]
578    pub fn get_state(&self) -> PinState {
579        if self._is_set_low() {
580            PinState::Low
581        } else {
582            PinState::High
583        }
584    }
585
586    #[inline(always)]
587    pub fn set_state(&mut self, state: PinState) {
588        self._set_state(state)
589    }
590
591    #[inline]
592    pub fn is_set_high(&self) -> bool {
593        !self._is_set_low()
594    }
595
596    #[inline]
597    pub fn is_set_low(&self) -> bool {
598        self._is_set_low()
599    }
600
601    #[inline]
602    pub fn toggle(&mut self) {
603        if self._is_set_low() {
604            self._set_high()
605        } else {
606            self._set_low()
607        }
608    }
609}
610
611impl<const P: char, const N: u8, MODE> Pin<P, N, Input<MODE>> {
612    #[inline]
613    pub fn is_high(&self) -> bool {
614        !self._is_low()
615    }
616
617    #[inline]
618    pub fn is_low(&self) -> bool {
619        self._is_low()
620    }
621}
622
623impl<const P: char, const N: u8> Pin<P, N, Output<OpenDrain>> {
624    #[inline]
625    pub fn is_high(&self) -> bool {
626        !self._is_low()
627    }
628
629    #[inline]
630    pub fn is_low(&self) -> bool {
631        self._is_low()
632    }
633}
634
635/// Opaque CR register
636#[non_exhaustive]
637pub struct Cr<const P: char, const H: bool>;
638
639impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
640where
641    MODE: Active,
642    Self: HL,
643{
644    /// Configures the pin to operate as an alternate function push-pull output
645    /// pin.
646    #[inline]
647    pub fn into_alternate_push_pull(
648        self,
649        cr: &mut <Self as HL>::Cr,
650    ) -> Pin<P, N, Alternate<PushPull>> {
651        self.into_mode(cr)
652    }
653
654    /// Configures the pin to operate as an alternate function open-drain output
655    /// pin.
656    #[inline]
657    pub fn into_alternate_open_drain(
658        self,
659        cr: &mut <Self as HL>::Cr,
660    ) -> Pin<P, N, Alternate<OpenDrain>> {
661        self.into_mode(cr)
662    }
663
664    /// Configures the pin to operate as a floating input pin
665    #[inline]
666    pub fn into_floating_input(self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Input<Floating>> {
667        self.into_mode(cr)
668    }
669
670    /// Configures the pin to operate as a pulled down input pin
671    #[inline]
672    pub fn into_pull_down_input(self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Input<PullDown>> {
673        self.into_mode(cr)
674    }
675
676    /// Configures the pin to operate as a pulled up input pin
677    #[inline]
678    pub fn into_pull_up_input(self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Input<PullUp>> {
679        self.into_mode(cr)
680    }
681
682    /// Configures the pin to operate as an open-drain output pin.
683    /// Initial state will be low.
684    #[inline]
685    pub fn into_open_drain_output(self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Output<OpenDrain>> {
686        self.into_open_drain_output_with_state(cr, PinState::Low)
687    }
688
689    /// Configures the pin to operate as an open-drain output pin.
690    /// `initial_state` specifies whether the pin should be initially high or low.
691    #[inline]
692    pub fn into_open_drain_output_with_state(
693        mut self,
694        cr: &mut <Self as HL>::Cr,
695        initial_state: PinState,
696    ) -> Pin<P, N, Output<OpenDrain>> {
697        self._set_state(initial_state);
698        self.into_mode(cr)
699    }
700
701    /// Configures the pin to operate as an push-pull output pin.
702    /// Initial state will be low.
703    #[inline]
704    pub fn into_push_pull_output(self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Output<PushPull>> {
705        self.into_push_pull_output_with_state(cr, PinState::Low)
706    }
707
708    /// Configures the pin to operate as an push-pull output pin.
709    /// `initial_state` specifies whether the pin should be initially high or low.
710    #[inline]
711    pub fn into_push_pull_output_with_state(
712        mut self,
713        cr: &mut <Self as HL>::Cr,
714        initial_state: PinState,
715    ) -> Pin<P, N, Output<PushPull>> {
716        self._set_state(initial_state);
717        self.into_mode(cr)
718    }
719
720    /// Configures the pin to operate as an push-pull output pin.
721    /// The state will not be changed.
722    #[inline]
723    pub fn into_push_pull_output_with_current_state(
724        self,
725        cr: &mut <Self as HL>::Cr,
726    ) -> Pin<P, N, Output<PushPull>> {
727        self.into_mode(cr)
728    }
729
730    /// Configures the pin to operate as an analog input pin
731    #[inline]
732    pub fn into_analog(self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Analog> {
733        self.into_mode(cr)
734    }
735
736    /// Configures the pin as a pin that can change between input
737    /// and output without changing the type. It starts out
738    /// as a floating input
739    #[inline]
740    pub fn into_dynamic(mut self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, Dynamic> {
741        self.mode::<Input<Floating>>(cr);
742        Pin::new()
743    }
744}
745
746// These macros are defined here instead of at the top level in order
747// to be able to refer to macro variables from the outer layers.
748macro_rules! impl_temp_output {
749    ($fn_name:ident, $stateful_fn_name:ident, $mode:ty) => {
750        /// Temporarily change the mode of the pin.
751        ///
752        /// The value of the pin after conversion is undefined. If you
753        /// want to control it, use `$stateful_fn_name`
754        #[inline]
755        pub fn $fn_name(
756            &mut self,
757            cr: &mut <Self as HL>::Cr,
758            mut f: impl FnMut(&mut Pin<P, N, $mode>),
759        ) {
760            self.mode::<$mode>(cr);
761            let mut temp = Pin::<P, N, $mode>::new();
762            f(&mut temp);
763            self.mode::<$mode>(cr);
764            Self::new();
765        }
766
767        /// Temporarily change the mode of the pin.
768        ///
769        /// Note that the new state is set slightly before conversion
770        /// happens. This can cause a short output glitch if switching
771        /// between output modes
772        #[inline]
773        pub fn $stateful_fn_name(
774            &mut self,
775            cr: &mut <Self as HL>::Cr,
776            state: PinState,
777            mut f: impl FnMut(&mut Pin<P, N, $mode>),
778        ) {
779            self._set_state(state);
780            self.mode::<$mode>(cr);
781            let mut temp = Pin::<P, N, $mode>::new();
782            f(&mut temp);
783            self.mode::<$mode>(cr);
784            Self::new();
785        }
786    };
787}
788macro_rules! impl_temp_input {
789    ($fn_name:ident, $mode:ty) => {
790        /// Temporarily change the mode of the pin.
791        #[inline]
792        pub fn $fn_name(
793            &mut self,
794            cr: &mut <Self as HL>::Cr,
795            mut f: impl FnMut(&mut Pin<P, N, $mode>),
796        ) {
797            self.mode::<$mode>(cr);
798            let mut temp = Pin::<P, N, $mode>::new();
799            f(&mut temp);
800            self.mode::<$mode>(cr);
801            Self::new();
802        }
803    };
804}
805
806impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
807where
808    MODE: Active + PinMode,
809    Self: HL,
810{
811    impl_temp_output!(
812        as_push_pull_output,
813        as_push_pull_output_with_state,
814        Output<PushPull>
815    );
816    impl_temp_output!(
817        as_open_drain_output,
818        as_open_drain_output_with_state,
819        Output<OpenDrain>
820    );
821    impl_temp_input!(as_floating_input, Input<Floating>);
822    impl_temp_input!(as_pull_up_input, Input<PullUp>);
823    impl_temp_input!(as_pull_down_input, Input<PullDown>);
824}
825
826impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
827where
828    Self: HL,
829{
830    #[inline(always)]
831    fn _set_speed(&mut self, _cr: &mut <Self as HL>::Cr, speed: IOPinSpeed) {
832        let gpio = unsafe { &(*gpiox::<P>()) };
833
834        match N {
835            0..=7 => {
836                gpio.crl().modify(|_, w| w.mode(N).variant(speed.into()));
837            }
838            8..=15 => {
839                gpio.crh()
840                    .modify(|_, w| unsafe { w.mode(N - 8).bits(speed as u8) });
841            }
842            _ => unreachable!(),
843        }
844    }
845}
846
847impl<const P: char, const N: u8, MODE> OutputSpeed for Pin<P, N, Output<MODE>>
848where
849    Self: HL,
850{
851    fn set_speed(&mut self, cr: &mut <Self as HL>::Cr, speed: IOPinSpeed) {
852        self._set_speed(cr, speed)
853    }
854}
855
856impl<const P: char, const N: u8> OutputSpeed for Pin<P, N, Alternate<PushPull>>
857where
858    Self: HL,
859{
860    fn set_speed(&mut self, cr: &mut <Self as HL>::Cr, speed: IOPinSpeed) {
861        self._set_speed(cr, speed)
862    }
863}
864
865// Dynamic pin
866
867impl<const P: char, const N: u8> Pin<P, N, Dynamic>
868where
869    Self: HL,
870{
871    #[inline]
872    pub fn make_pull_up_input(&mut self, cr: &mut <Self as HL>::Cr) {
873        // NOTE(unsafe), we have a mutable reference to the current pin
874        self.mode::<Input<PullUp>>(cr);
875        self.mode = Dynamic::InputPullUp;
876    }
877
878    #[inline]
879    pub fn make_pull_down_input(&mut self, cr: &mut <Self as HL>::Cr) {
880        // NOTE(unsafe), we have a mutable reference to the current pin
881        self.mode::<Input<PullDown>>(cr);
882        self.mode = Dynamic::InputPullDown;
883    }
884
885    #[inline]
886    pub fn make_floating_input(&mut self, cr: &mut <Self as HL>::Cr) {
887        // NOTE(unsafe), we have a mutable reference to the current pin
888        self.mode::<Input<Floating>>(cr);
889        self.mode = Dynamic::InputFloating;
890    }
891
892    #[inline]
893    pub fn make_push_pull_output(&mut self, cr: &mut <Self as HL>::Cr) {
894        // NOTE(unsafe), we have a mutable reference to the current pin
895        self.mode::<Output<PushPull>>(cr);
896        self.mode = Dynamic::OutputPushPull;
897    }
898
899    #[inline]
900    pub fn make_open_drain_output(&mut self, cr: &mut <Self as HL>::Cr) {
901        // NOTE(unsafe), we have a mutable reference to the current pin
902        self.mode::<Output<OpenDrain>>(cr);
903        self.mode = Dynamic::OutputOpenDrain;
904    }
905}
906
907impl PinMode for Analog {
908    const MODE: Mode = Mode::Input;
909    const CNF: Cnf = Cnf::PushPull;
910}
911
912impl PinMode for Input<Floating> {
913    const MODE: Mode = Mode::Input;
914    const CNF: Cnf = Cnf::OpenDrain;
915}
916
917impl PinMode for Input<PullDown> {
918    const MODE: Mode = Mode::Input;
919    const CNF: Cnf = Cnf::AltPushPull;
920    const PULL: Option<bool> = Some(false);
921}
922
923impl PinMode for Input<PullUp> {
924    const MODE: Mode = Mode::Input;
925    const CNF: Cnf = Cnf::AltPushPull;
926    const PULL: Option<bool> = Some(true);
927}
928
929impl PinMode for Output<PushPull> {
930    const MODE: Mode = Mode::Output50;
931    const CNF: Cnf = Cnf::PushPull;
932}
933
934impl PinMode for Output<OpenDrain> {
935    const MODE: Mode = Mode::Output50;
936    const CNF: Cnf = Cnf::OpenDrain;
937}
938
939impl PinMode for Alternate<PushPull> {
940    const MODE: Mode = Mode::Output50;
941    const CNF: Cnf = Cnf::AltPushPull;
942}
943
944impl PinMode for Alternate<OpenDrain> {
945    const MODE: Mode = Mode::Output50;
946    const CNF: Cnf = Cnf::AltOpenDrain;
947}
948
949impl<const P: char, const N: u8, M> Pin<P, N, M>
950where
951    Self: HL,
952{
953    fn mode<MODE: PinMode>(&mut self, _cr: &mut <Self as HL>::Cr) {
954        let gpio = unsafe { &(*gpiox::<P>()) };
955
956        // Input<PullUp> or Input<PullDown> mode
957        if let Some(pull) = MODE::PULL {
958            gpio.bsrr().write(|w| {
959                if pull {
960                    w.bs(N).set_bit()
961                } else {
962                    w.br(N).set_bit()
963                }
964            });
965        }
966
967        match N {
968            0..=7 => {
969                gpio.crl()
970                    .modify(|_, w| w.mode(N).variant(MODE::MODE).cnf(N).variant(MODE::CNF));
971            }
972            8..=15 => {
973                gpio.crh().modify(|_, w| unsafe {
974                    w.mode(N - 8).bits(MODE::MODE as u8);
975                    w.cnf(N - 8).bits(MODE::CNF as u8)
976                });
977            }
978            _ => unreachable!(),
979        }
980    }
981
982    #[inline]
983    pub(crate) fn into_mode<MODE: PinMode>(mut self, cr: &mut <Self as HL>::Cr) -> Pin<P, N, MODE> {
984        self.mode::<MODE>(cr);
985        Pin::new()
986    }
987}
988
989impl Analog {
990    pub fn new<const P: char, const N: u8, MODE>(
991        pin: Pin<P, N, MODE>,
992        cr: &mut <Pin<P, N, MODE> as HL>::Cr,
993    ) -> Pin<P, N, Self>
994    where
995        Pin<P, N, MODE>: HL,
996        Self: PinMode,
997    {
998        pin.into_mode(cr)
999    }
1000}
1001
1002impl<PULL> Input<PULL> {
1003    pub fn new<const P: char, const N: u8, MODE>(
1004        pin: Pin<P, N, MODE>,
1005        cr: &mut <Pin<P, N, MODE> as HL>::Cr,
1006        _pull: PULL,
1007    ) -> Pin<P, N, Self>
1008    where
1009        Pin<P, N, MODE>: HL,
1010        Self: PinMode,
1011    {
1012        pin.into_mode(cr)
1013    }
1014}
1015
1016impl<Otype> Output<Otype> {
1017    pub fn new<const P: char, const N: u8, MODE>(
1018        mut pin: Pin<P, N, MODE>,
1019        cr: &mut <Pin<P, N, MODE> as HL>::Cr,
1020        state: PinState,
1021    ) -> Pin<P, N, Self>
1022    where
1023        Pin<P, N, MODE>: HL,
1024        Self: PinMode,
1025    {
1026        pin._set_state(state);
1027        pin.into_mode(cr)
1028    }
1029}
1030
1031impl<Otype> Alternate<Otype> {
1032    pub fn new<const P: char, const N: u8, MODE>(
1033        pin: Pin<P, N, MODE>,
1034        cr: &mut <Pin<P, N, MODE> as HL>::Cr,
1035    ) -> Pin<P, N, Self>
1036    where
1037        Pin<P, N, MODE>: HL,
1038        Self: PinMode,
1039    {
1040        pin.into_mode(cr)
1041    }
1042}
1043
1044gpio!(GPIOA, gpioa, PAx, 'A', [
1045    PA0: (pa0, 0),
1046    PA1: (pa1, 1),
1047    PA2: (pa2, 2),
1048    PA3: (pa3, 3),
1049    PA4: (pa4, 4),
1050    PA5: (pa5, 5),
1051    PA6: (pa6, 6),
1052    PA7: (pa7, 7),
1053    PA8: (pa8, 8),
1054    PA9: (pa9, 9),
1055    PA10: (pa10, 10),
1056    PA11: (pa11, 11),
1057    PA12: (pa12, 12),
1058    PA13: (pa13, 13, Debugger),
1059    PA14: (pa14, 14, Debugger),
1060    PA15: (pa15, 15, Debugger),
1061]);
1062
1063gpio!(GPIOB, gpiob, PBx, 'B', [
1064    PB0: (pb0, 0),
1065    PB1: (pb1, 1),
1066    PB2: (pb2, 2),
1067    PB3: (pb3, 3, Debugger),
1068    PB4: (pb4, 4, Debugger),
1069    PB5: (pb5, 5),
1070    PB6: (pb6, 6),
1071    PB7: (pb7, 7),
1072    PB8: (pb8, 8),
1073    PB9: (pb9, 9),
1074    PB10: (pb10, 10),
1075    PB11: (pb11, 11),
1076    PB12: (pb12, 12),
1077    PB13: (pb13, 13),
1078    PB14: (pb14, 14),
1079    PB15: (pb15, 15),
1080]);
1081
1082gpio!(GPIOC, gpioc, PCx, 'C', [
1083    PC0: (pc0, 0),
1084    PC1: (pc1, 1),
1085    PC2: (pc2, 2),
1086    PC3: (pc3, 3),
1087    PC4: (pc4, 4),
1088    PC5: (pc5, 5),
1089    PC6: (pc6, 6),
1090    PC7: (pc7, 7),
1091    PC8: (pc8, 8),
1092    PC9: (pc9, 9),
1093    PC10: (pc10, 10),
1094    PC11: (pc11, 11),
1095    PC12: (pc12, 12),
1096    PC13: (pc13, 13),
1097    PC14: (pc14, 14),
1098    PC15: (pc15, 15),
1099]);
1100
1101gpio!(GPIOD, gpiod, PDx, 'D', [
1102    PD0: (pd0, 0),
1103    PD1: (pd1, 1),
1104    PD2: (pd2, 2),
1105    PD3: (pd3, 3),
1106    PD4: (pd4, 4),
1107    PD5: (pd5, 5),
1108    PD6: (pd6, 6),
1109    PD7: (pd7, 7),
1110    PD8: (pd8, 8),
1111    PD9: (pd9, 9),
1112    PD10: (pd10, 10),
1113    PD11: (pd11, 11),
1114    PD12: (pd12, 12),
1115    PD13: (pd13, 13),
1116    PD14: (pd14, 14),
1117    PD15: (pd15, 15),
1118]);
1119
1120gpio!(GPIOE, gpioe, PEx, 'E', [
1121    PE0: (pe0, 0),
1122    PE1: (pe1, 1),
1123    PE2: (pe2, 2),
1124    PE3: (pe3, 3),
1125    PE4: (pe4, 4),
1126    PE5: (pe5, 5),
1127    PE6: (pe6, 6),
1128    PE7: (pe7, 7),
1129    PE8: (pe8, 8),
1130    PE9: (pe9, 9),
1131    PE10: (pe10, 10),
1132    PE11: (pe11, 11),
1133    PE12: (pe12, 12),
1134    PE13: (pe13, 13),
1135    PE14: (pe14, 14),
1136    PE15: (pe15, 15),
1137]);
1138
1139#[cfg(any(feature = "xl", feature = "high"))]
1140gpio!(GPIOF, gpiof, PFx, 'F', [
1141    PF0:  (pf0, 0),
1142    PF1:  (pf1, 1),
1143    PF2:  (pf2, 2),
1144    PF3:  (pf3, 3),
1145    PF4:  (pf4, 4),
1146    PF5:  (pf5, 5),
1147    PF6:  (pf6, 6),
1148    PF7:  (pf7, 7),
1149    PF8:  (pf8, 8),
1150    PF9:  (pf9, 9),
1151    PF10: (pf10, 10),
1152    PF11: (pf11, 11),
1153    PF12: (pf12, 12),
1154    PF13: (pf13, 13),
1155    PF14: (pf14, 14),
1156    PF15: (pf15, 15),
1157]);
1158
1159#[cfg(any(feature = "xl", feature = "high"))]
1160gpio!(GPIOG, gpiog, PGx, 'G', [
1161    PG0:  (pg0, 0),
1162    PG1:  (pg1, 1),
1163    PG2:  (pg2, 2),
1164    PG3:  (pg3, 3),
1165    PG4:  (pg4, 4),
1166    PG5:  (pg5, 5),
1167    PG6:  (pg6, 6),
1168    PG7:  (pg7, 7),
1169    PG8:  (pg8, 8),
1170    PG9:  (pg9, 9),
1171    PG10: (pg10, 10),
1172    PG11: (pg11, 11),
1173    PG12: (pg12, 12),
1174    PG13: (pg13, 13),
1175    PG14: (pg14, 14),
1176    PG15: (pg15, 15),
1177]);
1178
1179const fn gpiox<const P: char>() -> *const crate::pac::gpioa::RegisterBlock {
1180    match P {
1181        'A' => crate::pac::GPIOA::ptr(),
1182        'B' => crate::pac::GPIOB::ptr() as _,
1183        'C' => crate::pac::GPIOC::ptr() as _,
1184        'D' => crate::pac::GPIOD::ptr() as _,
1185        'E' => crate::pac::GPIOE::ptr() as _,
1186        #[cfg(any(feature = "xl", feature = "high"))]
1187        'F' => crate::pac::GPIOF::ptr() as _,
1188        #[cfg(any(feature = "xl", feature = "high"))]
1189        'G' => crate::pac::GPIOG::ptr() as _,
1190        _ => unreachable!(),
1191    }
1192}