1use core::marker::PhantomData;
3
4use crate::rcc::Rcc;
5use core::convert::Infallible;
6use embedded_hal::digital::v2::PinState;
7use hal::digital::v2::{toggleable, InputPin, OutputPin, StatefulOutputPin};
8
9pub type DefaultMode = Analog;
11
12pub trait GpioExt {
14 type Parts;
16
17 fn split(self, rcc: &mut Rcc) -> Self::Parts;
19}
20
21trait GpioRegExt {
22 fn is_low(&self, pos: u8) -> bool;
23 fn is_set_low(&self, pos: u8) -> bool;
24 fn set_high(&self, pos: u8);
25 fn set_low(&self, pos: u8);
26}
27
28pub struct Input<MODE> {
30 _mode: PhantomData<MODE>,
31}
32
33pub struct Floating;
35
36pub struct PullDown;
38
39pub struct PullUp;
41
42pub struct OpenDrain;
44
45pub struct Analog;
47
48pub struct Output<MODE> {
50 _mode: PhantomData<MODE>,
51}
52
53pub struct PushPull;
55
56pub struct Pin<MODE> {
58 i: u8,
59 port: *const dyn GpioRegExt,
60 _mode: PhantomData<MODE>,
61}
62
63macro_rules! gpio_trait {
64 ($gpiox:ident) => {
65 impl GpioRegExt for crate::stm32::$gpiox::RegisterBlock {
66 fn is_low(&self, pos: u8) -> bool {
67 self.idr.read().bits() & (1 << pos) == 0
69 }
70
71 fn is_set_low(&self, pos: u8) -> bool {
72 self.odr.read().bits() & (1 << pos) == 0
74 }
75
76 fn set_high(&self, pos: u8) {
77 unsafe { self.bsrr.write(|w| w.bits(1 << pos)) }
79 }
80
81 fn set_low(&self, pos: u8) {
82 unsafe { self.bsrr.write(|w| w.bits(1 << (pos + 16))) }
84 }
85 }
86 };
87}
88
89gpio_trait!(gpioa);
90gpio_trait!(gpiob);
91
92unsafe impl<MODE> Sync for Pin<MODE> {}
94unsafe impl<MODE> Send for Pin<MODE> {}
97
98impl<MODE> StatefulOutputPin for Pin<Output<MODE>> {
99 #[inline(always)]
100 fn is_set_high(&self) -> Result<bool, Self::Error> {
101 self.is_set_low().map(|v| !v)
102 }
103
104 #[inline(always)]
105 fn is_set_low(&self) -> Result<bool, Self::Error> {
106 Ok(unsafe { (*self.port).is_set_low(self.i) })
107 }
108}
109
110impl<MODE> OutputPin for Pin<Output<MODE>> {
111 type Error = Infallible;
112
113 #[inline(always)]
114 fn set_high(&mut self) -> Result<(), Self::Error> {
115 unsafe { (*self.port).set_high(self.i) };
116 Ok(())
117 }
118
119 #[inline(always)]
120 fn set_low(&mut self) -> Result<(), Self::Error> {
121 unsafe { (*self.port).set_low(self.i) }
122 Ok(())
123 }
124}
125
126impl<MODE> toggleable::Default for Pin<Output<MODE>> {}
127
128impl InputPin for Pin<Output<OpenDrain>> {
129 type Error = Infallible;
130
131 #[inline(always)]
132 fn is_high(&self) -> Result<bool, Self::Error> {
133 self.is_low().map(|v| !v)
134 }
135
136 #[inline(always)]
137 fn is_low(&self) -> Result<bool, Self::Error> {
138 Ok(unsafe { (*self.port).is_low(self.i) })
139 }
140}
141
142impl<MODE> InputPin for Pin<Input<MODE>> {
143 type Error = Infallible;
144
145 #[inline(always)]
146 fn is_high(&self) -> Result<bool, Self::Error> {
147 self.is_low().map(|v| !v)
148 }
149
150 #[inline(always)]
151 fn is_low(&self) -> Result<bool, Self::Error> {
152 Ok(unsafe { (*self.port).is_low(self.i) })
153 }
154}
155
156#[derive(Debug, PartialEq, Eq, Clone, Copy)]
158pub enum Speed {
159 Low = 0,
160 Medium = 1,
161 High = 2,
162 VeryHigh = 3,
163}
164
165#[derive(Debug, PartialEq, Eq, Clone, Copy)]
167pub enum SignalEdge {
168 Rising,
169 Falling,
170 All,
171}
172
173#[allow(dead_code)]
174pub(crate) enum AltFunction {
175 AF0 = 0,
176 AF1 = 1,
177 AF2 = 2,
178 AF3 = 3,
179 AF4 = 4,
180 AF5 = 5,
181 AF6 = 6,
182 AF7 = 7,
183}
184
185macro_rules! gpio {
186 ($GPIOX:ident, $gpiox:ident, $PXx:ident, $Pxn:expr, [
187 $($PXi:ident: ($pxi:ident, $i:expr),)+
188 ]) => {
189 pub mod $gpiox {
191 use core::convert::Infallible;
192 use core::marker::PhantomData;
193 use hal::digital::v2::{toggleable, InputPin, OutputPin, StatefulOutputPin};
194 use crate::stm32::{EXTI, $GPIOX};
195 use crate::exti::{ExtiExt, Event};
196 use crate::rcc::{Enable, Rcc};
197 use super::*;
198
199 pub struct Parts {
201 $(
202 pub $pxi: $PXi<DefaultMode>,
203 )+
204 }
205
206 impl GpioExt for $GPIOX {
207 type Parts = Parts;
208
209 fn split(self, rcc: &mut Rcc) -> Parts {
210 <$GPIOX>::enable(rcc);
211
212 Parts {
213 $(
214 $pxi: $PXi { _mode: PhantomData },
215 )+
216 }
217 }
218 }
219
220 pub struct $PXx<MODE> {
222 i: u8,
223 _mode: PhantomData<MODE>,
224 }
225
226 impl<MODE> OutputPin for $PXx<Output<MODE>> {
227 type Error = Infallible;
228
229 fn set_high(&mut self) -> Result<(), Self::Error> {
230 unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) };
232 Ok(())
233 }
234
235 fn set_low(&mut self) -> Result<(), Self::Error> {
236 unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (self.i + 16))) };
238 Ok(())
239 }
240 }
241
242 impl<MODE> StatefulOutputPin for $PXx<Output<MODE>> {
243 fn is_set_high(&self) -> Result<bool, Self::Error> {
244 let is_set_high = !self.is_set_low()?;
245 Ok(is_set_high)
246 }
247
248 fn is_set_low(&self) -> Result<bool, Self::Error> {
249 let is_set_low = unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << self.i) == 0 };
251 Ok(is_set_low)
252 }
253 }
254
255 impl<MODE> toggleable::Default for $PXx<Output<MODE>> {
256 }
257
258 impl<MODE> InputPin for $PXx<Output<MODE>> {
259 type Error = Infallible;
260
261 fn is_high(&self) -> Result<bool, Self::Error> {
262 let is_high = !self.is_low()?;
263 Ok(is_high)
264 }
265
266 fn is_low(&self) -> Result<bool, Self::Error> {
267 let is_low = unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 };
269 Ok(is_low)
270 }
271 }
272
273 impl<MODE> InputPin for $PXx<Input<MODE>> {
274 type Error = Infallible;
275
276 fn is_high(&self) -> Result<bool, Self::Error> {
277 let is_high = !self.is_low()?;
278 Ok(is_high)
279 }
280
281 fn is_low(&self) -> Result<bool, Self::Error> {
282 let is_low = unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 };
284 Ok(is_low)
285 }
286 }
287
288 $(
289 pub struct $PXi<MODE> {
290 _mode: PhantomData<MODE>,
291 }
292
293 #[allow(clippy::from_over_into)]
294 impl Into<$PXi<Input<PullDown>>> for $PXi<DefaultMode> {
295 fn into(self) -> $PXi<Input<PullDown>> {
296 self.into_pull_down_input()
297 }
298 }
299
300 #[allow(clippy::from_over_into)]
301 impl Into<$PXi<Input<PullUp>>> for $PXi<DefaultMode> {
302 fn into(self) -> $PXi<Input<PullUp>> {
303 self.into_pull_up_input()
304 }
305 }
306
307 #[allow(clippy::from_over_into)]
308 impl Into<$PXi<Input<Floating>>> for $PXi<DefaultMode> {
309 fn into(self) -> $PXi<Input<Floating>> {
310 self.into_floating_input()
311 }
312 }
313
314 #[allow(clippy::from_over_into)]
315 impl Into<$PXi<Output<OpenDrain>>> for $PXi<DefaultMode> {
316 fn into(self) -> $PXi<Output<OpenDrain>> {
317 self.into_open_drain_output()
318 }
319 }
320
321 #[allow(clippy::from_over_into)]
322 impl Into<$PXi<Output<PushPull>>> for $PXi<DefaultMode> {
323 fn into(self) -> $PXi<Output<PushPull>> {
324 self.into_push_pull_output()
325 }
326 }
327
328 impl<MODE> $PXi<MODE> {
329 pub fn into_floating_input(self) -> $PXi<Input<Floating>> {
331 let offset = 2 * $i;
332 unsafe {
333 let gpio = &(*$GPIOX::ptr());
334 gpio.pupdr.modify(|r, w| {
335 w.bits(r.bits() & !(0b11 << offset))
336 });
337 gpio.moder.modify(|r, w| {
338 w.bits(r.bits() & !(0b11 << offset))
339 })
340 };
341 $PXi { _mode: PhantomData }
342 }
343
344 pub fn into_pull_down_input(self) -> $PXi<Input<PullDown>> {
346 let offset = 2 * $i;
347 unsafe {
348 let gpio = &(*$GPIOX::ptr());
349 gpio.pupdr.modify(|r, w| {
350 w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
351 });
352 gpio.moder.modify(|r, w| {
353 w.bits(r.bits() & !(0b11 << offset))
354 })
355 };
356 $PXi { _mode: PhantomData }
357 }
358
359 pub fn into_pull_up_input(self) -> $PXi<Input<PullUp>> {
361 let offset = 2 * $i;
362 unsafe {
363 let gpio = &(*$GPIOX::ptr());
364 gpio.pupdr.modify(|r, w| {
365 w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
366 });
367 gpio.moder.modify(|r, w| {
368 w.bits(r.bits() & !(0b11 << offset))
369 })
370 };
371 $PXi { _mode: PhantomData }
372 }
373
374 pub fn into_analog(self) -> $PXi<Analog> {
376 let offset = 2 * $i;
377 unsafe {
378 let gpio = &(*$GPIOX::ptr());
379 gpio.pupdr.modify(|r, w| {
380 w.bits(r.bits() & !(0b11 << offset))
381 });
382 gpio.moder.modify(|r, w| {
383 w.bits((r.bits() & !(0b11 << offset)) | (0b11 << offset))
384 });
385 }
386 $PXi { _mode: PhantomData }
387 }
388
389 pub fn into_open_drain_output_in_state(mut self, initial_state: PinState) -> $PXi<Output<OpenDrain>> {
393 self.internal_set_state(initial_state);
394 self.into_open_drain_output()
395 }
396
397 pub fn into_open_drain_output(self) -> $PXi<Output<OpenDrain>> {
399 let offset = 2 * $i;
400 unsafe {
401 let gpio = &(*$GPIOX::ptr());
402 gpio.pupdr.modify(|r, w| {
403 w.bits(r.bits() & !(0b11 << offset))
404 });
405 gpio.otyper.modify(|r, w| {
406 w.bits(r.bits() | (0b1 << $i))
407 });
408 gpio.moder.modify(|r, w| {
409 w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
410 })
411 };
412 $PXi { _mode: PhantomData }
413 }
414
415 pub fn into_push_pull_output_in_state(mut self, initial_state: PinState) -> $PXi<Output<PushPull>> {
419 self.internal_set_state(initial_state);
420 self.into_push_pull_output()
421 }
422
423 pub fn into_push_pull_output(self) -> $PXi<Output<PushPull>> {
425 let offset = 2 * $i;
426 unsafe {
427 let gpio = &(*$GPIOX::ptr());
428 gpio.pupdr.modify(|r, w| {
429 w.bits(r.bits() & !(0b11 << offset))
430 });
431 gpio.otyper.modify(|r, w| {
432 w.bits(r.bits() & !(0b1 << $i))
433 });
434 gpio.moder.modify(|r, w| {
435 w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
436 })
437 };
438 $PXi { _mode: PhantomData }
439 }
440
441 pub fn listen(self, edge: SignalEdge, exti: &mut EXTI) -> $PXi<Input<Floating>> {
443 let offset = 2 * $i;
444 unsafe {
445 let _ = &(*$GPIOX::ptr()).pupdr.modify(|r, w| {
446 w.bits(r.bits() & !(0b11 << offset))
447 });
448 &(*$GPIOX::ptr()).moder.modify(|r, w| {
449 w.bits(r.bits() & !(0b11 << offset))
450 })
451 };
452 let offset = ($i % 4) * 8;
453 let mask = $Pxn << offset;
454 let reset = !(0xff << offset);
455 match $i as u8 {
456 0..=3 => exti.exticr1.modify(|r, w| unsafe {
457 w.bits(r.bits() & reset | mask)
458 }),
459 4..=7 => exti.exticr2.modify(|r, w| unsafe {
460 w.bits(r.bits() & reset | mask)
461 }),
462 8..=11 => exti.exticr3.modify(|r, w| unsafe {
463 w.bits(r.bits() & reset | mask)
464 }),
465 12..=16 => exti.exticr4.modify(|r, w| unsafe {
466 w.bits(r.bits() & reset | mask)
467 }),
468 _ => unreachable!(),
469 }
470 exti.listen(Event::from_code($i), edge);
471 $PXi { _mode: PhantomData }
472 }
473
474 pub fn set_speed(self, speed: Speed) -> Self {
476 let offset = 2 * $i;
477 unsafe {
478 &(*$GPIOX::ptr()).ospeedr.modify(|r, w| {
479 w.bits((r.bits() & !(0b11 << offset)) | ((speed as u32) << offset))
480 })
481 };
482 self
483 }
484
485 #[allow(dead_code)]
486 pub(crate) fn set_alt_mode(&self, mode: AltFunction) {
487 let mode = mode as u32;
488 let offset = 2 * $i;
489 let offset2 = 4 * $i;
490 unsafe {
491 let gpio = &(*$GPIOX::ptr());
492 if offset2 < 32 {
493 gpio.afrl.modify(|r, w| {
494 w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2))
495 });
496 } else {
497 let offset2 = offset2 - 32;
498 gpio.afrh.modify(|r, w| {
499 w.bits((r.bits() & !(0b1111 << offset2)) | (mode << offset2))
500 });
501 }
502 gpio.moder.modify(|r, w| {
503 w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
504 });
505 }
506 }
507
508 fn internal_set_state(&mut self, state: PinState) {
509 match state {
510 PinState::High => {
511 unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) };
513 }
514 PinState::Low => {
515 unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << ($i + 16))) };
517 }
518 }
519 }
520 }
521
522 impl<MODE> $PXi<Output<MODE>> {
523 pub fn downgrade(self) -> $PXx<Output<MODE>> {
528 $PXx { i: $i, _mode: self._mode }
529 }
530 }
531
532 impl<MODE> OutputPin for $PXi<Output<MODE>> {
533 type Error = Infallible;
534
535 fn set_high(&mut self) -> Result<(), Self::Error> {
536 self.internal_set_state(PinState::High);
537 Ok(())
538 }
539
540 fn set_low(&mut self) -> Result<(), Self::Error>{
541 self.internal_set_state(PinState::Low);
542 Ok(())
543 }
544 }
545
546 impl<MODE> StatefulOutputPin for $PXi<Output<MODE>> {
547 fn is_set_high(&self) -> Result<bool, Self::Error> {
548 let is_set_high = !self.is_set_low()?;
549 Ok(is_set_high)
550 }
551
552 fn is_set_low(&self) -> Result<bool, Self::Error> {
553 let is_set_low = unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 };
555 Ok(is_set_low)
556 }
557 }
558
559 impl<MODE> toggleable::Default for $PXi<Output<MODE>> {
560 }
561
562 impl<MODE> InputPin for $PXi<Output<MODE>> {
563 type Error = Infallible;
564
565 fn is_high(&self) -> Result<bool, Self::Error> {
566 let is_high = !self.is_low()?;
567 Ok(is_high)
568 }
569
570 fn is_low(&self) -> Result<bool, Self::Error> {
571 let is_low = unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 };
573 Ok(is_low)
574 }
575 }
576
577 impl<MODE> $PXi<Input<MODE>> {
578 pub fn downgrade(self) -> $PXx<Input<MODE>> {
583 $PXx { i: $i, _mode: self._mode }
584 }
585 }
586
587 impl<MODE> InputPin for $PXi<Input<MODE>> {
588 type Error = Infallible;
589
590 fn is_high(&self) -> Result<bool, Self::Error> {
591 let is_high = !self.is_low()?;
592 Ok(is_high)
593 }
594
595 fn is_low(&self) -> Result<bool, Self::Error> {
596 let is_low = unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 };
598 Ok(is_low)
599 }
600 }
601 )+
602
603 impl<TYPE> $PXx<TYPE> {
604 pub fn get_id (&self) -> u8 {
605 self.i
606 }
607 }
608
609 impl<MODE> $PXx<Output<MODE>> {
610 pub fn downgrade(self) -> Pin<Output<MODE>> {
615 Pin {
616 i: self.get_id(),
617 port: $GPIOX::ptr() as *const dyn GpioRegExt,
618 _mode: self._mode,
619 }
620 }
621 }
622
623 impl<MODE> $PXx<Input<MODE>> {
624 pub fn downgrade(self) -> Pin<Input<MODE>> {
629 Pin {
630 i: self.get_id(),
631 port: $GPIOX::ptr() as *const dyn GpioRegExt,
632 _mode: self._mode,
633 }
634 }
635 }
636 }
637
638 pub use $gpiox::{ $($PXi,)+ };
639 }
640}
641
642gpio!(GPIOA, gpioa, PA, 0, [
643 PA0: (pa0, 0),
644 PA1: (pa1, 1),
645 PA2: (pa2, 2),
646 PA3: (pa3, 3),
647 PA4: (pa4, 4),
648 PA5: (pa5, 5),
649 PA6: (pa6, 6),
650 PA7: (pa7, 7),
651 PA8: (pa8, 8),
652 PA9: (pa9, 9),
653 PA10: (pa10, 10),
654 PA11: (pa11, 11),
655 PA12: (pa12, 12),
656 PA13: (pa13, 13),
657 PA14: (pa14, 14),
658 PA15: (pa15, 15),
659]);
660
661gpio!(GPIOB, gpiob, PB, 1, [
662 PB0: (pb0, 0),
663 PB1: (pb1, 1),
664 PB2: (pb2, 2),
665 PB3: (pb3, 3),
666 PB4: (pb4, 4),
667 PB5: (pb5, 5),
668 PB6: (pb6, 6),
669 PB7: (pb7, 7),
670 PB8: (pb8, 8),
671 PB9: (pb9, 9),
672 PB10: (pb10, 10),
673 PB11: (pb11, 11),
674 PB12: (pb12, 12),
675 PB13: (pb13, 13),
676 PB14: (pb14, 14),
677 PB15: (pb15, 15),
678]);
679
680gpio!(GPIOC, gpioc, PC, 2, [
681 PC0: (pc0, 0),
682 PC1: (pc1, 1),
683 PC2: (pc2, 2),
684 PC3: (pc3, 3),
685 PC4: (pc4, 4),
686 PC5: (pc5, 5),
687 PC6: (pc6, 6),
688 PC7: (pc7, 7),
689 PC8: (pc8, 8),
690 PC9: (pc9, 9),
691 PC10: (pc10, 10),
692 PC11: (pc11, 11),
693 PC12: (pc12, 12),
694 PC13: (pc13, 13),
695 PC14: (pc14, 14),
696 PC15: (pc15, 15),
697]);
698
699gpio!(GPIOD, gpiod, PD, 3, [
700 PD0: (pd0, 0),
701 PD1: (pd1, 1),
702 PD2: (pd2, 2),
703 PD3: (pd3, 3),
704 PD4: (pd4, 4),
705 PD5: (pd5, 5),
706 PD6: (pd6, 6),
707 PD7: (pd7, 7),
708 PD8: (pd8, 8),
709 PD9: (pd9, 9),
710 PD10: (pd10, 10),
711 PD11: (pd11, 11),
712 PD12: (pd12, 12),
713 PD13: (pd13, 13),
714 PD14: (pd14, 14),
715 PD15: (pd15, 15),
716]);
717
718gpio!(GPIOF, gpiof, PF, 5, [
719 PF0: (pf0, 0),
720 PF1: (pf1, 1),
721 PF2: (pf2, 2),
722 PF3: (pf3, 3),
723 PF4: (pf4, 4),
724 PF5: (pf5, 5),
725 PF6: (pf6, 6),
726 PF7: (pf7, 7),
727 PF8: (pf8, 8),
728 PF9: (pf9, 9),
729 PF10: (pf10, 10),
730 PF11: (pf11, 11),
731 PF12: (pf12, 12),
732 PF13: (pf13, 13),
733 PF14: (pf14, 14),
734 PF15: (pf15, 15),
735]);