1#![macro_use]
3
4use core::convert::Infallible;
5use core::hint::unreachable_unchecked;
6
7use cfg_if::cfg_if;
8use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType};
9
10use crate::pac;
11use crate::pac::common::{Reg, RW};
12use crate::pac::gpio;
13use crate::pac::gpio::vals;
14#[cfg(not(feature = "_nrf51"))]
15use crate::pac::shared::{regs::Psel, vals::Connect};
16
17#[derive(Debug, Eq, PartialEq)]
19pub enum Port {
20 Port0,
22
23 #[cfg(feature = "_gpio-p1")]
25 Port1,
26
27 #[cfg(feature = "_gpio-p2")]
29 Port2,
30}
31
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub enum Pull {
36 None,
38 Up,
40 Down,
42}
43
44pub struct Input<'d> {
46 pub(crate) pin: Flex<'d>,
47}
48
49impl<'d> Input<'d> {
50 #[inline]
52 pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self {
53 let mut pin = Flex::new(pin);
54 pin.set_as_input(pull);
55
56 Self { pin }
57 }
58
59 #[inline]
61 pub fn is_high(&self) -> bool {
62 self.pin.is_high()
63 }
64
65 #[inline]
67 pub fn is_low(&self) -> bool {
68 self.pin.is_low()
69 }
70
71 #[inline]
73 pub fn get_level(&self) -> Level {
74 self.pin.get_level()
75 }
76}
77
78impl Input<'static> {
79 pub fn persist(self) {
83 self.pin.persist()
84 }
85}
86
87#[derive(Clone, Copy, Debug, Eq, PartialEq)]
89#[cfg_attr(feature = "defmt", derive(defmt::Format))]
90pub enum Level {
91 Low,
93 High,
95}
96
97impl From<bool> for Level {
98 fn from(val: bool) -> Self {
99 match val {
100 true => Self::High,
101 false => Self::Low,
102 }
103 }
104}
105
106impl From<Level> for bool {
107 fn from(level: Level) -> bool {
108 match level {
109 Level::Low => false,
110 Level::High => true,
111 }
112 }
113}
114
115#[cfg(feature = "_nrf54l")]
118#[derive(Clone, Copy, Debug, PartialEq)]
119#[cfg_attr(feature = "defmt", derive(defmt::Format))]
120#[repr(u8)]
121pub enum LevelDrive {
122 Disconnect = 2,
124 Standard = 0,
126 High = 1,
128 ExtraHigh = 3,
130}
131
132#[cfg(feature = "_nrf54l")]
137#[derive(Clone, Copy, Debug, PartialEq)]
138#[cfg_attr(feature = "defmt", derive(defmt::Format))]
139pub struct OutputDrive {
140 low: LevelDrive,
141 high: LevelDrive,
142}
143
144#[cfg(feature = "_nrf54l")]
145#[allow(non_upper_case_globals)]
146impl OutputDrive {
147 pub const Standard: Self = Self {
149 low: LevelDrive::Standard,
150 high: LevelDrive::Standard,
151 };
152 pub const HighDrive0Standard1: Self = Self {
154 low: LevelDrive::High,
155 high: LevelDrive::Standard,
156 };
157 pub const Standard0HighDrive1: Self = Self {
159 low: LevelDrive::Standard,
160 high: LevelDrive::High,
161 };
162 pub const HighDrive: Self = Self {
164 low: LevelDrive::High,
165 high: LevelDrive::High,
166 };
167 pub const Disconnect0Standard1: Self = Self {
169 low: LevelDrive::Disconnect,
170 high: LevelDrive::Standard,
171 };
172 pub const Disconnect0HighDrive1: Self = Self {
174 low: LevelDrive::Disconnect,
175 high: LevelDrive::High,
176 };
177 pub const Standard0Disconnect1: Self = Self {
179 low: LevelDrive::Standard,
180 high: LevelDrive::Disconnect,
181 };
182 pub const HighDrive0Disconnect1: Self = Self {
184 low: LevelDrive::High,
185 high: LevelDrive::Disconnect,
186 };
187}
188
189#[cfg(not(feature = "_nrf54l"))]
192#[derive(Clone, Copy, Debug, PartialEq)]
193#[cfg_attr(feature = "defmt", derive(defmt::Format))]
194#[repr(u8)]
195pub enum OutputDrive {
196 Standard = 0,
198 HighDrive0Standard1 = 1,
200 Standard0HighDrive1 = 2,
202 HighDrive = 3,
204 Disconnect0Standard1 = 4,
206 Disconnect0HighDrive1 = 5,
208 Standard0Disconnect1 = 6,
210 HighDrive0Disconnect1 = 7,
212}
213
214pub struct Output<'d> {
216 pub(crate) pin: Flex<'d>,
217}
218
219impl<'d> Output<'d> {
220 #[inline]
222 pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level, drive: OutputDrive) -> Self {
223 let mut pin = Flex::new(pin);
224 match initial_output {
225 Level::High => pin.set_high(),
226 Level::Low => pin.set_low(),
227 }
228 pin.set_as_output(drive);
229
230 Self { pin }
231 }
232
233 #[inline]
235 pub fn set_high(&mut self) {
236 self.pin.set_high()
237 }
238
239 #[inline]
241 pub fn set_low(&mut self) {
242 self.pin.set_low()
243 }
244
245 #[inline]
247 pub fn toggle(&mut self) {
248 self.pin.toggle()
249 }
250
251 #[inline]
253 pub fn set_level(&mut self, level: Level) {
254 self.pin.set_level(level)
255 }
256
257 #[inline]
259 pub fn is_set_high(&self) -> bool {
260 self.pin.is_set_high()
261 }
262
263 #[inline]
265 pub fn is_set_low(&self) -> bool {
266 self.pin.is_set_low()
267 }
268
269 #[inline]
271 pub fn get_output_level(&self) -> Level {
272 self.pin.get_output_level()
273 }
274}
275
276impl Output<'static> {
277 pub fn persist(self) {
281 self.pin.persist()
282 }
283}
284
285pub(crate) fn convert_drive(w: &mut pac::gpio::regs::PinCnf, drive: OutputDrive) {
286 #[cfg(not(feature = "_nrf54l"))]
287 {
288 let drive = match drive {
289 OutputDrive::Standard => vals::Drive::S0S1,
290 OutputDrive::HighDrive0Standard1 => vals::Drive::H0S1,
291 OutputDrive::Standard0HighDrive1 => vals::Drive::S0H1,
292 OutputDrive::HighDrive => vals::Drive::H0H1,
293 OutputDrive::Disconnect0Standard1 => vals::Drive::D0S1,
294 OutputDrive::Disconnect0HighDrive1 => vals::Drive::D0H1,
295 OutputDrive::Standard0Disconnect1 => vals::Drive::S0D1,
296 OutputDrive::HighDrive0Disconnect1 => vals::Drive::H0D1,
297 };
298 w.set_drive(drive);
299 }
300
301 #[cfg(feature = "_nrf54l")]
302 {
303 fn convert(d: LevelDrive) -> vals::Drive {
304 match d {
305 LevelDrive::Disconnect => vals::Drive::D,
306 LevelDrive::Standard => vals::Drive::S,
307 LevelDrive::High => vals::Drive::H,
308 LevelDrive::ExtraHigh => vals::Drive::E,
309 }
310 }
311
312 w.set_drive0(convert(drive.low));
313 w.set_drive1(convert(drive.high));
314 }
315}
316
317fn convert_pull(pull: Pull) -> vals::Pull {
318 match pull {
319 Pull::None => vals::Pull::DISABLED,
320 Pull::Up => vals::Pull::PULLUP,
321 Pull::Down => vals::Pull::PULLDOWN,
322 }
323}
324
325pub struct Flex<'d> {
331 pub(crate) pin: Peri<'d, AnyPin>,
332}
333
334impl<'d> Flex<'d> {
335 #[inline]
340 pub fn new(pin: Peri<'d, impl Pin>) -> Self {
341 Self { pin: pin.into() }
343 }
344
345 #[inline]
347 pub fn set_as_input(&mut self, pull: Pull) {
348 self.pin.conf().write(|w| {
349 w.set_dir(vals::Dir::INPUT);
350 w.set_input(vals::Input::CONNECT);
351 w.set_pull(convert_pull(pull));
352 convert_drive(w, OutputDrive::Standard);
353 w.set_sense(vals::Sense::DISABLED);
354 });
355 }
356
357 #[inline]
362 pub fn set_as_output(&mut self, drive: OutputDrive) {
363 self.pin.conf().write(|w| {
364 w.set_dir(vals::Dir::OUTPUT);
365 w.set_input(vals::Input::DISCONNECT);
366 w.set_pull(vals::Pull::DISABLED);
367 convert_drive(w, drive);
368 w.set_sense(vals::Sense::DISABLED);
369 });
370 }
371
372 #[inline]
382 pub fn set_as_input_output(&mut self, pull: Pull, drive: OutputDrive) {
383 self.pin.conf().write(|w| {
384 w.set_dir(vals::Dir::OUTPUT);
385 w.set_input(vals::Input::CONNECT);
386 w.set_pull(convert_pull(pull));
387 convert_drive(w, drive);
388 w.set_sense(vals::Sense::DISABLED);
389 });
390 }
391
392 #[inline]
394 pub fn set_as_disconnected(&mut self) {
395 self.pin.conf().write(|w| {
396 w.set_input(vals::Input::DISCONNECT);
397 });
398 }
399
400 #[inline]
402 pub fn is_high(&self) -> bool {
403 self.pin.block().in_().read().pin(self.pin.pin() as _)
404 }
405
406 #[inline]
408 pub fn is_low(&self) -> bool {
409 !self.is_high()
410 }
411
412 #[inline]
414 pub fn get_level(&self) -> Level {
415 self.is_high().into()
416 }
417
418 #[inline]
420 pub fn set_high(&mut self) {
421 self.pin.set_high()
422 }
423
424 #[inline]
426 pub fn set_low(&mut self) {
427 self.pin.set_low()
428 }
429
430 #[inline]
432 pub fn toggle(&mut self) {
433 if self.is_set_low() {
434 self.set_high()
435 } else {
436 self.set_low()
437 }
438 }
439
440 #[inline]
442 pub fn set_level(&mut self, level: Level) {
443 match level {
444 Level::Low => self.pin.set_low(),
445 Level::High => self.pin.set_high(),
446 }
447 }
448
449 #[inline]
451 pub fn is_set_high(&self) -> bool {
452 self.pin.block().out().read().pin(self.pin.pin() as _)
453 }
454
455 #[inline]
457 pub fn is_set_low(&self) -> bool {
458 !self.is_set_high()
459 }
460
461 #[inline]
463 pub fn get_output_level(&self) -> Level {
464 self.is_set_high().into()
465 }
466}
467
468impl Flex<'static> {
469 pub fn persist(self) {
473 core::mem::forget(self);
474 }
475}
476
477impl<'d> Drop for Flex<'d> {
478 fn drop(&mut self) {
479 self.set_as_disconnected();
480 }
481}
482
483pub(crate) trait SealedPin {
484 fn pin_port(&self) -> u8;
485
486 #[inline]
487 fn _pin(&self) -> u8 {
488 cfg_if! {
489 if #[cfg(feature = "_gpio-p1")] {
490 self.pin_port() % 32
491 } else {
492 self.pin_port()
493 }
494 }
495 }
496
497 #[inline]
498 fn block(&self) -> gpio::Gpio {
499 match self.pin_port() / 32 {
500 #[cfg(feature = "_nrf51")]
501 0 => pac::GPIO,
502 #[cfg(not(feature = "_nrf51"))]
503 0 => pac::P0,
504 #[cfg(feature = "_gpio-p1")]
505 1 => pac::P1,
506 #[cfg(feature = "_gpio-p2")]
507 2 => pac::P2,
508 _ => unsafe { unreachable_unchecked() },
509 }
510 }
511
512 #[inline]
513 fn conf(&self) -> Reg<gpio::regs::PinCnf, RW> {
514 self.block().pin_cnf(self._pin() as usize)
515 }
516
517 #[inline]
519 fn set_high(&self) {
520 self.block().outset().write(|w| w.set_pin(self._pin() as _, true))
521 }
522
523 #[inline]
525 fn set_low(&self) {
526 self.block().outclr().write(|w| w.set_pin(self._pin() as _, true))
527 }
528}
529
530#[allow(private_bounds)]
532pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
533 #[inline]
535 fn pin(&self) -> u8 {
536 self._pin()
537 }
538
539 #[inline]
541 fn port(&self) -> Port {
542 match self.pin_port() / 32 {
543 0 => Port::Port0,
544 #[cfg(feature = "_gpio-p1")]
545 1 => Port::Port1,
546 #[cfg(feature = "_gpio-p2")]
547 2 => Port::Port2,
548 _ => unsafe { unreachable_unchecked() },
549 }
550 }
551
552 #[inline]
554 #[cfg(not(feature = "_nrf51"))]
555 fn psel_bits(&self) -> pac::shared::regs::Psel {
556 pac::shared::regs::Psel(self.pin_port() as u32)
557 }
558}
559
560pub struct AnyPin {
562 pub(crate) pin_port: u8,
563}
564
565impl AnyPin {
566 #[inline]
571 pub unsafe fn steal(pin_port: u8) -> Peri<'static, Self> {
572 Peri::new_unchecked(Self { pin_port })
573 }
574}
575
576impl_peripheral!(AnyPin);
577impl Pin for AnyPin {}
578impl SealedPin for AnyPin {
579 #[inline]
580 fn pin_port(&self) -> u8 {
581 self.pin_port
582 }
583}
584
585#[cfg(not(feature = "_nrf51"))]
588#[cfg_attr(feature = "_nrf54l", allow(unused))] pub(crate) trait PselBits {
590 fn psel_bits(&self) -> pac::shared::regs::Psel;
591}
592
593#[cfg(not(feature = "_nrf51"))]
594impl<'a, P: Pin> PselBits for Option<Peri<'a, P>> {
595 #[inline]
596 fn psel_bits(&self) -> pac::shared::regs::Psel {
597 match self {
598 Some(pin) => pin.psel_bits(),
599 None => DISCONNECTED,
600 }
601 }
602}
603
604#[cfg(not(feature = "_nrf51"))]
605#[cfg_attr(feature = "_nrf54l", allow(unused))] pub(crate) const DISCONNECTED: Psel = Psel(1 << 31);
607
608#[cfg(not(feature = "_nrf51"))]
609#[allow(dead_code)]
610pub(crate) fn deconfigure_pin(psel: Psel) {
611 if psel.connect() == Connect::DISCONNECTED {
612 return;
613 }
614 unsafe { AnyPin::steal(psel.0 as _) }.conf().write(|w| {
615 w.set_input(vals::Input::DISCONNECT);
616 })
617}
618
619macro_rules! impl_pin {
622 ($type:ident, $port_num:expr, $pin_num:expr) => {
623 impl crate::gpio::Pin for peripherals::$type {}
624 impl crate::gpio::SealedPin for peripherals::$type {
625 #[inline]
626 fn pin_port(&self) -> u8 {
627 $port_num * 32 + $pin_num
628 }
629 }
630
631 impl From<peripherals::$type> for crate::gpio::AnyPin {
632 fn from(_val: peripherals::$type) -> Self {
633 Self {
634 pin_port: $port_num * 32 + $pin_num,
635 }
636 }
637 }
638 };
639}
640
641mod eh02 {
644 use super::*;
645
646 impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> {
647 type Error = Infallible;
648
649 fn is_high(&self) -> Result<bool, Self::Error> {
650 Ok(self.is_high())
651 }
652
653 fn is_low(&self) -> Result<bool, Self::Error> {
654 Ok(self.is_low())
655 }
656 }
657
658 impl<'d> embedded_hal_02::digital::v2::OutputPin for Output<'d> {
659 type Error = Infallible;
660
661 fn set_high(&mut self) -> Result<(), Self::Error> {
662 self.set_high();
663 Ok(())
664 }
665
666 fn set_low(&mut self) -> Result<(), Self::Error> {
667 self.set_low();
668 Ok(())
669 }
670 }
671
672 impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d> {
673 fn is_set_high(&self) -> Result<bool, Self::Error> {
674 Ok(self.is_set_high())
675 }
676
677 fn is_set_low(&self) -> Result<bool, Self::Error> {
678 Ok(self.is_set_low())
679 }
680 }
681
682 impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> {
683 type Error = Infallible;
684 #[inline]
685 fn toggle(&mut self) -> Result<(), Self::Error> {
686 self.toggle();
687 Ok(())
688 }
689 }
690
691 impl<'d> embedded_hal_02::digital::v2::InputPin for Flex<'d> {
695 type Error = Infallible;
696
697 fn is_high(&self) -> Result<bool, Self::Error> {
698 Ok(self.is_high())
699 }
700
701 fn is_low(&self) -> Result<bool, Self::Error> {
702 Ok(self.is_low())
703 }
704 }
705
706 impl<'d> embedded_hal_02::digital::v2::OutputPin for Flex<'d> {
707 type Error = Infallible;
708
709 fn set_high(&mut self) -> Result<(), Self::Error> {
710 self.set_high();
711 Ok(())
712 }
713
714 fn set_low(&mut self) -> Result<(), Self::Error> {
715 self.set_low();
716 Ok(())
717 }
718 }
719
720 impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d> {
721 fn is_set_high(&self) -> Result<bool, Self::Error> {
722 Ok(self.is_set_high())
723 }
724
725 fn is_set_low(&self) -> Result<bool, Self::Error> {
726 Ok(self.is_set_low())
727 }
728 }
729
730 impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d> {
731 type Error = Infallible;
732 #[inline]
733 fn toggle(&mut self) -> Result<(), Self::Error> {
734 self.toggle();
735 Ok(())
736 }
737 }
738}
739
740impl<'d> embedded_hal_1::digital::ErrorType for Input<'d> {
741 type Error = Infallible;
742}
743
744impl<'d> embedded_hal_1::digital::InputPin for Input<'d> {
745 fn is_high(&mut self) -> Result<bool, Self::Error> {
746 Ok((*self).is_high())
747 }
748
749 fn is_low(&mut self) -> Result<bool, Self::Error> {
750 Ok((*self).is_low())
751 }
752}
753
754impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> {
755 type Error = Infallible;
756}
757
758impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> {
759 fn set_high(&mut self) -> Result<(), Self::Error> {
760 self.set_high();
761 Ok(())
762 }
763
764 fn set_low(&mut self) -> Result<(), Self::Error> {
765 self.set_low();
766 Ok(())
767 }
768}
769
770impl<'d> embedded_hal_1::digital::StatefulOutputPin for Output<'d> {
771 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
772 Ok((*self).is_set_high())
773 }
774
775 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
776 Ok((*self).is_set_low())
777 }
778}
779
780impl<'d> embedded_hal_1::digital::ErrorType for Flex<'d> {
781 type Error = Infallible;
782}
783
784impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> {
788 fn is_high(&mut self) -> Result<bool, Self::Error> {
789 Ok((*self).is_high())
790 }
791
792 fn is_low(&mut self) -> Result<bool, Self::Error> {
793 Ok((*self).is_low())
794 }
795}
796
797impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> {
798 fn set_high(&mut self) -> Result<(), Self::Error> {
799 self.set_high();
800 Ok(())
801 }
802
803 fn set_low(&mut self) -> Result<(), Self::Error> {
804 self.set_low();
805 Ok(())
806 }
807}
808
809impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> {
810 fn is_set_high(&mut self) -> Result<bool, Self::Error> {
811 Ok((*self).is_set_high())
812 }
813
814 fn is_set_low(&mut self) -> Result<bool, Self::Error> {
815 Ok((*self).is_set_low())
816 }
817}