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
//! > 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
//! 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
//! 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 that case, carefully
54
//! ensure that only a single driver configures the split pin, by selectively
55
//! [freezing](`InputSignal::freeze`) the signals.
56
#![cfg_attr(
57
    uart_driver_supported,
58
    doc = "\n\nFor example, if you want to route GPIO3 to both a Pulse Counter
59
 input and a [UART](crate::uart::Uart) RX line, you will need to make sure
60
 one of the signals is frozen, otherwise the driver that is configured later
61
 will overwrite the other driver's configuration. Configuring the signals on
62
 multiple cores is undefined behavior unless you ensure the configuration
63
 does not happen at the same time."
64
)]
65
//! ### Using pins and signals
66
//!
67
//! A GPIO pin can be configured either with a GPIO driver such as [`Input`], or
68
//! by a peripheral driver using a pin assignment method such as
69
#![cfg_attr(spi_master_driver_supported, doc = "[`Spi::with_mosi`].")]
70
#![cfg_attr(not(spi_master_driver_supported), doc = "`Spi::with_mosi`.")]
71
//! The peripheral drivers' preferences can be overridden by
72
//! passing a pin driver to the peripheral driver. When converting a driver to
73
//! signals, the underlying signals will be initially
74
//! [frozen](InputSignal::freeze) to support this use case.
75
//!
76
//! ## Inverting inputs and outputs
77
//!
78
//! The GPIO matrix allows for inverting the input and output signals. This can
79
//! be configured via [`InputSignal::with_input_inverter`] and
80
//! [`OutputSignal::with_input_inverter`]. The hardware is configured
81
//! accordingly when the signal is connected to a peripheral input or output.
82
//!
83
//! ## Connection rules
84
//!
85
//! Peripheral signals and GPIOs can be connected with the following
86
//! constraints:
87
//!
88
//! - A peripheral input signal must be driven by exactly one signal, which can be a GPIO input or a
89
//!   constant level.
90
//! - A peripheral output signal can be connected to any number of GPIOs. These GPIOs can be
91
//!   configured differently. The peripheral drivers will only support a single connection (that is,
92
//!   they disconnect previously configured signals on repeat calls to the same function), but you
93
//!   can use `esp_hal::gpio::OutputSignal::connect_to` (note that the type is currently hidden from
94
//!   the documentation) to connect multiple GPIOs to the same output signal.
95
//! - A GPIO input signal can be connected to any number of peripheral inputs.
96
//! - A GPIO output can be driven by only one peripheral output.
97
//!
98
//! [`GPIO0`]: crate::peripherals::GPIO0
99
#![cfg_attr(
100
    spi_master_driver_supported,
101
    doc = "[`Spi::with_mosi`]: crate::spi::master::Spi::with_mosi"
102
)]
103

            
104
use enumset::{EnumSet, EnumSetType};
105

            
106
#[cfg(feature = "unstable")]
107
use crate::gpio::{Input, Output};
108
use crate::{
109
    gpio::{self, AlternateFunction, AnyPin, Flex, Level, NoPin, OutputPin, Pin, PinGuard},
110
    peripherals::GPIO,
111
    private::{self, Sealed},
112
};
113

            
114
/// The base of all peripheral signals.
115
///
116
/// Represents a signal in the GPIO matrix. Signals are converted or
117
/// split from GPIO pins and can be connected to peripheral inputs and outputs.
118
///
119
/// All signals can be peripheral inputs, but not all output-like types should
120
/// be allowed to be passed as inputs. This trait bridges this gap by defining
121
/// the logic, but not declaring the signal to be an actual Input signal.
122
pub trait PeripheralSignal<'d>: Sealed {
123
    /// Connects the peripheral input to an input signal source.
124
    #[doc(hidden)] // Considered unstable
125
    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal);
126
}
127

            
128
/// A signal that can be connected to a peripheral input.
129
///
130
/// Peripheral drivers are encouraged to accept types that implement this and
131
/// [`PeripheralOutput`] as arguments instead of pin types.
132
///
133
/// To allow writing functions that are generic over GPIOs, this trait is
134
/// blanket-implemented for [`InputPin`][gpio::InputPin] types.
135
#[allow(
136
    private_bounds,
137
    reason = "InputSignal is unstable, but the trait needs to be public"
