embassy_stm32/
gpio.rs

1//! General-purpose Input/Output (GPIO)
2
3#![macro_use]
4use core::convert::Infallible;
5
6use critical_section::CriticalSection;
7use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
8
9use crate::pac::gpio::{self, vals};
10use crate::{peripherals, Peripheral};
11
12/// GPIO flexible pin.
13///
14/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain
15/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
16/// mode.
17pub struct Flex<'d> {
18    pub(crate) pin: PeripheralRef<'d, AnyPin>,
19}
20
21impl<'d> Flex<'d> {
22    /// Wrap the pin in a `Flex`.
23    ///
24    /// The pin remains disconnected. The initial output level is unspecified, but can be changed
25    /// before the pin is put into output mode.
26    ///
27    #[inline]
28    pub fn new(pin: impl Peripheral<P = impl Pin> + 'd) -> Self {
29        into_ref!(pin);
30        // Pin will be in disconnected state.
31        Self { pin: pin.map_into() }
32    }
33
34    /// Put the pin into input mode.
35    ///
36    /// The internal weak pull-up and pull-down resistors will be enabled according to `pull`.
37    #[inline(never)]
38    pub fn set_as_input(&mut self, pull: Pull) {
39        critical_section::with(|_| {
40            let r = self.pin.block();
41            let n = self.pin.pin() as usize;
42            #[cfg(gpio_v1)]
43            {
44                let cnf = match pull {
45                    Pull::Up => {
46                        r.bsrr().write(|w| w.set_bs(n, true));
47                        vals::CnfIn::PULL
48                    }
49                    Pull::Down => {
50                        r.bsrr().write(|w| w.set_br(n, true));
51                        vals::CnfIn::PULL
52                    }
53                    Pull::None => vals::CnfIn::FLOATING,
54                };
55
56                r.cr(n / 8).modify(|w| {
57                    w.set_mode(n % 8, vals::Mode::INPUT);
58                    w.set_cnf_in(n % 8, cnf);
59                });
60            }
61            #[cfg(gpio_v2)]
62            {
63                r.pupdr().modify(|w| w.set_pupdr(n, pull.to_pupdr()));
64                r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSH_PULL));
65                r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT));
66            }
67        });
68    }
69
70    /// Put the pin into push-pull output mode.
71    ///
72    /// The pin level will be whatever was set before (or low by default). If you want it to begin
73    /// at a specific level, call `set_high`/`set_low` on the pin first.
74    ///
75    /// The internal weak pull-up and pull-down resistors will be disabled.
76    #[inline(never)]
77    pub fn set_as_output(&mut self, speed: Speed) {
78        critical_section::with(|_| {
79            let r = self.pin.block();
80            let n = self.pin.pin() as usize;
81            #[cfg(gpio_v1)]
82            {
83                r.cr(n / 8).modify(|w| {
84                    w.set_mode(n % 8, speed.to_mode());
85                    w.set_cnf_out(n % 8, vals::CnfOut::PUSH_PULL);
86                });
87            }
88            #[cfg(gpio_v2)]
89            {
90                r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING));
91                r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSH_PULL));
92                r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr()));
93                r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT));
94            }
95        });
96    }
97
98    /// Put the pin into input + open-drain output mode.
99    ///
100    /// The hardware will drive the line low if you set it to low, and will leave it floating if you set
101    /// it to high, in which case you can read the input to figure out whether another device
102    /// is driving the line low.
103    ///
104    /// The pin level will be whatever was set before (or low by default). If you want it to begin
105    /// at a specific level, call `set_high`/`set_low` on the pin first.
106    ///
107    /// The internal weak pull-up and pull-down resistors will be disabled.
108    #[inline(never)]
109    pub fn set_as_input_output(&mut self, speed: Speed) {
110        #[cfg(gpio_v1)]
111        critical_section::with(|_| {
112            let r = self.pin.block();
113            let n = self.pin.pin() as usize;
114            r.cr(n / 8).modify(|w| w.set_mode(n % 8, speed.to_mode()));
115            r.cr(n / 8).modify(|w| w.set_cnf_out(n % 8, vals::CnfOut::OPEN_DRAIN));
116        });
117
118        #[cfg(gpio_v2)]
119        self.set_as_input_output_pull(speed, Pull::None);
120    }
121
122    /// Put the pin into input + open-drain output mode with internal pullup or pulldown.
123    ///
124    /// This works like [`Self::set_as_input_output()`], but it also allows to enable the internal
125    /// weak pull-up or pull-down resistors.
126    #[inline(never)]
127    #[cfg(gpio_v2)]
128    pub fn set_as_input_output_pull(&mut self, speed: Speed, pull: Pull) {
129        critical_section::with(|_| {
130            let r = self.pin.block();
131            let n = self.pin.pin() as usize;
132            r.pupdr().modify(|w| w.set_pupdr(n, pull.to_pupdr()));
133            r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPEN_DRAIN));
134            r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr()));
135            r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT));
136        });
137    }
138
139    /// Put the pin into analog mode
140    ///
141    /// This mode is used by ADC and COMP but usually there is no need to set this manually
142    /// as the mode change is handled by the driver.
143    #[inline]
144    pub fn set_as_analog(&mut self) {
145        // TODO: does this also need a critical section, like other methods?
146        self.pin.set_as_analog();
147    }
148
149    /// Put the pin into AF mode, unchecked.
150    ///
151    /// This puts the pin into the AF mode, with the requested number and AF type. This is
152    /// completely unchecked, it can attach the pin to literally any peripheral, so use with care.
153    #[inline]
154    pub fn set_as_af_unchecked(&mut self, af_num: u8, af_type: AfType) {
155        critical_section::with(|_| {
156            self.pin.set_as_af(af_num, af_type);
157        });
158    }
159
160    /// Get whether the pin input level is high.
161    #[inline]
162    pub fn is_high(&self) -> bool {
163        !self.is_low()
164    }
165
166    /// Get whether the pin input level is low.
167    #[inline]
168    pub fn is_low(&self) -> bool {
169        let state = self.pin.block().idr().read().idr(self.pin.pin() as _);
170        state == vals::Idr::LOW
171    }
172
173    /// Get the current pin input level.
174    #[inline]
175    pub fn get_level(&self) -> Level {
176        self.is_high().into()
177    }
178
179    /// Get whether the output level is set to high.
180    #[inline]
181    pub fn is_set_high(&self) -> bool {
182        !self.is_set_low()
183    }
184
185    /// Get whether the output level is set to low.
186    #[inline]
187    pub fn is_set_low(&self) -> bool {
188        let state = self.pin.block().odr().read().odr(self.pin.pin() as _);
189        state == vals::Odr::LOW
190    }
191
192    /// Get the current output level.
193    #[inline]
194    pub fn get_output_level(&self) -> Level {
195        self.is_set_high().into()
196    }
197
198    /// Set the output as high.
199    #[inline]
200    pub fn set_high(&mut self) {
201        self.pin.set_high();
202    }
203
204    /// Set the output as low.
205    #[inline]
206    pub fn set_low(&mut self) {
207        self.pin.set_low();
208    }
209
210    /// Set the output level.
211    #[inline]
212    pub fn set_level(&mut self, level: Level) {
213        match level {
214            Level::Low => self.pin.set_low(),
215            Level::High => self.pin.set_high(),
216        }
217    }
218
219    /// Toggle the output level.
220    #[inline]
221    pub fn toggle(&mut self) {
222        if self.is_set_low() {
223            self.set_high()
224        } else {
225            self.set_low()
226        }
227    }
228}
229
230impl<'d> Drop for Flex<'d> {
231    #[inline]
232    fn drop(&mut self) {
233        critical_section::with(|_| {
234            self.pin.set_as_disconnected();
235        });
236    }
237}
238
239/// Pull setting for an input.
240#[derive(Debug, Eq, PartialEq, Copy, Clone)]
241#[cfg_attr(feature = "defmt", derive(defmt::Format))]
242pub enum Pull {
243    /// No pull
244    None,
245    /// Pull up
246    Up,
247    /// Pull down
248    Down,
249}
250
251impl Pull {
252    #[cfg(gpio_v2)]
253    const fn to_pupdr(self) -> vals::Pupdr {
254        match self {
255            Pull::None => vals::Pupdr::FLOATING,
256            Pull::Up => vals::Pupdr::PULL_UP,
257            Pull::Down => vals::Pupdr::PULL_DOWN,
258        }
259    }
260}
261
262/// Speed setting for an output.
263///
264/// These vary depending on the chip, check the reference manual and datasheet ("I/O port
265/// characteristics") for details.
266#[derive(Debug, Copy, Clone)]
267#[cfg_attr(feature = "defmt", derive(defmt::Format))]
268pub enum Speed {
269    #[cfg_attr(gpio_v1, doc = "Output speed OUTPUT2MHZ")]
270    #[cfg_attr(gpio_v2, doc = "Output speed 00")]
271    Low,
272    #[cfg_attr(gpio_v1, doc = "Output speed OUTPUT10MHZ")]
273    #[cfg_attr(gpio_v2, doc = "Output speed 01")]
274    Medium,
275    #[cfg_attr(gpio_v2, doc = "Output speed 10")]
276    #[cfg(not(any(gpio_v1, syscfg_f0)))]
277    High,
278    #[cfg_attr(gpio_v1, doc = "Output speed OUTPUT50MHZ")]
279    #[cfg_attr(gpio_v2, doc = "Output speed 11")]
280    VeryHigh,
281}
282
283impl Speed {
284    #[cfg(gpio_v1)]
285    const fn to_mode(self) -> vals::Mode {
286        match self {
287            Speed::Low => vals::Mode::OUTPUT2MHZ,
288            Speed::Medium => vals::Mode::OUTPUT10MHZ,
289            Speed::VeryHigh => vals::Mode::OUTPUT50MHZ,
290        }
291    }
292
293    #[cfg(gpio_v2)]
294    const fn to_ospeedr(self: Speed) -> vals::Ospeedr {
295        match self {
296            Speed::Low => vals::Ospeedr::LOW_SPEED,
297            Speed::Medium => vals::Ospeedr::MEDIUM_SPEED,
298            #[cfg(not(syscfg_f0))]
299            Speed::High => vals::Ospeedr::HIGH_SPEED,
300            Speed::VeryHigh => vals::Ospeedr::VERY_HIGH_SPEED,
301        }
302    }
303}
304
305/// GPIO input driver.
306pub struct Input<'d> {
307    pub(crate) pin: Flex<'d>,
308}
309
310impl<'d> Input<'d> {
311    /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
312    #[inline]
313    pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, pull: Pull) -> Self {
314        let mut pin = Flex::new(pin);
315        pin.set_as_input(pull);
316        Self { pin }
317    }
318
319    /// Get whether the pin input level is high.
320    #[inline]
321    pub fn is_high(&self) -> bool {
322        self.pin.is_high()
323    }
324
325    /// Get whether the pin input level is low.
326    #[inline]
327    pub fn is_low(&self) -> bool {
328        self.pin.is_low()
329    }
330
331    /// Get the current pin input level.
332    #[inline]
333    pub fn get_level(&self) -> Level {
334        self.pin.get_level()
335    }
336}
337
338/// Digital input or output level.
339#[derive(Debug, Eq, PartialEq, Copy, Clone)]
340#[cfg_attr(feature = "defmt", derive(defmt::Format))]
341pub enum Level {
342    /// Low
343    Low,
344    /// High
345    High,
346}
347
348impl From<bool> for Level {
349    fn from(val: bool) -> Self {
350        match val {
351            true => Self::High,
352            false => Self::Low,
353        }
354    }
355}
356
357impl From<Level> for bool {
358    fn from(level: Level) -> bool {
359        match level {
360            Level::Low => false,
361            Level::High => true,
362        }
363    }
364}
365
366/// GPIO output driver.
367///
368/// Note that pins will **return to their floating state** when `Output` is dropped.
369/// If pins should retain their state indefinitely, either keep ownership of the
370/// `Output`, or pass it to [`core::mem::forget`].
371pub struct Output<'d> {
372    pub(crate) pin: Flex<'d>,
373}
374
375impl<'d> Output<'d> {
376    /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration.
377    #[inline]
378    pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level, speed: Speed) -> Self {
379        let mut pin = Flex::new(pin);
380        match initial_output {
381            Level::High => pin.set_high(),
382            Level::Low => pin.set_low(),
383        }
384        pin.set_as_output(speed);
385        Self { pin }
386    }
387
388    /// Set the output as high.
389    #[inline]
390    pub fn set_high(&mut self) {
391        self.pin.set_high();
392    }
393
394    /// Set the output as low.
395    #[inline]
396    pub fn set_low(&mut self) {
397        self.pin.set_low();
398    }
399
400    /// Set the output level.
401    #[inline]
402    pub fn set_level(&mut self, level: Level) {
403        self.pin.set_level(level)
404    }
405
406    /// Is the output pin set as high?
407    #[inline]
408    pub fn is_set_high(&self) -> bool {
409        self.pin.is_set_high()
410    }
411
412    /// Is the output pin set as low?
413    #[inline]
414    pub fn is_set_low(&self) -> bool {
415        self.pin.is_set_low()
416    }
417
418    /// What level output is set to
419    #[inline]
420    pub fn get_output_level(&self) -> Level {
421        self.pin.get_output_level()
422    }
423
424    /// Toggle pin output
425    #[inline]
426    pub fn toggle(&mut self) {
427        self.pin.toggle();
428    }
429}
430
431/// GPIO output open-drain driver.
432///
433/// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped.
434/// If pins should retain their state indefinitely, either keep ownership of the
435/// `OutputOpenDrain`, or pass it to [`core::mem::forget`].
436pub struct OutputOpenDrain<'d> {
437    pub(crate) pin: Flex<'d>,
438}
439
440impl<'d> OutputOpenDrain<'d> {
441    /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed].
442    #[inline]
443    pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level, speed: Speed) -> Self {
444        let mut pin = Flex::new(pin);
445        match initial_output {
446            Level::High => pin.set_high(),
447            Level::Low => pin.set_low(),
448        }
449        pin.set_as_input_output(speed);
450        Self { pin }
451    }
452
453    /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level], [Speed]
454    /// and [Pull].
455    #[inline]
456    #[cfg(gpio_v2)]
457    pub fn new_pull(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self {
458        let mut pin = Flex::new(pin);
459        match initial_output {
460            Level::High => pin.set_high(),
461            Level::Low => pin.set_low(),
462        }
463        pin.set_as_input_output_pull(speed, pull);
464        Self { pin }
465    }
466
467    /// Get whether the pin input level is high.
468    #[inline]
469    pub fn is_high(&self) -> bool {
470        !self.pin.is_low()
471    }
472
473    /// Get whether the pin input level is low.
474    #[inline]
475    pub fn is_low(&self) -> bool {
476        self.pin.is_low()
477    }
478
479    /// Get the current pin input level.
480    #[inline]
481    pub fn get_level(&self) -> Level {
482        self.pin.get_level()
483    }
484
485    /// Set the output as high.
486    #[inline]
487    pub fn set_high(&mut self) {
488        self.pin.set_high();
489    }
490
491    /// Set the output as low.
492    #[inline]
493    pub fn set_low(&mut self) {
494        self.pin.set_low();
495    }
496
497    /// Set the output level.
498    #[inline]
499    pub fn set_level(&mut self, level: Level) {
500        self.pin.set_level(level);
501    }
502
503    /// Get whether the output level is set to high.
504    #[inline]
505    pub fn is_set_high(&self) -> bool {
506        self.pin.is_set_high()
507    }
508
509    /// Get whether the output level is set to low.
510    #[inline]
511    pub fn is_set_low(&self) -> bool {
512        self.pin.is_set_low()
513    }
514
515    /// Get the current output level.
516    #[inline]
517    pub fn get_output_level(&self) -> Level {
518        self.pin.get_output_level()
519    }
520
521    /// Toggle pin output
522    #[inline]
523    pub fn toggle(&mut self) {
524        self.pin.toggle()
525    }
526}
527
528/// GPIO output type
529#[derive(Debug, Copy, Clone)]
530#[cfg_attr(feature = "defmt", derive(defmt::Format))]
531pub enum OutputType {
532    /// Drive the pin both high or low.
533    PushPull,
534    /// Drive the pin low, or don't drive it at all if the output level is high.
535    OpenDrain,
536}
537
538impl OutputType {
539    #[cfg(gpio_v1)]
540    const fn to_cnf_out(self) -> vals::CnfOut {
541        match self {
542            OutputType::PushPull => vals::CnfOut::ALT_PUSH_PULL,
543            OutputType::OpenDrain => vals::CnfOut::ALT_OPEN_DRAIN,
544        }
545    }
546
547    #[cfg(gpio_v2)]
548    const fn to_ot(self) -> vals::Ot {
549        match self {
550            OutputType::PushPull => vals::Ot::PUSH_PULL,
551            OutputType::OpenDrain => vals::Ot::OPEN_DRAIN,
552        }
553    }
554}
555
556/// Alternate function type settings.
557#[derive(Copy, Clone)]
558#[cfg(gpio_v1)]
559pub struct AfType {
560    mode: vals::Mode,
561    cnf: u8,
562    pull: Pull,
563}
564
565#[cfg(gpio_v1)]
566impl AfType {
567    /// Input with optional pullup or pulldown.
568    pub const fn input(pull: Pull) -> Self {
569        let cnf_in = match pull {
570            Pull::Up | Pull::Down => vals::CnfIn::PULL,
571            Pull::None => vals::CnfIn::FLOATING,
572        };
573        Self {
574            mode: vals::Mode::INPUT,
575            cnf: cnf_in.to_bits(),
576            pull,
577        }
578    }
579
580    /// Output with output type and speed and no pull-up or pull-down.
581    pub const fn output(output_type: OutputType, speed: Speed) -> Self {
582        Self {
583            mode: speed.to_mode(),
584            cnf: output_type.to_cnf_out().to_bits(),
585            pull: Pull::None,
586        }
587    }
588}
589
590#[inline(never)]
591#[cfg(gpio_v1)]
592fn set_as_af(pin_port: u8, _af_num: u8, af_type: AfType) {
593    let pin = unsafe { AnyPin::steal(pin_port) };
594    let r = pin.block();
595    let n = pin._pin() as usize;
596
597    r.cr(n / 8).modify(|w| {
598        w.set_mode(n % 8, af_type.mode);
599        // note that we are writing the CNF field, which is exposed as both `cnf_in` and `cnf_out`
600        // in the PAC. the choice of `cnf_in` instead of `cnf_out` in this code is arbitrary and
601        // does not affect the result.
602        w.set_cnf_in(n % 8, vals::CnfIn::from_bits(af_type.cnf));
603    });
604
605    match af_type.pull {
606        Pull::Up => r.bsrr().write(|w| w.set_bs(n, true)),
607        Pull::Down => r.bsrr().write(|w| w.set_br(n, true)),
608        Pull::None => {}
609    }
610}
611
612/// Alternate function type settings.
613#[derive(Copy, Clone)]
614#[cfg(gpio_v2)]
615pub struct AfType {
616    pupdr: vals::Pupdr,
617    ot: vals::Ot,
618    ospeedr: vals::Ospeedr,
619}
620
621#[cfg(gpio_v2)]
622impl AfType {
623    /// Input with optional pullup or pulldown.
624    pub const fn input(pull: Pull) -> Self {
625        Self {
626            pupdr: pull.to_pupdr(),
627            ot: vals::Ot::PUSH_PULL,
628            ospeedr: vals::Ospeedr::LOW_SPEED,
629        }
630    }
631
632    /// Output with output type and speed and no pull-up or pull-down.
633    pub const fn output(output_type: OutputType, speed: Speed) -> Self {
634        Self::output_pull(output_type, speed, Pull::None)
635    }
636
637    /// Output with output type, speed and pull-up or pull-down;
638    pub const fn output_pull(output_type: OutputType, speed: Speed, pull: Pull) -> Self {
639        Self {
640            pupdr: pull.to_pupdr(),
641            ot: output_type.to_ot(),
642            ospeedr: speed.to_ospeedr(),
643        }
644    }
645}
646
647#[inline(never)]
648#[cfg(gpio_v2)]
649fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) {
650    let pin = unsafe { AnyPin::steal(pin_port) };
651    let r = pin.block();
652    let n = pin._pin() as usize;
653
654    r.afr(n / 8).modify(|w| w.set_afr(n % 8, af_num));
655    r.pupdr().modify(|w| w.set_pupdr(n, af_type.pupdr));
656    r.otyper().modify(|w| w.set_ot(n, af_type.ot));
657    r.ospeedr().modify(|w| w.set_ospeedr(n, af_type.ospeedr));
658    r.moder().modify(|w| w.set_moder(n, vals::Moder::ALTERNATE));
659}
660
661#[inline(never)]
662#[cfg(gpio_v2)]
663fn set_speed(pin_port: u8, speed: Speed) {
664    let pin = unsafe { AnyPin::steal(pin_port) };
665    let r = pin.block();
666    let n = pin._pin() as usize;
667
668    r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr()));
669}
670
671#[inline(never)]
672fn set_as_analog(pin_port: u8) {
673    let pin = unsafe { AnyPin::steal(pin_port) };
674    let r = pin.block();
675    let n = pin._pin() as usize;
676
677    #[cfg(gpio_v1)]
678    r.cr(n / 8).modify(|w| {
679        w.set_mode(n % 8, vals::Mode::INPUT);
680        w.set_cnf_in(n % 8, vals::CnfIn::ANALOG);
681    });
682
683    #[cfg(gpio_v2)]
684    r.moder().modify(|w| w.set_moder(n, vals::Moder::ANALOG));
685}
686
687#[inline(never)]
688fn get_pull(pin_port: u8) -> Pull {
689    let pin = unsafe { AnyPin::steal(pin_port) };
690    let r = pin.block();
691    let n = pin._pin() as usize;
692
693    #[cfg(gpio_v1)]
694    return match r.cr(n / 8).read().mode(n % 8) {
695        vals::Mode::INPUT => match r.cr(n / 8).read().cnf_in(n % 8) {
696            vals::CnfIn::PULL => match r.odr().read().odr(n) {
697                vals::Odr::LOW => Pull::Down,
698                vals::Odr::HIGH => Pull::Up,
699            },
700            _ => Pull::None,
701        },
702        _ => Pull::None,
703    };
704
705    #[cfg(gpio_v2)]
706    return match r.pupdr().read().pupdr(n) {
707        vals::Pupdr::FLOATING => Pull::None,
708        vals::Pupdr::PULL_DOWN => Pull::Down,
709        vals::Pupdr::PULL_UP => Pull::Up,
710        vals::Pupdr::_RESERVED_3 => Pull::None,
711    };
712}
713
714pub(crate) trait SealedPin {
715    fn pin_port(&self) -> u8;
716
717    #[inline]
718    fn _pin(&self) -> u8 {
719        self.pin_port() % 16
720    }
721
722    #[inline]
723    fn _port(&self) -> u8 {
724        self.pin_port() / 16
725    }
726
727    #[inline]
728    fn block(&self) -> gpio::Gpio {
729        crate::_generated::gpio_block(self._port() as _)
730    }
731
732    /// Set the output as high.
733    #[inline]
734    fn set_high(&self) {
735        let n = self._pin() as _;
736        self.block().bsrr().write(|w| w.set_bs(n, true));
737    }
738
739    /// Set the output as low.
740    #[inline]
741    fn set_low(&self) {
742        let n = self._pin() as _;
743        self.block().bsrr().write(|w| w.set_br(n, true));
744    }
745
746    #[inline]
747    fn set_as_af(&self, af_num: u8, af_type: AfType) {
748        set_as_af(self.pin_port(), af_num, af_type)
749    }
750
751    #[inline]
752    #[cfg(gpio_v2)]
753    fn set_speed(&self, speed: Speed) {
754        set_speed(self.pin_port(), speed)
755    }
756
757    #[inline]
758    fn set_as_analog(&self) {
759        set_as_analog(self.pin_port());
760    }
761
762    /// Set the pin as "disconnected", ie doing nothing and consuming the lowest
763    /// amount of power possible.
764    ///
765    /// This is currently the same as [`Self::set_as_analog()`] but is semantically different
766    /// really. Drivers should `set_as_disconnected()` pins when dropped.
767    ///
768    /// Note that this also disables the internal weak pull-up and pull-down resistors.
769    #[inline]
770    fn set_as_disconnected(&self) {
771        self.set_as_analog();
772    }
773
774    /// Get the pull-up configuration.
775    #[inline]
776    fn pull(&self) -> Pull {
777        critical_section::with(|_| get_pull(self.pin_port()))
778    }
779}
780
781/// GPIO pin trait.
782#[allow(private_bounds)]
783pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static {
784    /// EXTI channel assigned to this pin.
785    ///
786    /// For example, PC4 uses EXTI4.
787    #[cfg(feature = "exti")]
788    type ExtiChannel: crate::exti::Channel;
789
790    /// Number of the pin within the port (0..31)
791    #[inline]
792    fn pin(&self) -> u8 {
793        self._pin()
794    }
795
796    /// Port of the pin
797    #[inline]
798    fn port(&self) -> u8 {
799        self._port()
800    }
801
802    /// Type-erase (degrade) this pin into an `AnyPin`.
803    ///
804    /// This converts pin singletons (`PA5`, `PB6`, ...), which
805    /// are all different types, into the same type. It is useful for
806    /// creating arrays of pins, or avoiding generics.
807    #[inline]
808    fn degrade(self) -> AnyPin {
809        AnyPin {
810            pin_port: self.pin_port(),
811        }
812    }
813}
814
815/// Type-erased GPIO pin
816pub struct AnyPin {
817    pin_port: u8,
818}
819
820impl AnyPin {
821    /// Unsafely create an `AnyPin` from a pin+port number.
822    ///
823    /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc...
824    #[inline]
825    pub unsafe fn steal(pin_port: u8) -> Self {
826        Self { pin_port }
827    }
828
829    #[inline]
830    fn _port(&self) -> u8 {
831        self.pin_port / 16
832    }
833
834    /// Get the GPIO register block for this pin.
835    #[cfg(feature = "unstable-pac")]
836    #[inline]
837    pub fn block(&self) -> gpio::Gpio {
838        crate::_generated::gpio_block(self._port() as _)
839    }
840}
841
842impl_peripheral!(AnyPin);
843impl Pin for AnyPin {
844    #[cfg(feature = "exti")]
845    type ExtiChannel = crate::exti::AnyChannel;
846}
847impl SealedPin for AnyPin {
848    #[inline]
849    fn pin_port(&self) -> u8 {
850        self.pin_port
851    }
852}
853
854// ====================
855
856foreach_pin!(
857    ($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => {
858        impl Pin for peripherals::$pin_name {
859            #[cfg(feature = "exti")]
860            type ExtiChannel = peripherals::$exti_ch;
861        }
862        impl SealedPin for peripherals::$pin_name {
863            #[inline]
864            fn pin_port(&self) -> u8 {
865                $port_num * 16 + $pin_num
866            }
867        }
868
869        impl From<peripherals::$pin_name> for AnyPin {
870            fn from(x: peripherals::$pin_name) -> Self {
871                x.degrade()
872            }
873        }
874    };
875);
876
877pub(crate) unsafe fn init(_cs: CriticalSection) {
878    #[cfg(afio)]
879    crate::rcc::enable_and_reset_with_cs::<crate::peripherals::AFIO>(_cs);
880
881    crate::_generated::init_gpio();
882}
883
884impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> {
885    type Error = Infallible;
886
887    #[inline]
888    fn is_high(&self) -> Result<bool, Self::Error> {
889        Ok(self.is_high())
890    }
891
892    #[inline]
893    fn is_low(&self) -> Result<bool, Self::Error> {
894        Ok(self.is_low())
895    }
896}
897
898impl<'d> embedded_hal_02::digital::v2::OutputPin for Output<'d> {
899    type Error = Infallible;
900
901    #[inline]
902    fn set_high(&mut self) -> Result<(), Self::Error> {
903        self.set_high();
904        Ok(())
905    }
906
907    #[inline]
908    fn set_low(&mut self) -> Result<(), Self::Error> {
909        self.set_low();
910        Ok(())
911    }
912}
913
914impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d> {
915    #[inline]
916    fn is_set_high(&self) -> Result<bool, Self::Error> {
917        Ok(self.is_set_high())
918    }
919
920    /// Is the output pin set as low?
921    #[inline]
922    fn is_set_low(&self) -> Result<bool, Self::Error> {
923        Ok(self.is_set_low())
924    }
925}
926
927impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> {
928    type Error = Infallible;
929    #[inline]
930    fn toggle(&mut self) -> Result<(), Self::Error> {
931        self.toggle();
932        Ok(())
933    }
934}
935
936impl<'d> embedded_hal_02::digital::v2::InputPin for OutputOpenDrain<'d> {
937    type Error = Infallible;
938
939    fn is_high(&self) -> Result<bool, Self::Error> {
940        Ok(self.is_high())
941    }
942
943    fn is_low(&self) -> Result<bool, Self::Error> {
944        Ok(self.is_low())
945    }
946}
947
948impl<'d> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d> {
949    type Error = Infallible;
950
951    #[inline]
952    fn set_high(&mut self) -> Result<(), Self::Error> {
953        self.set_high();
954        Ok(())
955    }
956
957    #[inline]
958    fn set_low(&mut self) -> Result<(), Self::Error> {
959        self.set_low();
960        Ok(())
961    }
962}
963
964impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d> {
965    #[inline]
966    fn is_set_high(&self) -> Result<bool, Self::Error> {
967        Ok(self.is_set_high())
968    }
969
970    /// Is the output pin set as low?
971    #[inline]
972    fn is_set_low(&self) -> Result<bool, Self::Error> {
973        Ok(self.is_set_low())
974    }
975}
976
977impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpenDrain<'d> {
978    type Error = Infallible;
979    #[inline]
980    fn toggle(&mut self) -> Result<(), Self::Error> {
981        self.toggle();
982        Ok(())
983    }
984}
985
986impl<'d> embedded_hal_02::digital::v2::InputPin for Flex<'d> {
987    type Error = Infallible;
988
989    #[inline]
990    fn is_high(&self) -> Result<bool, Self::Error> {
991        Ok(self.is_high())
992    }
993
994    #[inline]
995    fn is_low(&self) -> Result<bool, Self::Error> {
996        Ok(self.is_low())
997    }
998}
999
1000impl<'d> embedded_hal_02::digital::v2::OutputPin for Flex<'d> {
1001    type Error = Infallible;
1002
1003    #[inline]
1004    fn set_high(&mut self) -> Result<(), Self::Error> {
1005        self.set_high();
1006        Ok(())
1007    }
1008
1009    #[inline]
1010    fn set_low(&mut self) -> Result<(), Self::Error> {
1011        self.set_low();
1012        Ok(())
1013    }
1014}
1015
1016impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d> {
1017    #[inline]
1018    fn is_set_high(&self) -> Result<bool, Self::Error> {
1019        Ok(self.is_set_high())
1020    }
1021
1022    /// Is the output pin set as low?
1023    #[inline]
1024    fn is_set_low(&self) -> Result<bool, Self::Error> {
1025        Ok(self.is_set_low())
1026    }
1027}
1028
1029impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d> {
1030    type Error = Infallible;
1031    #[inline]
1032    fn toggle(&mut self) -> Result<(), Self::Error> {
1033        self.toggle();
1034        Ok(())
1035    }
1036}
1037
1038impl<'d> embedded_hal_1::digital::ErrorType for Input<'d> {
1039    type Error = Infallible;
1040}
1041
1042impl<'d> embedded_hal_1::digital::InputPin for Input<'d> {
1043    #[inline]
1044    fn is_high(&mut self) -> Result<bool, Self::Error> {
1045        Ok((*self).is_high())
1046    }
1047
1048    #[inline]
1049    fn is_low(&mut self) -> Result<bool, Self::Error> {
1050        Ok((*self).is_low())
1051    }
1052}
1053
1054impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> {
1055    type Error = Infallible;
1056}
1057
1058impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> {
1059    #[inline]
1060    fn set_high(&mut self) -> Result<(), Self::Error> {
1061        Ok(self.set_high())
1062    }
1063
1064    #[inline]
1065    fn set_low(&mut self) -> Result<(), Self::Error> {
1066        Ok(self.set_low())
1067    }
1068}
1069
1070impl<'d> embedded_hal_1::digital::StatefulOutputPin for Output<'d> {
1071    #[inline]
1072    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1073        Ok((*self).is_set_high())
1074    }
1075
1076    /// Is the output pin set as low?
1077    #[inline]
1078    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
1079        Ok((*self).is_set_low())
1080    }
1081}
1082
1083impl<'d> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d> {
1084    type Error = Infallible;
1085}
1086
1087impl<'d> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d> {
1088    #[inline]
1089    fn is_high(&mut self) -> Result<bool, Self::Error> {
1090        Ok((*self).is_high())
1091    }
1092
1093    #[inline]
1094    fn is_low(&mut self) -> Result<bool, Self::Error> {
1095        Ok((*self).is_low())
1096    }
1097}
1098
1099impl<'d> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d> {
1100    #[inline]
1101    fn set_high(&mut self) -> Result<(), Self::Error> {
1102        Ok(self.set_high())
1103    }
1104
1105    #[inline]
1106    fn set_low(&mut self) -> Result<(), Self::Error> {
1107        Ok(self.set_low())
1108    }
1109}
1110
1111impl<'d> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d> {
1112    #[inline]
1113    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1114        Ok((*self).is_set_high())
1115    }
1116
1117    /// Is the output pin set as low?
1118    #[inline]
1119    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
1120        Ok((*self).is_set_low())
1121    }
1122}
1123
1124impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> {
1125    #[inline]
1126    fn is_high(&mut self) -> Result<bool, Self::Error> {
1127        Ok((*self).is_high())
1128    }
1129
1130    #[inline]
1131    fn is_low(&mut self) -> Result<bool, Self::Error> {
1132        Ok((*self).is_low())
1133    }
1134}
1135
1136impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> {
1137    #[inline]
1138    fn set_high(&mut self) -> Result<(), Self::Error> {
1139        Ok(self.set_high())
1140    }
1141
1142    #[inline]
1143    fn set_low(&mut self) -> Result<(), Self::Error> {
1144        Ok(self.set_low())
1145    }
1146}
1147
1148impl<'d> embedded_hal_1::digital::ErrorType for Flex<'d> {
1149    type Error = Infallible;
1150}
1151
1152impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> {
1153    #[inline]
1154    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1155        Ok((*self).is_set_high())
1156    }
1157
1158    /// Is the output pin set as low?
1159    #[inline]
1160    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
1161        Ok((*self).is_set_low())
1162    }
1163}