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