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