138
)]
139
pub trait PeripheralInput<'d>: Into<InputSignal<'d>> + PeripheralSignal<'d> {}
140

            
141
/// A signal that can be connected to a peripheral input or output.
142
///
143
/// Peripheral drivers are encouraged to accept types that implement this and
144
/// [`PeripheralInput`] as arguments instead of pin types.
145
///
146
/// To allow writing functions that are generic over GPIOs, this trait is
147
/// blanket-implemented for [`OutputPin`] types.
148
#[allow(
149
    private_bounds,
150
    reason = "OutputSignal is unstable, but the trait needs to be public"
151
)]
152
pub trait PeripheralOutput<'d>: Into<OutputSignal<'d>> + PeripheralSignal<'d> {
153
    /// Connects the peripheral output to an output signal target.
154
    #[doc(hidden)] // Considered unstable
155
    fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal);
156

            
157
    /// Disconnects the peripheral output from an output signal target.
158
    ///
159
    /// Clears the entry in the IO MUX that associates this output pin with a
160
    /// previously connected [signal](`gpio::OutputSignal`). Any other outputs
161
    /// connected to the peripheral remain intact.
162
    #[doc(hidden)] // Considered unstable
163
    fn disconnect_from_peripheral_output(&self);
164
}
165

            
166
// Pin drivers
167
#[instability::unstable]
168
impl<'d> PeripheralSignal<'d> for Flex<'d> {
169
    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
170
4
        self.pin.connect_input_to_peripheral(signal);
171
    }
172
}
173
#[instability::unstable]
174
impl<'d> PeripheralInput<'d> for Flex<'d> {}
175
#[instability::unstable]
176
impl<'d> PeripheralOutput<'d> for Flex<'d> {
177
    fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
178
        self.pin.connect_peripheral_to_output(signal);
179
    }
180
    fn disconnect_from_peripheral_output(&self) {
181
        self.pin.disconnect_from_peripheral_output();
182
    }
183
}
184

            
185
#[instability::unstable]
186
impl<'d> PeripheralSignal<'d> for Input<'d> {
187
    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
188
        self.pin.connect_input_to_peripheral(signal);
189
    }
190
}
191
#[instability::unstable]
192
impl<'d> PeripheralInput<'d> for Input<'d> {}
193

            
194
#[instability::unstable]
195
impl<'d> PeripheralSignal<'d> for Output<'d> {
196
    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
197
        self.pin.connect_input_to_peripheral(signal);
198
    }
199
}
200
#[instability::unstable]
201
impl<'d> PeripheralOutput<'d> for Output<'d> {
202
    fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
203
        self.pin.connect_peripheral_to_output(signal);
204
    }
205
    fn disconnect_from_peripheral_output(&self) {
206
        self.pin.disconnect_from_peripheral_output();
207
    }
208
}
209

            
210
// Placeholders
211
impl PeripheralSignal<'_> for NoPin {
212
280
    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
213
        // Arbitrary choice but we need to overwrite a previous signal input
214
        // association.
215
        Level::Low.connect_input_to_peripheral(signal);
216
280
    }
217
}
218
impl PeripheralInput<'_> for NoPin {}
219
impl PeripheralOutput<'_> for NoPin {
220
    fn connect_peripheral_to_output(&self, _: gpio::OutputSignal) {
221
        // A peripheral's outputs may be connected to any number of GPIOs.
222
        // Connecting to, and disconnecting from a NoPin is therefore a
223
        // no-op, as we are adding and removing nothing from that list of
224
        // connections.
225
    }
226
    fn disconnect_from_peripheral_output(&self) {
227
        // A peripheral's outputs may be connected to any number of GPIOs.
228
        // Connecting to, and disconnecting from a NoPin is therefore a
229
        // no-op, as we are adding and removing nothing from that list of
230
        // connections.
231
    }
232
}
233

            
234
impl PeripheralSignal<'_> for Level {
235
3
    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
236
3
        Signal::Level(*self).connect_to_peripheral_input(signal, false, true);
237
3
    }
238
}
239
impl PeripheralInput<'_> for Level {}
240
impl PeripheralOutput<'_> for Level {
241
    fn connect_peripheral_to_output(&self, _: gpio::OutputSignal) {
242
        // There is no such thing as a constant-high level peripheral output,
243
        // the implementation just exists for convenience.
244
    }
