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