1use core::marker::PhantomData;
58
59use crate::pac::{self, RCC};
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
79pub trait GpioExt {
81 type Parts;
83
84 fn split(self, rcc: &mut RCC) -> Self::Parts;
86}
87
88pub trait PinExt {
90 type Mode;
92 fn pin_id(&self) -> u8;
94 fn port_id(&self) -> u8;
96}
97
98#[derive(Debug, Default)]
100#[cfg_attr(feature = "defmt", derive(defmt::Format))]
101pub struct Alternate<const A: u8, Otype = PushPull>(PhantomData<Otype>);
102
103#[derive(Debug, Default)]
105#[cfg_attr(feature = "defmt", derive(defmt::Format))]
106pub struct Input;
107
108#[derive(Clone, Copy, Debug, Eq, PartialEq)]
110#[cfg_attr(feature = "defmt", derive(defmt::Format))]
111pub enum Pull {
112 None = 0,
114 Up = 1,
116 Down = 2,
118}
119
120impl From<Pull> for pac::gpioa::pupdr::PULL {
121 fn from(value: Pull) -> Self {
122 match value {
123 Pull::Down => Self::PullDown,
124 Pull::Up => Self::PullUp,
125 Pull::None => Self::Floating,
126 }
127 }
128}
129
130#[derive(Debug, Default)]
132#[cfg_attr(feature = "defmt", derive(defmt::Format))]
133pub struct OpenDrain;
134
135#[derive(Debug, Default)]
137#[cfg_attr(feature = "defmt", derive(defmt::Format))]
138pub struct Output<Otype = PushPull> {
139 _mode: PhantomData<Otype>,
140}
141
142#[derive(Debug, Default)]
144#[cfg_attr(feature = "defmt", derive(defmt::Format))]
145pub struct PushPull;
146
147#[derive(Debug, Default)]
149#[cfg_attr(feature = "defmt", derive(defmt::Format))]
150pub struct Analog;
151
152pub type Debugger = Alternate<0, PushPull>;
154
155pub(crate) mod marker {
156 pub trait Interruptible {}
158 pub trait Readable {}
160 pub trait OutputSpeed {}
162 pub trait Active {}
164 pub trait NotAlt {}
166 pub trait IntoAf<const A: u8> {}
168}
169
170impl<MODE> marker::Interruptible for Output<MODE> {}
171impl marker::Interruptible for Input {}
172impl marker::Readable for Input {}
173impl marker::Readable for Output<OpenDrain> {}
174impl<const A: u8, Otype> marker::Interruptible for Alternate<A, Otype> {}
175impl<const A: u8, Otype> marker::Readable for Alternate<A, Otype> {}
176impl marker::Active for Input {}
177impl<Otype> marker::OutputSpeed for Output<Otype> {}
178impl<const A: u8, Otype> marker::OutputSpeed for Alternate<A, Otype> {}
179impl<Otype> marker::Active for Output<Otype> {}
180impl<const A: u8, Otype> marker::Active for Alternate<A, Otype> {}
181impl marker::NotAlt for Input {}
182impl<Otype> marker::NotAlt for Output<Otype> {}
183impl marker::NotAlt for Analog {}
184
185#[cfg_attr(feature = "defmt", derive(defmt::Format))]
187#[derive(Debug, PartialEq, Eq, Clone, Copy)]
188pub enum Speed {
189 Low = 0,
191 Medium = 1,
193 High = 2,
195 VeryHigh = 3,
197}
198
199impl From<Speed> for pac::gpioa::ospeedr::OUTPUT_SPEED {
200 fn from(value: Speed) -> Self {
201 match value {
202 Speed::Low => Self::LowSpeed,
203 Speed::Medium => Self::MediumSpeed,
204 Speed::High => Self::HighSpeed,
205 Speed::VeryHigh => Self::VeryHighSpeed,
206 }
207 }
208}
209
210#[cfg_attr(feature = "defmt", derive(defmt::Format))]
212#[derive(Debug, PartialEq, Eq, Clone, Copy)]
213pub enum Edge {
214 Rising,
216 Falling,
218 RisingFalling,
220}
221
222macro_rules! af {
223 ($($i:literal: $AFi:ident),+) => {
224 $(
225 #[doc = concat!("Alternate function ", $i, " (type state)" )]
226 pub type $AFi<Otype = PushPull> = Alternate<$i, Otype>;
227 )+
228 };
229}
230
231af!(
232 0: AF0,
233 1: AF1,
234 2: AF2,
235 3: AF3,
236 4: AF4,
237 5: AF5,
238 6: AF6,
239 7: AF7,
240 8: AF8,
241 9: AF9,
242 10: AF10,
243 11: AF11,
244 12: AF12,
245 13: AF13,
246 14: AF14,
247 15: AF15
248);
249
250pub struct Pin<const P: char, const N: u8, MODE = DefaultMode> {
256 _mode: PhantomData<MODE>,
257}
258impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
259 const fn new() -> Self {
260 Self { _mode: PhantomData }
261 }
262}
263
264impl<const P: char, const N: u8, MODE> fmt::Debug for Pin<P, N, MODE> {
265 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
266 formatter.write_fmt(format_args!(
267 "P{}{}<{}>",
268 P,
269 N,
270 crate::stripped_type_name::<MODE>()
271 ))
272 }
273}
274
275#[cfg(feature = "defmt")]
276impl<const P: char, const N: u8, MODE> defmt::Format for Pin<P, N, MODE> {
277 fn format(&self, f: defmt::Formatter) {
278 defmt::write!(f, "P{}{}<{}>", P, N, crate::stripped_type_name::<MODE>());
279 }
280}
281
282impl<const P: char, const N: u8, MODE> PinExt for Pin<P, N, MODE> {
283 type Mode = MODE;
284
285 #[inline(always)]
286 fn pin_id(&self) -> u8 {
287 N
288 }
289 #[inline(always)]
290 fn port_id(&self) -> u8 {
291 P as u8 - b'A'
292 }
293}
294
295pub trait PinSpeed: Sized {
296 fn set_speed(&mut self, speed: Speed);
298
299 #[inline(always)]
300 fn speed(mut self, speed: Speed) -> Self {
301 self.set_speed(speed);
302 self
303 }
304}
305
306pub trait PinPull: Sized {
307 fn set_internal_resistor(&mut self, resistor: Pull);
309
310 #[inline(always)]
311 fn internal_resistor(mut self, resistor: Pull) -> Self {
312 self.set_internal_resistor(resistor);
313 self
314 }
315}
316
317impl<const P: char, const N: u8, MODE> PinSpeed for Pin<P, N, MODE>
318where
319 MODE: marker::OutputSpeed,
320{
321 #[inline(always)]
322 fn set_speed(&mut self, speed: Speed) {
323 self.set_speed(speed)
324 }
325}
326
327impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
328where
329 MODE: marker::OutputSpeed,
330{
331 pub fn set_speed(&mut self, speed: Speed) {
333 unsafe { &(*gpiox::<P>()) }
334 .ospeedr()
335 .modify(|_, w| w.ospeedr(N).variant(speed.into()));
336 }
337
338 pub fn speed(mut self, speed: Speed) -> Self {
340 self.set_speed(speed);
341 self
342 }
343}
344
345impl<const P: char, const N: u8, MODE> PinPull for Pin<P, N, MODE>
346where
347 MODE: marker::Active,
348{
349 #[inline(always)]
350 fn set_internal_resistor(&mut self, resistor: Pull) {
351 self.set_internal_resistor(resistor)
352 }
353}
354
355impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
356where
357 MODE: marker::Active,
358{
359 pub fn set_internal_resistor(&mut self, resistor: Pull) {
361 unsafe { &(*gpiox::<P>()) }
362 .pupdr()
363 .modify(|_, w| w.pupdr(N).variant(resistor.into()));
364 }
365
366 pub fn internal_resistor(mut self, resistor: Pull) -> Self {
368 self.set_internal_resistor(resistor);
369 self
370 }
371
372 pub fn internal_pull_up(self, on: bool) -> Self {
374 if on {
375 self.internal_resistor(Pull::Up)
376 } else {
377 self.internal_resistor(Pull::None)
378 }
379 }
380
381 pub fn internal_pull_down(self, on: bool) -> Self {
383 if on {
384 self.internal_resistor(Pull::Down)
385 } else {
386 self.internal_resistor(Pull::None)
387 }
388 }
389}
390
391impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
392 pub fn erase_number(self) -> PartiallyErasedPin<P, MODE> {
397 PartiallyErasedPin::new(N)
398 }
399
400 pub fn erase(self) -> AnyPin<MODE> {
405 AnyPin::new(P as u8 - b'A', N)
406 }
407}
408
409impl<const P: char, const N: u8, MODE> From<Pin<P, N, MODE>> for PartiallyErasedPin<P, MODE> {
410 fn from(p: Pin<P, N, MODE>) -> Self {
414 p.erase_number()
415 }
416}
417
418impl<const P: char, const N: u8, MODE> From<Pin<P, N, MODE>> for AnyPin<MODE> {
419 fn from(p: Pin<P, N, MODE>) -> Self {
423 p.erase()
424 }
425}
426
427impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
428 #[inline(always)]
433 fn _set_state(&mut self, state: PinState) {
434 match state {
435 PinState::High => self._set_high(),
436 PinState::Low => self._set_low(),
437 }
438 }
439 #[inline(always)]
440 fn _set_high(&mut self) {
441 let gpio = unsafe { &(*gpiox::<P>()) };
443 gpio.bsrr().write(|w| w.bs(N).set_bit());
444 }
445 #[inline(always)]
446 fn _set_low(&mut self) {
447 let gpio = unsafe { &(*gpiox::<P>()) };
449 gpio.bsrr().write(|w| w.br(N).set_bit());
450 }
451 #[inline(always)]
452 fn _is_set_low(&self) -> bool {
453 let gpio = unsafe { &(*gpiox::<P>()) };
455 gpio.odr().read().odr(N).bit_is_clear()
456 }
457 #[inline(always)]
458 fn _is_low(&self) -> bool {
459 let gpio = unsafe { &(*gpiox::<P>()) };
461 gpio.idr().read().idr(N).bit_is_clear()
462 }
463}
464
465impl<const P: char, const N: u8, MODE> Pin<P, N, Output<MODE>> {
466 #[inline(always)]
468 pub fn set_high(&mut self) {
469 self._set_high()
470 }
471
472 #[inline(always)]
474 pub fn set_low(&mut self) {
475 self._set_low()
476 }
477
478 #[inline(always)]
480 pub fn get_state(&self) -> PinState {
481 if self.is_set_low() {
482 PinState::Low
483 } else {
484 PinState::High
485 }
486 }
487
488 #[inline(always)]
490 pub fn set_state(&mut self, state: PinState) {
491 match state {
492 PinState::Low => self.set_low(),
493 PinState::High => self.set_high(),
494 }
495 }
496
497 #[inline(always)]
499 pub fn is_set_high(&self) -> bool {
500 !self.is_set_low()
501 }
502
503 #[inline(always)]
505 pub fn is_set_low(&self) -> bool {
506 self._is_set_low()
507 }
508
509 #[inline(always)]
511 pub fn toggle(&mut self) {
512 if self.is_set_low() {
513 self.set_high()
514 } else {
515 self.set_low()
516 }
517 }
518}
519
520pub trait ReadPin {
521 #[inline(always)]
522 fn is_high(&self) -> bool {
523 !self.is_low()
524 }
525 fn is_low(&self) -> bool;
526}
527
528impl<const P: char, const N: u8, MODE> ReadPin for Pin<P, N, MODE>
529where
530 MODE: marker::Readable,
531{
532 #[inline(always)]
533 fn is_low(&self) -> bool {
534 self.is_low()
535 }
536}
537
538impl<const P: char, const N: u8, MODE> Pin<P, N, MODE>
539where
540 MODE: marker::Readable,
541{
542 #[inline(always)]
544 pub fn is_high(&self) -> bool {
545 !self.is_low()
546 }
547
548 #[inline(always)]
550 pub fn is_low(&self) -> bool {
551 self._is_low()
552 }
553}
554
555macro_rules! gpio {
556 ($GPIOX:ident, $gpiox:ident, $PEPin:ident, $port_id:expr, $PXn:ident, [
557 $($PXi:ident: ($pxi:ident, $i:expr, [$($A:literal),*] $(, $MODE:ty)?),)+
558 ]) => {
559 pub mod $gpiox {
561 use crate::pac::{$GPIOX, RCC};
562 use crate::rcc::{Enable, Reset};
563
564 pub struct Parts {
566 $(
567 pub $pxi: $PXi $(<$MODE>)?,
569 )+
570 }
571
572 impl super::GpioExt for $GPIOX {
573 type Parts = Parts;
574
575 fn split(self, rcc: &mut RCC) -> Parts {
576 $GPIOX::enable(rcc);
578 $GPIOX::reset(rcc);
579 Parts {
580 $(
581 $pxi: $PXi::new(),
582 )+
583 }
584 }
585 }
586
587 #[doc="Common type for "]
588 #[doc=stringify!($GPIOX)]
589 #[doc=" related pins"]
590 pub type $PXn<MODE> = super::PartiallyErasedPin<$port_id, MODE>;
591
592 $(
593 #[doc=stringify!($PXi)]
594 #[doc=" pin"]
595 pub type $PXi<MODE = super::DefaultMode> = super::Pin<$port_id, $i, MODE>;
596
597 $(
598 impl<MODE> super::marker::IntoAf<$A> for $PXi<MODE> { }
599 )*
600 )+
601
602 }
603
604 pub use $gpiox::{ $($PXi,)+ };
605 }
606}
607use gpio;
608
609mod f4;
610pub use f4::*;
611
612const fn gpiox<const P: char>() -> *const crate::pac::gpioa::RegisterBlock {
613 match P {
614 'A' => crate::pac::GPIOA::ptr(),
615 'B' => crate::pac::GPIOB::ptr() as _,
616 'C' => crate::pac::GPIOC::ptr() as _,
617 #[cfg(feature = "gpiod")]
618 'D' => crate::pac::GPIOD::ptr() as _,
619 #[cfg(feature = "gpioe")]
620 'E' => crate::pac::GPIOE::ptr() as _,
621 #[cfg(feature = "gpiof")]
622 'F' => crate::pac::GPIOF::ptr() as _,
623 #[cfg(feature = "gpiog")]
624 'G' => crate::pac::GPIOG::ptr() as _,
625 'H' => crate::pac::GPIOH::ptr() as _,
626 #[cfg(feature = "gpioi")]
627 'I' => crate::pac::GPIOI::ptr() as _,
628 #[cfg(feature = "gpioj")]
629 'J' => crate::pac::GPIOJ::ptr() as _,
630 #[cfg(feature = "gpiok")]
631 'K' => crate::pac::GPIOK::ptr() as _,
632 _ => panic!("Unknown GPIO port"),
633 }
634}