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