245
    fn disconnect_from_peripheral_output(&self) {
246
        // There is no such thing as a constant-high level peripheral output,
247
        // the implementation just exists for convenience.
248
    }
249
}
250

            
251
// Split signals
252
impl<'d> PeripheralSignal<'d> for InputSignal<'d> {
253
93
    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
254
        // Since there can only be one input signal connected to a peripheral
255
        // at a time, this function will disconnect any previously
256
        // connected input signals.
257
97
        self.pin.connect_to_peripheral_input(
258
            signal,
259
            self.is_input_inverted(),
260
            self.is_gpio_matrix_forced(),
261
        );
262
    }
263
}
264
impl<'d> PeripheralInput<'d> for InputSignal<'d> {}
265

            
266
impl<'d> PeripheralSignal<'d> for OutputSignal<'d> {
267
    fn connect_input_to_peripheral(&self, signal: gpio::InputSignal) {
268
60
        self.pin.connect_to_peripheral_input(
269
            signal,
270
            self.is_input_inverted(),
271
            self.is_gpio_matrix_forced(),
272
        );
273
    }
274
}
275
impl<'d> PeripheralOutput<'d> for OutputSignal<'d> {
276
331
    fn connect_peripheral_to_output(&self, signal: gpio::OutputSignal) {
277
331
        self.pin.connect_peripheral_to_output(
278
            signal,
279
            self.is_output_inverted(),
280
            self.is_gpio_matrix_forced(),
281
            true,
282
            false,
283
        );
284
331
    }
285
    fn disconnect_from_peripheral_output(&self) {
286
        self.pin.disconnect_from_peripheral_output();
287
    }
288
}
289

            
290
impl gpio::InputSignal {
291
    fn can_use_gpio_matrix(self) -> bool {
292
322
        self as usize <= property!("gpio.input_signal_max")
293
    }
294

            
295
    /// Connects a peripheral input signal to a GPIO or a constant level.
296
    ///
297
    /// Connecting multiple GPIOs to a single peripheral input is not possible,
298
    /// and the previous connection is replaced.
299
    ///
300
    /// A peripheral input must always be connected to something. To disconnect it
301
    /// from GPIOs, connect it to a constant level.
302
    ///
303
    /// Connects a peripheral input to either a [`PeripheralInput`] or
304
    /// [`PeripheralOutput`] implementation
305
    #[inline]
306
    #[instability::unstable]
307
    pub fn connect_to<'a>(self, pin: &impl PeripheralSignal<'a>) {
308
79
        pin.connect_input_to_peripheral(self);
309
    }
310
}
311

            
312
impl gpio::OutputSignal {
313
    fn can_use_gpio_matrix(self) -> bool {
314
156
        self as usize <= property!("gpio.output_signal_max")
315
    }
316

            
317
    /// Connects a peripheral output signal to a GPIO.
318
    ///
319
    /// Connecting multiple output signals to a single GPIO is not possible, and
320
    /// the previous connection is replaced.
321
    ///
322
    /// A peripheral output signal can be connected to multiple GPIOs. Old
323
    /// connections are not cleared automatically.
324
    #[inline]
325
    #[instability::unstable]
326
    pub fn connect_to<'d>(self, pin: &impl PeripheralOutput<'d>) {
327
313
        pin.connect_peripheral_to_output(self);
328
    }
329

            
330
    /// Disconnects a peripheral output signal from a GPIO.
331
    #[inline]
332
    #[instability::unstable]
333
    pub fn disconnect_from<'d>(self, pin: &impl PeripheralOutput<'d>) {
334
        pin.disconnect_from_peripheral_output();
335
    }
336
}
337

            
338
enum Signal<'d> {
339
    Pin(AnyPin<'d>),
340
    Level(Level),
341
}
342
impl Signal<'_> {
343
    fn gpio_number(&self) -> Option<u8> {
344
        match &self {
345
            Signal::Pin(pin) => Some(pin.number()),
346
            Signal::Level(_) => None,
347
        }
348
    }
349

            
350
    unsafe fn clone_unchecked(&self) -> Self {
351
        match self {
352
            Signal::Pin(pin) => Signal::Pin(unsafe { pin.clone_unchecked() }),
353
            Signal::Level(level) => Signal::Level(*level),
354
        }
355
    }
