1use core::marker::PhantomData;
58
59use crate::pac::{EXTI, SYSCFG};
60use crate::rcc::{Enable, APB2};
61
62mod convert;
63mod partially_erased;
64pub use partially_erased::{PEPin, PartiallyErasedPin};
65mod erased;
66pub use erased::{EPin, ErasedPin};
67mod dynamic;
68pub use dynamic::{Dynamic, DynamicPin};
69mod hal_02;
70
71pub use embedded_hal::digital::v2::PinState;
72
73use core::fmt;
74
75#[derive(Debug)]
77pub struct NoPin;
78
79pub trait GpioExt {
81 type Parts;
83
84 fn split(self) -> Self::Parts;
86}
87
88pub trait PinExt {
89 type Mode;
90 fn pin_id(&self) -> u8;
92 fn port_id(&self) -> u8;
94}
95
96pub struct Alternate<const A: u8, Otype = PushPull>(PhantomData<Otype>);
98
99pub struct Input<MODE = Floating> {
101 _mode: PhantomData<MODE>,
102}
103
104pub struct Floating;
106
107pub struct PullDown;
109
110pub struct PullUp;
112
113pub struct OpenDrain;
115
116pub struct Output<MODE = PushPull> {
118 _mode: PhantomData<MODE>,
119}
120
121pub struct PushPull;
123
124pub struct Analog;
126
127pub type Debugger = Alternate<0, PushPull>;
128
129#[derive(Debug, PartialEq, Eq, Clone, Copy)]
131pub enum Speed {
132 Low = 0,
133 Medium = 1,
134 High = 2,
135 VeryHigh = 3,
136}
137
138#[derive(Debug, PartialEq, Eq, Clone, Copy)]
139pub enum Edge {
140 Rising,
141 Falling,
142 RisingFalling,
143}
144
145mod sealed {
146 pub trait Interruptable {}
148}
149
150use sealed::Interruptable;
151impl<MODE> Interruptable for Output<MODE> {}
152impl<MODE> Interruptable for Input<MODE> {}
153impl<const A: u8, MODE> Interruptable for Alternate<A, MODE> {}
154
155pub trait ExtiPin {
157 fn make_interrupt_source(&mut self, syscfg: &mut SYSCFG, apb2: &mut APB2);
158 fn trigger_on_edge(&mut self, exti: &mut EXTI, level: Edge);
159 fn enable_interrupt(&mut self, exti: &mut EXTI);
160 fn disable_interrupt(&mut self, exti: &mut EXTI);
161 fn clear_interrupt_pending_bit(&mut self);
162 fn check_interrupt(&self) -> bool;
163}
164
165impl<PIN> ExtiPin for PIN
166where
167 PIN: PinExt,
168 PIN::Mode: Interruptable,
169{
170 #[inline(always)]
172 fn make_interrupt_source(&mut self, syscfg: &mut SYSCFG, apb2: &mut APB2) {
173 SYSCFG::enable(apb2);
175
176 let i = self.pin_id();
177 let port = self.port_id() as u32;
178 let offset = 4 * (i % 4);
179 match i {
180 0..=3 => {
181 syscfg.exticr1.modify(|r, w| unsafe {
182 w.bits((r.bits() & !(0xf << offset)) | (port << offset))
183 });
184 }
185 4..=7 => {
186 syscfg.exticr2.modify(|r, w| unsafe {
187 w.bits((r.bits() & !(0xf << offset)) | (port << offset))
188 });
189 }
190 8..=11 => {
191 syscfg.exticr3.modify(|r, w| unsafe {
192 w.bits((r.bits() & !(0xf << offset)) | (port << offset))
193 });
194 }
195 12..=15 => {
196 syscfg.exticr4.modify(|r, w| unsafe {
197 w.bits((r.bits() & !(0xf << offset)) | (port << offset))
198 });
199 }
200 _ => unreachable!(),
201 }
202 }
203
204 #[inline(always)]
206 fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: Edge) {
207 let i = self.pin_id();
208 match edge {
209 Edge::Rising => {
210 exti.rtsr
211 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
212 exti.ftsr
213 .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
214 }
215 Edge::Falling => {
216 exti.ftsr
217 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
218 exti.rtsr
219 .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) });
220 }
221 Edge::RisingFalling => {
222 exti.rtsr
223 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
224 exti.ftsr
225 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) });
226 }
227 }
228 }
229
230 #[inline(always)]
232 fn enable_interrupt(&mut self, exti: &mut EXTI) {
233 exti.imr
234 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.pin_id())) });
235 }
236
237 #[inline(always)]
239 fn disable_interrupt(&mut self, exti: &mut EXTI) {
240 exti.imr
241 .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id())) });
242 }
243
244 #[inline(always)]
246 fn clear_interrupt_pending_bit(&mut self) {
247 unsafe { (*EXTI::ptr()).pr.write(|w| w.bits(1 << self.pin_id())) };
248 }
249
250 #[inline(always)]
252 fn check_interrupt(&self) -> bool {
253 unsafe { ((*EXTI::ptr()).pr.read().bits() & (1 << self.pin_id())) != 0 }
254 }
255}
256
257pub struct Pin<const P: char, const N: u8, MODE = Input<Floating>> {
263 _mode: PhantomData<MODE>,
264}
265impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
266 const fn new() -> Self {
267 Self { _mode: PhantomData }
268 }
269}
270
271impl<const P: char, const N: u8, MODE> fmt::Debug for Pin<P, N, MODE> {
272 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
273 formatter.write_fmt(format_args!(
274 "P{}{}<{}>",
275 P,
276 N,
277 crate::stripped_type_name::<MODE>()
278 ))
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
295impl<const P: char, const N: u8, MODE> Pin<P, N, Output<MODE>> {
296 pub fn set_speed(self, speed: Speed) -> Self {
298 let offset = 2 * { N };
299
300 unsafe {
301 (*Gpio::<P>::ptr())
302 .ospeedr
303 .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | ((speed as u32) << offset)))
304 };
305
306 self
307 }
308}
309
310impl<const P: char, const N: u8> Pin<P, N, Output<OpenDrain>> {
311 pub fn internal_pull_up(self, on: bool) -> Self {
313 let offset = 2 * { N };
314 let value = if on { 0b01 } else { 0b00 };
315 unsafe {
316 (*Gpio::<P>::ptr())
317 .pupdr
318 .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (value << offset)))
319 };
320
321 self
322 }
323
324 pub fn internal_pull_down(self, on: bool) -> Self {
326 let offset = 2 * { N };
327 let value = if on { 0b10 } else { 0b00 };
328 unsafe {
329 (*Gpio::<P>::ptr())
330 .pupdr
331 .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (value << offset)))
332 };
333
334 self
335 }
336}
337
338impl<const P: char, const N: u8, const A: u8> Pin<P, N, Alternate<A, PushPull>> {
339 pub fn set_speed(self, speed: Speed) -> Self {
341 let offset = 2 * { N };
342
343 unsafe {
344 (*Gpio::<P>::ptr())
345 .ospeedr
346 .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | ((speed as u32) << offset)))
347 };
348
349 self
350 }
351
352 pub fn internal_pull_up(self, on: bool) -> Self {
354 let offset = 2 * { N };
355 let value = if on { 0b01 } else { 0b00 };
356 unsafe {
357 (*Gpio::<P>::ptr())
358 .pupdr
359 .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (value << offset)))
360 };
361
362 self
363 }
364
365 pub fn internal_pull_down(self, on: bool) -> Self {
367 let offset = 2 * { N };
368 let value = if on { 0b10 } else { 0b00 };
369 unsafe {
370 (*Gpio::<P>::ptr())
371 .pupdr
372 .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (value << offset)))
373 };
374
375 self
376 }
377}
378
379impl<const P: char, const N: u8, const A: u8> Pin<P, N, Alternate<A, PushPull>> {
380 pub fn set_open_drain(self) -> Pin<P, N, Alternate<A, OpenDrain>> {
382 let offset = { N };
383 unsafe {
384 (*Gpio::<P>::ptr())
385 .otyper
386 .modify(|r, w| w.bits(r.bits() | (1 << offset)))
387 };
388
389 Pin::new()
390 }
391}
392
393impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
394 pub fn erase_number(self) -> PEPin<P, MODE> {
399 PEPin::new(N)
400 }
401
402 pub fn erase(self) -> EPin<MODE> {
407 EPin::new(P as u8 - b'A', N)
408 }
409}
410
411impl<const P: char, const N: u8, MODE> Pin<P, N, MODE> {
412 #[inline(always)]
417 fn _set_state(&mut self, state: PinState) {
418 match state {
419 PinState::High => self._set_high(),
420 PinState::Low => self._set_low(),
421 }
422 }
423 #[inline(always)]
424 fn _set_high(&mut self) {
425 unsafe { (*Gpio::<P>::ptr()).bsrr.write(|w| w.bits(1 << N)) }
427 }
428 #[inline(always)]
429 fn _set_low(&mut self) {
430 unsafe { (*Gpio::<P>::ptr()).bsrr.write(|w| w.bits(1 << (16 + N))) }
432 }
433 #[inline(always)]
434 fn _is_set_low(&self) -> bool {
435 unsafe { (*Gpio::<P>::ptr()).odr.read().bits() & (1 << N) == 0 }
437 }
438 #[inline(always)]
439 fn _is_low(&self) -> bool {
440 unsafe { (*Gpio::<P>::ptr()).idr.read().bits() & (1 << N) == 0 }
442 }
443}
444
445impl<const P: char, const N: u8, MODE> Pin<P, N, Output<MODE>> {
446 #[inline(always)]
447 pub fn set_high(&mut self) {
448 self._set_high()
449 }
450
451 #[inline(always)]
452 pub fn set_low(&mut self) {
453 self._set_low()
454 }
455
456 #[inline(always)]
457 pub fn get_state(&self) -> PinState {
458 if self.is_set_low() {
459 PinState::Low
460 } else {
461 PinState::High
462 }
463 }
464
465 #[inline(always)]
466 pub fn set_state(&mut self, state: PinState) {
467 match state {
468 PinState::Low => self.set_low(),
469 PinState::High => self.set_high(),
470 }
471 }
472
473 #[inline(always)]
474 pub fn is_set_high(&self) -> bool {
475 !self.is_set_low()
476 }
477
478 #[inline(always)]
479 pub fn is_set_low(&self) -> bool {
480 self._is_set_low()
481 }
482
483 #[inline(always)]
484 pub fn toggle(&mut self) {
485 if self.is_set_low() {
486 self.set_high()
487 } else {
488 self.set_low()
489 }
490 }
491}
492
493impl<const P: char, const N: u8> Pin<P, N, Output<OpenDrain>> {
494 #[inline(always)]
495 pub fn is_high(&self) -> bool {
496 !self.is_low()
497 }
498
499 #[inline(always)]
500 pub fn is_low(&self) -> bool {
501 self._is_low()
502 }
503}
504
505impl<const P: char, const N: u8, MODE> Pin<P, N, Input<MODE>> {
506 #[inline(always)]
507 pub fn is_high(&self) -> bool {
508 !self.is_low()
509 }
510
511 #[inline(always)]
512 pub fn is_low(&self) -> bool {
513 self._is_low()
514 }
515}
516
517macro_rules! gpio {
518 ($GPIOX:ident, $gpiox:ident, $PEPin:ident, $port_id:expr, $PXn:ident, [
519 $($PXi:ident: ($pxi:ident, $i:expr $(, $MODE:ty)?),)+
520 ]) => {
521 pub mod $gpiox {
523 use crate::pac::$GPIOX;
524 use crate::rcc::{Enable, Reset};
525 use super::{
526 Floating, Input,
527 };
528
529 pub struct Parts {
531 $(
532 pub $pxi: $PXi $(<$MODE>)?,
534 )+
535 }
536
537 impl super::GpioExt for $GPIOX {
538 type Parts = Parts;
539
540 fn split(self) -> Parts {
541 unsafe {
542 <$GPIOX>::enable_unchecked();
543 <$GPIOX>::reset_unchecked();
544 }
545
546 Parts {
547 $(
548 $pxi: $PXi::new(),
549 )+
550 }
551 }
552 }
553
554 pub type $PXn<MODE> = super::PEPin<$port_id, MODE>;
555
556 $(
557 pub type $PXi<MODE = Input<Floating>> = super::Pin<$port_id, $i, MODE>;
558 )+
559
560 }
561
562 pub use $gpiox::{ $($PXi,)+ };
563 }
564}
565
566gpio!(GPIOA, gpioa, PA, 'A', PAn, [
567 PA0: (pa0, 0),
568 PA1: (pa1, 1),
569 PA2: (pa2, 2),
570 PA3: (pa3, 3),
571 PA4: (pa4, 4),
572 PA5: (pa5, 5),
573 PA6: (pa6, 6),
574 PA7: (pa7, 7),
575 PA8: (pa8, 8),
576 PA9: (pa9, 9),
577 PA10: (pa10, 10),
578 PA11: (pa11, 11),
579 PA12: (pa12, 12),
580 PA13: (pa13, 13, super::Debugger), PA14: (pa14, 14, super::Debugger), PA15: (pa15, 15, super::Debugger), ]);
584
585gpio!(GPIOB, gpiob, PB, 'B', PBn, [
586 PB0: (pb0, 0),
587 PB1: (pb1, 1),
588 PB2: (pb2, 2),
589 PB3: (pb3, 3, super::Debugger), PB4: (pb4, 4, super::Debugger), PB5: (pb5, 5),
592 PB6: (pb6, 6),
593 PB7: (pb7, 7),
594 PB8: (pb8, 8),
595 PB9: (pb9, 9),
596 PB10: (pb10, 10),
597 PB11: (pb11, 11),
598 PB12: (pb12, 12),
599 PB13: (pb13, 13),
600 PB14: (pb14, 14),
601 PB15: (pb15, 15),
602]);
603
604gpio!(GPIOC, gpioc, PC, 'C', PCn, [
605 PC0: (pc0, 0),
606 PC1: (pc1, 1),
607 PC2: (pc2, 2),
608 PC3: (pc3, 3),
609 PC4: (pc4, 4),
610 PC5: (pc5, 5),
611 PC6: (pc6, 6),
612 PC7: (pc7, 7),
613 PC8: (pc8, 8),
614 PC9: (pc9, 9),
615 PC10: (pc10, 10),
616 PC11: (pc11, 11),
617 PC12: (pc12, 12),
618 PC13: (pc13, 13),
619 PC14: (pc14, 14),
620 PC15: (pc15, 15),
621]);
622
623gpio!(GPIOD, gpiod, PD, 'D', PDn, [
624 PD0: (pd0, 0),
625 PD1: (pd1, 1),
626 PD2: (pd2, 2),
627 PD3: (pd3, 3),
628 PD4: (pd4, 4),
629 PD5: (pd5, 5),
630 PD6: (pd6, 6),
631 PD7: (pd7, 7),
632 PD8: (pd8, 8),
633 PD9: (pd9, 9),
634 PD10: (pd10, 10),
635 PD11: (pd11, 11),
636 PD12: (pd12, 12),
637 PD13: (pd13, 13),
638 PD14: (pd14, 14),
639 PD15: (pd15, 15),
640]);
641
642gpio!(GPIOE, gpioe, PE, 'E', PEn, [
643 PE0: (pe0, 0),
644 PE1: (pe1, 1),
645 PE2: (pe2, 2),
646 PE3: (pe3, 3),
647 PE4: (pe4, 4),
648 PE5: (pe5, 5),
649 PE6: (pe6, 6),
650 PE7: (pe7, 7),
651 PE8: (pe8, 8),
652 PE9: (pe9, 9),
653 PE10: (pe10, 10),
654 PE11: (pe11, 11),
655 PE12: (pe12, 12),
656 PE13: (pe13, 13),
657 PE14: (pe14, 14),
658 PE15: (pe15, 15),
659]);
660
661gpio!(GPIOF, gpiof, PF, 'F', PFn, [
662 PF0: (pf0, 0),
663 PF1: (pf1, 1),
664 PF2: (pf2, 2),
665 PF3: (pf3, 3),
666 PF4: (pf4, 4),
667 PF5: (pf5, 5),
668 PF6: (pf6, 6),
669 PF7: (pf7, 7),
670 PF8: (pf8, 8),
671 PF9: (pf9, 9),
672 PF10: (pf10, 10),
673 PF11: (pf11, 11),
674 PF12: (pf12, 12),
675 PF13: (pf13, 13),
676 PF14: (pf14, 14),
677 PF15: (pf15, 15),
678]);
679
680gpio!(GPIOG, gpiog, PG, 'G', PGn, [
681 PG0: (pg0, 0),
682 PG1: (pg1, 1),
683 PG2: (pg2, 2),
684 PG3: (pg3, 3),
685 PG4: (pg4, 4),
686 PG5: (pg5, 5),
687 PG6: (pg6, 6),
688 PG7: (pg7, 7),
689 PG8: (pg8, 8),
690 PG9: (pg9, 9),
691 PG10: (pg10, 10),
692 PG11: (pg11, 11),
693 PG12: (pg12, 12),
694 PG13: (pg13, 13),
695 PG14: (pg14, 14),
696 PG15: (pg15, 15),
697]);
698
699gpio!(GPIOH, gpioh, PH, 'H', PHn, [
700 PH0: (ph0, 0),
701 PH1: (ph1, 1),
702 PH2: (ph2, 2),
703 PH3: (ph3, 3),
704 PH4: (ph4, 4),
705 PH5: (ph5, 5),
706 PH6: (ph6, 6),
707 PH7: (ph7, 7),
708 PH8: (ph8, 8),
709 PH9: (ph9, 9),
710 PH10: (ph10, 10),
711 PH11: (ph11, 11),
712 PH12: (ph12, 12),
713 PH13: (ph13, 13),
714 PH14: (ph14, 14),
715 PH15: (ph15, 15),
716]);
717
718gpio!(GPIOI, gpioi, PI, 'I', PIn, [
719 PI0: (pi0, 0),
720 PI1: (pi1, 1),
721 PI2: (pi2, 2),
722 PI3: (pi3, 3),
723 PI4: (pi4, 4),
724 PI5: (pi5, 5),
725 PI6: (pi6, 6),
726 PI7: (pi7, 7),
727 PI8: (pi8, 8),
728 PI9: (pi9, 9),
729 PI10: (pi10, 10),
730 PI11: (pi11, 11),
731 PI12: (pi12, 12),
732 PI13: (pi13, 13),
733 PI14: (pi14, 14),
734 PI15: (pi15, 15),
735]);
736
737#[cfg(feature = "gpioj")]
738gpio!(GPIOJ, gpioj, PJ, 'J', PJn, [
739 PJ0: (pj0, 0),
740 PJ1: (pj1, 1),
741 PJ2: (pj2, 2),
742 PJ3: (pj3, 3),
743 PJ4: (pj4, 4),
744 PJ5: (pj5, 5),
745 PJ6: (pj6, 6),
746 PJ7: (pj7, 7),
747 PJ8: (pj8, 8),
748 PJ9: (pj9, 9),
749 PJ10: (pj10, 10),
750 PJ11: (pj11, 11),
751 PJ12: (pj12, 12),
752 PJ13: (pj13, 13),
753 PJ14: (pj14, 14),
754 PJ15: (pj15, 15),
755]);
756
757#[cfg(feature = "gpiok")]
758gpio!(GPIOK, gpiok, PK, 'K', PKn, [
759 PK0: (pk0, 0),
760 PK1: (pk1, 1),
761 PK2: (pk2, 2),
762 PK3: (pk3, 3),
763 PK4: (pk4, 4),
764 PK5: (pk5, 5),
765 PK6: (pk6, 6),
766 PK7: (pk7, 7),
767]);
768
769struct Gpio<const P: char>;
770impl<const P: char> Gpio<P> {
771 const fn ptr() -> *const crate::pac::gpioa::RegisterBlock {
772 match P {
773 'A' => crate::pac::GPIOA::ptr(),
774 'B' => crate::pac::GPIOB::ptr() as _,
775 'C' => crate::pac::GPIOC::ptr() as _,
776 'D' => crate::pac::GPIOD::ptr() as _,
777 'E' => crate::pac::GPIOE::ptr() as _,
778 'F' => crate::pac::GPIOF::ptr() as _,
779 'G' => crate::pac::GPIOG::ptr() as _,
780 'H' => crate::pac::GPIOH::ptr() as _,
781 'I' => crate::pac::GPIOI::ptr() as _,
782 #[cfg(feature = "gpioj")]
783 'J' => crate::pac::GPIOJ::ptr() as _,
784 #[cfg(feature = "gpiok")]
785 'K' => crate::pac::GPIOK::ptr() as _,
786 _ => crate::pac::GPIOA::ptr(),
787 }
788 }
789}