stm32f1xx_hal/
gpio.rs

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