356

            
357
    fn is_set_high(&self) -> bool {
358
        match &self {
359
            Signal::Pin(signal) => signal.is_set_high(),
360
            Signal::Level(level) => *level == Level::High,
361
        }
362
    }
363

            
364
    fn is_input_high(&self) -> bool {
365
        match &self {
366
            Signal::Pin(signal) => signal.is_input_high(),
367
            Signal::Level(level) => *level == Level::High,
368
        }
369
    }
370

            
371
157
    fn connect_to_peripheral_input(
372
        &self,
373
        signal: gpio::InputSignal,
374
        is_inverted: bool,
375
        force_gpio: bool,
376
    ) {
377
157
        let use_gpio_matrix = match self {
378
            Signal::Pin(pin) => {
379
118
                let af = if is_inverted || force_gpio {
380
                    AlternateFunction::GPIO
381
                } else {
382
                    pin.input_signals(private::Internal)
383
                        .iter()
384
                        .find(|(_af, s)| *s == signal)
385
4
                        .map(|(af, _)| *af)
386
                        .unwrap_or(AlternateFunction::GPIO)
387
                };
388
                pin.disable_usb_pads();
389
                pin.set_alternate_function(af);
390
                af == AlternateFunction::GPIO
391
            }
392
            Signal::Level(_) => true,
393
        };
394

            
395
322
        if !signal.can_use_gpio_matrix() {
396
            assert!(
397
                !use_gpio_matrix,
398
                "{:?} cannot be routed through the GPIO matrix",
399
                signal
400
            );
401
            // At this point we have set up the AF. The signal does not have a `func_in_sel_cfg`
402
            // register, and we must not try to write to it.
403
            return;
404
        }
405

            
406
39
        let input = match self {
407
            Signal::Pin(pin) => pin.number(),
408
            Signal::Level(Level::Low) => property!("gpio.constant_0_input"),
409
            Signal::Level(Level::High) => property!("gpio.constant_1_input"),
410
        };
411

            
412
        // No need for a critical section, this is a write and not a modify operation.
413
        let offset = property!("gpio.func_in_sel_offset");
414
        GPIO::regs()
415
            .func_in_sel_cfg(signal as usize - offset)
416
            .write(|w| unsafe {
417
                w.sel().bit(use_gpio_matrix);
418
                w.in_inv_sel().bit(is_inverted);
419
                // Connect to GPIO or constant level
420
                w.in_sel().bits(input)
421
            });
422
157
    }
423

            
424
    fn connect_peripheral_to_output(
425
        &self,
426
        signal: gpio::OutputSignal,
427
        is_inverted: bool,
428
        force_gpio: bool,
429
        peripheral_control_output_enable: bool,
430
        invert_output_enable: bool,
431
    ) {
432
331
        let Signal::Pin(pin) = self else {
433
            return;
434
        };
435
156
        let af = if is_inverted || force_gpio {
436
            AlternateFunction::GPIO
437
        } else {
438
            pin.output_signals(private::Internal)
439
                .iter()
440
                .find(|(_af, s)| *s == signal)
441
4
                .map(|(af, _)| *af)
442
                .unwrap_or(AlternateFunction::GPIO)
443
        };
444
        pin.disable_usb_pads();
445
        pin.set_alternate_function(af);
446

            
447
        let use_gpio_matrix = af == AlternateFunction::GPIO;
448

            
449
        assert!(
450
156
            signal.can_use_gpio_matrix() || !use_gpio_matrix,
451
            "{:?} cannot be routed through the GPIO matrix",
452
            signal
453
        );
454

            
455
        GPIO::regs()
456
            .func_out_sel_cfg(pin.number() as usize)
457
            .write(|w| unsafe {
458
156
                if use_gpio_matrix {
459
                    // Ignored if the signal is not routed through the GPIO matrix - alternate
460
                    // function selects peripheral signal directly.
461
                    w.out_sel().bits(signal as _);
462
                    w.inv_sel().bit(is_inverted);
463
                }
464
                w.oen_sel().bit(!peripheral_control_output_enable);
465
                w.oen_inv_sel().bit(invert_output_enable)
466
            });
467
    }
