aboutsummaryrefslogtreecommitdiff
path: root/embassy-mspm0/src/gpio.rs
diff options
context:
space:
mode:
authori509VCB <[email protected]>2025-03-13 22:10:45 -0500
committeri509VCB <[email protected]>2025-03-13 22:10:45 -0500
commite0cdc356ccd7f9e20c2b5355cc52b7eb7610147b (patch)
tree0c34424508b1ee8d5010dc186247b72fac7aca69 /embassy-mspm0/src/gpio.rs
parent38f26137fc67beb874aa73c9a7ab2150d9f3d372 (diff)
Embassy for MSPM0
This adds an embassy hal for the Texas Instruments MSPM0 microcontroller series. So far the GPIO and time drivers have been implemented. I have tested these drivers on the following parts: - C1104 - L1306 - L2228 - G3507 - G3519 The PAC is generated at https://github.com/mspm0-rs
Diffstat (limited to 'embassy-mspm0/src/gpio.rs')
-rw-r--r--embassy-mspm0/src/gpio.rs1070
1 files changed, 1070 insertions, 0 deletions
diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs
new file mode 100644
index 000000000..fd4dc55ab
--- /dev/null
+++ b/embassy-mspm0/src/gpio.rs
@@ -0,0 +1,1070 @@
1#![macro_use]
2
3use core::convert::Infallible;
4use core::future::Future;
5use core::pin::Pin as FuturePin;
6use core::task::{Context, Poll};
7
8use embassy_hal_internal::{impl_peripheral, into_ref, Peripheral, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker;
10#[cfg(all(feature = "rt", feature = "mspm0c110x"))]
11use crate::pac::interrupt;
12
13use crate::pac::{
14 self,
15 gpio::{self, vals::*},
16};
17
18/// Represents a digital input or output level.
19#[derive(Debug, Eq, PartialEq, Clone, Copy)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21pub enum Level {
22 /// Logical low.
23 Low,
24 /// Logical high.
25 High,
26}
27
28impl From<bool> for Level {
29 fn from(val: bool) -> Self {
30 match val {
31 true => Self::High,
32 false => Self::Low,
33 }
34 }
35}
36
37impl From<Level> for bool {
38 fn from(level: Level) -> bool {
39 match level {
40 Level::Low => false,
41 Level::High => true,
42 }
43 }
44}
45
46/// Represents a pull setting for an input.
47#[derive(Debug, Clone, Copy, Eq, PartialEq)]
48pub enum Pull {
49 /// No pull.
50 None,
51 /// Internal pull-up resistor.
52 Up,
53 /// Internal pull-down resistor.
54 Down,
55}
56
57/// A GPIO bank with up to 32 pins.
58#[derive(Debug, Clone, Copy, Eq, PartialEq)]
59pub enum Port {
60 /// Port A.
61 PortA = 0,
62
63 /// Port B.
64 #[cfg(gpio_pb)]
65 PortB = 1,
66
67 /// Port C.
68 #[cfg(gpio_pc)]
69 PortC = 2,
70}
71
72/// GPIO flexible pin.
73///
74/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain
75/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
76/// mode.
77pub struct Flex<'d> {
78 pin: PeripheralRef<'d, AnyPin>,
79}
80
81impl<'d> Flex<'d> {
82 /// Wrap the pin in a `Flex`.
83 ///
84 /// The pin remains disconnected. The initial output level is unspecified, but can be changed
85 /// before the pin is put into output mode.
86 #[inline]
87 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd) -> Self {
88 into_ref!(pin);
89
90 // Pin will be in disconnected state.
91 Self {
92 pin: pin.map_into(),
93 }
94 }
95
96 /// Set the pin's pull.
97 #[inline]
98 pub fn set_pull(&mut self, pull: Pull) {
99 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
100
101 pincm.modify(|w| {
102 w.set_pipd(matches!(pull, Pull::Down));
103 w.set_pipu(matches!(pull, Pull::Up));
104 });
105 }
106
107 /// Put the pin into input mode.
108 ///
109 /// The pull setting is left unchanged.
110 #[inline]
111 pub fn set_as_input(&mut self) {
112 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
113
114 pincm.modify(|w| {
115 w.set_pf(GPIO_PF);
116 w.set_hiz1(false);
117 w.set_pc(true);
118 w.set_inena(true);
119 });
120
121 self.pin.block().doeclr31_0().write(|w| {
122 w.set_dio(self.pin.bit_index(), true);
123 });
124 }
125
126 /// Put the pin into output mode.
127 ///
128 /// The pin level will be whatever was set before (or low by default). If you want it to begin
129 /// at a specific level, call `set_high`/`set_low` on the pin first.
130 #[inline]
131 pub fn set_as_output(&mut self) {
132 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
133
134 pincm.modify(|w| {
135 w.set_pf(GPIO_PF);
136 w.set_hiz1(false);
137 w.set_pc(true);
138 w.set_inena(false);
139 });
140
141 self.pin.block().doeset31_0().write(|w| {
142 w.set_dio(self.pin.bit_index(), true);
143 });
144 }
145
146 /// Put the pin into input + open-drain output mode.
147 ///
148 /// The hardware will drive the line low if you set it to low, and will leave it floating if you set
149 /// it to high, in which case you can read the input to figure out whether another device
150 /// is driving the line low.
151 ///
152 /// The pin level will be whatever was set before (or low by default). If you want it to begin
153 /// at a specific level, call `set_high`/`set_low` on the pin first.
154 ///
155 /// The internal weak pull-up and pull-down resistors will be disabled.
156 #[inline]
157 pub fn set_as_input_output(&mut self) {
158 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
159
160 pincm.modify(|w| {
161 w.set_pf(GPIO_PF);
162 w.set_hiz1(true);
163 w.set_pc(true);
164 w.set_inena(false);
165 });
166
167 self.set_pull(Pull::None);
168 }
169
170 /// Set the pin as "disconnected", ie doing nothing and consuming the lowest
171 /// amount of power possible.
172 ///
173 /// This is currently the same as [`Self::set_as_analog()`] but is semantically different
174 /// really. Drivers should `set_as_disconnected()` pins when dropped.
175 ///
176 /// Note that this also disables the internal weak pull-up and pull-down resistors.
177 #[inline]
178 pub fn set_as_disconnected(&mut self) {
179 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
180
181 pincm.modify(|w| {
182 w.set_pf(DISCONNECT_PF);
183 w.set_hiz1(false);
184 w.set_pc(false);
185 w.set_inena(false);
186 });
187
188 self.set_pull(Pull::None);
189 self.set_inversion(false);
190 }
191
192 /// Configure the logic inversion of this pin.
193 ///
194 /// Logic inversion applies to both the input and output path of this pin.
195 #[inline]
196 pub fn set_inversion(&mut self, invert: bool) {
197 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
198
199 pincm.modify(|w| {
200 w.set_inv(invert);
201 });
202 }
203
204 // TODO: drive strength, hysteresis, wakeup enable, wakeup compare
205
206 /// Put the pin into the PF mode, unchecked.
207 ///
208 /// This puts the pin into the PF mode, with the request number. This is completely unchecked,
209 /// it can attach the pin to literally any peripheral, so use with care. In addition the pin
210 /// peripheral is connected in the iomux.
211 ///
212 /// The peripheral attached to the pin depends on the part in use. Consult the datasheet
213 /// or technical reference manual for additional details.
214 #[inline]
215 pub fn set_pf_unchecked(&mut self, pf: u8) {
216 // Per SLAU893, PF is only 5 bits
217 assert!((pf & 0x3F) != 0, "PF is out of range");
218
219 let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize);
220
221 pincm.modify(|w| {
222 w.set_pf(pf);
223 // If the PF is manually set, connect the pin
224 w.set_pc(true);
225 });
226 }
227
228 /// Get whether the pin input level is high.
229 #[inline]
230 pub fn is_high(&self) -> bool {
231 !self.is_low()
232 }
233
234 /// Get whether the pin input level is low.
235 #[inline]
236 pub fn is_low(&self) -> bool {
237 self.pin.block().din31_0().read().dio(self.pin.bit_index())
238 }
239
240 /// Returns current pin level
241 #[inline]
242 pub fn get_level(&self) -> Level {
243 self.is_high().into()
244 }
245
246 /// Set the output as high.
247 #[inline]
248 pub fn set_high(&mut self) {
249 self.pin.block().doutset31_0().write(|w| {
250 w.set_dio(self.pin.bit_index() as usize, true);
251 });
252 }
253
254 /// Set the output as low.
255 #[inline]
256 pub fn set_low(&mut self) {
257 self.pin.block().doutclr31_0().write(|w| {
258 w.set_dio(self.pin.bit_index(), true);
259 });
260 }
261
262 /// Toggle pin output
263 #[inline]
264 pub fn toggle(&mut self) {
265 self.pin.block().douttgl31_0().write(|w| {
266 w.set_dio(self.pin.bit_index(), true);
267 })
268 }
269
270 /// Set the output level.
271 #[inline]
272 pub fn set_level(&mut self, level: Level) {
273 match level {
274 Level::Low => self.set_low(),
275 Level::High => self.set_high(),
276 }
277 }
278
279 /// Get the current pin input level.
280 #[inline]
281 pub fn get_output_level(&self) -> Level {
282 self.is_high().into()
283 }
284
285 /// Is the output level high?
286 #[inline]
287 pub fn is_set_high(&self) -> bool {
288 !self.is_set_low()
289 }
290
291 /// Is the output level low?
292 #[inline]
293 pub fn is_set_low(&self) -> bool {
294 (self.pin.block().dout31_0().read().0 & self.pin.bit_index() as u32) == 0
295 }
296
297 /// Wait until the pin is high. If it is already high, return immediately.
298 #[inline]
299 pub async fn wait_for_high(&mut self) {
300 if self.is_high() {
301 return;
302 }
303
304 self.wait_for_rising_edge().await
305 }
306
307 /// Wait until the pin is low. If it is already low, return immediately.
308 #[inline]
309 pub async fn wait_for_low(&mut self) {
310 if self.is_low() {
311 return;
312 }
313
314 self.wait_for_falling_edge().await
315 }
316
317 /// Wait for the pin to undergo a transition from low to high.
318 #[inline]
319 pub async fn wait_for_rising_edge(&mut self) {
320 InputFuture::new(self.pin.reborrow(), Polarity::RISE).await
321 }
322
323 /// Wait for the pin to undergo a transition from high to low.
324 #[inline]
325 pub async fn wait_for_falling_edge(&mut self) {
326 InputFuture::new(self.pin.reborrow(), Polarity::FALL).await
327 }
328
329 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
330 #[inline]
331 pub async fn wait_for_any_edge(&mut self) {
332 InputFuture::new(self.pin.reborrow(), Polarity::RISE_FALL).await
333 }
334}
335
336impl<'d> Drop for Flex<'d> {
337 #[inline]
338 fn drop(&mut self) {
339 self.set_as_disconnected();
340 }
341}
342
343/// GPIO input driver.
344pub struct Input<'d> {
345 pin: Flex<'d>,
346}
347
348impl<'d> Input<'d> {
349 /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration.
350 #[inline]
351 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, pull: Pull) -> Self {
352 let mut pin = Flex::new(pin);
353 pin.set_as_input();
354 pin.set_pull(pull);
355 Self { pin }
356 }
357
358 /// Get whether the pin input level is high.
359 #[inline]
360 pub fn is_high(&self) -> bool {
361 self.pin.is_high()
362 }
363
364 /// Get whether the pin input level is low.
365 #[inline]
366 pub fn is_low(&self) -> bool {
367 self.pin.is_low()
368 }
369
370 /// Get the current pin input level.
371 #[inline]
372 pub fn get_level(&self) -> Level {
373 self.pin.get_level()
374 }
375
376 /// Configure the logic inversion of this pin.
377 ///
378 /// Logic inversion applies to the input path of this pin.
379 #[inline]
380 pub fn set_inversion(&mut self, invert: bool) {
381 self.pin.set_inversion(invert)
382 }
383
384 /// Wait until the pin is high. If it is already high, return immediately.
385 #[inline]
386 pub async fn wait_for_high(&mut self) {
387 self.pin.wait_for_high().await
388 }
389
390 /// Wait until the pin is low. If it is already low, return immediately.
391 #[inline]
392 pub async fn wait_for_low(&mut self) {
393 self.pin.wait_for_low().await
394 }
395
396 /// Wait for the pin to undergo a transition from low to high.
397 #[inline]
398 pub async fn wait_for_rising_edge(&mut self) {
399 self.pin.wait_for_rising_edge().await
400 }
401
402 /// Wait for the pin to undergo a transition from high to low.
403 #[inline]
404 pub async fn wait_for_falling_edge(&mut self) {
405 self.pin.wait_for_falling_edge().await
406 }
407
408 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
409 #[inline]
410 pub async fn wait_for_any_edge(&mut self) {
411 self.pin.wait_for_any_edge().await
412 }
413}
414
415/// GPIO output driver.
416///
417/// Note that pins will **return to their floating state** when `Output` is dropped.
418/// If pins should retain their state indefinitely, either keep ownership of the
419/// `Output`, or pass it to [`core::mem::forget`].
420pub struct Output<'d> {
421 pin: Flex<'d>,
422}
423
424impl<'d> Output<'d> {
425 /// Create GPIO output driver for a [Pin] with the provided [Level] configuration.
426 #[inline]
427 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level) -> Self {
428 let mut pin = Flex::new(pin);
429 pin.set_as_output();
430 pin.set_level(initial_output);
431 Self { pin }
432 }
433
434 /// Set the output as high.
435 #[inline]
436 pub fn set_high(&mut self) {
437 self.pin.set_high();
438 }
439
440 /// Set the output as low.
441 #[inline]
442 pub fn set_low(&mut self) {
443 self.pin.set_low();
444 }
445
446 /// Set the output level.
447 #[inline]
448 pub fn set_level(&mut self, level: Level) {
449 self.pin.set_level(level)
450 }
451
452 /// Is the output pin set as high?
453 #[inline]
454 pub fn is_set_high(&self) -> bool {
455 self.pin.is_set_high()
456 }
457
458 /// Is the output pin set as low?
459 #[inline]
460 pub fn is_set_low(&self) -> bool {
461 self.pin.is_set_low()
462 }
463
464 /// What level output is set to
465 #[inline]
466 pub fn get_output_level(&self) -> Level {
467 self.pin.get_output_level()
468 }
469
470 /// Toggle pin output
471 #[inline]
472 pub fn toggle(&mut self) {
473 self.pin.toggle();
474 }
475
476 /// Configure the logic inversion of this pin.
477 ///
478 /// Logic inversion applies to the input path of this pin.
479 #[inline]
480 pub fn set_inversion(&mut self, invert: bool) {
481 self.pin.set_inversion(invert)
482 }
483}
484
485/// GPIO output open-drain driver.
486///
487/// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped.
488/// If pins should retain their state indefinitely, either keep ownership of the
489/// `OutputOpenDrain`, or pass it to [`core::mem::forget`].
490pub struct OutputOpenDrain<'d> {
491 pin: Flex<'d>,
492}
493
494impl<'d> OutputOpenDrain<'d> {
495 /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level].
496 #[inline]
497 pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level) -> Self {
498 let mut pin = Flex::new(pin);
499 pin.set_level(initial_output);
500 pin.set_as_input_output();
501 Self { pin }
502 }
503
504 /// Get whether the pin input level is high.
505 #[inline]
506 pub fn is_high(&self) -> bool {
507 !self.pin.is_low()
508 }
509
510 /// Get whether the pin input level is low.
511 #[inline]
512 pub fn is_low(&self) -> bool {
513 self.pin.is_low()
514 }
515
516 /// Get the current pin input level.
517 #[inline]
518 pub fn get_level(&self) -> Level {
519 self.pin.get_level()
520 }
521
522 /// Set the output as high.
523 #[inline]
524 pub fn set_high(&mut self) {
525 self.pin.set_high();
526 }
527
528 /// Set the output as low.
529 #[inline]
530 pub fn set_low(&mut self) {
531 self.pin.set_low();
532 }
533
534 /// Set the output level.
535 #[inline]
536 pub fn set_level(&mut self, level: Level) {
537 self.pin.set_level(level);
538 }
539
540 /// Get whether the output level is set to high.
541 #[inline]
542 pub fn is_set_high(&self) -> bool {
543 self.pin.is_set_high()
544 }
545
546 /// Get whether the output level is set to low.
547 #[inline]
548 pub fn is_set_low(&self) -> bool {
549 self.pin.is_set_low()
550 }
551
552 /// Get the current output level.
553 #[inline]
554 pub fn get_output_level(&self) -> Level {
555 self.pin.get_output_level()
556 }
557
558 /// Toggle pin output
559 #[inline]
560 pub fn toggle(&mut self) {
561 self.pin.toggle()
562 }
563
564 /// Configure the logic inversion of this pin.
565 ///
566 /// Logic inversion applies to the input path of this pin.
567 #[inline]
568 pub fn set_inversion(&mut self, invert: bool) {
569 self.pin.set_inversion(invert)
570 }
571
572 /// Wait until the pin is high. If it is already high, return immediately.
573 #[inline]
574 pub async fn wait_for_high(&mut self) {
575 self.pin.wait_for_high().await
576 }
577
578 /// Wait until the pin is low. If it is already low, return immediately.
579 #[inline]
580 pub async fn wait_for_low(&mut self) {
581 self.pin.wait_for_low().await
582 }
583
584 /// Wait for the pin to undergo a transition from low to high.
585 #[inline]
586 pub async fn wait_for_rising_edge(&mut self) {
587 self.pin.wait_for_rising_edge().await
588 }
589
590 /// Wait for the pin to undergo a transition from high to low.
591 #[inline]
592 pub async fn wait_for_falling_edge(&mut self) {
593 self.pin.wait_for_falling_edge().await
594 }
595
596 /// Wait for the pin to undergo any transition, i.e low to high OR high to low.
597 #[inline]
598 pub async fn wait_for_any_edge(&mut self) {
599 self.pin.wait_for_any_edge().await
600 }
601}
602
603/// Type-erased GPIO pin
604pub struct AnyPin {
605 pin_port: u8,
606}
607
608impl AnyPin {
609 /// Create an [AnyPin] for a specific pin.
610 ///
611 /// # Safety
612 /// - `pin_port` should not in use by another driver.
613 #[inline]
614 pub unsafe fn steal(pin_port: u8) -> Self {
615 Self { pin_port }
616 }
617}
618
619impl_peripheral!(AnyPin);
620
621impl Pin for AnyPin {}
622impl SealedPin for AnyPin {
623 #[inline]
624 fn pin_port(&self) -> u8 {
625 self.pin_port
626 }
627}
628
629/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin].
630#[allow(private_bounds)]
631pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static {
632 fn degrade(self) -> AnyPin {
633 AnyPin {
634 pin_port: self.pin_port(),
635 }
636 }
637
638 /// The index of this pin in PINCM (pin control management) registers.
639 #[inline]
640 fn pin_cm(&self) -> u8 {
641 self._pin_cm()
642 }
643}
644
645impl<'d> embedded_hal::digital::ErrorType for Flex<'d> {
646 type Error = Infallible;
647}
648
649impl<'d> embedded_hal::digital::InputPin for Flex<'d> {
650 #[inline]
651 fn is_high(&mut self) -> Result<bool, Self::Error> {
652 Ok((*self).is_high())
653 }
654
655 #[inline]
656 fn is_low(&mut self) -> Result<bool, Self::Error> {
657 Ok((*self).is_low())
658 }
659}
660
661impl<'d> embedded_hal::digital::OutputPin for Flex<'d> {
662 #[inline]
663 fn set_low(&mut self) -> Result<(), Self::Error> {
664 Ok(self.set_low())
665 }
666
667 #[inline]
668 fn set_high(&mut self) -> Result<(), Self::Error> {
669 Ok(self.set_high())
670 }
671}
672
673impl<'d> embedded_hal::digital::StatefulOutputPin for Flex<'d> {
674 #[inline]
675 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
676 Ok((*self).is_set_high())
677 }
678
679 #[inline]
680 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
681 Ok((*self).is_set_low())
682 }
683}
684
685impl<'d> embedded_hal_async::digital::Wait for Flex<'d> {
686 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
687 self.wait_for_high().await;
688 Ok(())
689 }
690
691 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
692 self.wait_for_low().await;
693 Ok(())
694 }
695
696 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
697 self.wait_for_rising_edge().await;
698 Ok(())
699 }
700
701 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
702 self.wait_for_falling_edge().await;
703 Ok(())
704 }
705
706 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
707 self.wait_for_any_edge().await;
708 Ok(())
709 }
710}
711
712impl<'d> embedded_hal::digital::ErrorType for Input<'d> {
713 type Error = Infallible;
714}
715
716impl<'d> embedded_hal::digital::InputPin for Input<'d> {
717 #[inline]
718 fn is_high(&mut self) -> Result<bool, Self::Error> {
719 Ok((*self).is_high())
720 }
721
722 #[inline]
723 fn is_low(&mut self) -> Result<bool, Self::Error> {
724 Ok((*self).is_low())
725 }
726}
727
728impl<'d> embedded_hal_async::digital::Wait for Input<'d> {
729 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
730 self.wait_for_high().await;
731 Ok(())
732 }
733
734 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
735 self.wait_for_low().await;
736 Ok(())
737 }
738
739 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
740 self.wait_for_rising_edge().await;
741 Ok(())
742 }
743
744 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
745 self.wait_for_falling_edge().await;
746 Ok(())
747 }
748
749 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
750 self.wait_for_any_edge().await;
751 Ok(())
752 }
753}
754
755impl<'d> embedded_hal::digital::ErrorType for Output<'d> {
756 type Error = Infallible;
757}
758
759impl<'d> embedded_hal::digital::OutputPin for Output<'d> {
760 #[inline]
761 fn set_low(&mut self) -> Result<(), Self::Error> {
762 Ok(self.set_low())
763 }
764
765 #[inline]
766 fn set_high(&mut self) -> Result<(), Self::Error> {
767 Ok(self.set_high())
768 }
769}
770
771impl<'d> embedded_hal::digital::StatefulOutputPin for Output<'d> {
772 #[inline]
773 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
774 Ok((*self).is_set_high())
775 }
776
777 #[inline]
778 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
779 Ok((*self).is_set_low())
780 }
781}
782
783impl<'d> embedded_hal::digital::ErrorType for OutputOpenDrain<'d> {
784 type Error = Infallible;
785}
786
787impl<'d> embedded_hal::digital::InputPin for OutputOpenDrain<'d> {
788 #[inline]
789 fn is_high(&mut self) -> Result<bool, Self::Error> {
790 Ok((*self).is_high())
791 }
792
793 #[inline]
794 fn is_low(&mut self) -> Result<bool, Self::Error> {
795 Ok((*self).is_low())
796 }
797}
798
799impl<'d> embedded_hal::digital::OutputPin for OutputOpenDrain<'d> {
800 #[inline]
801 fn set_low(&mut self) -> Result<(), Self::Error> {
802 Ok(self.set_low())
803 }
804
805 #[inline]
806 fn set_high(&mut self) -> Result<(), Self::Error> {
807 Ok(self.set_high())
808 }
809}
810
811impl<'d> embedded_hal::digital::StatefulOutputPin for OutputOpenDrain<'d> {
812 #[inline]
813 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
814 Ok((*self).is_set_high())
815 }
816
817 #[inline]
818 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
819 Ok((*self).is_set_low())
820 }
821}
822
823impl<'d> embedded_hal_async::digital::Wait for OutputOpenDrain<'d> {
824 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
825 self.wait_for_high().await;
826 Ok(())
827 }
828
829 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
830 self.wait_for_low().await;
831 Ok(())
832 }
833
834 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
835 self.wait_for_rising_edge().await;
836 Ok(())
837 }
838
839 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
840 self.wait_for_falling_edge().await;
841 Ok(())
842 }
843
844 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
845 self.wait_for_any_edge().await;
846 Ok(())
847 }
848}
849
850/// The pin function to disconnect peripherals from the pin.
851///
852/// This is also the pin function used to connect to analog peripherals, such as an ADC.
853const DISCONNECT_PF: u8 = 0;
854
855/// The pin function for the GPIO peripheral.
856///
857/// This is fixed to `1` for every part.
858const GPIO_PF: u8 = 1;
859
860macro_rules! impl_pin {
861 ($name: ident, $port: expr, $pin_num: expr) => {
862 impl crate::gpio::Pin for crate::peripherals::$name {}
863 impl crate::gpio::SealedPin for crate::peripherals::$name {
864 #[inline]
865 fn pin_port(&self) -> u8 {
866 ($port as u8) * 32 + $pin_num
867 }
868 }
869
870 impl From<crate::peripherals::$name> for crate::gpio::AnyPin {
871 fn from(val: crate::peripherals::$name) -> Self {
872 crate::gpio::Pin::degrade(val)
873 }
874 }
875 };
876}
877
878// TODO: Possible micro-op for C110X, not every pin is instantiated even on the 20 pin parts.
879// This would mean cfg guarding to just cfg guarding every pin instance.
880static PORTA_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
881#[cfg(gpio_pb)]
882static PORTB_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
883#[cfg(gpio_pc)]
884static PORTC_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32];
885
886pub(crate) trait SealedPin {
887 fn pin_port(&self) -> u8;
888
889 fn port(&self) -> Port {
890 match self.pin_port() / 32 {
891 0 => Port::PortA,
892 #[cfg(gpio_pb)]
893 1 => Port::PortB,
894 #[cfg(gpio_pc)]
895 2 => Port::PortC,
896 _ => unreachable!(),
897 }
898 }
899
900 fn waker(&self) -> &AtomicWaker {
901 match self.port() {
902 Port::PortA => &PORTA_WAKERS[self.bit_index()],
903 #[cfg(gpio_pb)]
904 Port::PortB => &PORTB_WAKERS[self.bit_index()],
905 #[cfg(gpio_pc)]
906 Port::PortC => &PORTC_WAKERS[self.bit_index()],
907 }
908 }
909
910 fn _pin_cm(&self) -> u8 {
911 // Some parts like the MSPM0L222x have pincm mappings all over the place.
912 crate::gpio_pincm(self.pin_port())
913 }
914
915 fn bit_index(&self) -> usize {
916 (self.pin_port() % 32) as usize
917 }
918
919 #[inline]
920 fn block(&self) -> gpio::Gpio {
921 match self.pin_port() / 32 {
922 0 => pac::GPIOA,
923 #[cfg(gpio_pb)]
924 1 => pac::GPIOB,
925 #[cfg(gpio_pc)]
926 2 => pac::GPIOC,
927 _ => unreachable!(),
928 }
929 }
930}
931
932#[must_use = "futures do nothing unless you `.await` or poll them"]
933struct InputFuture<'d> {
934 pin: PeripheralRef<'d, AnyPin>,
935}
936
937impl<'d> InputFuture<'d> {
938 fn new(pin: PeripheralRef<'d, AnyPin>, polarity: Polarity) -> Self {
939 let block = pin.block();
940
941 // First clear the bit for this event. Otherwise previous edge events may be recorded.
942 block.cpu_int().iclr().write(|w| {
943 w.set_dio(pin.bit_index(), true);
944 });
945
946 // Selecting which polarity events happens is a RMW operation.
947 //
948 // Guard with a critical section in case two different threads try to select events at the
949 // same time.
950 critical_section::with(|_cs| {
951 // Tell the hardware which pin event we want to receive.
952 if pin.bit_index() >= 16 {
953 block.polarity31_16().modify(|w| {
954 w.set_dio(pin.bit_index() - 16, polarity);
955 });
956 } else {
957 block.polarity15_0().modify(|w| {
958 w.set_dio(pin.bit_index(), polarity);
959 });
960 };
961 });
962
963 Self { pin }
964 }
965}
966
967impl<'d> Future for InputFuture<'d> {
968 type Output = ();
969
970 fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
971 // We need to register/re-register the waker for each poll because any
972 // calls to wake will deregister the waker.
973 let waker = self.pin.waker();
974 waker.register(cx.waker());
975
976 // The interrupt handler will mask the interrupt if the event has occurred.
977 if self
978 .pin
979 .block()
980 .cpu_int()
981 .ris()
982 .read()
983 .dio(self.pin.bit_index())
984 {
985 return Poll::Ready(());
986 }
987
988 // Unmasking the interrupt is a RMW operation.
989 //
990 // Guard with a critical section in case two different threads try to unmask at the same time.
991 critical_section::with(|_cs| {
992 self.pin.block().cpu_int().imask().modify(|w| {
993 w.set_dio(self.pin.bit_index(), true);
994 });
995 });
996
997 Poll::Pending
998 }
999}
1000
1001pub(crate) fn init(gpio: gpio::Gpio) {
1002 gpio.gprcm().rstctl().write(|w| {
1003 w.set_resetstkyclr(true);
1004 w.set_resetassert(true);
1005 w.set_key(ResetKey::KEY);
1006 });
1007
1008 gpio.gprcm().pwren().write(|w| {
1009 w.set_enable(true);
1010 w.set_key(PwrenKey::KEY);
1011 });
1012
1013 gpio.evt_mode().modify(|w| {
1014 // The CPU will clear it's own interrupts
1015 w.set_cpu_cfg(EvtCfg::SOFTWARE);
1016 });
1017}
1018
1019#[cfg(feature = "rt")]
1020fn irq_handler(gpio: gpio::Gpio, wakers: &[AtomicWaker; 32]) {
1021 // Only consider pins which have interrupts unmasked.
1022 let bits = gpio.cpu_int().mis().read().0;
1023
1024 for i in BitIter(bits) {
1025 wakers[i as usize].wake();
1026
1027 // Notify the future that an edge event has occurred by masking the interrupt for this pin.
1028 gpio.cpu_int().imask().modify(|w| {
1029 w.set_dio(i as usize, false);
1030 });
1031 }
1032}
1033
1034struct BitIter(u32);
1035
1036impl Iterator for BitIter {
1037 type Item = u32;
1038
1039 fn next(&mut self) -> Option<Self::Item> {
1040 match self.0.trailing_zeros() {
1041 32 => None,
1042 b => {
1043 self.0 &= !(1 << b);
1044 Some(b)
1045 }
1046 }
1047 }
1048}
1049
1050// C110x has a dedicated interrupt just for GPIOA, as it does not have a GROUP1 interrupt.
1051#[cfg(all(feature = "rt", feature = "mspm0c110x"))]
1052#[interrupt]
1053fn GPIOA() {
1054 gpioa_interrupt();
1055}
1056
1057#[cfg(feature = "rt")]
1058pub(crate) fn gpioa_interrupt() {
1059 irq_handler(pac::GPIOA, &PORTA_WAKERS);
1060}
1061
1062#[cfg(all(feature = "rt", gpio_pb))]
1063pub(crate) fn gpiob_interrupt() {
1064 irq_handler(pac::GPIOB, &PORTB_WAKERS);
1065}
1066
1067#[cfg(all(feature = "rt", gpio_pc))]
1068pub(crate) fn gpioc_interrupt() {
1069 irq_handler(pac::GPIOC, &PORTC_WAKERS);
1070}