1use core::marker::PhantomData;
58
59use crate::pac;
60pub mod alt;
61mod convert;
62pub use convert::PinMode;
63mod partially_erased;
64pub use partially_erased::{PEPin, PartiallyErasedPin};
65mod erased;
66pub use erased::{AnyPin, ErasedPin};
67mod exti;
68pub use exti::ExtiPin;
69mod dynamic;
70pub use dynamic::{Dynamic, DynamicPin};
71mod hal_02;
72mod hal_1;
73pub mod outport;
74
75pub use embedded_hal_02::digital::v2::PinState;
76
77use core::fmt;
78
79#[derive(Debug, Default)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82pub struct NoPin<Otype = PushPull>(PhantomData<Otype>);
83impl<Otype> NoPin<Otype> {
84 pub fn new() -> Self {
85 Self(PhantomData)
86 }
87}
88
89pub trait GpioExt {
91 type Parts;
93
94 fn split(self) -> Self::Parts;
96}
97
98pub trait PinExt {
100 type Mode;
102 fn pin_id(&self) -> u8;
104 fn port_id(&self) -> u8;
106}
107
108#[derive(Debug, Default)]
110#[cfg_attr(feature = "defmt", derive(defmt::Format))]
111pub struct Alternate<const A: u8, Otype = PushPull>(PhantomData<Otype>);
112
113#[derive(Debug, Default)]
115#[cfg_attr(feature = "defmt", derive(defmt::Format))]
116pub struct Input;
117
118#[derive(Clone, Copy, Debug, Eq, PartialEq)]
120#[cfg_attr(feature = "defmt", derive(defmt::Format))]
121pub enum Pull {
122 None = 0,
124 Up = 1,
126 Down = 2,
128}
129
130impl From<Pull> for pac::gpioa::pupdr::PUPDR0 {
131 fn from(value: Pull) -> Self {
132 match value {
133 Pull::Down => Self::PullDown,
134 Pull::Up => Self::PullUp,
135 Pull::None => Self::Floating,
136 }
137 }
138}
139
140#[derive(Debug, Default)]
142#[cfg_attr(feature = "defmt", derive(defmt::Format))]
143pub struct OpenDrain;
144
145#[derive(Debug, Default)]
147#[cfg_attr(feature = "defmt", derive(defmt::Format))]
148pub struct Output<Otype = PushPull> {
149 _mode: PhantomData<Otype>,
150}
151
152#[derive(Debug, Default)]
154#[cfg_attr(feature = "defmt", derive(defmt::Format))]
155pub struct PushPull;
156
157#[derive(Debug, Default)]
159#[cfg_attr(feature = "defmt", derive(defmt::Format))]
160pub struct Analog;
161
162pub type Debugger = Alternate<0, PushPull>;
164
165pub(crate) mod marker {
166 pub trait Interruptible {}
168 pub trait Readable {}
170 pub trait OutputSpeed {}
172 pub trait Active {}
174 pub trait NotAlt {}
176 pub trait IntoAf<const A: u8> {}
178}
179
180impl<MODE> marker::Interruptible for Output<MODE> {}
181impl marker::Interruptible for Input {}
182impl marker::Readable for Input {}
183impl marker::Readable for Output<OpenDrain> {}
184impl<const A: u8, Otype> marker::Interruptible for Alternate<A, Otype> {}
185impl<const A: u8, Otype> marker::Readable for Alternate<A, Otype> {}
186impl marker::Active for Input {}
187impl<Otype> marker::OutputSpeed for Output<Otype> {}
188impl<const A: u8, Otype> marker::OutputSpeed for Alternate<A, Otype> {}
189impl<Otype> marker::Active for Output<Otype> {}
190impl<const A: u8, Otype> marker::Active for Alternate<A, Otype> {}
191impl marker::NotAlt for Input {}
192impl<Otype> marker::NotAlt for Output<Otype> {}
193impl marker::NotAlt for Analog {}
194
195#[cfg_attr(feature = "defmt", derive(defmt::Format))]
197#[derive(Debug, PartialEq, Eq, Clone, Copy)]
198pub enum Speed {
199 Low = 0,
201 Medium = 1,
203 High = 2,
205 VeryHigh = 3,
207}
208
209impl From<Speed> for pac::gpioa::ospeedr::OSPEEDR0 {
210 fn from(value: Speed) -> Self {
211 match value {
212 Speed::Low => Self::LowSpeed,
213 Speed::Medium => Self::MediumSpeed,
214 Speed::High => Self::HighSpeed,
215 Speed::VeryHigh => Self::VeryHighSpeed,
216 }
217 }
218}
219
220#[cfg_attr(feature = "defmt", derive(defmt::Format))]
222#[derive(Debug, PartialEq, Eq, Clone, Copy)]
223pub enum Edge {
224 Rising,
226 Falling,
228 RisingFalling,
230}
231
232macro_rules! af {
233 ($($i:literal: $AFi:ident),+) => {
234 $(
235 #[doc = concat!("Alternate function ", $i, " (type state)" )]
236 pub type $AFi<Otype = PushPull> = Alternate<$i, Otype>;
237 )+
238 };
239}
240
241af!(
242 0: AF0,
243 1: AF1,
244 2: AF2,
245 3: AF3,
246 4: AF4,
247 5: AF5,
248 6: AF6,
249 7: AF7,
250 8: AF8,
251 9: AF9,
252 10: AF10,
253 11: AF11,
254 12: AF12,
255 13: AF13,
256 14: AF14,
257 15: AF15
258);
259
260pub struct Pin<const P: char, const N: u8, MODE = DefaultMode> {
266 _mode: PhantomData<MODE>,
267}
268impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
269 const fn new() -> Self {
270 Self { _mode: PhantomData }
271 }
272}
273
274impl<const P: char, const N: u8, MODE> fmt::Debug for Pin<P, N, MODE> {
275 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
276 formatter.write_fmt(format_args!(
277 "P{}{}<{}>",
278 P,
279 N,
280 crate::stripped_type_name::<MODE>()
281 ))
282 }
283}
284
285#[cfg(feature = "defmt")]
286impl<const P: char, const N: u8, MODE> defmt::Format for Pin<P, N, MODE> {
287 fn format(&self, f: defmt::Formatter) {
288 defmt::write!(f, "P{}{}<{}>", P, N, crate::stripped_type_name::<MODE>());
289 }
290}
291
292impl<const P: char, const N: u8, MODE> PinExt for Pin<P, N, MODE> {
293 type Mode = MODE;
294
295 #[inline(always)]
296 fn pin_id(&self) -> u8 {
297 N
298 }
299 #[inline(always)]
300 fn port_id(&self) -> u8 {
301 P as u8 - b'A'
302 }
303}
304
305pub trait PinSpeed: Sized {
306 fn set_speed(&mut self, speed: Speed);
308
309 #[inline(always)]
310 fn speed(mut self, speed: Speed) -> Self {
311 self.set_speed(speed);
312 self
313 }
314}
315
316pub trait PinPull: Sized {
317 fn set_internal_resistor(&mut self, resistor: Pull);
319
320 #[inline(always)]
321 fn internal_resistor(mut self, resistor: Pull) -> Self {
322 self.set_internal_resistor(resistor);
323 self
324 }
325}
326
327impl<const P: char, const N: u8, MODE> PinSpeed for Pin<P, N, MODE>
328where
329 MODE: marker::OutputSpeed,
330{
331 #[inline(always)]
332 fn set_speed(&mut self, speed: Speed) {
333 self.set_speed(speed)
334 }
335}
336
337impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
338where
339 MODE: marker::OutputSpeed,
340{
341 pub fn set_speed(&mut self, speed: Speed) {
343 unsafe { &(*gpiox::<P>()) }
344 .ospeedr()
345 .modify(|_, w| w.ospeedr(N).variant(speed.into()));
346 }
347
348 pub fn speed(mut self, speed: Speed) -> Self {
350 self.set_speed(speed);
351 self
352 }
353}
354
355impl<const P: char, const N: u8, MODE> PinPull for Pin<P, N, MODE>
356where
357 MODE: marker::Active,
358{
359 #[inline(always)]
360 fn set_internal_resistor(&mut self, resistor: Pull) {
361 self.set_internal_resistor(resistor)
362 }
363}
364
365impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
366where
367 MODE: marker::Active,
368{
369 pub fn set_internal_resistor(&mut self, resistor: Pull) {
371 unsafe { &(*gpiox::<P>()) }
372 .pupdr()
373 .modify(|_, w| w.pupdr(N).variant(resistor.into()));
374 }
375
376 pub fn internal_resistor(mut self, resistor: Pull) -> Self {
378 self.set_internal_resistor(resistor);
379 self
380 }
381
382 pub fn internal_pull_up(self, on: bool) -> Self {
384 if on {
385 self.internal_resistor(Pull::Up)
386 } else {
387 self.internal_resistor(Pull::None)
388 }
389 }
390
391 pub fn internal_pull_down(self, on: bool) -> Self {
393 if on {
394 self.internal_resistor(Pull::Down)
395 } else {
396 self.internal_resistor(Pull::None)
397 }
398 }
399}
400
401impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
402 pub fn erase_number(self) -> PartiallyErasedPin<P, MODE> {
407 PartiallyErasedPin::new(N)
408 }
409
410 pub fn erase(self) -> ErasedPin<MODE> {
415 ErasedPin::new(P as u8 - b'A', N)
416 }
417}
418
419impl<const P: char, const N: u8, MODE> From<Pin<P, N, MODE>> for PartiallyErasedPin<P, MODE> {
420 fn from(p: Pin<P, N, MODE>) -> Self {
424 p.erase_number()
425 }
426}
427
428impl<const P: char, const N: u8, MODE> From<Pin<P, N, MODE>> for ErasedPin<MODE> {
429 fn from(p: Pin<P, N, MODE>) -> Self {
433 p.erase()
434 }
435}
436
437impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
438 #[inline(always)]
443 fn _set_state(&mut self, state: PinState) {
444 match state {
445 PinState::High => self._set_high(),
446 PinState::Low => self._set_low(),
447 }
448 }
449 #[inline(always)]
450 fn _set_high(&mut self) {
451 let gpio = unsafe { &(*gpiox::<P>()) };
453 gpio.bsrr().write(|w| w.bs(N).set_bit())
454 }
455 #[inline(always)]
456 fn _set_low(&mut self) {
457 let gpio = unsafe { &(*gpiox::<P>()) };
459 gpio.bsrr().write(|w| w.br(N).set_bit())
460 }
461 #[inline(always)]
462 fn _is_set_low(&self) -> bool {
463 let gpio = unsafe { &(*gpiox::<P>()) };
465 gpio.odr().read().odr(N).bit_is_clear()
466 }
467 #[inline(always)]
468 fn _is_low(&self) -> bool {
469 let gpio = unsafe { &(*gpiox::<P>()) };
471 gpio.idr().read().idr(N).bit_is_clear()
472 }
473}
474
475impl<const P: char, const N: u8, MODE> Pin<P, N, Output<MODE>> {
476 #[inline(always)]
478 pub fn set_high(&mut self) {
479 self._set_high()
480 }
481
482 #[inline(always)]
484 pub fn set_low(&mut self) {
485 self._set_low()
486 }
487
488 #[inline(always)]
490 pub fn get_state(&self) -> PinState {
491 if self.is_set_low() {
492 PinState::Low
493 } else {
494 PinState::High
495 }
496 }
497
498 #[inline(always)]
500 pub fn set_state(&mut self, state: PinState) {
501 match state {
502 PinState::Low => self.set_low(),
503 PinState::High => self.set_high(),
504 }
505 }
506
507 #[inline(always)]
509 pub fn is_set_high(&self) -> bool {
510 !self.is_set_low()
511 }
512
513 #[inline(always)]
515 pub fn is_set_low(&self) -> bool {
516 self._is_set_low()
517 }
518
519 #[inline(always)]
521 pub fn toggle(&mut self) {
522 if self.is_set_low() {
523 self.set_high()
524 } else {
525 self.set_low()
526 }
527 }
528}
529
530pub trait ReadPin {
531 #[inline(always)]
532 fn is_high(&self) -> bool {
533 !self.is_low()
534 }
535 fn is_low(&self) -> bool;
536}
537
538impl<const P: char, const N: u8, MODE> ReadPin for Pin<P, N, MODE>
539where
540 MODE: marker::Readable,
541{
542 #[inline(always)]
543 fn is_low(&self) -> bool {
544 self.is_low()
545 }
546}
547
548impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
549where
550 MODE: marker::Readable,
551{
552 #[inline(always)]
554 pub fn is_high(&self) -> bool {
555 !self.is_low()
556 }
557
558 #[inline(always)]
560 pub fn is_low(&self) -> bool {
561 self._is_low()
562 }
563}
564
565macro_rules! gpio {
566 ($GPIOX:ident, $gpiox:ident, $PEPin:ident, $port_id:expr, $PXn:ident, [
567 $($PXi:ident: ($pxi:ident, $i:expr, [$($A:literal),*] $(, $MODE:ty)?),)+
568 ]) => {
569 pub mod $gpiox {
571 use crate::pac::$GPIOX;
572 use crate::rcc::{Enable, Reset};
573
574 pub struct Parts {
576 $(
577 pub $pxi: $PXi $(<$MODE>)?,
579 )+
580 }
581
582 impl super::GpioExt for $GPIOX {
583 type Parts = Parts;
584
585 fn split(self) -> Parts {
586 unsafe {
587 $GPIOX::enable_unchecked();
589 $GPIOX::reset_unchecked();
590 }
591 Parts {
592 $(
593 $pxi: $PXi::new(),
594 )+
595 }
596 }
597 }
598
599 #[doc="Common type for "]
600 #[doc=stringify!($GPIOX)]
601 #[doc=" related pins"]
602 pub type $PXn<MODE> = super::PartiallyErasedPin<$port_id, MODE>;
603
604 $(
605 #[doc=stringify!($PXi)]
606 #[doc=" pin"]
607 pub type $PXi<MODE = super::DefaultMode> = super::Pin<$port_id, $i, MODE>;
608
609 $(
610 impl<MODE> super::marker::IntoAf<$A> for $PXi<MODE> { }
611 )*
612 )+
613
614 }
615
616 pub use $gpiox::{ $($PXi,)+ };
617 }
618}
619use gpio;
620
621mod f4;
622pub use f4::*;
623
624const fn gpiox<const P: char>() -> *const crate::pac::gpioa::RegisterBlock {
625 match P {
626 'A' => crate::pac::GPIOA::ptr(),
627 'B' => crate::pac::GPIOB::ptr() as _,
628 'C' => crate::pac::GPIOC::ptr() as _,
629 #[cfg(feature = "gpiod")]
630 'D' => crate::pac::GPIOD::ptr() as _,
631 #[cfg(feature = "gpioe")]
632 'E' => crate::pac::GPIOE::ptr() as _,
633 #[cfg(feature = "gpiof")]
634 'F' => crate::pac::GPIOF::ptr() as _,
635 #[cfg(feature = "gpiog")]
636 'G' => crate::pac::GPIOG::ptr() as _,
637 'H' => crate::pac::GPIOH::ptr() as _,
638 #[cfg(feature = "gpioi")]
639 'I' => crate::pac::GPIOI::ptr() as _,
640 #[cfg(feature = "gpioj")]
641 'J' => crate::pac::GPIOJ::ptr() as _,
642 #[cfg(feature = "gpiok")]
643 'K' => crate::pac::GPIOK::ptr() as _,
644 _ => panic!("Unknown GPIO port"),
645 }
646}