468

            
469
    fn disconnect_from_peripheral_output(&self) {
470
        let Some(number) = self.gpio_number() else {
471
            return;
472
        };
473
        GPIO::regs()
474
            .func_out_sel_cfg(number as usize)
475
            .modify(|_, w| unsafe { w.out_sel().bits(gpio::OutputSignal::GPIO as _) });
476
    }
477
}
478

            
479
fn set_flag<T: EnumSetType>(flags: &mut EnumSet<T>, flag: T, value: bool) {
480
    if value {
481
        flags.insert(flag);
482
    } else {
483
        flags.remove(flag);
484
    }
485
}
486

            
487
#[derive(Debug, EnumSetType)]
488
enum InputFlags {
489
    ForceGpioMatrix,
490
    Frozen,
491
    InvertInput,
492
}
493

            
494
/// An input signal between a peripheral and a GPIO pin.
495
///
496
/// If the `InputSignal` was obtained from a pin driver such as
497
/// [`Input`](crate::gpio::Input::split), the GPIO driver will be responsible
498
/// for configuring the pin with the correct settings, peripheral drivers will
499
/// not be able to modify the pin settings.
500
///
501
/// Multiple input signals can be connected to one pin.
502
#[instability::unstable]
503
pub struct InputSignal<'d> {
504
    pin: Signal<'d>,
505
    flags: EnumSet<InputFlags>,
506
}
507

            
508
impl From<Level> for InputSignal<'_> {
509
    fn from(level: Level) -> Self {
510
        InputSignal::new_level(level)
511
    }
512
}
513

            
514
impl From<NoPin> for InputSignal<'_> {
515
    fn from(_pin: NoPin) -> Self {
516
        InputSignal::new_level(Level::Low)
517
    }
518
}
519

            
520
impl<'d, P> From<P> for InputSignal<'d>
521
where
522
    P: Pin + 'd,
523
{
524
    fn from(input: P) -> Self {
525
        // Safety: the pin singleton proves that no other signal drives this pad.
526
34
        unsafe { input.degrade().into_input_signal() }
527
    }
528
}
529

            
530
impl<'d> From<Flex<'d>> for InputSignal<'d> {
531
    fn from(pin: Flex<'d>) -> Self {
532
        pin.peripheral_input()
533
    }
534
}
535

            
536
#[instability::unstable]
537
impl<'d> From<Input<'d>> for InputSignal<'d> {
538
    fn from(pin: Input<'d>) -> Self {
539
        pin.pin.into()
540
    }
541
}
542

            
543
impl Sealed for InputSignal<'_> {}
544

            
545
impl Clone for InputSignal<'_> {
546
    fn clone(&self) -> Self {
547
        Self {
548
            pin: unsafe { self.pin.clone_unchecked() },
549
            flags: self.flags,
550
        }
551
    }
