From 4c5be2c907509d78e682376781a3d8cd3b790c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 6 Nov 2024 14:55:34 +0100 Subject: [PATCH] Interconnect: force signals through GPIO matrix if split (#2419) * Allow splitting off of gpio drivers * Extract and correct low level connection bits * Add Input/OutputSignal::connect_to * Remove unnecessary public API * Fix typos * Remove unused private methods * Add separate Direct signals that do bypass the GPIO matrix * Do not disable stage input * Clean up spi_slave test * Constrain to static Flex * Improve docs * Separate input_enable and open_drain parameters * Link to the chapter * Changelog * Clarify --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/gpio/interconnect.rs | 544 +++++++++++++++++++------------ esp-hal/src/gpio/mod.rs | 170 ++++++---- esp-hal/src/gpio/placeholder.rs | 38 +-- esp-hal/src/i2c.rs | 8 +- esp-hal/src/i2s.rs | 14 +- esp-hal/src/i2s_parallel.rs | 14 +- esp-hal/src/lcd_cam/cam.rs | 24 +- esp-hal/src/lcd_cam/lcd/i8080.rs | 14 +- esp-hal/src/ledc/channel.rs | 3 +- esp-hal/src/macros.rs | 17 + esp-hal/src/mcpwm/operator.rs | 4 +- esp-hal/src/otg_fs.rs | 9 +- esp-hal/src/parl_io.rs | 27 +- esp-hal/src/pcnt/channel.rs | 4 +- esp-hal/src/rmt.rs | 8 +- esp-hal/src/soc/esp32/gpio.rs | 7 +- esp-hal/src/soc/esp32/mod.rs | 6 + esp-hal/src/soc/esp32c2/gpio.rs | 7 +- esp-hal/src/soc/esp32c2/mod.rs | 6 + esp-hal/src/soc/esp32c3/gpio.rs | 7 +- esp-hal/src/soc/esp32c3/mod.rs | 6 + esp-hal/src/soc/esp32c6/gpio.rs | 7 +- esp-hal/src/soc/esp32c6/mod.rs | 6 + esp-hal/src/soc/esp32h2/gpio.rs | 7 +- esp-hal/src/soc/esp32h2/mod.rs | 6 + esp-hal/src/soc/esp32s2/gpio.rs | 7 +- esp-hal/src/soc/esp32s2/mod.rs | 6 + esp-hal/src/soc/esp32s3/gpio.rs | 10 +- esp-hal/src/soc/esp32s3/mod.rs | 6 + esp-hal/src/spi/master.rs | 49 +-- esp-hal/src/spi/slave.rs | 8 +- esp-hal/src/twai/mod.rs | 4 +- esp-hal/src/uart.rs | 8 +- hil-test/tests/spi_slave.rs | 80 ++--- 35 files changed, 648 insertions(+), 494 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 1733b3b9b7f..d112b9a9f65 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Calling `AnyPin::output_signals` on an input-only pin (ESP32 GPIO 34-39) will now result in a panic. (#2418) - UART configuration types have been moved to `esp_hal::uart` (#2449) - `spi::master::Spi::new()` no longer takes `frequency` and `mode` as a parameter. (#2448) +- Peripheral interconnections via GPIO pins now use the GPIO matrix. (#2419) ### Fixed diff --git a/esp-hal/src/gpio/interconnect.rs b/esp-hal/src/gpio/interconnect.rs index b86b76c2ae1..e07e8d97ec8 100644 --- a/esp-hal/src/gpio/interconnect.rs +++ b/esp-hal/src/gpio/interconnect.rs @@ -5,7 +5,9 @@ use crate::{ self, AlternateFunction, AnyPin, + Flex, InputPin, + InputSignalType, Level, NoPin, OutputPin, @@ -34,24 +36,179 @@ pub trait PeripheralInput: Into + 'static {} /// [`PeripheralInput`] as arguments instead of pin types. pub trait PeripheralOutput: Into + 'static {} +// Pins impl PeripheralInput for P {} impl PeripheralOutput for P {} -impl PeripheralInput for InputSignal {} -impl PeripheralInput for OutputSignal {} -impl PeripheralOutput for OutputSignal {} +// Pin drivers +impl PeripheralInput for Flex<'static, P> {} +impl PeripheralOutput for Flex<'static, P> {} +// Placeholders impl PeripheralInput for NoPin {} impl PeripheralOutput for NoPin {} impl PeripheralInput for Level {} impl PeripheralOutput for Level {} -impl PeripheralInput for InputConnection {} +// Split signals +impl PeripheralInput for InputSignal {} +impl PeripheralInput for OutputSignal {} +impl PeripheralOutput for OutputSignal {} +// Type-erased signals +impl PeripheralInput for InputConnection {} impl PeripheralInput for OutputConnection {} impl PeripheralOutput for OutputConnection {} +impl gpio::InputSignal { + fn can_use_gpio_matrix(self) -> bool { + self as InputSignalType <= INPUT_SIGNAL_MAX + } + + /// Connects a peripheral input signal to a GPIO or a constant level. + /// + /// Note that connecting multiple GPIOs to a single peripheral input is not + /// possible and the previous connection will be replaced. + /// + /// Also note that a peripheral input must always be connected to something, + /// so if you want to disconnect it from GPIOs, you should connect it to a + /// constant level. + #[inline] + pub fn connect_to(self, pin: impl Peripheral

) { + crate::into_mapped_ref!(pin); + + pin.connect_input_to_peripheral(self); + } +} + +impl gpio::OutputSignal { + fn can_use_gpio_matrix(self) -> bool { + self as OutputSignalType <= OUTPUT_SIGNAL_MAX + } + + /// Connects a peripheral output signal to a GPIO. + /// + /// Note that connecting multiple output signals to a single GPIO is not + /// possible and the previous connection will be replaced. + /// + /// Also note that it is possible to connect a peripheral output signal to + /// multiple GPIOs, and old connections will not be cleared automatically. + #[inline] + pub fn connect_to(self, pin: impl Peripheral

) { + crate::into_mapped_ref!(pin); + + pin.connect_peripheral_to_output(self); + } + + /// Disconnects a peripheral output signal from a GPIO. + #[inline] + pub fn disconnect_from(self, pin: impl Peripheral

) { + crate::into_mapped_ref!(pin); + + pin.disconnect_from_peripheral_output(self); + } +} + +/// Connects a peripheral input (`signal`, e.g. SPI MISO) to a GPIO or a +/// constant level (`input`). +/// +/// - `signal`: The input signal to connect to the pin +/// - `input`: The GPIO (or constant level) number to connect to the input +/// signal. +/// - `invert`: Configures whether or not to invert the input value +/// - `use_gpio_matrix`: true to route through the GPIO matrix +pub(crate) fn connect_input_signal( + signal: gpio::InputSignal, + input: u8, + invert: bool, + use_gpio_matrix: bool, +) { + assert!( + signal.can_use_gpio_matrix() || !use_gpio_matrix, + "{:?} cannot be routed through the GPIO matrix", + signal + ); + unsafe { GPIO::steal() } + .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) + .write(|w| unsafe { + w.sel().bit(use_gpio_matrix); + w.in_inv_sel().bit(invert); + w.in_sel().bits(input) // Connect to GPIO or constant level + }); +} + +fn connect_pin_to_input_signal( + pin: &mut AnyPin, + signal: gpio::InputSignal, + is_inverted: bool, + force_gpio: bool, +) { + let af = if is_inverted || force_gpio { + GPIO_FUNCTION + } else { + pin.input_signals(private::Internal) + .iter() + .find(|(_af, s)| *s == signal) + .map(|(af, _)| *af) + .unwrap_or(GPIO_FUNCTION) + }; + + pin.set_alternate_function(af, private::Internal); + + connect_input_signal(signal, pin.number(), is_inverted, af == GPIO_FUNCTION); +} + +fn connect_peripheral_to_output( + pin: &mut AnyPin, + signal: gpio::OutputSignal, + is_inverted: bool, + force_gpio: bool, + peripheral_control_output_enable: bool, + invert_output_enable: bool, +) { + let af = if is_inverted || force_gpio { + GPIO_FUNCTION + } else { + pin.output_signals(private::Internal) + .iter() + .find(|(_af, s)| *s == signal) + .map(|(af, _)| *af) + .unwrap_or(GPIO_FUNCTION) + }; + + assert!( + signal.can_use_gpio_matrix() || af != GPIO_FUNCTION, + "{:?} cannot be routed through the GPIO matrix", + signal + ); + + pin.set_alternate_function(af, private::Internal); + + // Inlined because output signals can only be connected to pins or nothing, so + // there is no other user. + unsafe { GPIO::steal() } + .func_out_sel_cfg(pin.number() as usize) + .write(|w| unsafe { + if af == GPIO_FUNCTION { + // Ignored if the signal is not routed through the GPIO matrix - alternate + // function selects peripheral signal directly. + w.out_sel().bits(signal as _); + w.inv_sel().bit(is_inverted); + } + w.oen_sel().bit(!peripheral_control_output_enable); + w.oen_inv_sel().bit(invert_output_enable) + }); +} + +fn disconnect_peripheral_output_from_pin(pin: &mut AnyPin, signal: gpio::OutputSignal) { + pin.set_alternate_function(GPIO_FUNCTION, private::Internal); + + unsafe { GPIO::steal() } + .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) + .write(|w| w.sel().clear_bit()); +} + /// A configurable input signal between a peripheral and a GPIO pin. /// /// Multiple input signals can be connected to one pin. @@ -69,6 +226,15 @@ where } } +impl

