From 0c867404183e105dc14c645644b936000c4abb24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 4 Nov 2024 12:29:28 +0100 Subject: [PATCH] Peripheral interconnect redo, vol 2 (`split()`) (#2418) * Replace peripheral connection conversions with split * Constrain Flex conversions --- esp-hal/CHANGELOG.md | 4 + esp-hal/MIGRATING-0.21.md | 21 +- esp-hal/src/gpio/interconnect.rs | 19 +- esp-hal/src/gpio/mod.rs | 283 ++++++++++++------ esp-hal/src/uart.rs | 8 +- examples/src/bin/embassy_twai.rs | 8 +- examples/src/bin/pcnt_encoder.rs | 12 +- examples/src/bin/twai.rs | 8 +- hil-test/tests/i2s.rs | 7 +- hil-test/tests/lcd_cam_i8080.rs | 32 +- hil-test/tests/parl_io_tx.rs | 17 +- hil-test/tests/parl_io_tx_async.rs | 17 +- hil-test/tests/qspi.rs | 25 +- hil-test/tests/spi_full_duplex.rs | 2 +- hil-test/tests/spi_half_duplex_write.rs | 2 +- hil-test/tests/spi_half_duplex_write_psram.rs | 2 +- hil-test/tests/spi_slave.rs | 89 +++--- hil-test/tests/twai.rs | 6 +- hil-test/tests/uart.rs | 9 +- 19 files changed, 354 insertions(+), 217 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index e01115be0..f4ada3c31 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -26,6 +26,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `DmaDescriptor` is now `Send` (#2456) - `into_async` and `into_blocking` functions for most peripherals (#2430) - API mode type parameter (currently always `Blocking`) to `master::Spi` and `slave::Spi` (#2430) +- `gpio::{GpioPin, AnyPin, Flex, Output, OutputOpenDrain}::split()` to obtain peripheral interconnect signals. (#2418) +- `gpio::Input::{split(), into_peripheral_output()}` when used with output pins. (#2418) +- `gpio::Output::peripheral_input()` (#2418) ### Changed @@ -42,6 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - SPI interrupt listening is now only available in Blocking mode. The `set_interrupt_handler` is available via `InterruptConfigurable` (#2442) - Allow users to create DMA `Preparation`s (#2455) - The `rmt::asynch::RxChannelAsync` and `rmt::asynch::TxChannelAsync` traits have been moved to `rmt` (#2430) +- Calling `AnyPin::output_signals` on an input-only pin (ESP32 GPIO 34-39) will now result in a panic. (#2418) ### Fixed diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index 70bc8386e..46708dfa2 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -194,7 +194,8 @@ You can now listen/unlisten multiple interrupt bits at once: -uart0.listen_at_cmd(); -uart0.listen_rx_fifo_full(); +uart0.listen(UartInterrupt::AtCmd | UartConterrupt::RxFifoFull); -```˛ +``` + ## Circular DMA transfer's `available` returns `Result` now In case of any error you should drop the transfer and restart it. @@ -211,3 +212,21 @@ In case of any error you should drop the transfer and restart it. + }, + }; ``` + +## Removed `peripheral_input` and `into_peripheral_output` from GPIO pin types + +Creating peripheral interconnect signals now consume the GPIO pin used for the connection. + +The previous signal function have been replaced by `split`. This change affects the following APIs: + +- `GpioPin` +- `AnyPin` + +```diff +-let input_signal = gpioN.peripheral_input(); +-let output_signal = gpioN.into_peripheral_output(); ++let (input_signal, output_signal) = gpioN.split(); +``` + +`into_peripheral_output`, `split` (for output pins only) and `peripheral_input` have been added to +the GPIO drivers (`Input`, `Output`, `OutputOpenDrain` and `Flex`) instead. diff --git a/esp-hal/src/gpio/interconnect.rs b/esp-hal/src/gpio/interconnect.rs index 126b66394..4f95a927c 100644 --- a/esp-hal/src/gpio/interconnect.rs +++ b/esp-hal/src/gpio/interconnect.rs @@ -54,9 +54,6 @@ impl PeripheralOutput for OutputConnection {} /// A configurable input signal between a peripheral and a GPIO pin. /// -/// Obtained by calling [`super::GpioPin::peripheral_input()`], -/// [`super::Flex::peripheral_input()`] or [`super::Input::peripheral_input()`]. -/// /// Multiple input signals can be connected to one pin. pub struct InputSignal { pin: AnyPin, @@ -188,10 +185,6 @@ impl InputSignal { /// A configurable output signal between a peripheral and a GPIO pin. /// -/// Obtained by calling [`super::GpioPin::into_peripheral_output()`], -/// [`super::Flex::into_peripheral_output()`] or -/// [`super::Output::into_peripheral_output()`]. -/// /// Multiple pins can be connected to one output signal. pub struct OutputSignal { pin: AnyPin, @@ -441,9 +434,9 @@ where P: InputPin, { fn from(input: P) -> Self { - Self(InputConnectionInner::Input( - input.degrade().peripheral_input(), - )) + Self(InputConnectionInner::Input(InputSignal::new( + input.degrade(), + ))) } } @@ -534,9 +527,9 @@ where P: OutputPin, { fn from(input: P) -> Self { - Self(OutputConnectionInner::Output( - input.degrade().into_peripheral_output(), - )) + Self(OutputConnectionInner::Output(OutputSignal::new( + input.degrade(), + ))) } } diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index 02eff2d7d..a73117293 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -723,13 +723,15 @@ where Self } - /// Returns a peripheral [input][interconnect::InputSignal] connected to - /// this pin. + /// Split the pin into an input and output signal. /// - /// The input signal can be passed to peripherals in place of an input pin. - #[inline] - pub fn peripheral_input(&self) -> interconnect::InputSignal { - interconnect::InputSignal::new(self.degrade_pin(private::Internal)) + /// Peripheral signals allow connecting peripherals together without using + /// external hardware. + pub fn split(self) -> (interconnect::InputSignal, interconnect::OutputSignal) { + ( + interconnect::InputSignal::new(self.degrade_pin(private::Internal)), + interconnect::OutputSignal::new(self.degrade_pin(private::Internal)), + ) } } @@ -777,21 +779,6 @@ where impl private::Sealed for GpioPin {} -impl GpioPin -where - Self: OutputPin, -{ - /// Turns the pin object into a peripheral - /// [output][interconnect::OutputSignal]. - /// - /// The output signal can be passed to peripherals in place of an output - /// pin. - #[inline] - pub fn into_peripheral_output(self) -> interconnect::OutputSignal { - interconnect::OutputSignal::new(self.degrade_pin(private::Internal)) - } -} - /// General Purpose Input/Output driver pub struct Io { _io_mux: IO_MUX, @@ -1151,20 +1138,41 @@ where /// Create GPIO output driver for a [GpioPin] with the provided level #[inline] pub fn new_typed(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { - let pin = Flex::new_typed(pin); - - Self::new_inner(pin, initial_output) - } - - fn new_inner(mut pin: Flex<'d, P>, initial_output: Level) -> Self { - pin.pin - .set_output_high(initial_output.into(), private::Internal); + let mut pin = Flex::new_typed(pin); + pin.set_level(initial_output); pin.set_as_output(); Self { pin } } + /// Split the pin into an input and output signal. + /// + /// Peripheral signals allow connecting peripherals together without using + /// external hardware. + pub fn split(self) -> (interconnect::InputSignal, interconnect::OutputSignal) { + self.pin.split() + } + + /// Returns a peripheral [input][interconnect::InputSignal] connected to + /// this pin. + /// + /// The input signal can be passed to peripherals in place of an input pin. + #[inline] + pub fn peripheral_input(&self) -> interconnect::InputSignal { + self.pin.peripheral_input() + } + + /// Turns the pin object into a peripheral + /// [output][interconnect::OutputSignal]. + /// + /// The output signal can be passed to peripherals in place of an output + /// pin. + #[inline] + pub fn into_peripheral_output(self) -> interconnect::OutputSignal { + self.pin.into_peripheral_output() + } + /// Set the output as high. #[inline] pub fn set_high(&mut self) { @@ -1212,16 +1220,6 @@ where pub fn set_drive_strength(&mut self, strength: DriveStrength) { self.pin.set_drive_strength(strength); } - - /// Turns the pin object into a peripheral - /// [output][interconnect::OutputSignal]. - /// - /// The output signal can be passed to peripherals in place of an output - /// pin. - #[inline] - pub fn into_peripheral_output(self) -> interconnect::OutputSignal { - self.pin.into_peripheral_output() - } } /// GPIO input driver. @@ -1262,6 +1260,15 @@ where Self { pin } } + /// Returns a peripheral [input][interconnect::InputSignal] connected to + /// this pin. + /// + /// The input signal can be passed to peripherals in place of an input pin. + #[inline] + pub fn peripheral_input(&self) -> interconnect::InputSignal { + self.pin.peripheral_input() + } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { @@ -1311,14 +1318,28 @@ where pub fn wakeup_enable(&mut self, enable: bool, event: WakeEvent) { self.pin.wakeup_enable(enable, event); } +} - /// Returns a peripheral [input][interconnect::InputSignal] connected to - /// this pin. +impl

Input<'_, P> +where + P: InputPin + OutputPin, +{ + /// Split the pin into an input and output signal. /// - /// The input signal can be passed to peripherals in place of an input pin. + /// Peripheral signals allow connecting peripherals together without using + /// external hardware. + pub fn split(self) -> (interconnect::InputSignal, interconnect::OutputSignal) { + self.pin.split() + } + + /// Turns the pin object into a peripheral + /// [output][interconnect::OutputSignal]. + /// + /// The output signal can be passed to peripherals in place of an output + /// pin. #[inline] - pub fn peripheral_input(&self) -> interconnect::InputSignal { - self.pin.peripheral_input() + pub fn into_peripheral_output(self) -> interconnect::OutputSignal { + self.pin.into_peripheral_output() } } @@ -1365,6 +1386,33 @@ where Self { pin } } + /// Split the pin into an input and output signal. + /// + /// Peripheral signals allow connecting peripherals together without using + /// external hardware. + pub fn split(self) -> (interconnect::InputSignal, interconnect::OutputSignal) { + self.pin.split() + } + + /// Returns a peripheral [input][interconnect::InputSignal] connected to + /// this pin. + /// + /// The input signal can be passed to peripherals in place of an input pin. + #[inline] + pub fn peripheral_input(&self) -> interconnect::InputSignal { + self.pin.peripheral_input() + } + + /// Turns the pin object into a peripheral + /// [output][interconnect::OutputSignal]. + /// + /// The output signal can be passed to peripherals in place of an output + /// pin. + #[inline] + pub fn into_peripheral_output(self) -> interconnect::OutputSignal { + self.pin.into_peripheral_output() + } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { @@ -1441,16 +1489,6 @@ where pub fn set_drive_strength(&mut self, strength: DriveStrength) { self.pin.set_drive_strength(strength); } - - /// Turns the pin object into a peripheral - /// [output][interconnect::OutputSignal]. - /// - /// The output signal can be passed to peripherals in place of an output - /// pin. - #[inline] - pub fn into_peripheral_output(self) -> interconnect::OutputSignal { - self.pin.into_peripheral_output() - } } /// Flexible pin driver. @@ -1487,6 +1525,15 @@ where crate::into_ref!(pin); Self { pin } } + + /// Returns a peripheral [input][interconnect::InputSignal] connected to + /// this pin. + /// + /// The input signal can be passed to peripherals in place of an input pin. + #[inline] + pub fn peripheral_input(&self) -> interconnect::InputSignal { + self.pin.degrade_pin(private::Internal).split().0 + } } impl

Flex<'_, P> @@ -1577,15 +1624,6 @@ where pub fn wakeup_enable(&mut self, enable: bool, event: WakeEvent) { self.listen_with_options(event.into(), false, false, enable); } - - /// Returns a peripheral [input][interconnect::InputSignal] connected to - /// this pin. - /// - /// The input signal can be passed to peripherals in place of an input pin. - #[inline] - pub fn peripheral_input(&self) -> interconnect::InputSignal { - interconnect::InputSignal::new(self.pin.degrade_pin(private::Internal)) - } } impl

Flex<'_, P> @@ -1646,6 +1684,20 @@ where self.pin.set_drive_strength(strength, private::Internal); } + /// Set the GPIO to open-drain mode. + pub fn set_as_open_drain(&mut self, pull: Pull) { + self.pin.set_to_open_drain_output(private::Internal); + self.pin.pull_direction(pull, private::Internal); + } + + /// Split the pin into an input and output signal. + /// + /// Peripheral signals allow connecting peripherals together without using + /// external hardware. + pub fn split(self) -> (interconnect::InputSignal, interconnect::OutputSignal) { + self.pin.degrade_pin(private::Internal).split() + } + /// Turns the pin object into a peripheral /// [output][interconnect::OutputSignal]. /// @@ -1653,18 +1705,7 @@ where /// pin. #[inline] pub fn into_peripheral_output(self) -> interconnect::OutputSignal { - interconnect::OutputSignal::new(self.pin.degrade_pin(private::Internal)) - } -} - -impl

Flex<'_, P> -where - P: InputPin + OutputPin, -{ - /// Set the GPIO to open-drain mode. - pub fn set_as_open_drain(&mut self, pull: Pull) { - self.pin.set_to_open_drain_output(private::Internal); - self.pin.pull_direction(pull, private::Internal); + self.split().1 } } @@ -1674,24 +1715,13 @@ pub(crate) mod internal { impl private::Sealed for AnyPin {} impl AnyPin { - /// Returns a peripheral [input][interconnect::InputSignal] connected to - /// this pin. + /// Split the pin into an input and output signal. /// - /// The input signal can be passed to peripherals in place of an input - /// pin. + /// Peripheral signals allow connecting peripherals together without + /// using external hardware. #[inline] - pub fn peripheral_input(&self) -> interconnect::InputSignal { - handle_gpio_input!(&self.0, target, { target.peripheral_input() }) - } - - /// Turns the pin object into a peripheral - /// [output][interconnect::OutputSignal]. - /// - /// The output signal can be passed to peripherals in place of an output - /// pin. - #[inline] - pub fn into_peripheral_output(self) -> interconnect::OutputSignal { - handle_gpio_output!(self.0, target, { target.into_peripheral_output() }) + pub fn split(self) -> (interconnect::InputSignal, interconnect::OutputSignal) { + handle_gpio_input!(self.0, target, { target.split() }) } } @@ -1717,7 +1747,7 @@ pub(crate) mod internal { } fn output_signals(&self, _: private::Internal) -> &[(AlternateFunction, OutputSignal)] { - handle_gpio_input!(&self.0, target, { + handle_gpio_output!(&self.0, target, { Pin::output_signals(target, private::Internal) }) } @@ -1736,7 +1766,74 @@ pub(crate) mod internal { } impl InputPin for AnyPin {} - impl OutputPin for AnyPin {} + + // Need to forward these one by one because not all pins support all functions. + impl OutputPin for AnyPin { + fn init_output( + &mut self, + alternate: AlternateFunction, + open_drain: bool, + _: private::Internal, + ) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::init_output(target, alternate, open_drain, private::Internal) + }) + } + + fn set_to_open_drain_output(&mut self, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::set_to_open_drain_output(target, private::Internal) + }) + } + + fn set_to_push_pull_output(&mut self, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::set_to_push_pull_output(target, private::Internal) + }) + } + + fn set_output_high(&mut self, high: bool, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::set_output_high(target, high, private::Internal) + }) + } + + fn set_drive_strength(&mut self, strength: DriveStrength, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::set_drive_strength(target, strength, private::Internal) + }) + } + + fn enable_open_drain(&mut self, on: bool, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::enable_open_drain(target, on, private::Internal) + }) + } + + fn enable_output_in_sleep_mode(&mut self, on: bool, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::enable_output_in_sleep_mode(target, on, private::Internal) + }) + } + + fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::internal_pull_up_in_sleep_mode(target, on, private::Internal) + }) + } + + fn internal_pull_down_in_sleep_mode(&mut self, on: bool, _: private::Internal) { + handle_gpio_output!(&mut self.0, target, { + OutputPin::internal_pull_down_in_sleep_mode(target, on, private::Internal) + }) + } + + fn is_set_high(&self, _: private::Internal) -> bool { + handle_gpio_output!(&self.0, target, { + OutputPin::is_set_high(target, private::Internal) + }) + } + } #[cfg(any(xtensa, esp32c2, esp32c3, esp32c6))] impl RtcPin for AnyPin { diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index 6a371e95b..a67c4b0e6 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -98,12 +98,12 @@ //! //! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! -//! let rx = io.pins.gpio2.peripheral_input().inverted(); -//! let tx = io.pins.gpio1.into_peripheral_output().inverted(); +//! let (rx, _) = io.pins.gpio2.split(); +//! let (_, tx) = io.pins.gpio1.split(); //! let mut uart1 = Uart::new( //! peripherals.UART1, -//! rx, -//! tx, +//! rx.inverted(), +//! tx.inverted(), //! ).unwrap(); //! # } //! ``` diff --git a/examples/src/bin/embassy_twai.rs b/examples/src/bin/embassy_twai.rs index b6140cd7c..36b94aa42 100644 --- a/examples/src/bin/embassy_twai.rs +++ b/examples/src/bin/embassy_twai.rs @@ -94,11 +94,11 @@ async fn main(spawner: Spawner) { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let tx_pin = io.pins.gpio2; - // let rx_pin = io.pins.gpio0; // Uncomment if you want to use an external transceiver. - // Without an external transceiver, we only need a single line between the two MCUs. - let rx_pin = tx_pin.peripheral_input(); // Comment this line if you want to use an external transceiver. + let (rx_pin, tx_pin) = io.pins.gpio2.split(); + // Use these if you want to use an external transceiver: + // let tx_pin = io.pins.gpio2; + // let rx_pin = io.pins.gpio0; // The speed of the bus. const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K; diff --git a/examples/src/bin/pcnt_encoder.rs b/examples/src/bin/pcnt_encoder.rs index 8f2344dc0..bf1b13941 100644 --- a/examples/src/bin/pcnt_encoder.rs +++ b/examples/src/bin/pcnt_encoder.rs @@ -49,18 +49,22 @@ fn main() -> ! { println!("setup channel 0"); let ch0 = &u0.channel0; + let pin_a = Input::new(io.pins.gpio4, Pull::Up); let pin_b = Input::new(io.pins.gpio5, Pull::Up); - ch0.set_ctrl_signal(pin_a.peripheral_input()); - ch0.set_edge_signal(pin_b.peripheral_input()); + let (input_a, _) = pin_a.split(); + let (input_b, _) = pin_b.split(); + + ch0.set_ctrl_signal(input_a.clone()); + ch0.set_edge_signal(input_b.clone()); ch0.set_ctrl_mode(channel::CtrlMode::Reverse, channel::CtrlMode::Keep); ch0.set_input_mode(channel::EdgeMode::Increment, channel::EdgeMode::Decrement); println!("setup channel 1"); let ch1 = &u0.channel1; - ch1.set_ctrl_signal(pin_b.peripheral_input()); - ch1.set_edge_signal(pin_a.peripheral_input()); + ch1.set_ctrl_signal(input_b); + ch1.set_edge_signal(input_a); ch1.set_ctrl_mode(channel::CtrlMode::Reverse, channel::CtrlMode::Keep); ch1.set_input_mode(channel::EdgeMode::Decrement, channel::EdgeMode::Increment); diff --git a/examples/src/bin/twai.rs b/examples/src/bin/twai.rs index 672ab25c5..fa0bcf9ee 100644 --- a/examples/src/bin/twai.rs +++ b/examples/src/bin/twai.rs @@ -42,11 +42,11 @@ fn main() -> ! { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let tx_pin = io.pins.gpio2; - // let rx_pin = io.pins.gpio0; // Uncomment if you want to use an external transceiver. - // Without an external transceiver, we only need a single line between the two MCUs. - let rx_pin = tx_pin.peripheral_input(); // Comment this line if you want to use an external transceiver. + let (rx_pin, tx_pin) = io.pins.gpio2.split(); + // Use these if you want to use an external transceiver: + // let tx_pin = io.pins.gpio2; + // let rx_pin = io.pins.gpio0; // The speed of the bus. const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K; diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs index b3d3a733a..0156c26b8 100644 --- a/hil-test/tests/i2s.rs +++ b/hil-test/tests/i2s.rs @@ -151,7 +151,7 @@ mod tests { let (_, dout) = hil_test::common_test_pins!(ctx.io); - let din = dout.peripheral_input(); + let (din, dout) = dout.split(); let i2s_tx = i2s .i2s_tx @@ -205,7 +205,7 @@ mod tests { let (_, dout) = hil_test::common_test_pins!(ctx.io); - let din = dout.peripheral_input(); + let (din, dout) = dout.split(); let mut i2s_tx = i2s .i2s_tx @@ -347,7 +347,8 @@ mod tests { ); let (_, dout) = hil_test::common_test_pins!(ctx.io); - let din = dout.peripheral_input(); + + let (din, dout) = dout.split(); let mut i2s_rx = i2s .i2s_rx diff --git a/hil-test/tests/lcd_cam_i8080.rs b/hil-test/tests/lcd_cam_i8080.rs index 2ac4b856b..1d4555bfa 100644 --- a/hil-test/tests/lcd_cam_i8080.rs +++ b/hil-test/tests/lcd_cam_i8080.rs @@ -102,20 +102,14 @@ mod tests { // issue with configuring pins as outputs after inputs have been sorted // out. See https://github.com/esp-rs/esp-hal/pull/2173#issue-2529323702 - let cs_signal = ctx.io.pins.gpio8; - let unit0_signal = ctx.io.pins.gpio11; - let unit1_signal = ctx.io.pins.gpio12; - let unit2_signal = ctx.io.pins.gpio16; - let unit3_signal = ctx.io.pins.gpio17; + let (unit_ctrl, cs_signal) = ctx.io.pins.gpio8.split(); + let (unit0_input, unit0_signal) = ctx.io.pins.gpio11.split(); + let (unit1_input, unit1_signal) = ctx.io.pins.gpio12.split(); + let (unit2_input, unit2_signal) = ctx.io.pins.gpio16.split(); + let (unit3_input, unit3_signal) = ctx.io.pins.gpio17.split(); let pcnt = ctx.pcnt; - let unit_ctrl = cs_signal.peripheral_input(); - let unit0_input = unit0_signal.peripheral_input(); - let unit1_input = unit1_signal.peripheral_input(); - let unit2_input = unit2_signal.peripheral_input(); - let unit3_input = unit3_signal.peripheral_input(); - pcnt.unit0 .channel0 .set_ctrl_mode(CtrlMode::Keep, CtrlMode::Disable); @@ -219,20 +213,14 @@ mod tests { // issue with configuring pins as outputs after inputs have been sorted // out. See https://github.com/esp-rs/esp-hal/pull/2173#issue-2529323702 - let cs_signal = ctx.io.pins.gpio8; - let unit0_signal = ctx.io.pins.gpio11; - let unit1_signal = ctx.io.pins.gpio12; - let unit2_signal = ctx.io.pins.gpio16; - let unit3_signal = ctx.io.pins.gpio17; + let (unit_ctrl, cs_signal) = ctx.io.pins.gpio8.split(); + let (unit0_input, unit0_signal) = ctx.io.pins.gpio11.split(); + let (unit1_input, unit1_signal) = ctx.io.pins.gpio12.split(); + let (unit2_input, unit2_signal) = ctx.io.pins.gpio16.split(); + let (unit3_input, unit3_signal) = ctx.io.pins.gpio17.split(); let pcnt = ctx.pcnt; - let unit_ctrl = cs_signal.peripheral_input(); - let unit0_input = unit0_signal.peripheral_input(); - let unit1_input = unit1_signal.peripheral_input(); - let unit2_input = unit2_signal.peripheral_input(); - let unit3_input = unit3_signal.peripheral_input(); - pcnt.unit0 .channel0 .set_ctrl_mode(CtrlMode::Keep, CtrlMode::Disable); diff --git a/hil-test/tests/parl_io_tx.rs b/hil-test/tests/parl_io_tx.rs index 3bec7b56c..f2b2cceb5 100644 --- a/hil-test/tests/parl_io_tx.rs +++ b/hil-test/tests/parl_io_tx.rs @@ -8,7 +8,11 @@ use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits}; use esp_hal::{ dma::{ChannelCreator, Dma, DmaPriority}, - gpio::{interconnect::InputSignal, AnyPin, Io, NoPin}, + gpio::{ + interconnect::{InputSignal, OutputSignal}, + Io, + NoPin, + }, parl_io::{ BitPackOrder, ClkOutPin, @@ -30,8 +34,8 @@ use hil_test as _; struct Context { parl_io: PARL_IO, dma_channel: ChannelCreator<0>, - clock: AnyPin, - valid: AnyPin, + clock: OutputSignal, + valid: OutputSignal, clock_loopback: InputSignal, valid_loopback: InputSignal, pcnt_unit: Unit<'static, 0>, @@ -50,10 +54,9 @@ mod tests { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let (clock, _) = hil_test::common_test_pins!(io); - let valid = io.pins.gpio0.degrade(); - let clock_loopback = clock.peripheral_input(); - let valid_loopback = valid.peripheral_input(); - let clock = clock.degrade(); + let valid = hil_test::unconnected_pin!(io); + let (clock_loopback, clock) = clock.split(); + let (valid_loopback, valid) = valid.split(); let pcnt = Pcnt::new(peripherals.PCNT); let pcnt_unit = pcnt.unit0; let dma = Dma::new(peripherals.DMA); diff --git a/hil-test/tests/parl_io_tx_async.rs b/hil-test/tests/parl_io_tx_async.rs index 2557672c4..2c4522f02 100644 --- a/hil-test/tests/parl_io_tx_async.rs +++ b/hil-test/tests/parl_io_tx_async.rs @@ -10,7 +10,11 @@ use esp_hal::parl_io::{TxPinConfigWithValidPin, TxSixteenBits}; use esp_hal::{ dma::{ChannelCreator, Dma, DmaPriority}, - gpio::{interconnect::InputSignal, AnyPin, Io, NoPin}, + gpio::{ + interconnect::{InputSignal, OutputSignal}, + Io, + NoPin, + }, parl_io::{ BitPackOrder, ClkOutPin, @@ -32,8 +36,8 @@ use hil_test as _; struct Context { parl_io: PARL_IO, dma_channel: ChannelCreator<0>, - clock: AnyPin, - valid: AnyPin, + clock: OutputSignal, + valid: OutputSignal, clock_loopback: InputSignal, valid_loopback: InputSignal, pcnt_unit: Unit<'static, 0>, @@ -52,10 +56,9 @@ mod tests { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let (clock, _) = hil_test::common_test_pins!(io); - let valid = io.pins.gpio0.degrade(); - let clock_loopback = clock.peripheral_input(); - let valid_loopback = valid.peripheral_input(); - let clock = clock.degrade(); + let valid = hil_test::unconnected_pin!(io); + let (clock_loopback, clock) = clock.split(); + let (valid_loopback, valid) = valid.split(); let pcnt = Pcnt::new(peripherals.PCNT); let pcnt_unit = pcnt.unit0; let dma = Dma::new(peripherals.DMA); diff --git a/hil-test/tests/qspi.rs b/hil-test/tests/qspi.rs index 641098f1a..9322a7b05 100644 --- a/hil-test/tests/qspi.rs +++ b/hil-test/tests/qspi.rs @@ -335,7 +335,9 @@ mod tests { let unit0 = pcnt.unit0; let unit1 = pcnt.unit1; - unit0.channel0.set_edge_signal(mosi.peripheral_input()); + let (mosi_loopback, mosi) = mosi.split(); + + unit0.channel0.set_edge_signal(mosi_loopback); unit0 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); @@ -359,12 +361,15 @@ mod tests { let unit0 = pcnt.unit0; let unit1 = pcnt.unit1; - unit0.channel0.set_edge_signal(mosi.peripheral_input()); + let (mosi_loopback, mosi) = mosi.split(); + let (gpio_loopback, gpio) = gpio.split(); + + unit0.channel0.set_edge_signal(mosi_loopback); unit0 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - unit1.channel0.set_edge_signal(gpio.peripheral_input()); + unit1.channel0.set_edge_signal(gpio_loopback); unit1 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); @@ -389,12 +394,15 @@ mod tests { let unit0 = pcnt.unit0; let unit1 = pcnt.unit1; - unit0.channel0.set_edge_signal(mosi.peripheral_input()); + let (mosi_loopback, mosi) = mosi.split(); + let (gpio_loopback, gpio) = gpio.split(); + + unit0.channel0.set_edge_signal(mosi_loopback); unit0 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - unit1.channel0.set_edge_signal(gpio.peripheral_input()); + unit1.channel0.set_edge_signal(gpio_loopback); unit1 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); @@ -419,12 +427,15 @@ mod tests { let unit0 = pcnt.unit0; let unit1 = pcnt.unit1; - unit0.channel0.set_edge_signal(mosi.peripheral_input()); + let (mosi_loopback, mosi) = mosi.split(); + let (gpio_loopback, gpio) = gpio.split(); + + unit0.channel0.set_edge_signal(mosi_loopback); unit0 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - unit1.channel0.set_edge_signal(gpio.peripheral_input()); + unit1.channel0.set_edge_signal(gpio_loopback); unit1 .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs index 326501e23..2d465a25b 100644 --- a/hil-test/tests/spi_full_duplex.rs +++ b/hil-test/tests/spi_full_duplex.rs @@ -73,7 +73,7 @@ mod tests { } #[cfg(pcnt)] - let mosi_loopback_pcnt = mosi.peripheral_input(); + let (mosi_loopback_pcnt, mosi) = mosi.split(); // Need to set miso first so that mosi can overwrite the // output connection (because we are using the same pin to loop back) let spi = Spi::new(peripherals.SPI2, 10000.kHz(), SpiMode::Mode0) diff --git a/hil-test/tests/spi_half_duplex_write.rs b/hil-test/tests/spi_half_duplex_write.rs index a44dda260..f06a80f3e 100644 --- a/hil-test/tests/spi_half_duplex_write.rs +++ b/hil-test/tests/spi_half_duplex_write.rs @@ -50,7 +50,7 @@ mod tests { } } - let mosi_loopback = mosi.peripheral_input(); + let (mosi_loopback, mosi) = mosi.split(); let spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) .with_sck(sclk) diff --git a/hil-test/tests/spi_half_duplex_write_psram.rs b/hil-test/tests/spi_half_duplex_write_psram.rs index eea6b6254..f40f81dc2 100644 --- a/hil-test/tests/spi_half_duplex_write_psram.rs +++ b/hil-test/tests/spi_half_duplex_write_psram.rs @@ -62,7 +62,7 @@ mod tests { let dma_channel = dma.channel0; - let mosi_loopback = mosi.peripheral_input(); + let (mosi_loopback, mosi) = mosi.split(); let spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) .with_sck(sclk) diff --git a/hil-test/tests/spi_slave.rs b/hil-test/tests/spi_slave.rs index 76aac7818..4d60f3b79 100644 --- a/hil-test/tests/spi_slave.rs +++ b/hil-test/tests/spi_slave.rs @@ -11,7 +11,10 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, - gpio::{interconnect::InputSignal, Io, Level, Output}, + gpio::{ + interconnect::{InputSignal, OutputSignal}, + Io, + }, spi::{slave::Spi, SpiMode}, Blocking, }; @@ -32,19 +35,32 @@ struct Context { } struct BitbangSpi { - sclk: Output<'static>, - mosi: Output<'static>, + sclk: OutputSignal, + mosi: OutputSignal, miso: InputSignal, - cs: Output<'static>, + cs: OutputSignal, } impl BitbangSpi { fn new( - sclk: Output<'static>, - mosi: Output<'static>, - miso: InputSignal, - cs: Output<'static>, + mut sclk: OutputSignal, + mut mosi: OutputSignal, + mut miso: InputSignal, + mut cs: OutputSignal, ) -> Self { + // TODO remove this (#2273) + // FIXME: devise a public API for signals + miso.enable_input(true, unsafe { esp_hal::Internal::conjure() }); + + mosi.set_output_high(false, unsafe { esp_hal::Internal::conjure() }); + mosi.enable_output(true, unsafe { esp_hal::Internal::conjure() }); + + cs.set_output_high(true, unsafe { esp_hal::Internal::conjure() }); + cs.enable_output(true, unsafe { esp_hal::Internal::conjure() }); + + sclk.set_output_high(false, unsafe { esp_hal::Internal::conjure() }); + sclk.enable_output(true, unsafe { esp_hal::Internal::conjure() }); + Self { sclk, mosi, @@ -54,22 +70,29 @@ impl BitbangSpi { } fn assert_cs(&mut self) { - self.sclk.set_level(Level::Low); - self.cs.set_level(Level::Low); + self.sclk + .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); + self.cs + .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); } fn deassert_cs(&mut self) { - self.sclk.set_level(Level::Low); - self.cs.set_level(Level::High); + self.sclk + .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); + self.cs + .set_output_high(true, unsafe { esp_hal::Internal::conjure() }); } // Mode 1, so sampled on the rising edge and set on the falling edge. fn shift_bit(&mut self, bit: bool) -> bool { - self.mosi.set_level(Level::from(bit)); - self.sclk.set_level(Level::High); + self.mosi + .set_output_high(bit, unsafe { esp_hal::Internal::conjure() }); + self.sclk + .set_output_high(true, unsafe { esp_hal::Internal::conjure() }); let miso = self.miso.get_level().into(); - self.sclk.set_level(Level::Low); + self.sclk + .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); miso } @@ -105,7 +128,7 @@ mod tests { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let (mosi_pin, miso_pin) = hil_test::i2c_pins!(io); - let (sclk_pin, sclk_gpio) = hil_test::common_test_pins!(io); + let (sclk_pin, _) = hil_test::common_test_pins!(io); let cs_pin = hil_test::unconnected_pin!(io); let dma = Dma::new(peripherals.DMA); @@ -118,30 +141,22 @@ mod tests { } } - let cs = cs_pin.peripheral_input(); - let mosi = mosi_pin.peripheral_input(); - let mut miso = miso_pin.peripheral_input(); - let sclk_signal = sclk_pin.peripheral_input(); - - let mosi_gpio = Output::new(mosi_pin, Level::Low); - let cs_gpio = Output::new(cs_pin, Level::High); - let sclk_gpio = Output::new(sclk_gpio, Level::Low); - - let spi = Spi::new( - peripherals.SPI2, - sclk_signal, - mosi, - miso_pin, - cs, - SpiMode::Mode1, - ); - - miso.enable_input(true, unsafe { esp_hal::Internal::conjure() }); + let (cs, cs_pin) = cs_pin.split(); + let (mosi, mosi_pin) = mosi_pin.split(); + let (miso, miso_pin) = miso_pin.split(); + let (sclk_signal, sclk_pin) = sclk_pin.split(); Context { - spi, + spi: Spi::new( + peripherals.SPI2, + sclk_signal, + mosi, + miso_pin, + cs, + SpiMode::Mode1, + ), + bitbang_spi: BitbangSpi::new(sclk_pin, mosi_pin, miso, cs_pin), dma_channel, - bitbang_spi: BitbangSpi::new(sclk_gpio, mosi_gpio, miso, cs_gpio), } } diff --git a/hil-test/tests/twai.rs b/hil-test/tests/twai.rs index da41f1dc2..a1be5524e 100644 --- a/hil-test/tests/twai.rs +++ b/hil-test/tests/twai.rs @@ -32,10 +32,12 @@ mod tests { let (loopback_pin, _) = hil_test::common_test_pins!(io); + let (rx, tx) = loopback_pin.split(); + let mut config = twai::TwaiConfiguration::new( peripherals.TWAI0, - loopback_pin.peripheral_input(), - loopback_pin, + rx, + tx, twai::BaudRate::B1000K, TwaiMode::SelfTest, ); diff --git a/hil-test/tests/uart.rs b/hil-test/tests/uart.rs index f653873cf..5b1a74cb8 100644 --- a/hil-test/tests/uart.rs +++ b/hil-test/tests/uart.rs @@ -32,12 +32,9 @@ mod tests { let (_, pin) = hil_test::common_test_pins!(io); - let uart = Uart::new( - peripherals.UART1, - pin.peripheral_input(), - pin.into_peripheral_output(), - ) - .unwrap(); + let (rx, tx) = pin.split(); + + let uart = Uart::new(peripherals.UART1, rx, tx).unwrap(); Context { uart } }