552
}
553

            
554
impl<'d> InputSignal<'d> {
555
    fn new_inner(inner: Signal<'d>) -> Self {
556
        Self {
557
            pin: inner,
558
            flags: EnumSet::empty(),
559
        }
560
    }
561

            
562
    pub(crate) fn new(pin: AnyPin<'d>) -> Self {
563
        Self::new_inner(Signal::Pin(pin))
564
    }
565

            
566
    pub(crate) fn new_level(level: Level) -> Self {
567
        Self::new_inner(Signal::Level(level))
568
    }
569

            
570
    /// Freezes the pin configuration.
571
    ///
572
    /// This will prevent peripheral drivers using this signal from modifying
573
    /// the pin settings.
574
    pub fn freeze(mut self) -> Self {
575
        self.flags.insert(InputFlags::Frozen);
576
        self
577
    }
578

            
579
    /// Unfreezes the pin configuration.
580
    ///
581
    /// This will enable peripheral drivers to modify the pin settings
582
    /// again.
583
    ///
584
    /// # Safety
585
    ///
586
    /// Lets peripherals modify the pin configuration again. This can lead to
587
    /// undefined behavior if the pin is being configured by multiple peripherals
588
    /// at the same time. It can also lead to surprising behavior if the pin is
589
    /// passed to multiple peripherals that expect conflicting settings.
590
    pub unsafe fn unfreeze(&mut self) {
591
        self.flags.remove(InputFlags::Frozen);
592
    }
593

            
594
    /// Returns the GPIO number of the underlying pin.
595
    ///
596
    /// Returns `None` if the signal is a constant level.
597
    pub fn gpio_number(&self) -> Option<u8> {
598
        self.pin.gpio_number()
599
    }
600

            
601
    /// Returns whether the input signal is high.
602
    ///
603
    /// Does not take [`Self::with_input_inverter`] into account.
604
    pub fn is_input_high(&self) -> bool {
605
        self.pin.is_input_high()
606
    }
607

            
608
    /// Returns the current signal level.
609
    ///
610
    /// Does not take [`Self::with_input_inverter`] into account.
611
    pub fn level(&self) -> Level {
612
        self.is_input_high().into()
613
    }
614

            
615
    /// Returns whether the input signal is configured to be inverted.
616
    ///
617
    /// The hardware is not configured until the signal is actually connected to
618
    /// a peripheral.
619
    pub fn is_input_inverted(&self) -> bool {
620
        self.flags.contains(InputFlags::InvertInput)
621
    }
622

            
623
    /// Consumes the signal and returns a new one that inverts the peripheral's
624
    /// input signal.
625
    pub fn with_input_inverter(mut self, invert: bool) -> Self {
626
        set_flag(&mut self.flags, InputFlags::InvertInput, invert);
627
        self
628
    }
629

            
630
    /// Consumes the signal and returns a new one that forces the GPIO matrix
631
    /// to be used.
632
    pub fn with_gpio_matrix_forced(mut self, force: bool) -> Self {
633
        set_flag(&mut self.flags, InputFlags::ForceGpioMatrix, force);
634
        self
635
    }
636

            
637
    /// Returns whether the input signal must be routed through the GPIO
638
    /// matrix.
639
    pub fn is_gpio_matrix_forced(&self) -> bool {
640
        self.flags.contains(InputFlags::ForceGpioMatrix)
641
    }
642

            
643
    delegate::delegate! {
644
        #[instability::unstable]
645
        #[doc(hidden)]
646
        to match &self.pin {
647
            Signal::Pin(signal) => signal,
648
            Signal::Level(_) => NoOp,
649
        } {
650
            pub fn input_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::InputSignal)];
651
        }
652
    }
653

            
654
    delegate::delegate! {
655
        #[instability::unstable]
656
        #[doc(hidden)]
657
42
        to match &self.pin {
658
            Signal::Pin(_) if self.flags.contains(InputFlags::Frozen) => NoOp,
659
            Signal::Pin(signal) => signal,
660
            Signal::Level(_) => NoOp,
661
        } {
662
            pub fn apply_input_config(&self, _config: &gpio::InputConfig);
663
            pub fn set_input_enable(&self, on: bool);
664
        }
665
    }
666
}
667

            
668
#[derive(Debug, EnumSetType)]
669
enum OutputFlags {
670
    ForceGpioMatrix,
671
    Frozen,
672
    InvertInput,
673
    InvertOutput,
674
}
675

            
676
/// An (input and) output signal between a peripheral and a GPIO pin.
677
///
678
/// If the `OutputSignal` was obtained from a pin driver such as
679
/// [`Output`](crate::gpio::Output::split), the GPIO driver will be responsible
680
/// for configuring the pin with the correct settings, peripheral drivers will
681
/// not be able to modify the pin settings.
682
///
683
/// Connecting this to a peripheral input enables the input stage of the GPIO
684
/// pin.
685
///
686
/// Multiple pins can be connected to one output signal.
687
#[instability::unstable]
688
pub struct OutputSignal<'d> {
689
    pin: Signal<'d>,
690
    flags: EnumSet<OutputFlags>,
691
}
692

            
693
impl Sealed for OutputSignal<'_> {}
694

            
695
impl From<Level> for OutputSignal<'_> {
696
    fn from(level: Level) -> Self {
697
        OutputSignal::new_level(level)
698
    }
699
}
700

            
701
impl From<NoPin> for OutputSignal<'_> {
702
    fn from(_pin: NoPin) -> Self {
703
        OutputSignal::new_level(Level::Low)
704
    }
705
}
706

            
707
impl<'d, P> From<P> for OutputSignal<'d>
708
where
709
    P: OutputPin + 'd,
