esp_hal/gpio/
interconnect.rs

1//! # Peripheral signal interconnect using the GPIO matrix.
2//!
3//! The GPIO matrix offers flexible connection options between GPIO pins and
4//! peripherals. This module offers capabilities not covered by GPIO pin types
5//! and drivers, like routing fixed logic levels to peripheral inputs, or
6//! inverting input and output signals.
7//!
8//! > Note that routing a signal through the GPIO matrix adds some latency to
9//! > the signal. This is not a problem for most peripherals, but it can be an
10//! > issue for high-speed peripherals like SPI or I2S. `esp-hal` tries to
11//! > bypass the GPIO matrix when possible (e.g. when the pin can be configured
12//! > as a suitable Alternate Function for the peripheral signal, and other
13//! > settings are compatible), but silently falls back to the GPIO matrix for
14//! > flexibility.
15#![doc = concat!("## Relation to the ", crate::trm_markdown_link!("iomuxgpio"))]
16//! The GPIO drivers implement IO MUX and pin functionality (input/output
17//! buffers, pull resistors, etc.). The GPIO matrix is represented by signals
18//! and the [`PeripheralInput`] and [`PeripheralOutput`] traits. There is some
19//! overlap between them: signal routing depends on what type is passed to a
20//! peripheral driver's pin setter functions.
21//!
22//! ## Signals
23//!
24//! GPIO signals are represented by the [`InputSignal`] and [`OutputSignal`]
25//! structs. Peripheral drivers accept [`PeripheralInput`] and
26//! [`PeripheralOutput`] implementations which are implemented for anything that
27//! can be converted into the signal types:
28//! - GPIO pins and drivers
29//! - A fixed logic [`Level`]
30//! - [`NoPin`]
31//!
32//! Note that some of these exist for convenience only. `Level` is meaningful as
33//! a peripheral input, but not as a peripheral output. `NoPin` is a placeholder
34//! for when a peripheral driver does not require a pin, but the API requires
35//! one. It is equivalent to [`Level::Low`].
36//!
37//! ### Splitting drivers into signals
38//!
39//! Each GPIO pin driver such as [`Input`], can be converted
40//! into input or output signals. [`Flex`], which can be either input or output,
41//! can be [`split`](Flex::split) into both signals at once. These signals can
42//! then be individually connected to a peripheral input or output signal. This
43//! allows for flexible routing of signals between peripherals and GPIO pins.
44//!
45//! Note that only configured GPIO drivers can be safely turned into signals.
46//! This conversion freezes the pin configuration, otherwise it would be
47//! possible for multiple peripheral drivers to configure the same GPIO pin at
48//! the same time, which is undefined behavior.
49//!
50//! ### Splitting pins into signals
51//!
52//! GPIO pin types such as [`GPIO0`] or [`AnyPin`] can be **unsafely**
53//! [split](AnyPin::split) into signals. In this case you need to carefully
54//! ensure that only a single driver configures the split pin, by selectively
55//! [freezing](`InputSignal::freeze`) the signals.
56//!
57//! For example, if you want to route GPIO3 to both a Pulse Counter
58//! input and a [UART](crate::uart::Uart) RX line, you will need to make sure
59//! one of the signals is frozen, otherwise the driver that is configured later
60//! will overwrite the other driver's configuration. Configuring the signals on
61//! multiple cores is undefined behaviour unless you ensure the configuration
62//! does not happen at the same time.
63//!
64//! ### Using pins and signals
65//!
66//! A GPIO pin can be configured either with a GPIO driver such as [`Input`], or
67//! by a peripheral driver using a pin assignment method such as
68//! [`Spi::with_mosi`]. The peripheral drivers' preferences can be overridden by
69//! passing a pin driver to the peripheral driver. When converting a driver to
70//! signals, the underlying signals will be initially
71//! [frozen](InputSignal::freeze) to support this use case.
72//!
73//! ## Inverting inputs and outputs
74//!
75//! The GPIO matrix allows for inverting the input and output signals. This can
76//! be configured via [`InputSignal::with_input_inverter`] and
77//! [`OutputSignal::with_input_inverter`]. The hardware is configured
78//! accordingly when the signal is connected to a peripheral input or output.
79//!
80//! ## Connection rules
81//!
82//! Peripheral signals and GPIOs can be connected with the following
83//! constraints:
84//!
85//! - A peripheral input signal must be driven by exactly one signal, which can be a GPIO input or a
86//!   constant level.
87//! - A peripheral output signal can be connected to any number of GPIOs. These GPIOs can be
88//!   configured differently. The peripheral drivers will only support a single connection (that is,
89//!   they disconnect previously configured signals on repeat calls to the same function), but you
90//!   can use `esp_hal::gpio::OutputSignal::connect_to` (note that the type is currently hidden from
91//!   the documentation) to connect multiple GPIOs to the same output signal.
92//! - A GPIO input signal can be connected to any number of peripheral inputs.
93//! - A GPIO output can be driven by only one peripheral output.
94//!
95//! [`GPIO0`]: crate::peripherals::GPIO0
96//! [`Spi::with_mosi`]: crate::spi::master::Spi::with_mosi
97
98#[cfg(feature = "unstable")]
99use crate::gpio::{Input, Output};
100use crate::{
101    gpio::{
102        self,
103        AlternateFunction,
104        AnyPin,
105        Flex,
106        InputPin,
107        Level,
108        NoPin,
109        OutputPin,
110        Pin,
111        PinGuard,
112    },
113    peripherals::GPIO,
114    private::{self, Sealed},
115};
116
117/// The base of all peripheral signals.
118///
119/// This trait represents a signal in the GPIO matrix. Signals are converted or
120/// split from GPIO pins and can be connected to peripheral inputs and outputs.
121///
122/// All signals can be peripheral inputs, but not all output-like types should
123/// be allowed to be passed as inputs. This trait bridges this gap by defining
124/// the logic, but not declaring the signal to be an actual Input signal.
125pub trait PeripheralSignal<'d>: Sealed {
126    /// Connects the peripheral input to an input signal source.
127    #[doc(hidden)] // Considered unstable
128    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal);
129}
130
131/// A signal that can be connected to a peripheral input.
132///
133/// Peripheral drivers are encouraged to accept types that implement this and
134/// [`PeripheralOutput`] as arguments instead of pin types.
135#[allow(
136    private_bounds,
137    reason = "InputSignal is unstable, but the trait needs to be public"
138)]
139pub trait PeripheralInput<'d>: Into<InputSignal<'d>> + PeripheralSignal<'d> {}
140
141/// A signal that can be connected to a peripheral input and/or output.
142///
143/// Peripheral drivers are encouraged to accept types that implement this and
144/// [`PeripheralInput`] as arguments instead of pin types.
145#[allow(
146    private_bounds,
147    reason = "OutputSignal is unstable, but the trait needs to be public"
148)]
149pub trait PeripheralOutput<'d>: Into<OutputSignal<'d>> + PeripheralSignal<'d> {
150    /// Connects the peripheral output to an output signal target.
151    #[doc(hidden)] // Considered unstable
152    fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal);
153
154    /// Disconnects the peripheral output from an output signal target.
155    ///
156    /// This function clears the entry in the IO MUX that
157    /// associates this output pin with a previously connected
158    /// [signal](`gpio::OutputSignal`). Any other outputs connected to the
159    /// peripheral remain intact.
160    #[doc(hidden)] // Considered unstable
161    fn disconnect_from_peripheral_output(&self);
162}
163
164// Pins
165impl<'d, P> PeripheralSignal<'d> for P
166where
167    P: Pin + 'd,
168{
169    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
170        let pin = unsafe { AnyPin::steal(self.number()) };
171        InputSignal::new(pin).connect_input_to_peripheral(signal);
172    }
173}
174impl<'d, P> PeripheralInput<'d> for P where P: InputPin + 'd {}
175
176impl<'d, P> PeripheralOutput<'d> for P
177where
178    P: OutputPin + 'd,
179{
180    fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
181        let pin = unsafe { AnyPin::steal(self.number()) };
182        OutputSignal::new(pin).connect_peripheral_to_output(signal);
183    }
184    fn disconnect_from_peripheral_output(&self) {
185        let pin = unsafe { AnyPin::steal(self.number()) };
186        OutputSignal::new(pin).disconnect_from_peripheral_output();
187    }
188}
189
190// Pin drivers
191#[instability::unstable]
192impl<'d> PeripheralSignal<'d> for Flex<'d> {
193    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
194        self.pin.connect_input_to_peripheral(signal);
195    }
196}
197#[instability::unstable]
198impl<'d> PeripheralInput<'d> for Flex<'d> {}
199#[instability::unstable]
200impl<'d> PeripheralOutput<'d> for Flex<'d> {
201    fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
202        self.pin.connect_peripheral_to_output(signal);
203    }
204    fn disconnect_from_peripheral_output(&self) {
205        self.pin.disconnect_from_peripheral_output();
206    }
207}
208
209#[instability::unstable]
210impl<'d> PeripheralSignal<'d> for Input<'d> {
211    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
212        self.pin.connect_input_to_peripheral(signal);
213    }
214}
215#[instability::unstable]
216impl<'d> PeripheralInput<'d> for Input<'d> {}
217
218#[instability::unstable]
219impl<'d> PeripheralSignal<'d> for Output<'d> {
220    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
221        self.pin.connect_input_to_peripheral(signal);
222    }
223}
224#[instability::unstable]
225impl<'d> PeripheralOutput<'d> for Output<'d> {
226    fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
227        self.pin.connect_peripheral_to_output(signal);
228    }
229    fn disconnect_from_peripheral_output(&self) {
230        self.pin.disconnect_from_peripheral_output();
231    }
232}
233
234// Placeholders
235impl PeripheralSignal<'_> for NoPin {
236    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
237        // Arbitrary choice but we need to overwrite a previous signal input
238        // association.
239        Level::Low.connect_input_to_peripheral(signal);
240    }
241}
242impl PeripheralInput<'_> for NoPin {}
243impl PeripheralOutput<'_> for NoPin {
244    fn connect_peripheral_to_output(&self, _: gpio::OutputSignal) {
245        // A peripheral's outputs may be connected to any number of GPIOs.
246        // Connecting to, and disconnecting from a NoPin is therefore a
247        // no-op, as we are adding and removing nothing from that list of
248        // connections.
249    }
250    fn disconnect_from_peripheral_output(&self) {
251        // A peripheral's outputs may be connected to any number of GPIOs.
252        // Connecting to, and disconnecting from a NoPin is therefore a
253        // no-op, as we are adding and removing nothing from that list of
254        // connections.
255    }
256}
257
258impl PeripheralSignal<'_> for Level {
259    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
260        Signal::Level(*self).connect_to_peripheral_input(signal, false, true);
261    }
262}
263impl PeripheralInput<'_> for Level {}
264impl PeripheralOutput<'_> for Level {
265    fn connect_peripheral_to_output(&self, _: gpio::OutputSignal) {
266        // There is no such thing as a constant-high level peripheral output,
267        // the implementation just exists for convenience.
268    }
269    fn disconnect_from_peripheral_output(&self) {
270        // There is no such thing as a constant-high level peripheral output,
271        // the implementation just exists for convenience.
272    }
273}
274
275// Split signals
276impl<'d> PeripheralSignal<'d> for InputSignal<'d> {
277    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
278        // Since there can only be one input signal connected to a peripheral
279        // at a time, this function will disconnect any previously
280        // connected input signals.
281        self.pin.connect_to_peripheral_input(
282            signal,
283            self.is_input_inverted(),
284            self.is_gpio_matrix_forced(),
285        );
286    }
287}
288impl<'d> PeripheralInput<'d> for InputSignal<'d> {}
289
290impl<'d> PeripheralSignal<'d> for OutputSignal<'d> {
291    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
292        self.pin.connect_to_peripheral_input(
293            signal,
294            self.is_input_inverted(),
295            self.is_gpio_matrix_forced(),
296        );
297    }
298}
299impl<'d> PeripheralOutput<'d> for OutputSignal<'d> {
300    fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
301        self.pin.connect_peripheral_to_output(
302            signal,
303            self.is_output_inverted(),
304            self.is_gpio_matrix_forced(),
305            true,
306            false,
307        );
308    }
309    fn disconnect_from_peripheral_output(&self) {
310        self.pin.disconnect_from_peripheral_output();
311    }
312}
313
314impl gpio::InputSignal {
315    fn can_use_gpio_matrix(self) -> bool {
316        self as usize <= property!("gpio.input_signal_max")
317    }
318
319    /// Connects a peripheral input signal to a GPIO or a constant level.
320    ///
321    /// Note that connecting multiple GPIOs to a single peripheral input is not
322    /// possible and the previous connection will be replaced.
323    ///
324    /// Also note that a peripheral input must always be connected to something,
325    /// so if you want to disconnect it from GPIOs, you should connect it to a
326    /// constant level.
327    ///
328    /// This function allows connecting a peripheral input to either a
329    /// [`PeripheralInput`] or [`PeripheralOutput`] implementation.
330    #[inline]
331    #[instability::unstable]
332    pub fn connect_to<'a>(self, pin: &impl PeripheralSignal<'a>) {
333        pin.connect_input_to_peripheral(self);
334    }
335}
336
337impl gpio::OutputSignal {
338    fn can_use_gpio_matrix(self) -> bool {
339        self as usize <= property!("gpio.output_signal_max")
340    }
341
342    /// Connects a peripheral output signal to a GPIO.
343    ///
344    /// Note that connecting multiple output signals to a single GPIO is not
345    /// possible and the previous connection will be replaced.
346    ///
347    /// Also note that it is possible to connect a peripheral output signal to
348    /// multiple GPIOs, and old connections will not be cleared automatically.
349    #[inline]
350    #[instability::unstable]
351    pub fn connect_to<'d>(self, pin: &impl PeripheralOutput<'d>) {
352        pin.connect_peripheral_to_output(self);
353    }
354
355    /// Disconnects a peripheral output signal from a GPIO.
356    #[inline]
357    #[instability::unstable]
358    pub fn disconnect_from<'d>(self, pin: &impl PeripheralOutput<'d>) {
359        pin.disconnect_from_peripheral_output();
360    }
361}
362
363enum Signal<'d> {
364    Pin(AnyPin<'d>),
365    Level(Level),
366}
367impl Signal<'_> {
368    fn gpio_number(&self) -> Option<u8> {
369        match &self {
370            Signal::Pin(pin) => Some(pin.number()),
371            Signal::Level(_) => None,
372        }
373    }
374
375    unsafe fn clone_unchecked(&self) -> Self {
376        match self {
377            Signal::Pin(pin) => Signal::Pin(unsafe { pin.clone_unchecked() }),
378            Signal::Level(level) => Signal::Level(*level),
379        }
380    }
381
382    fn is_set_high(&self) -> bool {
383        match &self {
384            Signal::Pin(signal) => signal.is_set_high(),
385            Signal::Level(level) => *level == Level::High,
386        }
387    }
388
389    fn is_input_high(&self) -> bool {
390        match &self {
391            Signal::Pin(signal) => signal.is_input_high(),
392            Signal::Level(level) => *level == Level::High,
393        }
394    }
395
396    fn connect_with_guard(self, signal: crate::gpio::OutputSignal) -> PinGuard {
397        match self {
398            Signal::Pin(pin) => PinGuard::new(pin, signal),
399            Signal::Level(_) => PinGuard::new_unconnected(signal),
400        }
401    }
402
403    fn connect_to_peripheral_input(
404        &self,
405        signal: gpio::InputSignal,
406        is_inverted: bool,
407        force_gpio: bool,
408    ) {
409        let use_gpio_matrix = match self {
410            Signal::Pin(pin) => {
411                let af = if is_inverted || force_gpio {
412                    AlternateFunction::GPIO
413                } else {
414                    pin.input_signals(private::Internal)
415                        .iter()
416                        .find(|(_af, s)| *s == signal)
417                        .map(|(af, _)| *af)
418                        .unwrap_or(AlternateFunction::GPIO)
419                };
420                pin.disable_usb_pads();
421                pin.set_alternate_function(af);
422                af == AlternateFunction::GPIO
423            }
424            Signal::Level(_) => true,
425        };
426
427        let input = match self {
428            Signal::Pin(pin) => pin.number(),
429            Signal::Level(Level::Low) => property!("gpio.constant_0_input"),
430            Signal::Level(Level::High) => property!("gpio.constant_1_input"),
431        };
432
433        assert!(
434            signal.can_use_gpio_matrix() || !use_gpio_matrix,
435            "{:?} cannot be routed through the GPIO matrix",
436            signal
437        );
438        // No need for a critical section, this is a write and not a modify operation.
439        let offset = property!("gpio.func_in_sel_offset");
440        GPIO::regs()
441            .func_in_sel_cfg(signal as usize - offset)
442            .write(|w| unsafe {
443                w.sel().bit(use_gpio_matrix);
444                w.in_inv_sel().bit(is_inverted);
445                // Connect to GPIO or constant level
446                w.in_sel().bits(input)
447            });
448    }
449
450    fn connect_peripheral_to_output(
451        &self,
452        signal: gpio::OutputSignal,
453        is_inverted: bool,
454        force_gpio: bool,
455        peripheral_control_output_enable: bool,
456        invert_output_enable: bool,
457    ) {
458        let Signal::Pin(pin) = self else {
459            return;
460        };
461        let af = if is_inverted || force_gpio {
462            AlternateFunction::GPIO
463        } else {
464            pin.output_signals(private::Internal)
465                .iter()
466                .find(|(_af, s)| *s == signal)
467                .map(|(af, _)| *af)
468                .unwrap_or(AlternateFunction::GPIO)
469        };
470        pin.disable_usb_pads();
471        pin.set_alternate_function(af);
472
473        let use_gpio_matrix = af == AlternateFunction::GPIO;
474
475        assert!(
476            signal.can_use_gpio_matrix() || use_gpio_matrix,
477            "{:?} cannot be routed through the GPIO matrix",
478            signal
479        );
480
481        GPIO::regs()
482            .func_out_sel_cfg(pin.number() as usize)
483            .write(|w| unsafe {
484                if use_gpio_matrix {
485                    // Ignored if the signal is not routed through the GPIO matrix - alternate
486                    // function selects peripheral signal directly.
487                    w.out_sel().bits(signal as _);
488                    w.inv_sel().bit(is_inverted);
489                }
490                w.oen_sel().bit(!peripheral_control_output_enable);
491                w.oen_inv_sel().bit(invert_output_enable)
492            });
493    }
494
495    fn disconnect_from_peripheral_output(&self) {
496        let Some(number) = self.gpio_number() else {
497            return;
498        };
499        GPIO::regs()
500            .func_out_sel_cfg(number as usize)
501            .modify(|_, w| unsafe { w.out_sel().bits(gpio::OutputSignal::GPIO as _) });
502    }
503}
504
505bitflags::bitflags! {
506    #[derive(Clone, Copy)]
507    struct InputFlags: u8 {
508        const ForceGpioMatrix = 1 << 0;
509        const Frozen          = 1 << 1;
510        const InvertInput     = 1 << 2;
511    }
512}
513
514/// An input signal between a peripheral and a GPIO pin.
515///
516/// If the `InputSignal` was obtained from a pin driver such as
517/// [`Input`](crate::gpio::Input::split), the GPIO driver will be responsible
518/// for configuring the pin with the correct settings, peripheral drivers will
519/// not be able to modify the pin settings.
520///
521/// Multiple input signals can be connected to one pin.
522#[instability::unstable]
523pub struct InputSignal<'d> {
524    pin: Signal<'d>,
525    flags: InputFlags,
526}
527
528impl From<Level> for InputSignal<'_> {
529    fn from(level: Level) -> Self {
530        InputSignal::new_level(level)
531    }
532}
533
534impl From<NoPin> for InputSignal<'_> {
535    fn from(_pin: NoPin) -> Self {
536        InputSignal::new_level(Level::Low)
537    }
538}
539
540impl<'d, P> From<P> for InputSignal<'d>
541where
542    P: Pin + 'd,
543{
544    fn from(input: P) -> Self {
545        InputSignal::new(input.degrade())
546    }
547}
548
549impl<'d> From<Flex<'d>> for InputSignal<'d> {
550    fn from(pin: Flex<'d>) -> Self {
551        pin.peripheral_input()
552    }
553}
554
555#[instability::unstable]
556impl<'d> From<Input<'d>> for InputSignal<'d> {
557    fn from(pin: Input<'d>) -> Self {
558        pin.pin.into()
559    }
560}
561
562impl Sealed for InputSignal<'_> {}
563
564impl Clone for InputSignal<'_> {
565    fn clone(&self) -> Self {
566        Self {
567            pin: unsafe { self.pin.clone_unchecked() },
568            flags: self.flags,
569        }
570    }
571}
572
573impl<'d> InputSignal<'d> {
574    fn new_inner(inner: Signal<'d>) -> Self {
575        Self {
576            pin: inner,
577            flags: InputFlags::empty(),
578        }
579    }
580
581    pub(crate) fn new(pin: AnyPin<'d>) -> Self {
582        Self::new_inner(Signal::Pin(pin))
583    }
584
585    pub(crate) fn new_level(level: Level) -> Self {
586        Self::new_inner(Signal::Level(level))
587    }
588
589    /// Freezes the pin configuration.
590    ///
591    /// This will prevent peripheral drivers using this signal from modifying
592    /// the pin settings.
593    pub fn freeze(mut self) -> Self {
594        self.flags.insert(InputFlags::Frozen);
595        self
596    }
597
598    /// Unfreezes the pin configuration.
599    ///
600    /// This will enable peripheral drivers to modify the pin settings
601    /// again.
602    ///
603    /// # Safety
604    ///
605    /// This function is unsafe because it allows peripherals to modify the pin
606    /// configuration again. This can lead to undefined behavior if the pin
607    /// is being configured by multiple peripherals at the same time. It can
608    /// also lead to surprising behavior if the pin is passed to multiple
609    /// peripherals that expect conflicting settings.
610    pub unsafe fn unfreeze(&mut self) {
611        self.flags.remove(InputFlags::Frozen);
612    }
613
614    /// Returns the GPIO number of the underlying pin.
615    ///
616    /// Returns `None` if the signal is a constant level.
617    pub fn gpio_number(&self) -> Option<u8> {
618        self.pin.gpio_number()
619    }
620
621    /// Returns `true` if the input signal is high.
622    ///
623    /// Note that this does not take [`Self::with_input_inverter`] into account.
624    pub fn is_input_high(&self) -> bool {
625        self.pin.is_input_high()
626    }
627
628    /// Returns the current signal level.
629    ///
630    /// Note that this does not take [`Self::with_input_inverter`] into account.
631    pub fn level(&self) -> Level {
632        self.is_input_high().into()
633    }
634
635    /// Returns `true` if the input signal is configured to be inverted.
636    ///
637    /// Note that the hardware is not configured until the signal is actually
638    /// connected to a peripheral.
639    pub fn is_input_inverted(&self) -> bool {
640        self.flags.contains(InputFlags::InvertInput)
641    }
642
643    /// Consumes the signal and returns a new one that inverts the peripheral's
644    /// input signal.
645    pub fn with_input_inverter(mut self, invert: bool) -> Self {
646        self.flags.set(InputFlags::InvertInput, invert);
647        self
648    }
649
650    /// Consumes the signal and returns a new one that forces the GPIO matrix
651    /// to be used.
652    pub fn with_gpio_matrix_forced(mut self, force: bool) -> Self {
653        self.flags.set(InputFlags::ForceGpioMatrix, force);
654        self
655    }
656
657    /// Returns `true` if the input signal must be routed through the GPIO
658    /// matrix.
659    pub fn is_gpio_matrix_forced(&self) -> bool {
660        self.flags.contains(InputFlags::ForceGpioMatrix)
661    }
662
663    delegate::delegate! {
664        #[instability::unstable]
665        #[doc(hidden)]
666        to match &self.pin {
667            Signal::Pin(signal) => signal,
668            Signal::Level(_) => NoOp,
669        } {
670            pub fn input_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::InputSignal)];
671        }
672    }
673
674    delegate::delegate! {
675        #[instability::unstable]
676        #[doc(hidden)]
677        to match &self.pin {
678            Signal::Pin(_) if self.flags.contains(InputFlags::Frozen) => NoOp,
679            Signal::Pin(signal) => signal,
680            Signal::Level(_) => NoOp,
681        } {
682            pub fn apply_input_config(&self, _config: &gpio::InputConfig);
683            pub fn set_input_enable(&self, on: bool);
684        }
685    }
686}
687
688bitflags::bitflags! {
689    #[derive(Clone, Copy)]
690    struct OutputFlags: u8 {
691        const ForceGpioMatrix = 1 << 0;
692        const Frozen          = 1 << 1;
693        const InvertInput     = 1 << 2;
694        const InvertOutput    = 1 << 3;
695    }
696}
697
698/// An (input and) output signal between a peripheral and a GPIO pin.
699///
700/// If the `OutputSignal` was obtained from a pin driver such as
701/// [`Output`](crate::gpio::Output::split), the GPIO driver will be responsible
702/// for configuring the pin with the correct settings, peripheral drivers will
703/// not be able to modify the pin settings.
704///
705/// Note that connecting this to a peripheral input will enable the input stage
706/// of the GPIO pin.
707///
708/// Multiple pins can be connected to one output signal.
709#[instability::unstable]
710pub struct OutputSignal<'d> {
711    pin: Signal<'d>,
712    flags: OutputFlags,
713}
714
715impl Sealed for OutputSignal<'_> {}
716
717impl From<Level> for OutputSignal<'_> {
718    fn from(level: Level) -> Self {
719        OutputSignal::new_level(level)
720    }
721}
722
723impl From<NoPin> for OutputSignal<'_> {
724    fn from(_pin: NoPin) -> Self {
725        OutputSignal::new_level(Level::Low)
726    }
727}
728
729impl<'d, P> From<P> for OutputSignal<'d>
730where
731    P: OutputPin + 'd,
732{
733    fn from(output: P) -> Self {
734        OutputSignal::new(output.degrade())
735    }
736}
737
738impl<'d> From<Flex<'d>> for OutputSignal<'d> {
739    fn from(pin: Flex<'d>) -> Self {
740        pin.into_peripheral_output()
741    }
742}
743
744#[instability::unstable]
745impl<'d> From<Output<'d>> for OutputSignal<'d> {
746    fn from(pin: Output<'d>) -> Self {
747        pin.pin.into()
748    }
749}
750
751impl<'d> OutputSignal<'d> {
752    fn new_inner(inner: Signal<'d>) -> Self {
753        Self {
754            pin: inner,
755            flags: OutputFlags::empty(),
756        }
757    }
758
759    pub(crate) fn new(pin: AnyPin<'d>) -> Self {
760        Self::new_inner(Signal::Pin(pin))
761    }
762
763    pub(crate) fn new_level(level: Level) -> Self {
764        Self::new_inner(Signal::Level(level))
765    }
766
767    /// Freezes the pin configuration.
768    ///
769    /// This will prevent peripheral drivers using this signal from
770    /// modifying the pin settings.
771    pub fn freeze(mut self) -> Self {
772        self.flags.insert(OutputFlags::Frozen);
773        self
774    }
775
776    /// Unfreezes the pin configuration.
777    ///
778    /// This will enable peripheral drivers to modify the pin settings
779    /// again.
780    ///
781    /// # Safety
782    ///
783    /// This function is unsafe because it allows peripherals to modify the pin
784    /// configuration again. This can lead to undefined behavior if the pin
785    /// is being configured by multiple peripherals at the same time.
786    /// It can also lead to surprising behavior if the pin is passed to multiple
787    /// peripherals that expect conflicting settings.
788    pub unsafe fn unfreeze(&mut self) {
789        self.flags.remove(OutputFlags::Frozen);
790    }
791
792    /// Returns the GPIO number of the underlying pin.
793    ///
794    /// Returns `None` if the signal is a constant level.
795    pub fn gpio_number(&self) -> Option<u8> {
796        self.pin.gpio_number()
797    }
798
799    /// Returns `true` if the input signal is configured to be inverted.
800    ///
801    /// Note that the hardware is not configured until the signal is actually
802    /// connected to a peripheral.
803    pub fn is_input_inverted(&self) -> bool {
804        self.flags.contains(OutputFlags::InvertInput)
805    }
806
807    /// Returns `true` if the output signal is configured to be inverted.
808    ///
809    /// Note that the hardware is not configured until the signal is actually
810    /// connected to a peripheral.
811    pub fn is_output_inverted(&self) -> bool {
812        self.flags.contains(OutputFlags::InvertOutput)
813    }
814
815    /// Consumes the signal and returns a new one that inverts the peripheral's
816    /// output signal.
817    pub fn with_output_inverter(mut self, invert: bool) -> Self {
818        self.flags.set(OutputFlags::InvertOutput, invert);
819        self
820    }
821
822    /// Consumes the signal and returns a new one that inverts the peripheral's
823    /// input signal.
824    pub fn with_input_inverter(mut self, invert: bool) -> Self {
825        self.flags.set(OutputFlags::InvertInput, invert);
826        self
827    }
828
829    /// Consumes the signal and returns a new one that forces the GPIO matrix
830    /// to be used.
831    pub fn with_gpio_matrix_forced(mut self, force: bool) -> Self {
832        self.flags.set(OutputFlags::ForceGpioMatrix, force);
833        self
834    }
835
836    /// Returns `true` if the input signal must be routed through the GPIO
837    /// matrix.
838    pub fn is_gpio_matrix_forced(&self) -> bool {
839        self.flags.contains(OutputFlags::ForceGpioMatrix)
840    }
841
842    /// Returns `true` if the input signal is high.
843    ///
844    /// Note that this does not take [`Self::with_input_inverter`] into account.
845    pub fn is_input_high(&self) -> bool {
846        self.pin.is_input_high()
847    }
848
849    /// Returns `true` if the output signal is set high.
850    ///
851    /// Note that this does not take [`Self::with_output_inverter`] into
852    /// account.
853    pub fn is_set_high(&self) -> bool {
854        self.pin.is_set_high()
855    }
856
857    #[doc(hidden)]
858    #[instability::unstable]
859    pub(crate) fn connect_with_guard(self, signal: crate::gpio::OutputSignal) -> PinGuard {
860        signal.connect_to(&self);
861        self.pin.connect_with_guard(signal)
862    }
863
864    delegate::delegate! {
865        #[instability::unstable]
866        #[doc(hidden)]
867        to match &self.pin {
868            Signal::Pin(signal) => signal,
869            Signal::Level(_) => NoOp,
870        } {
871            pub fn input_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::InputSignal)];
872            pub fn output_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::OutputSignal)];
873        }
874    }
875
876    delegate::delegate! {
877        #[instability::unstable]
878        #[doc(hidden)]
879        to match &self.pin {
880            Signal::Pin(_) if self.flags.contains(OutputFlags::Frozen) => NoOp,
881            Signal::Pin(pin) => pin,
882            Signal::Level(_) => NoOp,
883        } {
884            pub fn apply_input_config(&self, _config: &gpio::InputConfig);
885            pub fn apply_output_config(&self, _config: &gpio::OutputConfig);
886            pub fn set_input_enable(&self, on: bool);
887            pub fn set_output_enable(&self, on: bool);
888            pub fn set_output_high(&self, on: bool);
889        }
890    }
891}
892
893struct NoOp;
894
895impl NoOp {
896    fn set_input_enable(&self, _on: bool) {}
897    fn set_output_enable(&self, _on: bool) {}
898    fn set_output_high(&self, _on: bool) {}
899    fn apply_input_config(&self, _config: &gpio::InputConfig) {}
900    fn apply_output_config(&self, _config: &gpio::OutputConfig) {}
901
902    fn input_signals(
903        &self,
904        _: private::Internal,
905    ) -> &'static [(AlternateFunction, gpio::InputSignal)] {
906        &[]
907    }
908
909    fn output_signals(
910        &self,
911        _: private::Internal,
912    ) -> &'static [(AlternateFunction, gpio::OutputSignal)] {
913        &[]
914    }
915}
916
917#[procmacros::doc_replace]
918/// ```rust,compile_fail
919/// // Regression test for <https://github.com/esp-rs/esp-hal/issues/3313>
920/// // This test case is expected to generate the following error:
921/// // error[E0277]: the trait bound `Output<'_>: PeripheralInput<'_>` is not satisfied
922/// //   --> src\gpio\interconnect.rs:977:5
923/// //    |
924/// // 31 |   function_expects_input(
925/// //    |   ---------------------- required by a bound introduced by this call
926/// // 32 | /     Output::new(peripherals.GPIO0,
927/// // 33 | |     Level::Low,
928/// // 34 | |     Default::default()),
929/// //    | |_______________________^ the trait `InputPin` is not implemented for `Output<'_>`
930/// // FIXME: due to <https://github.com/rust-lang/rust/issues/139924> this test may be ineffective.
931/// //        It can be manually verified by changing it to `no_run` for a `run-doc-tests` run.
932/// # {before_snippet}
933/// use esp_hal::gpio::{Output, Level, interconnect::PeripheralInput};
934///
935/// fn function_expects_input<'d>(_: impl PeripheralInput<'d>) {}
936///
937/// function_expects_input(
938///     Output::new(peripherals.GPIO0,
939///     Level::Low,
940///     Default::default()),
941/// );
942///
943/// # {after_snippet}
944/// ```
945fn _compile_tests() {}