From> for InputSignal +where + P: InputPin, +{ + fn from(input: Flex<'static, P>) -> Self { + Self::new(input.degrade()) + } +} + impl Clone for InputSignal { fn clone(&self) -> Self { Self { @@ -113,7 +279,7 @@ impl InputSignal { self.is_inverted = !self.is_inverted; } - /// Consumed the signal and returns a new one that inverts the peripheral's + /// Consumes the signal and returns a new one that inverts the peripheral's /// input signal. /// /// Calling this function multiple times toggles the setting. @@ -122,64 +288,13 @@ impl InputSignal { self } - /// - signal: The input signal to connect to the pin - /// - invert: Configures whether or not to invert the input value - /// - input: The GPIO number to connect to the input signal - fn connect(&self, signal: usize, invert: bool, input: u8) { - unsafe { GPIO::steal() } - .func_in_sel_cfg(signal - FUNC_IN_SEL_OFFSET) - .modify(|_, w| unsafe { - w.sel().set_bit(); - w.in_inv_sel().bit(invert); - w.in_sel().bits(input) - }); - } - /// Connect the pin to a peripheral input signal. /// /// Since there can only be one input signal connected to a peripheral at a /// time, this function will disconnect any previously connected input /// signals. - fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal, _: private::Internal) { - let signal_nr = signal as usize; - - let af = if self.is_inverted { - GPIO_FUNCTION - } else { - self.input_signals(private::Internal) - .iter() - .find(|(_af, s)| *s == signal) - .map(|(af, _)| *af) - .unwrap_or(GPIO_FUNCTION) - }; - - if af == GPIO_FUNCTION && signal_nr > INPUT_SIGNAL_MAX as usize { - panic!("Cannot connect GPIO to this peripheral"); - } - - self.pin.set_alternate_function(af, private::Internal); - - if signal_nr <= INPUT_SIGNAL_MAX as usize { - self.connect(signal_nr, self.is_inverted, self.pin.number()); - } - } - - /// Remove this pin from a connected peripheral input. - /// - /// Clears the entry in the GPIO matrix / Io mux that associates this input - /// pin with the given [input `signal`](`InputSignal`). Any other - /// connected signals remain intact. - fn disconnect_input_from_peripheral( - &mut self, - signal: gpio::InputSignal, - _: private::Internal, - ) { - self.pin - .set_alternate_function(GPIO_FUNCTION, private::Internal); - - unsafe { GPIO::steal() } - .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) - .modify(|_, w| w.sel().clear_bit()); + fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal) { + connect_pin_to_input_signal(&mut self.pin, signal, self.is_inverted, true); } delegate::delegate! { @@ -190,7 +305,44 @@ impl InputSignal { pub fn init_input(&self, pull: Pull, _internal: private::Internal); pub fn is_input_high(&self, _internal: private::Internal) -> bool; pub fn enable_input(&mut self, on: bool, _internal: private::Internal); - pub fn enable_input_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); + } + } +} + +/// A limited, private version of [InputSignal] that allows bypassing the GPIO +/// matrix. This is only usable when the GPIO pin connected to the signal is not +/// split. +struct DirectInputSignal { + pin: AnyPin, +} + +impl Clone for DirectInputSignal { + fn clone(&self) -> Self { + Self::new(unsafe { self.pin.clone_unchecked() }) + } +} + +impl DirectInputSignal { + pub(crate) fn new(pin: AnyPin) -> Self { + Self { pin } + } + + /// Connect the pin to a peripheral input signal. + /// + /// Since there can only be one input signal connected to a peripheral at a + /// time, this function will disconnect any previously connected input + /// signals. + fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal) { + connect_pin_to_input_signal(&mut self.pin, signal, false, false); + } + + delegate::delegate! { + to self.pin { + fn pull_direction(&self, pull: Pull, _internal: private::Internal); + fn input_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::InputSignal)]; + fn init_input(&self, pull: Pull, _internal: private::Internal); + fn is_input_high(&self, _internal: private::Internal) -> bool; + fn enable_input(&mut self, on: bool, _internal: private::Internal); } } } @@ -212,6 +364,15 @@ where } } +impl

From> for OutputSignal +where + P: OutputPin, +{ + fn from(input: Flex<'static, P>) -> Self { + Self::new(input.degrade()) + } +} + impl Peripheral for OutputSignal { type P = Self; @@ -245,7 +406,7 @@ impl OutputSignal { self.is_inverted = !self.is_inverted; } - /// Consumed the signal and returns a new one that inverts the peripheral's + /// Consumes the signal and returns a new one that inverts the peripheral's /// output signal. /// /// Calling this function multiple times toggles the setting. @@ -254,139 +415,18 @@ impl OutputSignal { self } - /// - signal: The input signal to connect to the pin - /// - invert: Configures whether or not to invert the input value - /// - input: The GPIO number to connect to the input signal - fn connect_input(&self, signal: usize, invert: bool, input: u8) { - unsafe { GPIO::steal() } - .func_in_sel_cfg(signal - FUNC_IN_SEL_OFFSET) - .modify(|_, w| unsafe { - w.sel().set_bit(); - w.in_inv_sel().bit(invert); - w.in_sel().bits(input) - }); - } - - /// - signal: The output signal to connect to the pin - /// - invert: Configures whether or not to invert the output value - /// - invert_enable: Configures whether or not to invert the output enable - /// signal - /// - enable_from_gpio: Configures to select the source of output enable - /// signal. - /// - false: Use output enable signal from peripheral - /// - true: Force the output enable signal to be sourced from bit n of - /// GPIO_ENABLE_REG - /// - output: The GPIO number to connect to the output signal - fn connect_output( - &self, - signal: OutputSignalType, - invert: bool, - invert_enable: bool, - enable_from_gpio: bool, - output: u8, - ) { - unsafe { GPIO::steal() } - .func_out_sel_cfg(output as usize) - .modify(|_, w| unsafe { - w.out_sel().bits(signal); - w.inv_sel().bit(invert); - w.oen_sel().bit(enable_from_gpio); - w.oen_inv_sel().bit(invert_enable) - }); - } - - /// Connect the pin to a peripheral input signal. - /// - /// Since there can only be one signal connected to a peripheral input at a - /// time, this function will disconnect any previously connected input - /// signals. - fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal, _: private::Internal) { - let signal_nr = signal as usize; - - let af = if self.is_inverted { - GPIO_FUNCTION - } else { - self.input_signals(private::Internal) - .iter() - .find(|(_af, s)| *s == signal) - .map(|(af, _)| *af) - .unwrap_or(GPIO_FUNCTION) - }; - - if af == GPIO_FUNCTION && signal_nr > INPUT_SIGNAL_MAX as usize { - panic!("Cannot connect GPIO to this peripheral"); - } - - self.pin.set_alternate_function(af, private::Internal); - - if signal_nr <= INPUT_SIGNAL_MAX as usize { - self.connect_input(signal_nr, self.is_inverted, self.pin.number()); - } - } - - /// Remove this pin from a connected peripheral input. - /// - /// Clears the entry in the GPIO matrix / Io mux that associates this input - /// pin with the given [input `signal`](`InputSignal`). Any other - /// connected signals remain intact. - fn disconnect_input_from_peripheral( - &mut self, - signal: gpio::InputSignal, - _: private::Internal, - ) { - self.pin - .set_alternate_function(GPIO_FUNCTION, private::Internal); - - unsafe { GPIO::steal() } - .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) - .modify(|_, w| w.sel().clear_bit()); + /// Connect the pin to a peripheral output signal. + fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal) { + connect_peripheral_to_output(&mut self.pin, signal, self.is_inverted, true, true, false); } - /// Connect the pin to a peripheral output signal. - fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal, _: private::Internal) { - let af = if self.is_inverted { - GPIO_FUNCTION - } else { - self.output_signals(private::Internal) - .iter() - .find(|(_af, s)| *s == signal) - .map(|(af, _)| *af) - .unwrap_or(GPIO_FUNCTION) - }; - - self.pin.set_alternate_function(af, private::Internal); - - let clipped_signal = if signal as usize <= OUTPUT_SIGNAL_MAX as usize { - signal as OutputSignalType - } else { - OUTPUT_SIGNAL_MAX - }; - - self.connect_output( - clipped_signal, - self.is_inverted, - false, - false, - self.pin.number(), - ); - } - - /// Remove this output pin from a connected [signal](`OutputSignal`). + /// Remove this output pin from a connected [signal](`gpio::OutputSignal`). /// /// Clears the entry in the GPIO matrix / Io mux that associates this output - /// pin with a previously connected [signal](`OutputSignal`). Any other - /// outputs connected to the peripheral remain intact. - fn disconnect_from_peripheral_output( - &mut self, - signal: gpio::OutputSignal, - _: private::Internal, - ) { - self.pin - .set_alternate_function(GPIO_FUNCTION, private::Internal); - - unsafe { GPIO::steal() } - .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) - .modify(|_, w| w.sel().clear_bit()); + /// pin with a previously connected [signal](`gpio::OutputSignal`). Any + /// other outputs connected to the peripheral remain intact. + fn disconnect_from_peripheral_output(&mut self, signal: gpio::OutputSignal) { + disconnect_peripheral_output_from_pin(&mut self.pin, signal); } delegate::delegate! { @@ -397,7 +437,6 @@ impl OutputSignal { pub fn init_input(&self, pull: Pull, _internal: private::Internal); pub fn is_input_high(&self, _internal: private::Internal) -> bool; pub fn enable_input(&mut self, on: bool, _internal: private::Internal); - pub fn enable_input_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); pub fn output_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::OutputSignal)]; pub fn set_to_open_drain_output(&mut self, _internal: private::Internal); @@ -406,7 +445,6 @@ impl OutputSignal { pub fn set_output_high(&mut self, on: bool, _internal: private::Internal); pub fn set_drive_strength(&mut self, strength: gpio::DriveStrength, _internal: private::Internal); pub fn enable_open_drain(&mut self, on: bool, _internal: private::Internal); - pub fn enable_output_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); pub fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); pub fn internal_pull_down_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); pub fn is_set_high(&self, _internal: private::Internal) -> bool; @@ -414,13 +452,62 @@ impl OutputSignal { } } +/// A limited, private version of [OutputSignal] that allows bypassing the GPIO +/// matrix. This is only usable when the GPIO pin connected to the signal is not +/// split. +struct DirectOutputSignal { + pin: AnyPin, +} + +impl DirectOutputSignal { + pub(crate) fn new(pin: AnyPin) -> Self { + Self { pin } + } + + /// Connect the pin to a peripheral output signal. + fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal) { + connect_peripheral_to_output(&mut self.pin, signal, false, false, true, false); + } + + /// Remove this output pin from a connected [signal](`gpio::OutputSignal`). + /// + /// Clears the entry in the GPIO matrix / Io mux that associates this output + /// pin with a previously connected [signal](`gpio::OutputSignal`). Any + /// other outputs connected to the peripheral remain intact. + fn disconnect_from_peripheral_output(&mut self, signal: gpio::OutputSignal) { + disconnect_peripheral_output_from_pin(&mut self.pin, signal); + } + + delegate::delegate! { + to self.pin { + fn pull_direction(&self, pull: Pull, _internal: private::Internal); + fn input_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::InputSignal)]; + fn init_input(&self, pull: Pull, _internal: private::Internal); + fn is_input_high(&self, _internal: private::Internal) -> bool; + fn enable_input(&mut self, on: bool, _internal: private::Internal); + + fn output_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::OutputSignal)]; + fn set_to_open_drain_output(&mut self, _internal: private::Internal); + fn set_to_push_pull_output(&mut self, _internal: private::Internal); + fn enable_output(&mut self, on: bool, _internal: private::Internal); + fn set_output_high(&mut self, on: bool, _internal: private::Internal); + fn set_drive_strength(&mut self, strength: gpio::DriveStrength, _internal: private::Internal); + fn enable_open_drain(&mut self, on: bool, _internal: private::Internal); + fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); + fn internal_pull_down_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); + fn is_set_high(&self, _internal: private::Internal) -> bool; + } + } +} + #[derive(Clone)] enum InputConnectionInner { Input(InputSignal), + DirectInput(DirectInputSignal), Constant(Level), } -/// A type-erased peripheral input signal connection. +/// A peripheral input signal connection. /// /// This is mainly intended for internal use, but it can be used to connect /// peripherals within the MCU without external hardware. @@ -471,15 +558,33 @@ impl From for InputConnection { } } +impl From for InputConnection { + fn from(output_signal: DirectOutputSignal) -> Self { + Self(InputConnectionInner::DirectInput(DirectInputSignal::new( + output_signal.pin, + ))) + } +} + impl From for InputConnection { fn from(conn: OutputConnection) -> Self { match conn.0 { OutputConnectionInner::Output(inner) => inner.into(), + OutputConnectionInner::DirectOutput(inner) => inner.into(), OutputConnectionInner::Constant(inner) => inner.into(), } } } +impl

From> for InputConnection +where + P: InputPin, +{ + fn from(pin: Flex<'static, P>) -> Self { + pin.peripheral_input().into() + } +} + impl Sealed for InputConnection {} impl InputConnection { @@ -487,6 +592,7 @@ impl InputConnection { #[doc(hidden)] to match &self.0 { InputConnectionInner::Input(pin) => pin, + InputConnectionInner::DirectInput(pin) => pin, InputConnectionInner::Constant(level) => level, } { pub fn pull_direction(&self, pull: Pull, _internal: private::Internal); @@ -498,22 +604,22 @@ impl InputConnection { #[doc(hidden)] to match &mut self.0 { InputConnectionInner::Input(pin) => pin, + InputConnectionInner::DirectInput(pin) => pin, InputConnectionInner::Constant(level) => level, } { pub fn enable_input(&mut self, on: bool, _internal: private::Internal); - pub fn enable_input_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); - pub fn connect_input_to_peripheral(&mut self, signal: crate::gpio::InputSignal, _internal: private::Internal); - pub fn disconnect_input_from_peripheral(&mut self, signal: crate::gpio::InputSignal, _internal: private::Internal); + fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal); } } } enum OutputConnectionInner { Output(OutputSignal), + DirectOutput(DirectOutputSignal), Constant(Level), } -/// A type-erased peripheral (input and) output signal connection. +/// A peripheral (input and) output signal connection. /// /// This is mainly intended for internal use, but it can be used to connect /// peripherals within the MCU without external hardware. @@ -527,6 +633,9 @@ impl Peripheral for OutputConnection { unsafe fn clone_unchecked(&self) -> Self::P { match self { Self(OutputConnectionInner::Output(signal)) => Self::from(signal.clone_unchecked()), + Self(OutputConnectionInner::DirectOutput(signal)) => { + Self::from(DirectOutputSignal::new(signal.pin.clone_unchecked())) + } Self(OutputConnectionInner::Constant(level)) => Self::from(*level), } } @@ -559,54 +668,55 @@ impl From for OutputConnection { } } +impl

From> for OutputConnection +where + P: OutputPin, +{ + fn from(pin: Flex<'static, P>) -> Self { + pin.into_peripheral_output().into() + } +} + +impl From for OutputConnection { + fn from(signal: DirectOutputSignal) -> Self { + Self(OutputConnectionInner::DirectOutput(signal)) + } +} + impl OutputConnection { delegate::delegate! { #[doc(hidden)] to match &self.0 { OutputConnectionInner::Output(pin) => pin, + OutputConnectionInner::DirectOutput(pin) => pin, OutputConnectionInner::Constant(level) => level, } { pub fn is_input_high(&self, _internal: private::Internal) -> bool; pub fn input_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::InputSignal)]; + + pub fn is_set_high(&self, _internal: private::Internal) -> bool; + pub fn output_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::OutputSignal)]; } #[doc(hidden)] to match &mut self.0 { OutputConnectionInner::Output(pin) => pin, + OutputConnectionInner::DirectOutput(pin) => pin, OutputConnectionInner::Constant(level) => level, } { pub fn pull_direction(&mut self, pull: Pull, _internal: private::Internal); pub fn init_input(&mut self, pull: Pull, _internal: private::Internal); pub fn enable_input(&mut self, on: bool, _internal: private::Internal); - pub fn enable_input_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); - pub fn connect_input_to_peripheral(&mut self, signal: crate::gpio::InputSignal, _internal: private::Internal); - pub fn disconnect_input_from_peripheral(&mut self, signal: crate::gpio::InputSignal, _internal: private::Internal); - } - #[doc(hidden)] - to match &self.0 { - OutputConnectionInner::Output(pin) => pin, - OutputConnectionInner::Constant(level) => level, - } { - pub fn is_set_high(&self, _internal: private::Internal) -> bool; - pub fn output_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::OutputSignal)]; - } - - #[doc(hidden)] - to match &mut self.0 { - OutputConnectionInner::Output(pin) => pin, - OutputConnectionInner::Constant(level) => level, - } { pub fn set_to_open_drain_output(&mut self, _internal: private::Internal); pub fn set_to_push_pull_output(&mut self, _internal: private::Internal); pub fn enable_output(&mut self, on: bool, _internal: private::Internal); pub fn set_output_high(&mut self, on: bool, _internal: private::Internal); pub fn set_drive_strength(&mut self, strength: gpio::DriveStrength, _internal: private::Internal); pub fn enable_open_drain(&mut self, on: bool, _internal: private::Internal); - pub fn enable_output_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); pub fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); pub fn internal_pull_down_in_sleep_mode(&mut self, on: bool, _internal: private::Internal); - pub fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal, _internal: private::Internal); - pub fn disconnect_from_peripheral_output(&mut self, signal: gpio::OutputSignal, _internal: private::Internal); + fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal); + fn disconnect_from_peripheral_output(&mut self, signal: gpio::OutputSignal); } } } diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index a7311729351..4186dc4d719 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -1,39 +1,49 @@ -//! # General Purpose I/Os (GPIO) +//! # General Purpose Input/Output (GPIO) //! //! ## Overview //! //! Each pin can be used as a general-purpose I/O, or be connected to one or //! more internal peripheral signals. +#![cfg_attr( + soc_etm, + doc = "The GPIO pins also provide tasks and events via the ETM interconnect system. For more information, see the [etm] module." +)] +#![doc = ""] +//! ## Working with pins //! -//! ## Configuration +//! Before use, the GPIO module must be initialized by creating an instance of +//! the [`Io`] struct. This struct provides access to the pins on the chip. //! -//! This driver supports various operations on GPIO pins, including setting the -//! pin mode, direction, and manipulating the pin state (setting high/low, -//! toggling). It provides an interface to interact with GPIO pins on ESP chips, -//! allowing developers to control and read the state of the pins. +//! The [`Io`] struct can also be used to configure the interrupt handler for +//! GPIO interrupts. For more information, see the +//! [`Io::set_interrupt_handler`]. //! -//! ## Usage +//! The pins are accessible via [`Io::pins`]. These pins can then be passed to +//! peripherals (such as SPI, UART, I2C, etc.), to pin drivers or can be +//! [`GpioPin::split`] into peripheral signals. //! -//! This module also implements a number of traits from [embedded-hal] to -//! provide a common interface for GPIO pins. +//! Each pin is a different type initially. Internally, `esp-hal` will often +//! erase their types automatically, but they can also be converted into +//! [`AnyPin`] manually by calling [`Pin::degrade`]. //! -//! To get access to the pins, you first need to convert them into a HAL -//! designed struct from the pac struct `GPIO` and `IO_MUX` using [`Io::new`]. +//! Pin drivers can be created using [`Flex::new`], [`Input::new`], +//! [`Output::new`] and [`OutputOpenDrain::new`]. If you need the pin drivers to +//! carry the type of the pin, you can use the [`Flex::new_typed`], +//! [`Input::new_typed`], [`Output::new_typed`], and +//! [`OutputOpenDrain::new_typed`] functions. //! -//! ### Pin Types +//! ## GPIO interconnect //! -//! - [Input] pins can be used as digital inputs. -//! - [Output] and [OutputOpenDrain] pins can be used as digital outputs. -//! - [Flex] pin is a pin that can be used as an input and output pin. -//! - [AnyPin] is a type-erased GPIO pin with support for inverted signalling. -//! - [NoPin] is a useful for cases where peripheral driver requires a pin, but -//! real pin cannot be used. +//! Sometimes you may want to connect peripherals together without using +//! external hardware. The [`interconnect`] module provides tools to achieve +//! this using GPIO pins. //! -//! ### GPIO interconnect -//! -//! Each GPIO can be connected to one output signal and any number of input -//! signals. This allows connections inside of the MCU without allocating and -//! connecting multiple pins for loopback functionality. +//! To obtain peripheral signals, use the [`GpioPin::split`] method to split a +//! pin into an input and output signal. Alternatively, you may use +//! [`Flex::split`], [`Flex::into_peripheral_output`], +//! [`Flex::peripheral_input`], and similar methods to split a pin driver into +//! an input and output signal. You can then pass these signals to the +//! peripheral drivers similar to how you would pass a pin. //! //! ## Examples //! @@ -49,14 +59,14 @@ //! //! ### Blink an LED //! -//! See the [Blinky] section of the crate documentation. +//! See the [Blinky][crate#blinky] section of the crate documentation. +//! +//! ### Inverting peripheral signals //! -//! ### Inverting a signal using `AnyPin` //! See the [Inverting TX and RX Pins] example of the UART documentation. //! //! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/ -//! [Blinky]: ../index.html#blinky -//! [Inverting TX and RX Pins]: ../uart/index.html#inverting-tx-and-rx-pins +//! [Inverting TX and RX Pins]: crate::uart#inverting-rx-and-tx-pins use portable_atomic::{AtomicPtr, Ordering}; use procmacros::ram; @@ -217,9 +227,13 @@ pub enum DriveStrength { /// /// GPIO pins can be configured for various functions, such as GPIO /// or being directly connected to a peripheral's signal like UART, SPI, etc. -/// The `AlternateFunction` enum allows to select one of several functions that +/// The `AlternateFunction` enum allows selecting one of several functions that /// a pin can perform, rather than using it as a general-purpose input or /// output. +/// +/// The different variants correspond to different functionality depending on +/// the chip and the specific pin. For more information, refer to your chip's +#[doc = crate::trm_markdown_link!("iomuxgpio")] #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AlternateFunction { @@ -384,12 +398,6 @@ pub trait InputPin: Pin + Into + 'static { }); } - /// Enable input in sleep mode for the pin - #[doc(hidden)] - fn enable_input_in_sleep_mode(&mut self, on: bool, _: private::Internal) { - get_io_mux_reg(self.number()).modify(|_, w| w.mcu_ie().bit(on)); - } - /// The current state of the input #[doc(hidden)] fn is_input_high(&self, _: private::Internal) -> bool { @@ -405,6 +413,7 @@ pub trait OutputPin: Pin + Into + 'static { &mut self, alternate: AlternateFunction, open_drain: bool, + input_enable: Option, _: private::Internal, ) { self.enable_output(true, private::Internal); @@ -422,7 +431,9 @@ pub trait OutputPin: Pin + Into + 'static { get_io_mux_reg(self.number()).modify(|_, w| unsafe { w.mcu_sel().bits(alternate as u8); - w.fun_ie().bit(open_drain); + if let Some(input_enable) = input_enable { + w.fun_ie().bit(input_enable); + } w.fun_drv().bits(DriveStrength::I20mA as u8); w.slp_sel().clear_bit() }); @@ -431,13 +442,13 @@ pub trait OutputPin: Pin + Into + 'static { /// Configure open-drain mode #[doc(hidden)] fn set_to_open_drain_output(&mut self, _: private::Internal) { - self.init_output(GPIO_FUNCTION, true, private::Internal); + self.init_output(GPIO_FUNCTION, true, Some(true), private::Internal); } /// Configure output mode #[doc(hidden)] fn set_to_push_pull_output(&mut self, _: private::Internal) { - self.init_output(GPIO_FUNCTION, false, private::Internal); + self.init_output(GPIO_FUNCTION, false, None, private::Internal); } /// Set the pin's level to high or low @@ -461,12 +472,6 @@ pub trait OutputPin: Pin + Into + 'static { .modify(|_, w| w.pad_driver().bit(on)); } - /// Enable/disable output in sleep mode - #[doc(hidden)] - fn enable_output_in_sleep_mode(&mut self, on: bool, _: private::Internal) { - get_io_mux_reg(self.number()).modify(|_, w| w.mcu_oe().bit(on)); - } - /// Configure internal pull-up resistor in sleep mode #[doc(hidden)] fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _: private::Internal) { @@ -1115,9 +1120,9 @@ pub struct Output<'d, P = AnyPin> { impl

private::Sealed for Output<'_, P> {} -impl

Peripheral for Output<'_, P> { - type P = P; - unsafe fn clone_unchecked(&self) -> P { +impl<'d, P> Peripheral for Output<'d, P> { + type P = Flex<'d, P>; + unsafe fn clone_unchecked(&self) -> Self::P { self.pin.clone_unchecked() } } @@ -1229,9 +1234,9 @@ pub struct Input<'d, P = AnyPin> { impl

private::Sealed for Input<'_, P> {} -impl

Peripheral for Input<'_, P> { - type P = P; - unsafe fn clone_unchecked(&self) -> P { +impl<'d, P> Peripheral for Input<'d, P> { + type P = Flex<'d, P>; + unsafe fn clone_unchecked(&self) -> Self::P { self.pin.clone_unchecked() } } @@ -1350,9 +1355,9 @@ pub struct OutputOpenDrain<'d, P = AnyPin> { impl

private::Sealed for OutputOpenDrain<'_, P> {} -impl

Peripheral for OutputOpenDrain<'_, P> { - type P = P; - unsafe fn clone_unchecked(&self) -> P { +impl<'d, P> Peripheral for OutputOpenDrain<'d, P> { + type P = Flex<'d, P>; + unsafe fn clone_unchecked(&self) -> Self::P { self.pin.clone_unchecked() } } @@ -1498,10 +1503,12 @@ pub struct Flex<'d, P = AnyPin> { impl

private::Sealed for Flex<'_, P> {} -impl

Peripheral for Flex<'_, P> { - type P = P; - unsafe fn clone_unchecked(&self) -> P { - core::ptr::read(&*self.pin as *const _) +impl<'d, P> Peripheral for Flex<'d, P> { + type P = Self; + unsafe fn clone_unchecked(&self) -> Self::P { + Self { + pin: PeripheralRef::new(core::ptr::read(&*self.pin as *const P)), + } } } @@ -1709,6 +1716,42 @@ where } } +// Unfortunate implementation details responsible for: +// - making pin drivers work with the peripheral signal system +// - making the pin drivers work with the sleep API +impl Pin for Flex<'_, P> { + delegate::delegate! { + to self.pin { + fn number(&self) -> u8; + fn degrade_pin(&self, _internal: private::Internal) -> AnyPin; + fn output_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, OutputSignal)]; + fn input_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, InputSignal)]; + fn gpio_bank(&self, _internal: private::Internal) -> GpioRegisterAccess; + } + } +} +impl RtcPin for Flex<'_, P> { + delegate::delegate! { + to self.pin { + #[cfg(xtensa)] + fn rtc_number(&self) -> u8; + #[cfg(any(xtensa, esp32c6))] + fn rtc_set_config(&mut self, input_enable: bool, mux: bool, func: RtcFunction); + fn rtcio_pad_hold(&mut self, enable: bool); + #[cfg(any(esp32c3, esp32c2, esp32c6))] + unsafe fn apply_wakeup(&mut self, wakeup: bool, level: u8); + } + } +} +impl RtcPinWithResistors for Flex<'_, P> { + delegate::delegate! { + to self.pin { + fn rtcio_pullup(&mut self, enable: bool); + fn rtcio_pulldown(&mut self, enable: bool); + } + } +} + pub(crate) mod internal { use super::*; @@ -1773,10 +1816,17 @@ pub(crate) mod internal { &mut self, alternate: AlternateFunction, open_drain: bool, + input_enable: Option, _: private::Internal, ) { handle_gpio_output!(&mut self.0, target, { - OutputPin::init_output(target, alternate, open_drain, private::Internal) + OutputPin::init_output( + target, + alternate, + open_drain, + input_enable, + private::Internal, + ) }) } @@ -1810,12 +1860,6 @@ pub(crate) mod 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) diff --git a/esp-hal/src/gpio/placeholder.rs b/esp-hal/src/gpio/placeholder.rs index 84c918fce76..bf269c4d262 100644 --- a/esp-hal/src/gpio/placeholder.rs +++ b/esp-hal/src/gpio/placeholder.rs @@ -6,6 +6,7 @@ // polluting the main module. use super::*; +use crate::gpio::interconnect::connect_input_signal; impl crate::peripheral::Peripheral for Level { type P = Self; @@ -29,45 +30,26 @@ impl Level { pub(crate) fn enable_input(&mut self, _on: bool, _: private::Internal) {} - pub(crate) fn enable_input_in_sleep_mode(&mut self, _on: bool, _: private::Internal) {} - pub(crate) fn is_input_high(&self, _: private::Internal) -> bool { *self == Level::High } #[doc(hidden)] - pub(crate) fn connect_input_to_peripheral( - &mut self, - signal: InputSignal, - _: private::Internal, - ) { + pub(crate) fn connect_input_to_peripheral(&mut self, signal: InputSignal) { let value = match self { Level::High => ONE_INPUT, Level::Low => ZERO_INPUT, }; - unsafe { GPIO::steal() } - .func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET) - .modify(|_, w| unsafe { - w.sel().set_bit(); - w.in_inv_sel().bit(false); - w.in_sel().bits(value) - }); + connect_input_signal(signal, value, false, true); } - pub(crate) fn disconnect_input_from_peripheral( - &mut self, - _signal: InputSignal, - _: private::Internal, - ) { - } pub(crate) fn set_to_open_drain_output(&mut self, _: private::Internal) {} pub(crate) fn set_to_push_pull_output(&mut self, _: private::Internal) {} pub(crate) fn enable_output(&mut self, _on: bool, _: private::Internal) {} pub(crate) fn set_output_high(&mut self, _on: bool, _: private::Internal) {} pub(crate) fn set_drive_strength(&mut self, _strength: DriveStrength, _: private::Internal) {} pub(crate) fn enable_open_drain(&mut self, _on: bool, _: private::Internal) {} - pub(crate) fn enable_output_in_sleep_mode(&mut self, _on: bool, _: private::Internal) {} pub(crate) fn internal_pull_up_in_sleep_mode(&mut self, _on: bool, _: private::Internal) {} pub(crate) fn internal_pull_down_in_sleep_mode(&mut self, _on: bool, _: private::Internal) {} @@ -82,19 +64,9 @@ impl Level { &[] } - pub(crate) fn connect_peripheral_to_output( - &mut self, - _signal: OutputSignal, - _: private::Internal, - ) { - } + pub(crate) fn connect_peripheral_to_output(&mut self, _signal: OutputSignal) {} - pub(crate) fn disconnect_from_peripheral_output( - &mut self, - _signal: OutputSignal, - _: private::Internal, - ) { - } + pub(crate) fn disconnect_from_peripheral_output(&mut self, _signal: OutputSignal) {} } /// Placeholder pin, used when no pin is required when using a peripheral. diff --git a/esp-hal/src/i2c.rs b/esp-hal/src/i2c.rs index 452369252f4..0e636efe22d 100644 --- a/esp-hal/src/i2c.rs +++ b/esp-hal/src/i2c.rs @@ -336,15 +336,15 @@ where scl.enable_input(true, crate::private::Internal); scl.pull_direction(Pull::Up, crate::private::Internal); - scl.connect_input_to_peripheral(i2c.i2c.scl_input_signal(), crate::private::Internal); - scl.connect_peripheral_to_output(i2c.i2c.scl_output_signal(), crate::private::Internal); + i2c.i2c.scl_input_signal().connect_to(&mut scl); + i2c.i2c.scl_output_signal().connect_to(&mut scl); sda.set_to_open_drain_output(crate::private::Internal); sda.enable_input(true, crate::private::Internal); sda.pull_direction(Pull::Up, crate::private::Internal); - sda.connect_input_to_peripheral(i2c.i2c.sda_input_signal(), crate::private::Internal); - sda.connect_peripheral_to_output(i2c.i2c.sda_output_signal(), crate::private::Internal); + i2c.i2c.sda_input_signal().connect_to(&mut sda); + i2c.i2c.sda_output_signal().connect_to(&mut sda); i2c.i2c.setup(frequency, None); i2c diff --git a/esp-hal/src/i2s.rs b/esp-hal/src/i2s.rs index c5b2c1bbc34..0a44a75fa6d 100644 --- a/esp-hal/src/i2s.rs +++ b/esp-hal/src/i2s.rs @@ -469,7 +469,7 @@ where pub fn with_mclk(self, pin: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(pin); pin.set_to_push_pull_output(crate::private::Internal); - pin.connect_peripheral_to_output(self.i2s_tx.i2s.mclk_signal(), crate::private::Internal); + self.i2s_tx.i2s.mclk_signal().connect_to(pin); self } @@ -826,7 +826,7 @@ mod private { { crate::into_mapped_ref!(pin); pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(self.i2s.bclk_signal(), private::Internal); + self.i2s.bclk_signal().connect_to(pin); self } @@ -837,7 +837,7 @@ mod private { { crate::into_mapped_ref!(pin); pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(self.i2s.ws_signal(), private::Internal); + self.i2s.ws_signal().connect_to(pin); self } @@ -848,7 +848,7 @@ mod private { { crate::into_mapped_ref!(pin); pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(self.i2s.dout_signal(), private::Internal); + self.i2s.dout_signal().connect_to(pin); self } @@ -885,7 +885,7 @@ mod private { { crate::into_mapped_ref!(pin); pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(self.i2s.bclk_rx_signal(), private::Internal); + self.i2s.bclk_rx_signal().connect_to(pin); self } @@ -896,7 +896,7 @@ mod private { { crate::into_mapped_ref!(pin); pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(self.i2s.ws_rx_signal(), private::Internal); + self.i2s.ws_rx_signal().connect_to(pin); self } @@ -907,7 +907,7 @@ mod private { { crate::into_mapped_ref!(pin); pin.init_input(crate::gpio::Pull::None, private::Internal); - pin.connect_input_to_peripheral(self.i2s.din_signal(), private::Internal); + self.i2s.din_signal().connect_to(pin); self } diff --git a/esp-hal/src/i2s_parallel.rs b/esp-hal/src/i2s_parallel.rs index 556ccc00ecb..37fd6585d43 100644 --- a/esp-hal/src/i2s_parallel.rs +++ b/esp-hal/src/i2s_parallel.rs @@ -61,7 +61,7 @@ use crate::{ }, peripheral::{Peripheral, PeripheralRef}, peripherals::{i2s0::RegisterBlock, I2S0, I2S1}, - private, + private::Internal, system::PeripheralClockControl, Async, Mode, @@ -123,8 +123,8 @@ impl<'d> TxPins<'d> for TxSixteenBits<'d> { crate::into_ref!(instance); let bits = self.bus_width(); for (i, pin) in self.pins.iter_mut().enumerate() { - pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(instance.data_out_signal(i, bits), private::Internal); + pin.set_to_push_pull_output(Internal); + instance.data_out_signal(i, bits).connect_to(pin); } } } @@ -165,8 +165,8 @@ impl<'d> TxPins<'d> for TxEightBits<'d> { crate::into_ref!(instance); let bits = self.bus_width(); for (i, pin) in self.pins.iter_mut().enumerate() { - pin.set_to_push_pull_output(private::Internal); - pin.connect_peripheral_to_output(instance.data_out_signal(i, bits), private::Internal); + pin.set_to_push_pull_output(Internal); + instance.data_out_signal(i, bits).connect_to(pin); } } } @@ -228,8 +228,8 @@ where // configure the I2S peripheral for parallel mode i2s.setup(frequency, pins.bus_width()); // setup the clock pin - clock_pin.set_to_push_pull_output(private::Internal); - clock_pin.connect_peripheral_to_output(i2s.ws_signal(), private::Internal); + clock_pin.set_to_push_pull_output(Internal); + i2s.ws_signal().connect_to(clock_pin); pins.configure(i2s.reborrow()); Self { diff --git a/esp-hal/src/lcd_cam/cam.rs b/esp-hal/src/lcd_cam/cam.rs index dee3a375949..5cb3b9cf263 100644 --- a/esp-hal/src/lcd_cam/cam.rs +++ b/esp-hal/src/lcd_cam/cam.rs @@ -243,8 +243,10 @@ impl<'d> Camera<'d> { mclk: impl Peripheral

+ 'd, ) -> Self { crate::into_mapped_ref!(mclk); + mclk.set_to_push_pull_output(crate::private::Internal); - mclk.connect_peripheral_to_output(OutputSignal::CAM_CLK, crate::private::Internal); + OutputSignal::CAM_CLK.connect_to(mclk); + self } @@ -256,7 +258,7 @@ impl<'d> Camera<'d> { crate::into_mapped_ref!(pclk); pclk.init_input(Pull::None, crate::private::Internal); - pclk.connect_input_to_peripheral(InputSignal::CAM_PCLK, crate::private::Internal); + InputSignal::CAM_PCLK.connect_to(pclk); self } @@ -271,9 +273,9 @@ impl<'d> Camera<'d> { crate::into_mapped_ref!(vsync, h_enable); vsync.init_input(Pull::None, crate::private::Internal); - vsync.connect_input_to_peripheral(InputSignal::CAM_V_SYNC, crate::private::Internal); + InputSignal::CAM_V_SYNC.connect_to(vsync); h_enable.init_input(Pull::None, crate::private::Internal); - h_enable.connect_input_to_peripheral(InputSignal::CAM_H_ENABLE, crate::private::Internal); + InputSignal::CAM_H_ENABLE.connect_to(h_enable); self.lcd_cam .cam_ctrl1() @@ -297,11 +299,11 @@ impl<'d> Camera<'d> { crate::into_mapped_ref!(vsync, hsync, h_enable); vsync.init_input(Pull::None, crate::private::Internal); - vsync.connect_input_to_peripheral(InputSignal::CAM_V_SYNC, crate::private::Internal); + InputSignal::CAM_V_SYNC.connect_to(vsync); hsync.init_input(Pull::None, crate::private::Internal); - hsync.connect_input_to_peripheral(InputSignal::CAM_H_SYNC, crate::private::Internal); + InputSignal::CAM_H_SYNC.connect_to(hsync); h_enable.init_input(Pull::None, crate::private::Internal); - h_enable.connect_input_to_peripheral(InputSignal::CAM_H_ENABLE, crate::private::Internal); + InputSignal::CAM_H_ENABLE.connect_to(h_enable); self.lcd_cam .cam_ctrl1() @@ -514,9 +516,9 @@ impl RxEightBits { (pin_7, InputSignal::CAM_DATA_7), ]; - for (mut pin, signal) in pairs.into_iter() { + for (pin, signal) in pairs.into_iter() { pin.init_input(Pull::None, crate::private::Internal); - pin.connect_input_to_peripheral(signal, crate::private::Internal); + signal.connect_to(pin); } Self { _pins: () } @@ -591,9 +593,9 @@ impl RxSixteenBits { (pin_15, InputSignal::CAM_DATA_15), ]; - for (mut pin, signal) in pairs.into_iter() { + for (pin, signal) in pairs.into_iter() { pin.init_input(Pull::None, crate::private::Internal); - pin.connect_input_to_peripheral(signal, crate::private::Internal); + signal.connect_to(pin); } Self { _pins: () } diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index 2017f4d07cb..6c9d3e614d3 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -239,7 +239,7 @@ impl<'d, DM: Mode> I8080<'d, DM> { pub fn with_cs(self, cs: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(cs); cs.set_to_push_pull_output(crate::private::Internal); - cs.connect_peripheral_to_output(OutputSignal::LCD_CS, crate::private::Internal); + OutputSignal::LCD_CS.connect_to(cs); self } @@ -253,10 +253,10 @@ impl<'d, DM: Mode> I8080<'d, DM> { crate::into_mapped_ref!(dc, wrx); dc.set_to_push_pull_output(crate::private::Internal); - dc.connect_peripheral_to_output(OutputSignal::LCD_DC, crate::private::Internal); + OutputSignal::LCD_DC.connect_to(dc); wrx.set_to_push_pull_output(crate::private::Internal); - wrx.connect_peripheral_to_output(OutputSignal::LCD_PCLK, crate::private::Internal); + OutputSignal::LCD_PCLK.connect_to(wrx); self } @@ -628,9 +628,9 @@ impl<'d> TxPins for TxEightBits<'d> { OutputSignal::LCD_DATA_7, ]; - for (pin, signal) in self.pins.iter_mut().zip(SIGNALS.iter()) { + for (pin, signal) in self.pins.iter_mut().zip(SIGNALS.into_iter()) { pin.set_to_push_pull_output(crate::private::Internal); - pin.connect_peripheral_to_output(*signal, crate::private::Internal); + signal.connect_to(pin); } } } @@ -697,9 +697,9 @@ impl<'d> TxPins for TxSixteenBits<'d> { OutputSignal::LCD_DATA_15, ]; - for (pin, signal) in self.pins.iter_mut().zip(SIGNALS.iter()) { + for (pin, signal) in self.pins.iter_mut().zip(SIGNALS.into_iter()) { pin.set_to_push_pull_output(crate::private::Internal); - pin.connect_peripheral_to_output(*signal, crate::private::Internal); + signal.connect_to(pin); } } } diff --git a/esp-hal/src/ledc/channel.rs b/esp-hal/src/ledc/channel.rs index a1f18c5ba41..67b43e3f289 100644 --- a/esp-hal/src/ledc/channel.rs +++ b/esp-hal/src/ledc/channel.rs @@ -610,8 +610,7 @@ where Number::Channel7 => OutputSignal::LEDC_LS_SIG7, }; - self.output_pin - .connect_peripheral_to_output(signal, crate::private::Internal); + signal.connect_to(&mut self.output_pin); } else { return Err(Error::Timer); } diff --git a/esp-hal/src/macros.rs b/esp-hal/src/macros.rs index 4f2fa8748b1..c22b5a44a6b 100644 --- a/esp-hal/src/macros.rs +++ b/esp-hal/src/macros.rs @@ -26,6 +26,23 @@ macro_rules! before_snippet { }; } +#[doc(hidden)] +#[macro_export] +macro_rules! trm_markdown_link { + () => { + concat!("[Technical Reference Manual](", $crate::trm_link!(), ")") + }; + ($anchor:literal) => { + concat!( + "[Technical Reference Manual](", + $crate::trm_link!(), + "#", + $anchor, + ")" + ) + }; +} + #[doc(hidden)] /// Shorthand to define enums with From implementations. #[macro_export] diff --git a/esp-hal/src/mcpwm/operator.rs b/esp-hal/src/mcpwm/operator.rs index d2df0a68ec9..f467d9f32fc 100644 --- a/esp-hal/src/mcpwm/operator.rs +++ b/esp-hal/src/mcpwm/operator.rs @@ -298,9 +298,7 @@ impl<'d, PWM: PwmPeripheral, const OP: u8, const IS_A: bool> PwmPin<'d, PWM, OP, pin.set_actions(config.actions); pin.set_update_method(config.update_method); - let output_signal = PWM::output_signal::(); - pin.pin - .connect_peripheral_to_output(output_signal, private::Internal); + PWM::output_signal::().connect_to(&mut pin.pin); pin.pin.enable_output(true, private::Internal); pin diff --git a/esp-hal/src/otg_fs.rs b/esp-hal/src/otg_fs.rs index 095126468dd..97e0d246f0c 100644 --- a/esp-hal/src/otg_fs.rs +++ b/esp-hal/src/otg_fs.rs @@ -43,7 +43,6 @@ use crate::{ gpio::InputSignal, peripheral::{Peripheral, PeripheralRef}, peripherals, - private::Internal, system::{Peripheral as PeripheralEnable, PeripheralClockControl}, }; @@ -99,10 +98,10 @@ impl<'d> Usb<'d> { use crate::gpio::Level; - Level::High.connect_input_to_peripheral(InputSignal::USB_OTG_IDDIG, Internal); // connected connector is mini-B side - Level::High.connect_input_to_peripheral(InputSignal::USB_SRP_BVALID, Internal); // HIGH to force USB device mode - Level::High.connect_input_to_peripheral(InputSignal::USB_OTG_VBUSVALID, Internal); // receiving a valid Vbus from device - Level::Low.connect_input_to_peripheral(InputSignal::USB_OTG_AVALID, Internal); + InputSignal::USB_OTG_IDDIG.connect_to(Level::High); // connected connector is mini-B side + InputSignal::USB_SRP_BVALID.connect_to(Level::High); // HIGH to force USB device mode + InputSignal::USB_OTG_VBUSVALID.connect_to(Level::High); // receiving a valid Vbus from device + InputSignal::USB_OTG_AVALID.connect_to(Level::Low); } } diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index c552a3c197c..57b558cc5ff 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -292,10 +292,7 @@ impl<'d> ClkOutPin<'d> { impl TxClkPin for ClkOutPin<'_> { fn configure(&mut self) { self.pin.set_to_push_pull_output(crate::private::Internal); - self.pin.connect_peripheral_to_output( - crate::gpio::OutputSignal::PARL_TX_CLK, - crate::private::Internal, - ); + crate::gpio::OutputSignal::PARL_TX_CLK.connect_to(&mut self.pin); } } @@ -318,10 +315,7 @@ impl TxClkPin for ClkInPin<'_> { self.pin .init_input(crate::gpio::Pull::None, crate::private::Internal); - self.pin.connect_input_to_peripheral( - crate::gpio::InputSignal::PARL_TX_CLK, - crate::private::Internal, - ); + crate::gpio::InputSignal::PARL_TX_CLK.connect_to(&mut self.pin); } } @@ -348,10 +342,7 @@ impl RxClkPin for RxClkInPin<'_> { self.pin .init_input(crate::gpio::Pull::None, crate::private::Internal); - self.pin.connect_input_to_peripheral( - crate::gpio::InputSignal::PARL_RX_CLK, - crate::private::Internal, - ); + crate::gpio::InputSignal::PARL_RX_CLK.connect_to(&mut self.pin); Instance::set_rx_clk_edge_sel(self.sample_edge); } @@ -390,10 +381,7 @@ where self.tx_pins.configure()?; self.valid_pin .set_to_push_pull_output(crate::private::Internal); - self.valid_pin.connect_peripheral_to_output( - Instance::tx_valid_pin_signal(), - crate::private::Internal, - ); + Instance::tx_valid_pin_signal().connect_to(&mut self.valid_pin); Instance::set_tx_hw_valid_en(true); Ok(()) } @@ -464,7 +452,7 @@ macro_rules! tx_pins { fn configure(&mut self) -> Result<(), Error>{ $( self.[< pin_ $pin:lower >].set_to_push_pull_output(crate::private::Internal); - self.[< pin_ $pin:lower >].connect_peripheral_to_output(crate::gpio::OutputSignal::$signal, crate::private::Internal); + crate::gpio::OutputSignal::$signal.connect_to(&mut self.[< pin_ $pin:lower >]); )+ private::Instance::set_tx_bit_width( private::WidSel::[< Bits $width >]); @@ -584,8 +572,7 @@ where self.rx_pins.configure()?; self.valid_pin .init_input(crate::gpio::Pull::None, crate::private::Internal); - self.valid_pin - .connect_input_to_peripheral(Instance::rx_valid_pin_signal(), crate::private::Internal); + Instance::rx_valid_pin_signal().connect_to(&mut self.valid_pin); Instance::set_rx_sw_en(false); if let Some(sel) = self.enable_mode.pulse_submode_sel() { Instance::set_rx_pulse_submode_sel(sel); @@ -684,7 +671,7 @@ macro_rules! rx_pins { fn configure(&mut self) -> Result<(), Error> { $( self.[< pin_ $pin:lower >].init_input(crate::gpio::Pull::None, crate::private::Internal); - self.[< pin_ $pin:lower >].connect_input_to_peripheral(crate::gpio::InputSignal::$signal, crate::private::Internal); + crate::gpio::InputSignal::$signal.connect_to(&mut self.[< pin_ $pin:lower >]); )+ private::Instance::set_rx_bit_width( private::WidSel::[< Bits $width >]); diff --git a/esp-hal/src/pcnt/channel.rs b/esp-hal/src/pcnt/channel.rs index b85a4b05f0d..c1c565b38e2 100644 --- a/esp-hal/src/pcnt/channel.rs +++ b/esp-hal/src/pcnt/channel.rs @@ -118,7 +118,7 @@ impl Channel<'_, UNIT, NUM> { if (signal as usize) <= crate::gpio::INPUT_SIGNAL_MAX as usize { crate::into_mapped_ref!(source); source.enable_input(true, crate::private::Internal); - source.connect_input_to_peripheral(signal, crate::private::Internal); + signal.connect_to(source); } self } @@ -176,7 +176,7 @@ impl Channel<'_, UNIT, NUM> { if (signal as usize) <= crate::gpio::INPUT_SIGNAL_MAX as usize { crate::into_mapped_ref!(source); source.enable_input(true, crate::private::Internal); - source.connect_input_to_peripheral(signal, crate::private::Internal); + signal.connect_to(source); } self } diff --git a/esp-hal/src/rmt.rs b/esp-hal/src/rmt.rs index 1ba39b3423d..984d621cf54 100644 --- a/esp-hal/src/rmt.rs +++ b/esp-hal/src/rmt.rs @@ -312,8 +312,8 @@ fn configure_rx_channel<'d, P: PeripheralInput, T: RxChannelInternal, M: crat } crate::into_mapped_ref!(pin); - pin.init_input(crate::gpio::Pull::None, crate::Internal); - pin.connect_input_to_peripheral(T::input_signal(), crate::Internal); + pin.init_input(crate::gpio::Pull::None, crate::private::Internal); + T::input_signal().connect_to(pin); T::set_divider(config.clk_divider); T::set_carrier( @@ -333,8 +333,8 @@ fn configure_tx_channel<'d, P: PeripheralOutput, T: TxChannelInternal, M: cra config: TxChannelConfig, ) -> Result { crate::into_mapped_ref!(pin); - pin.set_to_push_pull_output(crate::Internal); - pin.connect_peripheral_to_output(T::output_signal(), crate::Internal); + pin.set_to_push_pull_output(crate::private::Internal); + T::output_signal().connect_to(pin); T::set_divider(config.clk_divider); T::set_carrier( diff --git a/esp-hal/src/soc/esp32/gpio.rs b/esp-hal/src/soc/esp32/gpio.rs index f5899cbd209..b2e34a52ff3 100644 --- a/esp-hal/src/soc/esp32/gpio.rs +++ b/esp-hal/src/soc/esp32/gpio.rs @@ -53,6 +53,7 @@ pub const NUM_PINS: usize = 40; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u16; pub(crate) type OutputSignalType = u16; pub(crate) const OUTPUT_SIGNAL_MAX: u16 = 548; pub(crate) const INPUT_SIGNAL_MAX: u16 = 539; @@ -119,7 +120,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { SPICLK = 0, @@ -310,7 +312,8 @@ pub enum InputSignal { /// Peripheral output signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum OutputSignal { SPICLK = 0, diff --git a/esp-hal/src/soc/esp32/mod.rs b/esp-hal/src/soc/esp32/mod.rs index 6ce747d8335..513675bc8ab 100644 --- a/esp-hal/src/soc/esp32/mod.rs +++ b/esp-hal/src/soc/esp32/mod.rs @@ -26,6 +26,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf" }; +} + pub use chip; pub(crate) mod constants { diff --git a/esp-hal/src/soc/esp32c2/gpio.rs b/esp-hal/src/soc/esp32c2/gpio.rs index f639d54fd71..5304cc66c1b 100644 --- a/esp-hal/src/soc/esp32c2/gpio.rs +++ b/esp-hal/src/soc/esp32c2/gpio.rs @@ -45,6 +45,7 @@ pub const NUM_PINS: usize = 21; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u8; pub(crate) type OutputSignalType = u8; pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128; pub(crate) const INPUT_SIGNAL_MAX: u8 = 100; @@ -64,7 +65,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { SPIQ = 0, @@ -104,7 +106,8 @@ pub enum InputSignal { /// Peripheral output signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum OutputSignal { SPIQ = 0, diff --git a/esp-hal/src/soc/esp32c2/mod.rs b/esp-hal/src/soc/esp32c2/mod.rs index f479a7e767c..da4a41fa440 100644 --- a/esp-hal/src/soc/esp32c2/mod.rs +++ b/esp-hal/src/soc/esp32c2/mod.rs @@ -19,6 +19,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp8684_technical_reference_manual_en.pdf" }; +} + pub use chip; #[allow(unused)] diff --git a/esp-hal/src/soc/esp32c3/gpio.rs b/esp-hal/src/soc/esp32c3/gpio.rs index 5139199f0c2..80af84bb36f 100644 --- a/esp-hal/src/soc/esp32c3/gpio.rs +++ b/esp-hal/src/soc/esp32c3/gpio.rs @@ -46,6 +46,7 @@ pub const NUM_PINS: usize = 22; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u8; pub(crate) type OutputSignalType = u8; pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128; pub(crate) const INPUT_SIGNAL_MAX: u8 = 100; @@ -65,7 +66,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { SPIQ = 0, @@ -114,7 +116,8 @@ pub enum InputSignal { /// Peripheral output signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum OutputSignal { SPIQ = 0, diff --git a/esp-hal/src/soc/esp32c3/mod.rs b/esp-hal/src/soc/esp32c3/mod.rs index 0b3d43f1b60..6955b5c78c7 100644 --- a/esp-hal/src/soc/esp32c3/mod.rs +++ b/esp-hal/src/soc/esp32c3/mod.rs @@ -23,6 +23,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp32-c3_technical_reference_manual_en.pdf" }; +} + pub use chip; #[allow(unused)] diff --git a/esp-hal/src/soc/esp32c6/gpio.rs b/esp-hal/src/soc/esp32c6/gpio.rs index 5844ec08eb8..32c73525600 100644 --- a/esp-hal/src/soc/esp32c6/gpio.rs +++ b/esp-hal/src/soc/esp32c6/gpio.rs @@ -46,6 +46,7 @@ pub const NUM_PINS: usize = 31; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u8; pub(crate) type OutputSignalType = u8; pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128; pub(crate) const INPUT_SIGNAL_MAX: u8 = 124; @@ -65,7 +66,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { EXT_ADC_START = 0, @@ -169,7 +171,8 @@ pub enum InputSignal { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum OutputSignal { LEDC_LS_SIG0 = 0, diff --git a/esp-hal/src/soc/esp32c6/mod.rs b/esp-hal/src/soc/esp32c6/mod.rs index 461b5e55163..1ed7e74db87 100644 --- a/esp-hal/src/soc/esp32c6/mod.rs +++ b/esp-hal/src/soc/esp32c6/mod.rs @@ -25,6 +25,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp32-c6_technical_reference_manual_en.pdf" }; +} + pub use chip; #[allow(unused)] diff --git a/esp-hal/src/soc/esp32h2/gpio.rs b/esp-hal/src/soc/esp32h2/gpio.rs index 44d7c4ce6cd..fba6b839dd2 100644 --- a/esp-hal/src/soc/esp32h2/gpio.rs +++ b/esp-hal/src/soc/esp32h2/gpio.rs @@ -47,6 +47,7 @@ pub const NUM_PINS: usize = 28; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u8; pub(crate) type OutputSignalType = u8; pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128; pub(crate) const INPUT_SIGNAL_MAX: u8 = 124; @@ -66,7 +67,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { EXT_ADC_START = 0, @@ -151,7 +153,8 @@ pub enum InputSignal { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum OutputSignal { LEDC_LS_SIG0 = 0, diff --git a/esp-hal/src/soc/esp32h2/mod.rs b/esp-hal/src/soc/esp32h2/mod.rs index d87720b4247..9997f73fb2e 100644 --- a/esp-hal/src/soc/esp32h2/mod.rs +++ b/esp-hal/src/soc/esp32h2/mod.rs @@ -24,6 +24,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp32-h2_technical_reference_manual_en.pdf" }; +} + pub use chip; #[allow(unused)] diff --git a/esp-hal/src/soc/esp32s2/gpio.rs b/esp-hal/src/soc/esp32s2/gpio.rs index a90998f2c8f..faa6b8bcd6d 100644 --- a/esp-hal/src/soc/esp32s2/gpio.rs +++ b/esp-hal/src/soc/esp32s2/gpio.rs @@ -59,6 +59,7 @@ pub const NUM_PINS: usize = 47; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u16; pub(crate) type OutputSignalType = u16; pub(crate) const OUTPUT_SIGNAL_MAX: u16 = 256; pub(crate) const INPUT_SIGNAL_MAX: u16 = 204; @@ -126,7 +127,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { SPIQ = 0, @@ -212,7 +214,8 @@ pub enum InputSignal { /// Peripheral output signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum OutputSignal { SPIQ = 0, diff --git a/esp-hal/src/soc/esp32s2/mod.rs b/esp-hal/src/soc/esp32s2/mod.rs index 476b4b99c5e..ca2dd1dfa38 100644 --- a/esp-hal/src/soc/esp32s2/mod.rs +++ b/esp-hal/src/soc/esp32s2/mod.rs @@ -31,6 +31,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf" }; +} + pub use chip; pub(crate) mod constants { diff --git a/esp-hal/src/soc/esp32s3/gpio.rs b/esp-hal/src/soc/esp32s3/gpio.rs index 8bcb487987d..2822ec1cfa0 100644 --- a/esp-hal/src/soc/esp32s3/gpio.rs +++ b/esp-hal/src/soc/esp32s3/gpio.rs @@ -46,6 +46,7 @@ pub const NUM_PINS: usize = 49; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; +pub(crate) type InputSignalType = u16; pub(crate) type OutputSignalType = u16; pub(crate) const OUTPUT_SIGNAL_MAX: u16 = 256; pub(crate) const INPUT_SIGNAL_MAX: u16 = 189; @@ -65,7 +66,8 @@ pub(crate) fn gpio_intr_enable(int_enable: bool, nmi_enable: bool) -> u8 { /// Peripheral input signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[doc(hidden)] pub enum InputSignal { SPIQ = 0, @@ -203,8 +205,10 @@ pub enum InputSignal { /// Peripheral output signals for the GPIO mux #[allow(non_camel_case_types)] -#[derive(PartialEq, Copy, Clone)] -#[doc(hidden)] +#[derive(Debug, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[doc(hidden)] // TODO connection operations are now public on these, we might want to publish + // them pub enum OutputSignal { SPIQ = 0, SPID = 1, diff --git a/esp-hal/src/soc/esp32s3/mod.rs b/esp-hal/src/soc/esp32s3/mod.rs index be34da1364b..0d1dbde1b85 100644 --- a/esp-hal/src/soc/esp32s3/mod.rs +++ b/esp-hal/src/soc/esp32s3/mod.rs @@ -32,6 +32,12 @@ macro_rules! chip { }; } +/// A link to the Technical Reference Manual (TRM) for the chip. +#[macro_export] +macro_rules! trm_link { + () => { "https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf" }; +} + pub use chip; pub(crate) mod constants { diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index bab494fa82b..141a348a836 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -90,12 +90,7 @@ use crate::{ Rx, Tx, }, - gpio::{ - interconnect::{OutputConnection, PeripheralOutput}, - InputSignal, - NoPin, - OutputSignal, - }, + gpio::{interconnect::PeripheralOutput, InputSignal, NoPin, OutputSignal}, interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, peripherals::spi2::RegisterBlock, @@ -608,20 +603,10 @@ where let is_qspi = this.driver().sio2_input.is_some(); if is_qspi { - let mut signal = OutputConnection::from(NoPin); - - signal - .connect_input_to_peripheral(unwrap!(this.driver().sio2_input), private::Internal); - signal.connect_peripheral_to_output( - unwrap!(this.driver().sio2_output), - private::Internal, - ); - signal - .connect_input_to_peripheral(unwrap!(this.driver().sio3_input), private::Internal); - signal.connect_peripheral_to_output( - unwrap!(this.driver().sio3_output), - private::Internal, - ); + unwrap!(this.driver().sio2_input).connect_to(NoPin); + unwrap!(this.driver().sio2_output).connect_to(NoPin); + unwrap!(this.driver().sio3_input).connect_to(NoPin); + unwrap!(this.driver().sio3_output).connect_to(NoPin); } this @@ -634,10 +619,10 @@ where pub fn with_mosi(self, mosi: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(mosi); mosi.enable_output(true, private::Internal); - mosi.connect_peripheral_to_output(self.driver().mosi, private::Internal); - mosi.enable_input(true, private::Internal); - mosi.connect_input_to_peripheral(self.driver().sio0_input, private::Internal); + + self.driver().mosi.connect_to(&mut mosi); + self.driver().sio0_input.connect_to(&mut mosi); self } @@ -649,10 +634,10 @@ where pub fn with_miso(self, miso: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(miso); miso.enable_input(true, private::Internal); - miso.connect_input_to_peripheral(self.driver().miso, private::Internal); - miso.enable_output(true, private::Internal); - miso.connect_peripheral_to_output(self.driver().sio1_output, private::Internal); + + self.driver().miso.connect_to(&mut miso); + self.driver().sio1_output.connect_to(&mut miso); self } @@ -664,7 +649,7 @@ where pub fn with_sck(self, sclk: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(sclk); sclk.set_to_push_pull_output(private::Internal); - sclk.connect_peripheral_to_output(self.driver().sclk, private::Internal); + self.driver().sclk.connect_to(sclk); self } @@ -676,7 +661,7 @@ where pub fn with_cs(self, cs: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(cs); cs.set_to_push_pull_output(private::Internal); - cs.connect_peripheral_to_output(self.driver().cs, private::Internal); + self.driver().cs.connect_to(cs); self } @@ -716,8 +701,8 @@ where sio2.enable_input(true, private::Internal); sio2.enable_output(true, private::Internal); - sio2.connect_input_to_peripheral(unwrap!(self.driver().sio2_input), private::Internal); - sio2.connect_peripheral_to_output(unwrap!(self.driver().sio2_output), private::Internal); + unwrap!(self.driver().sio2_input).connect_to(&mut sio2); + unwrap!(self.driver().sio2_output).connect_to(&mut sio2); self } @@ -734,8 +719,8 @@ where sio3.enable_input(true, private::Internal); sio3.enable_output(true, private::Internal); - sio3.connect_input_to_peripheral(unwrap!(self.driver().sio3_input), private::Internal); - sio3.connect_peripheral_to_output(unwrap!(self.driver().sio3_output), private::Internal); + unwrap!(self.driver().sio3_input).connect_to(&mut sio3); + unwrap!(self.driver().sio3_output).connect_to(&mut sio3); self } diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index a4e190ecd5a..675d66b2d36 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -144,16 +144,16 @@ where // TODO: with_pins et. al. sclk.enable_input(true, private::Internal); - sclk.connect_input_to_peripheral(this.spi.sclk_signal(), private::Internal); + this.spi.sclk_signal().connect_to(sclk); mosi.enable_input(true, private::Internal); - mosi.connect_input_to_peripheral(this.spi.mosi_signal(), private::Internal); + this.spi.mosi_signal().connect_to(mosi); miso.set_to_push_pull_output(private::Internal); - miso.connect_peripheral_to_output(this.spi.miso_signal(), private::Internal); + this.spi.miso_signal().connect_to(miso); cs.enable_input(true, private::Internal); - cs.connect_input_to_peripheral(this.spi.cs_signal(), private::Internal); + this.spi.cs_signal().connect_to(cs); this } diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index b1db036b1b7..5739ffd6d85 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -806,13 +806,13 @@ where tx_pin.set_to_push_pull_output(crate::private::Internal); Pull::None }; - tx_pin.connect_peripheral_to_output(this.twai.output_signal(), crate::private::Internal); + this.twai.output_signal().connect_to(tx_pin); // Setting up RX pin later allows us to use a single pin in tests. // `set_to_push_pull_output` disables input, here we re-enable it if rx_pin // uses the same GPIO. rx_pin.init_input(rx_pull, crate::private::Internal); - rx_pin.connect_input_to_peripheral(this.twai.input_signal(), crate::private::Internal); + this.twai.input_signal().connect_to(rx_pin); // Freeze REC by changing to LOM mode this.set_mode(TwaiMode::ListenOnly); diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index f37c16a568c..812b4abd134 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -460,7 +460,7 @@ where fn with_rx(self, rx: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(rx); rx.init_input(Pull::Up, Internal); - rx.connect_input_to_peripheral(self.uart.info().rx_signal, Internal); + self.uart.info().rx_signal.connect_to(rx); self } @@ -470,7 +470,7 @@ where // Make sure we don't cause an unexpected low pulse on the pin. tx.set_output_high(true, Internal); tx.set_to_push_pull_output(Internal); - tx.connect_peripheral_to_output(self.uart.info().tx_signal, Internal); + self.uart.info().tx_signal.connect_to(tx); self } @@ -558,7 +558,7 @@ where pub fn with_rts(self, rts: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(rts); rts.set_to_push_pull_output(Internal); - rts.connect_peripheral_to_output(self.uart.info().rts_signal, Internal); + self.uart.info().rts_signal.connect_to(rts); self } @@ -766,7 +766,7 @@ where pub fn with_cts(self, cts: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(cts); cts.init_input(Pull::None, Internal); - cts.connect_input_to_peripheral(self.uart.info().cts_signal, Internal); + self.uart.info().cts_signal.connect_to(cts); self } diff --git a/hil-test/tests/spi_slave.rs b/hil-test/tests/spi_slave.rs index 4d60f3b79cb..6d8c1aeaf14 100644 --- a/hil-test/tests/spi_slave.rs +++ b/hil-test/tests/spi_slave.rs @@ -11,10 +11,8 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, - gpio::{ - interconnect::{InputSignal, OutputSignal}, - Io, - }, + gpio::{Input, Io, Level, Output, Pull}, + peripheral::Peripheral, spi::{slave::Spi, SpiMode}, Blocking, }; @@ -35,32 +33,19 @@ struct Context { } struct BitbangSpi { - sclk: OutputSignal, - mosi: OutputSignal, - miso: InputSignal, - cs: OutputSignal, + sclk: Output<'static>, + mosi: Output<'static>, + miso: Input<'static>, + cs: Output<'static>, } impl BitbangSpi { fn new( - mut sclk: OutputSignal, - mut mosi: OutputSignal, - mut miso: InputSignal, - mut cs: OutputSignal, + sclk: Output<'static>, + mosi: Output<'static>, + miso: Input<'static>, + cs: Output<'static>, ) -> 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, @@ -70,29 +55,22 @@ impl BitbangSpi { } fn assert_cs(&mut self) { - self.sclk - .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); - self.cs - .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); + self.sclk.set_level(Level::Low); + self.cs.set_level(Level::Low); } fn deassert_cs(&mut self) { - self.sclk - .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); - self.cs - .set_output_high(true, unsafe { esp_hal::Internal::conjure() }); + self.sclk.set_level(Level::Low); + self.cs.set_level(Level::High); } // 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_output_high(bit, unsafe { esp_hal::Internal::conjure() }); - self.sclk - .set_output_high(true, unsafe { esp_hal::Internal::conjure() }); + self.mosi.set_level(Level::from(bit)); + self.sclk.set_level(Level::High); let miso = self.miso.get_level().into(); - self.sclk - .set_output_high(false, unsafe { esp_hal::Internal::conjure() }); + self.sclk.set_level(Level::Low); miso } @@ -141,21 +119,19 @@ mod tests { } } - 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(); + let mosi_gpio = Output::new(mosi_pin, Level::Low); + let cs_gpio = Output::new(cs_pin, Level::High); + let sclk_gpio = Output::new(sclk_pin, Level::Low); + let miso_gpio = Input::new(miso_pin, Pull::None); + + let cs = cs_gpio.peripheral_input(); + let sclk = sclk_gpio.peripheral_input(); + let mosi = mosi_gpio.peripheral_input(); + let miso = unsafe { miso_gpio.clone_unchecked() }.into_peripheral_output(); Context { - spi: Spi::new( - peripherals.SPI2, - sclk_signal, - mosi, - miso_pin, - cs, - SpiMode::Mode1, - ), - bitbang_spi: BitbangSpi::new(sclk_pin, mosi_pin, miso, cs_pin), + spi: Spi::new(peripherals.SPI2, sclk, mosi, miso, cs, SpiMode::Mode1), + bitbang_spi: BitbangSpi::new(sclk_gpio, mosi_gpio, miso_gpio, cs_gpio), dma_channel, } }