710
{
711
    fn from(output: P) -> Self {
712
        output.degrade().into_output_signal()
713
    }
714
}
715

            
716
impl<'d> From<Flex<'d>> for OutputSignal<'d> {
717
17
    fn from(pin: Flex<'d>) -> Self {
718
        pin.into_peripheral_output()
719
17
    }
720
}
721

            
722
#[instability::unstable]
723
impl<'d> From<Output<'d>> for OutputSignal<'d> {
724
    fn from(pin: Output<'d>) -> Self {
725
        pin.pin.into()
726
    }
727
}
728

            
729
impl<'d> OutputSignal<'d> {
730
    fn new_inner(inner: Signal<'d>) -> Self {
731
8
        Self {
732
            pin: inner,
733
            flags: EnumSet::empty(),
734
        }
735
    }
736

            
737
    pub(crate) fn new(pin: AnyPin<'d>) -> Self {
738
        Self::new_inner(Signal::Pin(pin))
739
    }
740

            
741
    pub(crate) fn new_level(level: Level) -> Self {
742
        Self::new_inner(Signal::Level(level))
743
    }
744

            
745
    /// Freezes the pin configuration.
746
    ///
747
    /// This will prevent peripheral drivers using this signal from
748
    /// modifying the pin settings.
749
    pub fn freeze(mut self) -> Self {
750
        self.flags.insert(OutputFlags::Frozen);
751
        self
752
    }
753

            
754
    /// Unfreezes the pin configuration.
755
    ///
756
    /// This will enable peripheral drivers to modify the pin settings
757
    /// again.
758
    ///
759
    /// # Safety
760
    ///
761
    /// Lets peripherals modify the pin configuration again. This can lead to
762
    /// undefined behavior if the pin is being configured by multiple peripherals
763
    /// at the same time. It can also lead to surprising behavior if the pin is
764
    /// passed to multiple peripherals that expect conflicting settings.
765
    pub unsafe fn unfreeze(&mut self) {
766
        self.flags.remove(OutputFlags::Frozen);
767
    }
768

            
769
    /// Returns the GPIO number of the underlying pin.
770
    ///
771
    /// Returns `None` if the signal is a constant level.
772
    pub fn gpio_number(&self) -> Option<u8> {
773
        self.pin.gpio_number()
774
    }
775

            
776
    /// Returns whether the input signal is configured to be inverted.
777
    ///
778
    /// The hardware is not configured until the signal is actually connected to
779
    /// a peripheral.
780
    pub fn is_input_inverted(&self) -> bool {
781
        self.flags.contains(OutputFlags::InvertInput)
782
    }
783

            
784
    /// Returns whether the output signal is configured to be inverted.
785
    ///
786
    /// The hardware is not configured until the signal is actually connected to
787
    /// a peripheral.
788
    pub fn is_output_inverted(&self) -> bool {
789
        self.flags.contains(OutputFlags::InvertOutput)
790
    }
791

            
792
    /// Consumes the signal and returns a new one that inverts the peripheral's
793
    /// output signal.
794
    pub fn with_output_inverter(mut self, invert: bool) -> Self {
795
        set_flag(&mut self.flags, OutputFlags::InvertOutput, invert);
796
        self
797
    }
798

            
799
    /// Consumes the signal and returns a new one that inverts the peripheral's
800
    /// input signal.
801
    pub fn with_input_inverter(mut self, invert: bool) -> Self {
802
        set_flag(&mut self.flags, OutputFlags::InvertInput, invert);
803
        self
804
    }
805

            
806
    /// Consumes the signal and returns a new one that forces the GPIO matrix
807
    /// to be used.
808
    pub fn with_gpio_matrix_forced(mut self, force: bool) -> Self {
809
        set_flag(&mut self.flags, OutputFlags::ForceGpioMatrix, force);
810
        self
811
    }
812

            
813
    /// Returns whether the output signal must be routed through the GPIO
814
    /// matrix.
815
    pub fn is_gpio_matrix_forced(&self) -> bool {
816
        self.flags.contains(OutputFlags::ForceGpioMatrix)
817
    }
818

            
819
    /// Returns whether the input signal is high.
820
    ///
821
    /// Does not take [`Self::with_input_inverter`] into account.
822
    pub fn is_input_high(&self) -> bool {
823
        self.pin.is_input_high()
824
    }
825

            
826
    /// Returns whether the output signal is set high.
827
    ///
828
    /// Does not take [`Self::with_output_inverter`] into account.
829
    pub fn is_set_high(&self) -> bool {
830
        self.pin.is_set_high()
831
    }
832

            
833
    #[doc(hidden)]
834
    #[instability::unstable]
835
    #[cfg_attr(
836
        not(any(
837
            i2c_master_driver_supported,
838
            spi_master_driver_supported,
839
            uart_driver_supported
840
        )),
841
        expect(unused)
842
    )]
