Skip to main content

ra_hal/
gpio.rs

1//! General Purpose Input/Output (`PORT`).
2
3use core::{convert::Infallible, future::poll_fn, marker::PhantomData, task::Poll};
4
5use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral, interrupt::InterruptExt as _};
6use embassy_sync::waitqueue::AtomicWaker;
7
8use crate::{
9    event_link::{IcuInterrupt as _, InterruptEvent},
10    interrupt,
11    interrupt::typelevel::{Handler as InterruptHandler, Interrupt as InterruptType},
12    pac::{
13        self,
14        common::RW,
15        pfs::Pfs,
16        pfs::vals::{OutputType, PortDirection, PortMode},
17    },
18    write_protect::ProtectedModify as _,
19};
20
21// This needs to be updated to deal with other RA8 variants and variants with multiple processors.
22#[cfg(not(ra8))]
23use crate::pac::icu::vals::{Fclksel, Irqmd};
24#[cfg(ra8)]
25use crate::pac::icu_common::vals::{Fclksel, Irqmd};
26
27#[cfg(any(pfs_ra8, pfs_port_drive))]
28use crate::pac::pfs::vals::PortDrive;
29
30/// Uniquely identifies a pin.
31///
32/// Upper bits are the port index, lower bits are the pin index.
33/// The `RA4M1` has 10 GPIO ports each with up to 16 pins.
34#[derive(Copy, Clone, PartialEq)]
35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
36pub struct PinId(u8);
37
38impl PinId {
39    /// Constructs a `PinId` from separate port and pin numbers e.g. `4` and `8`.
40    #[inline(always)]
41    pub const fn from_port_pin(port: u8, pin: u8) -> Self {
42        // This isn't gated by "strict-assertions" because
43        // SealedPin::regs() depends on port being valid.
44        assert!(port <= 9);
45
46        // A port may have less than 16 pins, but we're not
47        // worried.
48        assert!(pin <= 15);
49
50        let pin_number = ((port & 0x0F) << 4) | (pin & 0x0F);
51        Self(pin_number)
52    }
53
54    /// Returns the index of the port associated with the pin.
55    #[inline(always)]
56    pub const fn port(&self) -> u8 {
57        (self.0 >> 4) & 0x0F
58    }
59
60    /// Returns the index of the pin within its associated port.
61    #[inline(always)]
62    pub const fn pin(&self) -> u8 {
63        self.0 & 0x0F
64    }
65}
66
67/// Output drive capacity.
68///
69/// For the `RA4M1` (Cortex-M4F) the maximum combined output of all pins is 60 mA, and each pin can be configured for max 4.0 mA or max 8.0 mA.
70/// Cortex-M33 devices have different limits.
71/// See the RA4 Quick Design Guide R01AN5988, §10.2.3 for more information.
72#[derive(Debug, Eq, PartialEq, Copy, Clone)]
73#[cfg_attr(feature = "defmt", derive(defmt::Format))]
74pub enum DriveCapacity {
75    /// Low drive, max output 4.0 mA.
76    Low,
77
78    /// Medium drive, max output 8.0 mA.
79    Middle,
80}
81
82/// Output mode for a GPIO pin.
83#[derive(Debug, Eq, PartialEq, Copy, Clone)]
84#[cfg_attr(feature = "defmt", derive(defmt::Format))]
85pub enum OutputMode {
86    /// Push-pull output
87    PushPull,
88
89    /// Open drain output
90    OpenDrain,
91}
92
93/// On a change in input level, which edge to trigger an interrupt on.
94#[derive(Clone, Copy)]
95pub enum GpioTrigger {
96    #[allow(missing_docs)]
97    Falling,
98    #[allow(missing_docs)]
99    Rising,
100    #[allow(missing_docs)]
101    Both,
102}
103
104/// Digital (debounce) filter configuration.
105///
106/// §13.2.1, §13.4.3
107#[cfg_attr(feature = "defmt", derive(defmt::Format))]
108pub enum Debounce {
109    /// Turn the digital filter off
110    Off,
111
112    /// Event must last 1 `PCLKB` cycle to trigger an interrupt.
113    Min1,
114
115    /// Event must last 8 `PCLKB` cycles to trigger an interrupt.
116    Min8,
117
118    /// Event must last 32 `PCLKB` cycles to trigger an interrupt.
119    Min32,
120
121    /// Event must last 64 `PCLKB` cycles to trigger an interrupt.
122    Min64,
123}
124
125/// Digital input or output level.
126#[derive(Debug, Eq, PartialEq, Copy, Clone)]
127#[cfg_attr(feature = "defmt", derive(defmt::Format))]
128pub enum Level {
129    #[allow(missing_docs)]
130    Low,
131    #[allow(missing_docs)]
132    High,
133}
134
135/// Links a GPIO pin to an interrupt. See also [`InterruptFlex`].
136#[allow(private_bounds)]
137pub trait GpioIrq<I: InterruptiblePin>: SealedGpioIrq {}
138
139pub(crate) trait SealedGpioIrq: PeripheralType {}
140
141macro_rules! declare_port_irq {
142    ($num:literal) => {
143        paste::paste! {
144            impl crate::gpio::SealedGpioIrq for crate::peripherals::[< GPIO_IRQ $num >] {}
145        }
146    };
147}
148pub(crate) use declare_port_irq;
149
150/// Type-erased GPIO pin
151pub struct AnyPin {
152    pub(crate) pin_port: PinId,
153}
154
155/// Indicates what GPIO capabilities a pin has.
156#[allow(private_bounds)]
157pub trait ControlKind: SealedControlKind {}
158trait SealedControlKind {}
159
160/// GPIO pin with basic functionality
161///
162/// See [`Pin`] for a list of available pins.
163pub enum Basic {}
164impl ControlKind for Basic {}
165impl SealedControlKind for Basic {}
166
167/// GPIO pin that has a internal pull-up resistor but does not support open-drain output.
168///
169/// See [`PullUpPin`] for a list of compatible pins.
170pub enum WithPullUp {}
171impl ControlKind for WithPullUp {}
172impl SealedControlKind for WithPullUp {}
173
174/// GPIO pin that has a internal pull-up resistor and supports open-drain output.
175///
176/// See [`OpenDrainPin`] for a list of compatible pins.
177pub enum WithOpenDrain {}
178impl ControlKind for WithOpenDrain {}
179impl SealedControlKind for WithOpenDrain {}
180
181/// GPIO flexible pin.
182///
183/// This pin can be configured for input, output, or attached to a peripheral.
184pub struct Flex<'d, C: ControlKind> {
185    pin: Peri<'d, AnyPin>,
186    phantom: PhantomData<C>,
187}
188
189/// A flexible GPIO pin that can asynchronously wait for data.
190#[allow(private_bounds)]
191pub struct InterruptFlex<'d, I: InterruptiblePin, C: ControlKind> {
192    pin: Flex<'d, C>,
193    phantom: PhantomData<&'d I>,
194    phantom_k: PhantomData<C>,
195}
196
197/// GPIO input driver
198pub struct Input<'d, C: ControlKind> {
199    pin: Flex<'d, C>,
200}
201
202/// GPIO output driver
203pub struct Output<'d, C: ControlKind> {
204    pin: Flex<'d, C>,
205}
206
207// Should this just export the type from the PAC?
208/// Additional, non-GPIO, functions that can be assigned to a pin.
209///
210/// Not every function applies to every pin.
211/// See tables 19.5–19.17 in the reference manual for details.
212#[cfg_attr(feature = "defmt", derive(defmt::Format))]
213#[derive(Copy, Clone)]
214#[repr(u8)]
215pub enum PortFunction {
216    #[doc = "Hi-Z / JTAG / SWD"]
217    HiZ = 0x0,
218    #[doc = "Low-Power Asynchronous General Purpose Timer"]
219    Agt = 0x01,
220    #[doc = "General PWM Timer"]
221    Gpt0 = 0x02,
222    #[doc = "General PWM Timer"]
223    Gpt1 = 0x03,
224    #[doc = "Serial Communications Interface"]
225    Sci0 = 0x04,
226    #[doc = "Serial Communications Interface"]
227    Sci1 = 0x05,
228    #[doc = "Serial Peripheral Interface"]
229    Spi = 0x06,
230    #[doc = "Inter-Integrated Circuit Bus Interface"]
231    I2c = 0x07,
232    #[doc = "Key Interrupt Function"]
233    Kint = 0x08,
234    #[doc = "CLKOUT / Analog Comparator / Real-Time Clock"]
235    ClkCmpRtc = 0x09,
236    #[doc = "Clock Frequency Accuracy / ADC14"]
237    CacAdc = 0x0a,
238    #[doc = "Capacitive Touch"]
239    Ctsu = 0x0c,
240    #[doc = "Segment LCD"]
241    Slcdc = 0x0d,
242    #[doc = "Controller Area Network Bus"]
243    Can = 0x10,
244    #[doc = "Serial Sound Interface Enhanced"]
245    Ssie = 0x12,
246    #[doc = "USB Full-Speed"]
247    UsbFs = 0x13,
248}
249
250/// Interrupt handler for an [`InterruptFlex`] pin.
251pub struct InputInterruptHandler<I: Pin> {
252    _phantom: PhantomData<I>,
253}
254
255trait PortPin {
256    fn port_pin(&self, port: u8, pin: u8) -> pac::common::Reg<pac::pfs::regs::Pin, RW>;
257}
258
259impl PortPin for Pfs {
260    #[inline(always)]
261    fn port_pin(&self, port_num: u8, pin_num: u8) -> pac::common::Reg<pac::pfs::regs::Pin, RW> {
262        self.pin((usize::from(port_num) * 16) + usize::from(pin_num))
263    }
264}
265
266pub(crate) trait SealedPin {
267    fn pin_port(&self) -> PinId;
268
269    #[inline(always)]
270    fn _pin(&self) -> u8 {
271        self.pin_port().pin()
272    }
273
274    #[inline(always)]
275    fn _port(&self) -> u8 {
276        self.pin_port().port()
277    }
278
279    #[inline]
280    #[cfg(any(pfs_ra8, pfs_port_drive))]
281    fn set_drive_capacity(&self, drive_capacity: DriveCapacity) {
282        let pfs = pac::PFS;
283        let port_num = self._port() as _;
284        let pin_num = self._pin() as _;
285        let pfs_reg = pfs.port_pin(port_num, pin_num);
286
287        pfs_reg.protected_modify(|r| match drive_capacity {
288            DriveCapacity::Low => r.set_dscr(PortDrive::Low),
289            DriveCapacity::Middle => r.set_dscr(PortDrive::Middle),
290        });
291    }
292
293    fn set_output_mode(&self, output_mode: OutputMode) {
294        let pfs = pac::PFS;
295        let port_num = self._port() as _;
296        let pin_num = self._pin() as _;
297        let pfs_reg = pfs.port_pin(port_num, pin_num);
298
299        match output_mode {
300            OutputMode::PushPull => pfs_reg.protected_modify(|r| r.set_ncodr(OutputType::Cmos)),
301            OutputMode::OpenDrain => pfs_reg.protected_modify(|r| r.set_ncodr(OutputType::Nmos)),
302        }
303    }
304
305    fn set_pull_up(&self, pull_up: bool) {
306        let pfs = pac::PFS;
307        let port_num = self._port() as _;
308        let pin_num = self._pin() as _;
309        let pfs_reg = pfs.port_pin(port_num, pin_num);
310
311        trace!("P{}{:02}: set_pull_up({})", port_num, pin_num, pull_up);
312
313        // TODO: §19.5.5
314        // When the P402, P403, and P404 pins are configured as outputs or inputs with the internal
315        // pull-up resistor, set the VBTCR1.BPWSWSTP bit to 1 before setting the I/O registers
316        // regardless of whether or not the battery backup function is used. This setting is only
317        // required one time after a power-on reset. Clear the VBTCR1.BPWSWSTP bit to 0 again after
318        // setting registers associated with the battery backup function, when using the battery
319        // backup function.
320
321        pfs_reg.protected_modify(|r| r.set_pcr(pull_up));
322
323        #[cfg(feature = "strict-assert")]
324        assert_eq!(pfs_reg.read().pcr(), pull_up, "set_pull_up failed");
325
326        trace!("P{}{:02}: {}", port_num, pin_num, pfs_reg.read());
327    }
328
329    /// Set the output as high.
330    #[inline(always)]
331    fn set_high(&self) {
332        let port = self.regs();
333        port.pcntr3().write(|r| r.set_posr(self._pin() as _, true));
334    }
335
336    /// Set the output as low.
337    #[inline(always)]
338    fn set_low(&self) {
339        let port = self.regs();
340        port.pcntr3().write(|r| r.set_porr(self._pin() as _, true));
341    }
342
343    /// Is the input high?
344    #[inline]
345    fn is_high(&self) -> bool {
346        let port = self.regs();
347        port.pcntr2().read().pidr(self._pin() as _)
348    }
349
350    /// Is the input low?
351    #[inline]
352    fn is_low(&self) -> bool {
353        !self.is_high()
354    }
355
356    /// What level is the input?
357    #[inline]
358    fn level(&self) -> Level {
359        let port = self.regs();
360
361        match port.pcntr2().read().pidr(self._pin() as _) {
362            false => Level::Low,
363            true => Level::High,
364        }
365    }
366
367    /// Set the output level.
368    #[inline(always)]
369    fn set_level(&self, level: Level) {
370        match level {
371            Level::Low => self.set_low(),
372            Level::High => self.set_high(),
373        }
374    }
375
376    /// Is the pin output set as logic low?
377    #[inline(always)]
378    fn is_set_low(&self) -> bool {
379        !self.is_set_high()
380    }
381
382    /// Is the pin output set as logic high?
383    #[inline(always)]
384    fn is_set_high(&self) -> bool {
385        let port = self.regs();
386        port.pcntr1().read().podr(self._pin() as _)
387    }
388
389    /// What is the output level set to?
390    #[inline]
391    fn output_level(&self) -> Level {
392        match self.is_set_high() {
393            true => Level::High,
394            false => Level::Low,
395        }
396    }
397
398    /// Toggle pin output
399    #[inline(always)]
400    fn toggle(&self) {
401        match self.is_set_high() {
402            true => self.set_low(),
403            false => self.set_high(),
404        }
405    }
406
407    #[inline]
408    fn set_as_output(&self) {
409        // It's possible to configure direction via PCNTR registers too.
410        // It's simpler.
411        // But we want to disable the pull-up resistor so PFS it is.
412        // let port = self.block();
413        // let pin = self._pin() as _;
414        // port.pcntr1().modify(|r| {
415        //     r.set_pdr(pin, true);
416        // });
417
418        let pfs = pac::PFS;
419        let port_num = self._port() as _;
420        let pin_num = self._pin() as _;
421        let pfs_reg = pfs.port_pin(port_num, pin_num);
422
423        trace!("P{}{:02}: → Output", port_num, pin_num);
424
425        // TODO: RA4M1 §19.5.7
426        // When P914 and P915 are used as GPIO pins, their operation is affected by the pull-up /
427        // pull-down function of the USBFS registers. Therefore, before using the GPIO function,
428        // disable the pull-up and pull-down control of the USBFS registers using the SYSCFG.DMRPU,
429        // SYSCFG.DPRPU and SYSCFG.DRPD bits.
430
431        pfs_reg.protected_modify(|r| {
432            r.set_pmr(PortMode::Gpio);
433            r.set_pdr(PortDirection::Output);
434            r.set_pcr(false);
435        });
436
437        #[cfg(feature = "strict-assert")]
438        {
439            let status = pfs_reg.read();
440            assert_eq!(status.pmr(), PortMode::Gpio);
441            assert_eq!(status.pdr(), PortDirection::Output);
442            assert_eq!(status.pcr(), false);
443        }
444    }
445
446    #[inline]
447    fn set_as_input(&self) {
448        let pfs = pac::PFS;
449        let port_num = self._port() as _;
450        let pin_num = self._pin() as _;
451        let pfs_reg = pfs.port_pin(port_num, pin_num);
452
453        trace!("P{}{:02}: → Input", port_num, pin_num);
454
455        // TODO: §19.5.7
456        // When P914 and P915 are used as GPIO pins, their operation is affected by the pull-up /
457        // pull-down function of the USBFS registers. Therefore, before using the GPIO function,
458        // disable the pull-up and pull-down control of the USBFS registers using the SYSCFG.DMRPU,
459        // SYSCFG.DPRPU and SYSCFG.DRPD bits.
460
461        pfs_reg.protected_modify(|r| {
462            r.set_pmr(PortMode::Gpio);
463            r.set_pdr(PortDirection::Input);
464        });
465
466        #[cfg(feature = "strict-assert")]
467        {
468            let status = pfs_reg.read();
469            assert_eq!(status.pmr(), PortMode::Gpio);
470            assert_eq!(status.pdr(), PortDirection::Input);
471        }
472    }
473
474    /// Sets a pin to analog mode for use with the ADC.
475    fn set_as_analog(&self) {
476        let pfs = pac::PFS;
477
478        let port_num = self._port() as _;
479        let pin_num = self._pin() as _;
480        let pfs_reg = pfs.port_pin(port_num, pin_num);
481
482        pfs_reg.protected_modify(|r| {
483            r.set_pdr(PortDirection::Input);
484            r.set_asel(true);
485            r.set_pcr(false);
486        });
487
488        #[cfg(feature = "strict-assert")]
489        {
490            let status = pfs_reg.read();
491            assert_eq!(status.pdr(), PortDirection::Input);
492            assert_eq!(status.asel(), true);
493            assert_eq!(status.pcr(), false);
494        }
495    }
496
497    fn set_as_pf(&self, port_func: PortFunction) {
498        let port_num = self._port() as _;
499        let pin_num = self._pin() as _;
500
501        let pfs = crate::pac::PFS;
502
503        let pfs_reg = pfs.port_pin(port_num, pin_num);
504
505        // The quick design guide suggests that first setting the pin to GPIO ensure the peripheral doesn't get any spurious input
506        pfs_reg.protected_modify(|r| r.set_pmr(PortMode::Gpio));
507
508        pfs_reg.protected_modify(|r| {
509            r.set_pmr(PortMode::Peripheral);
510            r.set_psel(port_func.into());
511        });
512
513        debug!("P{}{:02}: {}", port_num, pin_num, pfs_reg.read());
514
515        #[cfg(feature = "strict-assert")]
516        {
517            let status = pfs_reg.read();
518            assert_eq!(status.pmr(), PortMode::Peripheral, "PMR was ignored");
519            assert_eq!(status.psel(), port_func.into(), "PSEL was ignored");
520        }
521    }
522
523    /// Get the GPIO register block for this pin.
524    fn regs(&self) -> crate::pac::port::Port;
525}
526
527/// Peripheral that can be used as a GPIO pin.
528#[allow(private_bounds)]
529pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
530    /// Number of the pin within the port, typically 0..16.
531    ///
532    /// Consult the reference manual tables 19.5–19.17 for more details.
533    #[inline]
534    fn pin(&self) -> u8 {
535        self._pin()
536    }
537
538    /// Port of the pin
539    #[inline]
540    fn port(&self) -> u8 {
541        self._port()
542    }
543
544    /// Encoded port+pin number of the pin
545    #[inline]
546    fn pin_port(&self) -> PinId {
547        SealedPin::pin_port(self)
548    }
549}
550
551/// A GPIO pin with an internal pull-up resistor.
552///
553/// # Notes
554/// Pull-ups do not work when a pin is assigned to a peripheral.
555#[allow(private_bounds)]
556pub trait PullUpPin: SealedPullUpPin {}
557
558pub(crate) trait SealedPullUpPin: Pin {}
559
560/// A GPIO pin with an internal pull-up resistor and the ability to be configured for open-drain output.
561///
562/// # Notes
563/// Pull-ups do not work when a pin is assigned to a peripheral.
564#[allow(private_bounds)]
565pub trait OpenDrainPin: SealedOpenDrainPin {}
566
567pub(crate) trait SealedOpenDrainPin: Pin {}
568
569/// A GPIO pin that can generate interrupts based on input events.
570#[allow(private_bounds)]
571pub trait InterruptiblePin: SealedIntPin + Pin {}
572
573pub(crate) trait SealedIntPin {
574    const INTERRUPT_EVENT: InterruptEvent;
575
576    fn waker() -> &'static AtomicWaker;
577}
578
579impl From<PortFunction> for pac::pfs::vals::PortFunction {
580    fn from(value: PortFunction) -> Self {
581        Self::from_bits(value as u8)
582    }
583}
584
585impl From<bool> for Level {
586    fn from(value: bool) -> Self {
587        match value {
588            false => Self::Low,
589            true => Self::High,
590        }
591    }
592}
593
594impl Pin for AnyPin {}
595
596impl SealedPin for AnyPin {
597    #[inline(always)]
598    fn pin_port(&self) -> PinId {
599        self.pin_port
600    }
601
602    #[inline(always)]
603    fn regs(&self) -> crate::pac::port::Port {
604        // This is safe because we know the ports are laid out
605        // contiguously at fixed intervals and that the PinId
606        // constructor won't allow an invalid port number.
607        let port_ptr = crate::pac::PORT0.as_ptr() as usize;
608        let offset = 0x20 * self._port() as usize;
609        unsafe { crate::pac::port::Port::from_ptr(port_ptr.wrapping_add(offset) as _) }
610    }
611}
612
613impl AnyPin {
614    /// Unsafely create an `AnyPin` from a `PinId` number.
615    ///
616    /// # Safety
617    ///
618    /// This only works for valid port + pin combinations.
619    /// Consult the reference manual to see which ports and pins your MCU has.
620    #[inline]
621    pub unsafe fn steal(pin_port: PinId) -> Peri<'static, Self> {
622        unsafe { Peri::new_unchecked(Self { pin_port }) }
623    }
624
625    /// Get the GPIO register block for this pin.
626    #[cfg(feature = "unstable-pac")]
627    #[inline]
628    pub fn block(&self) -> crate::pac::port::Port {
629        SealedPin::regs(self)
630    }
631}
632
633impl<'d> Input<'d, Basic> {
634    /// Create GPIO input driver for a [`Pin`] without pull-up capabilities.
635    ///
636    /// # Arguments
637    /// * `pin` the [`Pin`]
638    pub fn new_basic(pin: Peri<'d, impl Pin>) -> Self {
639        Self::new(pin)
640    }
641}
642
643impl<'d> Input<'d, WithPullUp> {
644    /// Create GPIO input driver for a [`Pin`] with the ability to toggle an internal pull-up resistor.
645    ///
646    /// # Arguments
647    /// * `pin` suitable input pin
648    /// * `pull_up` enable the internal pull-up resistor
649    #[inline]
650    pub fn new_with_pull_up(pin: Peri<'d, impl Pin>, pull_up: bool) -> Self {
651        let mut this = Self::new(pin);
652
653        this.set_pull_up(pull_up);
654
655        this
656    }
657
658    /// Enable the internal pull-up resistor?
659    ///
660    /// # Notes
661    ///
662    /// This is ignored by the MCU unless the pin is configured for input.
663    pub fn set_pull_up(&mut self, pull_up: bool) {
664        self.pin.set_pull_up(pull_up);
665    }
666}
667
668impl<'d, C: ControlKind> Input<'d, C> {
669    /// Create GPIO input driver for a [`Pin`].
670    ///
671    /// # Arguments
672    /// * `pin` suitable input pin
673    #[inline]
674    pub fn new(pin: Peri<'d, impl Pin>) -> Self {
675        let mut pin = Flex::new(pin);
676
677        pin.set_as_input();
678
679        Self { pin }
680    }
681
682    /// Is the input level low?
683    #[inline]
684    pub fn is_low(&mut self) -> bool {
685        self.pin.is_low()
686    }
687
688    /// Is the input level high?
689    #[inline]
690    pub fn is_high(&mut self) -> bool {
691        self.pin.is_high()
692    }
693
694    /// Input level
695    #[inline]
696    pub fn level(&mut self) -> Level {
697        self.pin.level()
698    }
699}
700
701impl<'d> Output<'d, Basic> {
702    /// Create GPIO output driver for a [`Pin`] without pull-up or open-drain capabilities.
703    ///
704    /// # Arguments
705    /// * `pin` the [`Pin`]
706    /// * `initial` set the initial output level to logic low or high
707    /// * `drive_capacity` sets the output current, see [`DriveCapacity`] for details.
708    pub fn new_basic(
709        pin: Peri<'d, impl Pin>,
710        initial: Level,
711        #[cfg(any(pfs_ra8, pfs_port_drive))] drive_capacity: DriveCapacity,
712    ) -> Self {
713        Self::new(
714            pin,
715            initial,
716            #[cfg(any(pfs_ra8, pfs_port_drive))]
717            drive_capacity,
718        )
719    }
720}
721
722impl<'d> Output<'d, WithOpenDrain> {
723    /// Create GPIO output driver for a [`Pin`] that supports open-drain output.
724    ///
725    /// # Arguments
726    /// * `pin` the [`Pin`]
727    /// * `initial` set the initial output level to logic low or high
728    /// * `drive_capacity` sets the output current, see [`DriveCapacity`] for details.
729    #[inline]
730    pub fn new_with_open_drain(
731        pin: Peri<'d, impl Pin>,
732        initial: Level,
733        #[cfg(any(pfs_ra8, pfs_port_drive))] drive_capacity: DriveCapacity,
734        output_mode: OutputMode,
735    ) -> Self {
736        let mut this = Self::new(
737            pin,
738            initial,
739            #[cfg(any(pfs_ra8, pfs_port_drive))]
740            drive_capacity,
741        );
742
743        this.set_output_mode(output_mode);
744
745        this
746    }
747
748    /// Sets a pin's output mode to either open-drain or push-pull.
749    #[inline]
750    pub fn set_output_mode(&mut self, output_mode: OutputMode) {
751        self.pin.set_output_mode(output_mode);
752    }
753}
754
755impl<'d, C: ControlKind> Output<'d, C> {
756    /// Create GPIO output driver for a [`Pin`].
757    ///
758    /// # Arguments
759    /// * `pin` the [`Pin`]
760    /// * `initial` set the initial output level to logic low or high
761    /// * `drive_capacity` sets the output current, see [`DriveCapacity`] for details.
762    #[inline]
763    pub(crate) fn new(
764        pin: Peri<'d, impl Pin>,
765        initial: Level,
766        #[cfg(any(pfs_ra8, pfs_port_drive))] drive_capacity: DriveCapacity,
767    ) -> Self {
768        let mut this = Flex::new(pin);
769
770        this.set_as_output();
771        this.set_level(initial);
772        #[cfg(any(pfs_ra8, pfs_port_drive))]
773        this.set_drive_capacity(drive_capacity);
774
775        Self { pin: this }
776    }
777
778    /// Sets the output drive capacity of a pin.
779    ///
780    /// # Notes
781    ///
782    /// Be aware of the maximum permissible combined current output for all pins, see [`DriveCapacity`] for more information.
783    #[inline]
784    #[cfg(any(pfs_ra8, pfs_port_drive))]
785    pub fn set_drive_capacity(&mut self, drive_capacity: DriveCapacity) {
786        self.pin.set_drive_capacity(drive_capacity)
787    }
788
789    /// Set the output as low.
790    #[inline(always)]
791    pub fn set_low(&mut self) {
792        self.pin.set_low();
793    }
794
795    /// Set the output as high.
796    #[inline(always)]
797    pub fn set_high(&mut self) {
798        self.pin.set_high();
799    }
800
801    /// Set the output level.
802    #[inline(always)]
803    pub fn set_level(&mut self, level: Level) {
804        self.pin.set_level(level)
805    }
806
807    /// Toggle pin output.
808    #[inline(always)]
809    pub fn toggle(&mut self) {
810        self.pin.toggle();
811    }
812
813    /// Is the pin output set as logic low?
814    #[inline]
815    pub fn is_set_low(&mut self) -> bool {
816        self.pin.is_set_low()
817    }
818
819    /// Is the pin output set as logic high?
820    #[inline]
821    pub fn is_set_high(&mut self) -> bool {
822        self.pin.is_set_high()
823    }
824
825    /// What is the output level set to?
826    #[inline]
827    pub fn output_level(&mut self) -> Level {
828        self.pin.output_level()
829    }
830
831    /// Log current PFS state at `debug` level.
832    #[inline]
833    pub fn print_pfs_state(&self) {
834        self.pin.print_pfs_state();
835    }
836}
837
838impl<'d> Flex<'d, WithPullUp> {
839    /// Create `Flex` from pin with the ability to toggle an internal pull-up resistor.
840    #[inline]
841    pub fn new_with_pull_up(pin: Peri<'d, impl PullUpPin>, pull_up: bool) -> Self {
842        let mut this = Self {
843            pin: pin.into(),
844            phantom: PhantomData,
845        };
846
847        this.set_pull_up(pull_up);
848
849        trace!(
850            "Flex<WithPullUp>: port={}, pin={}",
851            this.pin._port(),
852            this.pin._pin()
853        );
854
855        this
856    }
857
858    /// Enable the internal pull-up resistor?
859    ///
860    /// # Notes
861    ///
862    /// This will be ignored by the MCU unless the pin is configured for input.
863    pub fn set_pull_up(&mut self, pull_up: bool) {
864        self.pin.set_pull_up(pull_up);
865    }
866}
867
868impl<'d> Flex<'d, WithOpenDrain> {
869    /// Create `Flex` from pin with support for an internal pull-up resistor and open-drain capability.
870    #[inline]
871    pub fn new_with_open_drain(
872        pin: Peri<'d, impl OpenDrainPin>,
873        pull_up: bool,
874        output_mode: OutputMode,
875    ) -> Self {
876        let mut this = Self {
877            pin: pin.into(),
878            phantom: PhantomData,
879        };
880
881        this.set_pull_up(pull_up);
882        this.set_output_mode(output_mode);
883
884        trace!(
885            "Flex<OpenDrain>: port={}, pin={}",
886            this.pin._port(),
887            this.pin._pin()
888        );
889
890        this
891    }
892
893    /// Enable the internal pull-up resistor?
894    ///
895    /// # Notes
896    ///
897    /// This will be ignored by the MCU unless the pin is configured for input.
898    #[inline]
899    pub fn set_pull_up(&mut self, pull_up: bool) {
900        self.pin.set_pull_up(pull_up);
901    }
902
903    /// Sets a pin's output mode to either open-drain or push-pull.
904    #[inline]
905    pub fn set_output_mode(&mut self, output_mode: OutputMode) {
906        self.pin.set_output_mode(output_mode);
907    }
908}
909
910impl<'d> Flex<'d, Basic> {
911    /// Create `Flex` from pin with no internal pull-up resistor or open-drain capability.
912    #[inline]
913    pub fn new_basic(pin: Peri<'d, impl Pin>) -> Self {
914        let this = Self {
915            pin: pin.into(),
916            phantom: PhantomData,
917        };
918
919        trace!(
920            "Flex<Basic>: port={}, pin={}",
921            this.pin._port(),
922            this.pin._pin()
923        );
924
925        this
926    }
927}
928
929impl<'d, C: ControlKind> Flex<'d, C> {
930    /// Create `Flex` from pin.
931    #[inline]
932    pub(crate) fn new(pin: Peri<'d, impl Pin>) -> Self {
933        let this = Self {
934            pin: pin.into(),
935            phantom: PhantomData,
936        };
937
938        trace!(
939            "Flex<Basic>: port={}, pin={}",
940            this.pin._port(),
941            this.pin._pin()
942        );
943
944        this
945    }
946
947    /// Places pin into input mode.
948    #[inline]
949    pub fn set_as_input(&mut self) {
950        self.pin.set_as_input();
951    }
952
953    /// Is the input level low?
954    #[inline]
955    pub fn is_low(&mut self) -> bool {
956        self.pin.is_low()
957    }
958
959    /// Is the input level high?
960    #[inline]
961    pub fn is_high(&mut self) -> bool {
962        self.pin.is_high()
963    }
964
965    /// Input level
966    #[inline]
967    pub fn level(&mut self) -> Level {
968        self.pin.level()
969    }
970
971    /// Places pin in output mode.
972    #[inline]
973    pub fn set_as_output(&mut self) {
974        self.pin.set_as_output();
975    }
976
977    /// Sets the output drive capacity of a pin.
978    ///
979    /// Note: be aware of the maximum permissible combined current output for all pins, see [`DriveCapacity`] for more information.
980    #[inline]
981    #[cfg(any(pfs_ra8, pfs_port_drive))]
982    pub fn set_drive_capacity(&mut self, drive_capacity: DriveCapacity) {
983        self.pin.set_drive_capacity(drive_capacity)
984    }
985
986    /// Set the output as low.
987    #[inline(always)]
988    pub fn set_low(&mut self) {
989        self.pin.set_low();
990    }
991
992    /// Set the output as high.
993    #[inline(always)]
994    pub fn set_high(&mut self) {
995        self.pin.set_high();
996    }
997
998    /// Set the output level.
999    #[inline(always)]
1000    pub fn set_level(&mut self, level: Level) {
1001        self.pin.set_level(level)
1002    }
1003
1004    /// Toggle pin output.
1005    #[inline(always)]
1006    pub fn toggle(&mut self) {
1007        self.pin.toggle();
1008    }
1009
1010    /// Is the pin output set as logic low?
1011    #[inline]
1012    pub fn is_set_low(&mut self) -> bool {
1013        self.pin.is_set_low()
1014    }
1015
1016    /// Is the pin output set as logic high?
1017    #[inline]
1018    pub fn is_set_high(&mut self) -> bool {
1019        self.pin.is_set_high()
1020    }
1021
1022    /// What is the output level set to?
1023    #[inline]
1024    pub fn output_level(&mut self) -> Level {
1025        self.pin.output_level()
1026    }
1027
1028    /// Sets a pin to analog mode for use with the ADC.
1029    pub fn set_as_analog(&mut self) {
1030        self.pin.set_as_analog();
1031    }
1032
1033    /// Sets the pin into peripheral mode and selects port function `func`.
1034    pub fn set_as_pf(&mut self, func: PortFunction) {
1035        self.pin.set_as_pf(func);
1036    }
1037
1038    /// Log current PFS state at `debug` level.
1039    pub fn print_pfs_state(&self) {
1040        #[cfg(feature = "defmt")]
1041        {
1042            let pfs = pac::PFS;
1043            let port_num = self.pin._port() as _;
1044            let pin_num = self.pin._pin() as _;
1045
1046            // info!("Port{}, Pin{}, Output", port_num, pin_num);
1047            let pfs_reg = pfs.port_pin(port_num, pin_num);
1048            debug!("P{}{:02}: {}", port_num, pin_num, pfs_reg.read());
1049        }
1050    }
1051}
1052
1053impl<'d, C: ControlKind> Drop for Flex<'d, C> {
1054    fn drop(&mut self) {
1055        trace!("P{}{:02} Flex::drop", self.pin.port(), self.pin._pin());
1056        self.set_as_input();
1057        self.pin.set_pull_up(false);
1058    }
1059}
1060
1061impl<'d, I: InterruptiblePin> InterruptFlex<'d, I, WithPullUp> {
1062    /// Enable the internal pull-up resistor?
1063    ///
1064    /// # Notes
1065    /// This is ignored by the MCU unless the pin is configured for input.
1066    pub fn set_pull_up(&mut self, pull_up: bool) {
1067        self.pin.set_pull_up(pull_up);
1068    }
1069}
1070
1071impl<'d, I: InterruptiblePin, C: ControlKind> InterruptFlex<'d, I, C> {
1072    /// Creates an `InterruptFlex` configured for input that detects falling edge events and has the debounce filter disabled.
1073    #[inline]
1074    pub fn new<Int: InterruptType>(
1075        pin: Peri<'d, I>,
1076        gpio_irq: Peri<'d, impl GpioIrq<I>>,
1077        irq: impl interrupt::typelevel::Binding<Int, InputInterruptHandler<I>>,
1078    ) -> Self {
1079        let _ = gpio_irq;
1080        let _ = irq;
1081
1082        // Safety: Interrupt handlers are defined by the irq argument and thus the interrupt is safe to enable.
1083        unsafe {
1084            Int::IRQ.enable();
1085            Int::IRQ.icu_enable(I::INTERRUPT_EVENT);
1086        }
1087
1088        let pfs = pac::PFS;
1089        let pin = Flex::new(pin);
1090
1091        let port_num = pin.pin._port() as _;
1092        let pin_num = pin.pin._pin() as _;
1093        let pfs_reg = pfs.port_pin(port_num, pin_num);
1094
1095        pfs_reg.protected_modify(|r| r.set_isel(true));
1096
1097        let mut this = Self {
1098            pin,
1099            phantom: PhantomData,
1100            phantom_k: PhantomData,
1101        };
1102
1103        this.set_as_input();
1104        this.set_trigger(GpioTrigger::Falling);
1105        this.set_debounce(Debounce::Off);
1106
1107        this
1108    }
1109
1110    // The RM says:
1111    // For a CPU interrupt or DTC trigger:
1112    // Change the IRQCRi register setting before setting the target IELSRn (n = 0 to 31).
1113    // You can change the register values only when the IELSRn.IELS[7:0] bits are 00h.
1114    //
1115    // But this doesn't seem to be the case?
1116
1117    /// When to trigger the interrupt (edge detection only).
1118    ///
1119    /// §13.2.1
1120    pub fn set_trigger(&mut self, trigger: GpioTrigger) {
1121        #[cfg(not(ra8m1))]
1122        let icu = pac::ICU;
1123        #[cfg(ra8m1)]
1124        let icu = pac::ICU_COMMON;
1125
1126        // GROSS
1127        let reg = icu.irqcr((I::INTERRUPT_EVENT as u8 - 1) as _);
1128
1129        match trigger {
1130            GpioTrigger::Falling => reg.modify(|r| r.set_irqmd(Irqmd::FallingEdge)),
1131            GpioTrigger::Rising => reg.modify(|r| r.set_irqmd(Irqmd::RisingEdge)),
1132            GpioTrigger::Both => reg.modify(|r| r.set_irqmd(Irqmd::AnyEdge)),
1133        }
1134    }
1135
1136    /// Configure the internal digital (debounce) filter.
1137    ///
1138    /// §13.2.1, §13.4.3
1139    pub fn set_debounce(&mut self, debounce: Debounce) {
1140        #[cfg(not(ra8m1))]
1141        let icu = pac::ICU;
1142        #[cfg(ra8m1)]
1143        let icu = pac::ICU_COMMON;
1144
1145        // GROSS
1146        let reg = icu.irqcr((I::INTERRUPT_EVENT as u8 - 1) as _);
1147
1148        match debounce {
1149            Debounce::Off => reg.modify(|r| r.set_flten(false)),
1150            Debounce::Min1 => {
1151                reg.modify(|r| {
1152                    r.set_flten(true);
1153                    r.set_fclksel(Fclksel::Pclkb1);
1154                });
1155            }
1156            Debounce::Min8 => {
1157                reg.modify(|r| {
1158                    r.set_flten(true);
1159                    r.set_fclksel(Fclksel::Pclkb8);
1160                });
1161            }
1162            Debounce::Min32 => {
1163                reg.modify(|r| {
1164                    r.set_flten(true);
1165                    r.set_fclksel(Fclksel::Pclkb32);
1166                });
1167            }
1168            Debounce::Min64 => {
1169                reg.modify(|r| {
1170                    r.set_flten(true);
1171                    r.set_fclksel(Fclksel::Pclkb64);
1172                });
1173            }
1174        }
1175    }
1176
1177    /// Places pin into input mode.
1178    ///
1179    /// # Arguments
1180    /// * `pull_up` enable the built-in pull-up resistor if true.
1181    #[inline]
1182    pub fn set_as_input(&mut self) {
1183        self.pin.set_as_input();
1184    }
1185
1186    /// Waits for the pin to go low.
1187    ///
1188    /// # Notes
1189    ///
1190    /// If the pin is low when this function is called it will return immediately.
1191    /// See also [`set_trigger`](InterruptFlex::set_trigger).
1192    pub async fn wait_for_low(&mut self) {
1193        poll_fn(|cx| {
1194            if self.pin.is_low() {
1195                return Poll::Ready(());
1196            }
1197            I::waker().register(cx.waker());
1198            Poll::Pending
1199        })
1200        .await
1201    }
1202
1203    /// Waits for the pin to go high.
1204    ///
1205    /// # Notes
1206    ///
1207    /// If the pin is high when this function is called it will return immediately.
1208    /// See also [`set_trigger`](InterruptFlex::set_trigger).
1209    pub async fn wait_for_high(&mut self) {
1210        poll_fn(|cx| {
1211            if self.pin.is_high() {
1212                return Poll::Ready(());
1213            }
1214            I::waker().register(cx.waker());
1215            Poll::Pending
1216        })
1217        .await
1218    }
1219
1220    /// Waits for a change in input level and returns the level after the interrupt is fired.
1221    /// See also [`set_trigger`](InterruptFlex::set_trigger).
1222    pub async fn wait_for_event(&mut self) -> Level {
1223        let mut event = false;
1224        poll_fn(|cx| {
1225            if !event {
1226                event = true;
1227                I::waker().register(cx.waker());
1228                Poll::Pending
1229            } else {
1230                Poll::Ready(self.pin.level())
1231            }
1232        })
1233        .await
1234    }
1235
1236    /// Is the input level low?
1237    #[inline]
1238    pub fn is_low(&mut self) -> bool {
1239        self.pin.is_low()
1240    }
1241
1242    /// Is the input level high?
1243    #[inline]
1244    pub fn is_high(&mut self) -> bool {
1245        self.pin.is_high()
1246    }
1247
1248    /// Input level
1249    #[inline]
1250    pub fn level(&mut self) -> Level {
1251        self.pin.level()
1252    }
1253
1254    /// Places pin in output mode.
1255    #[inline]
1256    pub fn set_as_output(&mut self) {
1257        self.pin.set_as_output();
1258    }
1259
1260    /// Sets the output drive capacity of a pin.
1261    ///
1262    /// Note: be aware of the maximum permissible combined current output for all pins, see [`DriveCapacity`] for more information.
1263    #[inline]
1264    #[cfg(any(pfs_ra8, pfs_port_drive))]
1265    pub fn set_drive_capacity(&mut self, drive_capacity: DriveCapacity) {
1266        self.pin.set_drive_capacity(drive_capacity)
1267    }
1268
1269    /// Set the output as low.
1270    #[inline]
1271    pub fn set_low(&mut self) {
1272        self.pin.set_low();
1273    }
1274
1275    /// Set the output as high.
1276    #[inline]
1277    pub fn set_high(&mut self) {
1278        self.pin.set_high();
1279    }
1280
1281    /// Set the output level.
1282    #[inline]
1283    pub fn set_level(&mut self, level: Level) {
1284        self.pin.set_level(level)
1285    }
1286
1287    /// Toggle pin output.
1288    #[inline]
1289    pub fn toggle(&mut self) {
1290        self.pin.toggle();
1291    }
1292
1293    /// Is the pin output set as logic low?
1294    #[inline]
1295    pub fn is_set_low(&mut self) -> bool {
1296        self.pin.is_set_low()
1297    }
1298
1299    /// Is the pin output set as logic high?
1300    #[inline]
1301    pub fn is_set_high(&mut self) -> bool {
1302        self.pin.is_set_high()
1303    }
1304
1305    /// What is the output level set to?
1306    #[inline]
1307    pub fn output_level(&mut self) -> Level {
1308        self.pin.output_level()
1309    }
1310
1311    /// Sets the pin into peripheral mode and selects port function `func`.
1312    pub fn set_as_pf(&mut self, func: PortFunction) {
1313        self.pin.set_as_pf(func);
1314    }
1315
1316    /// Log current PFS state at `debug` level.
1317    pub fn print_pfs_state(&self) {
1318        self.pin.print_pfs_state();
1319    }
1320}
1321
1322macro_rules! gpio_pin {
1323    ($pin_name:ident, $port_number:literal, $pin_number:literal, $port:ident) => {
1324        impl crate::gpio::Pin for crate::peripherals::$pin_name {}
1325
1326        impl crate::gpio::SealedPin for crate::peripherals::$pin_name {
1327            #[inline(always)]
1328            fn pin_port(&self) -> crate::gpio::PinId {
1329                crate::gpio::PinId::from_port_pin($port_number, $pin_number)
1330            }
1331
1332            #[inline(always)]
1333            fn regs(&self) -> crate::pac::port::Port {
1334                // This is more or less safe as ports with event link simply add fields
1335                // and by constructing a base port we're ignoring the additions.
1336                unsafe { crate::pac::port::Port::from_ptr(crate::pac::$port.as_ptr() as _) }
1337            }
1338        }
1339
1340        impl From<crate::peripherals::$pin_name> for crate::gpio::AnyPin {
1341            fn from(val: crate::peripherals::$pin_name) -> Self {
1342                use crate::gpio::SealedPin as _;
1343                Self {
1344                    pin_port: val.pin_port(),
1345                }
1346            }
1347        }
1348    };
1349}
1350pub(crate) use gpio_pin;
1351
1352impl_peripheral!(AnyPin);
1353
1354impl<Pin: InterruptiblePin, Int: InterruptType> InterruptHandler<Int>
1355    for InputInterruptHandler<Pin>
1356{
1357    unsafe fn on_interrupt() {
1358        Int::IRQ.icu_unpend();
1359        Pin::waker().wake()
1360    }
1361}
1362
1363impl<'d, C: ControlKind> embedded_hal_1::digital::ErrorType for Input<'d, C> {
1364    type Error = Infallible;
1365}
1366
1367impl<'d, C: ControlKind> embedded_hal_1::digital::InputPin for Input<'d, C> {
1368    fn is_high(&mut self) -> Result<bool, Self::Error> {
1369        Ok(self.is_high())
1370    }
1371
1372    fn is_low(&mut self) -> Result<bool, Self::Error> {
1373        Ok(self.is_low())
1374    }
1375}
1376
1377impl<'d, C: ControlKind> embedded_hal_1::digital::ErrorType for Output<'d, C> {
1378    type Error = Infallible;
1379}
1380
1381impl<'d, C: ControlKind> embedded_hal_1::digital::OutputPin for Output<'d, C> {
1382    fn set_low(&mut self) -> Result<(), Self::Error> {
1383        self.set_low();
1384        Ok(())
1385    }
1386
1387    fn set_high(&mut self) -> Result<(), Self::Error> {
1388        self.set_high();
1389        Ok(())
1390    }
1391}
1392
1393impl<'d, C: ControlKind> embedded_hal_1::digital::StatefulOutputPin for Output<'d, C> {
1394    fn is_set_high(&mut self) -> Result<bool, Self::Error> {
1395        Ok(self.is_set_high())
1396    }
1397
1398    fn is_set_low(&mut self) -> Result<bool, Self::Error> {
1399        Ok(self.is_set_low())
1400    }
1401
1402    fn toggle(&mut self) -> Result<(), Self::Error> {
1403        self.toggle();
1404        Ok(())
1405    }
1406}