843
247
    pub(crate) fn connect_with_guard(self, signal: crate::gpio::OutputSignal) -> PinGuard {
844
        signal.connect_to(&self);
845
247
        match self.pin {
846
            Signal::Pin(pin) => PinGuard::new(pin),
847
            Signal::Level(_) => PinGuard::new_unconnected(),
848
        }
849
247
    }
850

            
851
    delegate::delegate! {
852
        #[instability::unstable]
853
        #[doc(hidden)]
854
        to match &self.pin {
855
            Signal::Pin(signal) => signal,
856
            Signal::Level(_) => NoOp,
857
        } {
858
            pub fn input_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::InputSignal)];
859
            pub fn output_signals(&self, _internal: private::Internal) -> &'static [(AlternateFunction, gpio::OutputSignal)];
860
        }
861
    }
862

            
863
    delegate::delegate! {
864
        #[instability::unstable]
865
        #[doc(hidden)]
866
148
        to match &self.pin {
867
30
            Signal::Pin(_) if self.flags.contains(OutputFlags::Frozen) => NoOp,
868
            Signal::Pin(pin) => pin,
869
            Signal::Level(_) => NoOp,
870
        } {
871
            pub fn apply_input_config(&self, _config: &gpio::InputConfig);
872
            pub fn apply_output_config(&self, _config: &gpio::OutputConfig);
873
            pub fn set_input_enable(&self, on: bool);
874
            pub fn set_output_enable(&self, on: bool);
875
            pub fn set_output_high(&self, on: bool);
876
        }
877
    }
878
}
879

            
880
struct NoOp;
881

            
882
impl NoOp {
883
    fn set_input_enable(&self, _on: bool) {}
884
    fn set_output_enable(&self, _on: bool) {}
885
    fn set_output_high(&self, _on: bool) {}
886
    fn apply_input_config(&self, _config: &gpio::InputConfig) {}
887
    fn apply_output_config(&self, _config: &gpio::OutputConfig) {}
888

            
889
    fn input_signals(
890
        &self,
891
        _: private::Internal,
892
    ) -> &'static [(AlternateFunction, gpio::InputSignal)] {
893
        &[]
894
    }
895

            
896
    fn output_signals(
897
        &self,
898
        _: private::Internal,
899
    ) -> &'static [(AlternateFunction, gpio::OutputSignal)] {
900
        &[]
901
    }
902
}
903

            
904
#[procmacros::doc_replace]
905
/// ```rust,compile_fail
906
/// // Regression test for <https://github.com/esp-rs/esp-hal/issues/3313>
907
/// // This test case is expected to generate the following error:
908
/// // error[E0277]: the trait bound `Output<'_>: PeripheralInput<'_>` is not satisfied
909
/// //   --> src\gpio\interconnect.rs:977:5
910
/// //    |
911
/// // 31 |   function_expects_input(
912
/// //    |   ---------------------- required by a bound introduced by this call
913
/// // 32 | /     Output::new(peripherals.GPIO0,
914
/// // 33 | |     Level::Low,
915
/// // 34 | |     Default::default()),
916
/// //    | |_______________________^ the trait `InputPin` is not implemented for `Output<'_>`
917
/// // FIXME: due to <https://github.com/rust-lang/rust/issues/139924> this test may be ineffective.
918
/// //        It can be manually verified by changing it to `no_run` for a `run-doc-tests` run.
919
/// # {before_snippet}
920
/// use esp_hal::gpio::{Output, Level, interconnect::PeripheralInput};
921
///
922
/// fn function_expects_input<'d>(_: impl PeripheralInput<'d>) {}
923
///
924
/// function_expects_input(
925
///     Output::new(peripherals.GPIO0,
926
///     Level::Low,
927
///     Default::default()),
928
/// );
929
///
930
/// # {after_snippet}
931
/// ```
932
fn _compile_tests() {}