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
This commit is contained in:
Dániel Buga 2024-11-06 14:55:34 +01:00 committed by GitHub
parent ccb3a1ba40
commit 4c5be2c907
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
35 changed files with 647 additions and 493 deletions

View File

@ -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) - 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) - 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) - `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 ### Fixed

View File

@ -5,7 +5,9 @@ use crate::{
self, self,
AlternateFunction, AlternateFunction,
AnyPin, AnyPin,
Flex,
InputPin, InputPin,
InputSignalType,
Level, Level,
NoPin, NoPin,
OutputPin, OutputPin,
@ -34,24 +36,179 @@ pub trait PeripheralInput: Into<InputConnection> + 'static {}
/// [`PeripheralInput`] as arguments instead of pin types. /// [`PeripheralInput`] as arguments instead of pin types.
pub trait PeripheralOutput: Into<OutputConnection> + 'static {} pub trait PeripheralOutput: Into<OutputConnection> + 'static {}
// Pins
impl<P: InputPin> PeripheralInput for P {} impl<P: InputPin> PeripheralInput for P {}
impl<P: OutputPin> PeripheralOutput for P {} impl<P: OutputPin> PeripheralOutput for P {}
impl PeripheralInput for InputSignal {} // Pin drivers
impl PeripheralInput for OutputSignal {} impl<P: InputPin> PeripheralInput for Flex<'static, P> {}
impl PeripheralOutput for OutputSignal {} impl<P: OutputPin> PeripheralOutput for Flex<'static, P> {}
// Placeholders
impl PeripheralInput for NoPin {} impl PeripheralInput for NoPin {}
impl PeripheralOutput for NoPin {} impl PeripheralOutput for NoPin {}
impl PeripheralInput for Level {} impl PeripheralInput for Level {}
impl PeripheralOutput 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 PeripheralInput for OutputConnection {}
impl PeripheralOutput 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<P = impl PeripheralInput>) {
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<P = impl PeripheralOutput>) {
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<P = impl PeripheralOutput>) {
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. /// A configurable input signal between a peripheral and a GPIO pin.
/// ///
/// Multiple input signals can be connected to one pin. /// Multiple input signals can be connected to one pin.
@ -69,6 +226,15 @@ where
} }
} }
impl<P> From<Flex<'static, P>> for InputSignal
where
P: InputPin,
{
fn from(input: Flex<'static, P>) -> Self {
Self::new(input.degrade())
}
}
impl Clone for InputSignal { impl Clone for InputSignal {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
@ -113,7 +279,7 @@ impl InputSignal {
self.is_inverted = !self.is_inverted; 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. /// input signal.
/// ///
/// Calling this function multiple times toggles the setting. /// Calling this function multiple times toggles the setting.
@ -122,64 +288,13 @@ impl InputSignal {
self 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. /// Connect the pin to a peripheral input signal.
/// ///
/// Since there can only be one input signal connected to a peripheral at a /// Since there can only be one input signal connected to a peripheral at a
/// time, this function will disconnect any previously connected input /// time, this function will disconnect any previously connected input
/// signals. /// signals.
fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal, _: private::Internal) { fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal) {
let signal_nr = signal as usize; connect_pin_to_input_signal(&mut self.pin, signal, self.is_inverted, true);
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());
} }
delegate::delegate! { delegate::delegate! {
@ -190,7 +305,44 @@ impl InputSignal {
pub fn init_input(&self, pull: Pull, _internal: private::Internal); pub fn init_input(&self, pull: Pull, _internal: private::Internal);
pub fn is_input_high(&self, _internal: private::Internal) -> bool; 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(&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<P> From<Flex<'static, P>> for OutputSignal
where
P: OutputPin,
{
fn from(input: Flex<'static, P>) -> Self {
Self::new(input.degrade())
}
}
impl Peripheral for OutputSignal { impl Peripheral for OutputSignal {
type P = Self; type P = Self;
@ -245,7 +406,7 @@ impl OutputSignal {
self.is_inverted = !self.is_inverted; 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. /// output signal.
/// ///
/// Calling this function multiple times toggles the setting. /// Calling this function multiple times toggles the setting.
@ -254,139 +415,18 @@ impl OutputSignal {
self 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. /// Connect the pin to a peripheral output signal.
fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal, _: private::Internal) { fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal) {
let af = if self.is_inverted { connect_peripheral_to_output(&mut self.pin, signal, self.is_inverted, true, true, false);
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 /// Clears the entry in the GPIO matrix / Io mux that associates this output
/// pin with a previously connected [signal](`OutputSignal`). Any other /// pin with a previously connected [signal](`gpio::OutputSignal`). Any
/// outputs connected to the peripheral remain intact. /// other outputs connected to the peripheral remain intact.
fn disconnect_from_peripheral_output( fn disconnect_from_peripheral_output(&mut self, signal: gpio::OutputSignal) {
&mut self, disconnect_peripheral_output_from_pin(&mut self.pin, signal);
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());
} }
delegate::delegate! { delegate::delegate! {
@ -397,7 +437,6 @@ impl OutputSignal {
pub fn init_input(&self, pull: Pull, _internal: private::Internal); pub fn init_input(&self, pull: Pull, _internal: private::Internal);
pub fn is_input_high(&self, _internal: private::Internal) -> bool; 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(&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 output_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::OutputSignal)];
pub fn set_to_open_drain_output(&mut self, _internal: private::Internal); 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_output_high(&mut self, on: bool, _internal: private::Internal);
pub fn set_drive_strength(&mut self, strength: gpio::DriveStrength, _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_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_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 internal_pull_down_in_sleep_mode(&mut self, on: bool, _internal: private::Internal);
pub fn is_set_high(&self, _internal: private::Internal) -> bool; 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)] #[derive(Clone)]
enum InputConnectionInner { enum InputConnectionInner {
Input(InputSignal), Input(InputSignal),
DirectInput(DirectInputSignal),
Constant(Level), 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 /// This is mainly intended for internal use, but it can be used to connect
/// peripherals within the MCU without external hardware. /// peripherals within the MCU without external hardware.
@ -471,15 +558,33 @@ impl From<OutputSignal> for InputConnection {
} }
} }
impl From<DirectOutputSignal> for InputConnection {
fn from(output_signal: DirectOutputSignal) -> Self {
Self(InputConnectionInner::DirectInput(DirectInputSignal::new(
output_signal.pin,
)))
}
}
impl From<OutputConnection> for InputConnection { impl From<OutputConnection> for InputConnection {
fn from(conn: OutputConnection) -> Self { fn from(conn: OutputConnection) -> Self {
match conn.0 { match conn.0 {
OutputConnectionInner::Output(inner) => inner.into(), OutputConnectionInner::Output(inner) => inner.into(),
OutputConnectionInner::DirectOutput(inner) => inner.into(),
OutputConnectionInner::Constant(inner) => inner.into(), OutputConnectionInner::Constant(inner) => inner.into(),
} }
} }
} }
impl<P> From<Flex<'static, P>> for InputConnection
where
P: InputPin,
{
fn from(pin: Flex<'static, P>) -> Self {
pin.peripheral_input().into()
}
}
impl Sealed for InputConnection {} impl Sealed for InputConnection {}
impl InputConnection { impl InputConnection {
@ -487,6 +592,7 @@ impl InputConnection {
#[doc(hidden)] #[doc(hidden)]
to match &self.0 { to match &self.0 {
InputConnectionInner::Input(pin) => pin, InputConnectionInner::Input(pin) => pin,
InputConnectionInner::DirectInput(pin) => pin,
InputConnectionInner::Constant(level) => level, InputConnectionInner::Constant(level) => level,
} { } {
pub fn pull_direction(&self, pull: Pull, _internal: private::Internal); pub fn pull_direction(&self, pull: Pull, _internal: private::Internal);
@ -498,22 +604,22 @@ impl InputConnection {
#[doc(hidden)] #[doc(hidden)]
to match &mut self.0 { to match &mut self.0 {
InputConnectionInner::Input(pin) => pin, InputConnectionInner::Input(pin) => pin,
InputConnectionInner::DirectInput(pin) => pin,
InputConnectionInner::Constant(level) => level, InputConnectionInner::Constant(level) => level,
} { } {
pub fn enable_input(&mut self, on: bool, _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); fn connect_input_to_peripheral(&mut self, signal: gpio::InputSignal);
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);
} }
} }
} }
enum OutputConnectionInner { enum OutputConnectionInner {
Output(OutputSignal), Output(OutputSignal),
DirectOutput(DirectOutputSignal),
Constant(Level), 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 /// This is mainly intended for internal use, but it can be used to connect
/// peripherals within the MCU without external hardware. /// peripherals within the MCU without external hardware.
@ -527,6 +633,9 @@ impl Peripheral for OutputConnection {
unsafe fn clone_unchecked(&self) -> Self::P { unsafe fn clone_unchecked(&self) -> Self::P {
match self { match self {
Self(OutputConnectionInner::Output(signal)) => Self::from(signal.clone_unchecked()), 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), Self(OutputConnectionInner::Constant(level)) => Self::from(*level),
} }
} }
@ -559,54 +668,55 @@ impl From<OutputSignal> for OutputConnection {
} }
} }
impl<P> From<Flex<'static, P>> for OutputConnection
where
P: OutputPin,
{
fn from(pin: Flex<'static, P>) -> Self {
pin.into_peripheral_output().into()
}
}
impl From<DirectOutputSignal> for OutputConnection {
fn from(signal: DirectOutputSignal) -> Self {
Self(OutputConnectionInner::DirectOutput(signal))
}
}
impl OutputConnection { impl OutputConnection {
delegate::delegate! { delegate::delegate! {
#[doc(hidden)] #[doc(hidden)]
to match &self.0 { to match &self.0 {
OutputConnectionInner::Output(pin) => pin, OutputConnectionInner::Output(pin) => pin,
OutputConnectionInner::DirectOutput(pin) => pin,
OutputConnectionInner::Constant(level) => level, OutputConnectionInner::Constant(level) => level,
} { } {
pub fn is_input_high(&self, _internal: private::Internal) -> bool; pub fn is_input_high(&self, _internal: private::Internal) -> bool;
pub fn input_signals(&self, _internal: private::Internal) -> &[(AlternateFunction, gpio::InputSignal)]; 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)] #[doc(hidden)]
to match &mut self.0 { to match &mut self.0 {
OutputConnectionInner::Output(pin) => pin, OutputConnectionInner::Output(pin) => pin,
OutputConnectionInner::DirectOutput(pin) => pin,
OutputConnectionInner::Constant(level) => level, OutputConnectionInner::Constant(level) => level,
} { } {
pub fn pull_direction(&mut self, pull: Pull, _internal: private::Internal); pub fn pull_direction(&mut self, pull: Pull, _internal: private::Internal);
pub fn init_input(&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(&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_open_drain_output(&mut self, _internal: private::Internal);
pub fn set_to_push_pull_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 enable_output(&mut self, on: bool, _internal: private::Internal);
pub fn set_output_high(&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 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_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_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 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); fn connect_peripheral_to_output(&mut self, signal: gpio::OutputSignal);
pub fn disconnect_from_peripheral_output(&mut self, signal: gpio::OutputSignal, _internal: private::Internal); fn disconnect_from_peripheral_output(&mut self, signal: gpio::OutputSignal);
} }
} }
} }

View File

@ -1,39 +1,49 @@
//! # General Purpose I/Os (GPIO) //! # General Purpose Input/Output (GPIO)
//! //!
//! ## Overview //! ## Overview
//! //!
//! Each pin can be used as a general-purpose I/O, or be connected to one or //! Each pin can be used as a general-purpose I/O, or be connected to one or
//! more internal peripheral signals. //! 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 //! The [`Io`] struct can also be used to configure the interrupt handler for
//! pin mode, direction, and manipulating the pin state (setting high/low, //! GPIO interrupts. For more information, see the
//! toggling). It provides an interface to interact with GPIO pins on ESP chips, //! [`Io::set_interrupt_handler`].
//! allowing developers to control and read the state of the pins.
//! //!
//! ## 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 //! Each pin is a different type initially. Internally, `esp-hal` will often
//! provide a common interface for GPIO pins. //! 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 //! Pin drivers can be created using [`Flex::new`], [`Input::new`],
//! designed struct from the pac struct `GPIO` and `IO_MUX` using [`Io::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. //! Sometimes you may want to connect peripherals together without using
//! - [Output] and [OutputOpenDrain] pins can be used as digital outputs. //! external hardware. The [`interconnect`] module provides tools to achieve
//! - [Flex] pin is a pin that can be used as an input and output pin. //! this using GPIO pins.
//! - [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.
//! //!
//! ### GPIO interconnect //! To obtain peripheral signals, use the [`GpioPin::split`] method to split a
//! //! pin into an input and output signal. Alternatively, you may use
//! Each GPIO can be connected to one output signal and any number of input //! [`Flex::split`], [`Flex::into_peripheral_output`],
//! signals. This allows connections inside of the MCU without allocating and //! [`Flex::peripheral_input`], and similar methods to split a pin driver into
//! connecting multiple pins for loopback functionality. //! an input and output signal. You can then pass these signals to the
//! peripheral drivers similar to how you would pass a pin.
//! //!
//! ## Examples //! ## Examples
//! //!
@ -49,14 +59,14 @@
//! //!
//! ### Blink an LED //! ### 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. //! See the [Inverting TX and RX Pins] example of the UART documentation.
//! //!
//! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/ //! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/
//! [Blinky]: ../index.html#blinky //! [Inverting TX and RX Pins]: crate::uart#inverting-rx-and-tx-pins
//! [Inverting TX and RX Pins]: ../uart/index.html#inverting-tx-and-rx-pins
use portable_atomic::{AtomicPtr, Ordering}; use portable_atomic::{AtomicPtr, Ordering};
use procmacros::ram; use procmacros::ram;
@ -217,9 +227,13 @@ pub enum DriveStrength {
/// ///
/// GPIO pins can be configured for various functions, such as GPIO /// GPIO pins can be configured for various functions, such as GPIO
/// or being directly connected to a peripheral's signal like UART, SPI, etc. /// 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 /// a pin can perform, rather than using it as a general-purpose input or
/// output. /// 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)] #[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum AlternateFunction { pub enum AlternateFunction {
@ -384,12 +398,6 @@ pub trait InputPin: Pin + Into<AnyPin> + '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 /// The current state of the input
#[doc(hidden)] #[doc(hidden)]
fn is_input_high(&self, _: private::Internal) -> bool { fn is_input_high(&self, _: private::Internal) -> bool {
@ -405,6 +413,7 @@ pub trait OutputPin: Pin + Into<AnyPin> + 'static {
&mut self, &mut self,
alternate: AlternateFunction, alternate: AlternateFunction,
open_drain: bool, open_drain: bool,
input_enable: Option<bool>,
_: private::Internal, _: private::Internal,
) { ) {
self.enable_output(true, private::Internal); self.enable_output(true, private::Internal);
@ -422,7 +431,9 @@ pub trait OutputPin: Pin + Into<AnyPin> + 'static {
get_io_mux_reg(self.number()).modify(|_, w| unsafe { get_io_mux_reg(self.number()).modify(|_, w| unsafe {
w.mcu_sel().bits(alternate as u8); 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.fun_drv().bits(DriveStrength::I20mA as u8);
w.slp_sel().clear_bit() w.slp_sel().clear_bit()
}); });
@ -431,13 +442,13 @@ pub trait OutputPin: Pin + Into<AnyPin> + 'static {
/// Configure open-drain mode /// Configure open-drain mode
#[doc(hidden)] #[doc(hidden)]
fn set_to_open_drain_output(&mut self, _: private::Internal) { 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 /// Configure output mode
#[doc(hidden)] #[doc(hidden)]
fn set_to_push_pull_output(&mut self, _: private::Internal) { 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 /// Set the pin's level to high or low
@ -461,12 +472,6 @@ pub trait OutputPin: Pin + Into<AnyPin> + 'static {
.modify(|_, w| w.pad_driver().bit(on)); .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 /// Configure internal pull-up resistor in sleep mode
#[doc(hidden)] #[doc(hidden)]
fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _: private::Internal) { fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _: private::Internal) {
@ -1115,9 +1120,9 @@ pub struct Output<'d, P = AnyPin> {
impl<P> private::Sealed for Output<'_, P> {} impl<P> private::Sealed for Output<'_, P> {}
impl<P> Peripheral for Output<'_, P> { impl<'d, P> Peripheral for Output<'d, P> {
type P = P; type P = Flex<'d, P>;
unsafe fn clone_unchecked(&self) -> P { unsafe fn clone_unchecked(&self) -> Self::P {
self.pin.clone_unchecked() self.pin.clone_unchecked()
} }
} }
@ -1229,9 +1234,9 @@ pub struct Input<'d, P = AnyPin> {
impl<P> private::Sealed for Input<'_, P> {} impl<P> private::Sealed for Input<'_, P> {}
impl<P> Peripheral for Input<'_, P> { impl<'d, P> Peripheral for Input<'d, P> {
type P = P; type P = Flex<'d, P>;
unsafe fn clone_unchecked(&self) -> P { unsafe fn clone_unchecked(&self) -> Self::P {
self.pin.clone_unchecked() self.pin.clone_unchecked()
} }
} }
@ -1350,9 +1355,9 @@ pub struct OutputOpenDrain<'d, P = AnyPin> {
impl<P> private::Sealed for OutputOpenDrain<'_, P> {} impl<P> private::Sealed for OutputOpenDrain<'_, P> {}
impl<P> Peripheral for OutputOpenDrain<'_, P> { impl<'d, P> Peripheral for OutputOpenDrain<'d, P> {
type P = P; type P = Flex<'d, P>;
unsafe fn clone_unchecked(&self) -> P { unsafe fn clone_unchecked(&self) -> Self::P {
self.pin.clone_unchecked() self.pin.clone_unchecked()
} }
} }
@ -1498,10 +1503,12 @@ pub struct Flex<'d, P = AnyPin> {
impl<P> private::Sealed for Flex<'_, P> {} impl<P> private::Sealed for Flex<'_, P> {}
impl<P> Peripheral for Flex<'_, P> { impl<'d, P> Peripheral for Flex<'d, P> {
type P = P; type P = Self;
unsafe fn clone_unchecked(&self) -> P { unsafe fn clone_unchecked(&self) -> Self::P {
core::ptr::read(&*self.pin as *const _) 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<P: Pin> 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<P: RtcPin> 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<P: RtcPinWithResistors> 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 { pub(crate) mod internal {
use super::*; use super::*;
@ -1773,10 +1816,17 @@ pub(crate) mod internal {
&mut self, &mut self,
alternate: AlternateFunction, alternate: AlternateFunction,
open_drain: bool, open_drain: bool,
input_enable: Option<bool>,
_: private::Internal, _: private::Internal,
) { ) {
handle_gpio_output!(&mut self.0, target, { 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) { fn internal_pull_up_in_sleep_mode(&mut self, on: bool, _: private::Internal) {
handle_gpio_output!(&mut self.0, target, { handle_gpio_output!(&mut self.0, target, {
OutputPin::internal_pull_up_in_sleep_mode(target, on, private::Internal) OutputPin::internal_pull_up_in_sleep_mode(target, on, private::Internal)

View File

@ -6,6 +6,7 @@
// polluting the main module. // polluting the main module.
use super::*; use super::*;
use crate::gpio::interconnect::connect_input_signal;
impl crate::peripheral::Peripheral for Level { impl crate::peripheral::Peripheral for Level {
type P = Self; 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(&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 { pub(crate) fn is_input_high(&self, _: private::Internal) -> bool {
*self == Level::High *self == Level::High
} }
#[doc(hidden)] #[doc(hidden)]
pub(crate) fn connect_input_to_peripheral( pub(crate) fn connect_input_to_peripheral(&mut self, signal: InputSignal) {
&mut self,
signal: InputSignal,
_: private::Internal,
) {
let value = match self { let value = match self {
Level::High => ONE_INPUT, Level::High => ONE_INPUT,
Level::Low => ZERO_INPUT, Level::Low => ZERO_INPUT,
}; };
unsafe { GPIO::steal() } connect_input_signal(signal, value, false, true);
.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)
});
} }
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_open_drain_output(&mut self, _: private::Internal) {}
pub(crate) fn set_to_push_pull_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 enable_output(&mut self, _on: bool, _: private::Internal) {}
pub(crate) fn set_output_high(&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 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_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_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) {} 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( pub(crate) fn connect_peripheral_to_output(&mut self, _signal: OutputSignal) {}
&mut self,
_signal: OutputSignal,
_: private::Internal,
) {
}
pub(crate) fn disconnect_from_peripheral_output( pub(crate) fn disconnect_from_peripheral_output(&mut self, _signal: OutputSignal) {}
&mut self,
_signal: OutputSignal,
_: private::Internal,
) {
}
} }
/// Placeholder pin, used when no pin is required when using a peripheral. /// Placeholder pin, used when no pin is required when using a peripheral.

View File

@ -336,15 +336,15 @@ where
scl.enable_input(true, crate::private::Internal); scl.enable_input(true, crate::private::Internal);
scl.pull_direction(Pull::Up, crate::private::Internal); scl.pull_direction(Pull::Up, crate::private::Internal);
scl.connect_input_to_peripheral(i2c.i2c.scl_input_signal(), crate::private::Internal); i2c.i2c.scl_input_signal().connect_to(&mut scl);
scl.connect_peripheral_to_output(i2c.i2c.scl_output_signal(), crate::private::Internal); i2c.i2c.scl_output_signal().connect_to(&mut scl);
sda.set_to_open_drain_output(crate::private::Internal); sda.set_to_open_drain_output(crate::private::Internal);
sda.enable_input(true, crate::private::Internal); sda.enable_input(true, crate::private::Internal);
sda.pull_direction(Pull::Up, crate::private::Internal); sda.pull_direction(Pull::Up, crate::private::Internal);
sda.connect_input_to_peripheral(i2c.i2c.sda_input_signal(), crate::private::Internal); i2c.i2c.sda_input_signal().connect_to(&mut sda);
sda.connect_peripheral_to_output(i2c.i2c.sda_output_signal(), crate::private::Internal); i2c.i2c.sda_output_signal().connect_to(&mut sda);
i2c.i2c.setup(frequency, None); i2c.i2c.setup(frequency, None);
i2c i2c

View File

@ -469,7 +469,7 @@ where
pub fn with_mclk<P: PeripheralOutput>(self, pin: impl Peripheral<P = P> + 'd) -> Self { pub fn with_mclk<P: PeripheralOutput>(self, pin: impl Peripheral<P = P> + 'd) -> Self {
crate::into_mapped_ref!(pin); crate::into_mapped_ref!(pin);
pin.set_to_push_pull_output(crate::private::Internal); 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 self
} }
@ -826,7 +826,7 @@ mod private {
{ {
crate::into_mapped_ref!(pin); crate::into_mapped_ref!(pin);
pin.set_to_push_pull_output(private::Internal); 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 self
} }
@ -837,7 +837,7 @@ mod private {
{ {
crate::into_mapped_ref!(pin); crate::into_mapped_ref!(pin);
pin.set_to_push_pull_output(private::Internal); 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 self
} }
@ -848,7 +848,7 @@ mod private {
{ {
crate::into_mapped_ref!(pin); crate::into_mapped_ref!(pin);
pin.set_to_push_pull_output(private::Internal); 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 self
} }
@ -885,7 +885,7 @@ mod private {
{ {
crate::into_mapped_ref!(pin); crate::into_mapped_ref!(pin);
pin.set_to_push_pull_output(private::Internal); 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 self
} }
@ -896,7 +896,7 @@ mod private {
{ {
crate::into_mapped_ref!(pin); crate::into_mapped_ref!(pin);
pin.set_to_push_pull_output(private::Internal); 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 self
} }
@ -907,7 +907,7 @@ mod private {
{ {
crate::into_mapped_ref!(pin); crate::into_mapped_ref!(pin);
pin.init_input(crate::gpio::Pull::None, private::Internal); 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 self
} }

View File

@ -61,7 +61,7 @@ use crate::{
}, },
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::{i2s0::RegisterBlock, I2S0, I2S1}, peripherals::{i2s0::RegisterBlock, I2S0, I2S1},
private, private::Internal,
system::PeripheralClockControl, system::PeripheralClockControl,
Async, Async,
Mode, Mode,
@ -123,8 +123,8 @@ impl<'d> TxPins<'d> for TxSixteenBits<'d> {
crate::into_ref!(instance); crate::into_ref!(instance);
let bits = self.bus_width(); let bits = self.bus_width();
for (i, pin) in self.pins.iter_mut().enumerate() { for (i, pin) in self.pins.iter_mut().enumerate() {
pin.set_to_push_pull_output(private::Internal); pin.set_to_push_pull_output(Internal);
pin.connect_peripheral_to_output(instance.data_out_signal(i, bits), private::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); crate::into_ref!(instance);
let bits = self.bus_width(); let bits = self.bus_width();
for (i, pin) in self.pins.iter_mut().enumerate() { for (i, pin) in self.pins.iter_mut().enumerate() {
pin.set_to_push_pull_output(private::Internal); pin.set_to_push_pull_output(Internal);
pin.connect_peripheral_to_output(instance.data_out_signal(i, bits), private::Internal); instance.data_out_signal(i, bits).connect_to(pin);
} }
} }
} }
@ -228,8 +228,8 @@ where
// configure the I2S peripheral for parallel mode // configure the I2S peripheral for parallel mode
i2s.setup(frequency, pins.bus_width()); i2s.setup(frequency, pins.bus_width());
// setup the clock pin // setup the clock pin
clock_pin.set_to_push_pull_output(private::Internal); clock_pin.set_to_push_pull_output(Internal);
clock_pin.connect_peripheral_to_output(i2s.ws_signal(), private::Internal); i2s.ws_signal().connect_to(clock_pin);
pins.configure(i2s.reborrow()); pins.configure(i2s.reborrow());
Self { Self {

View File

@ -243,8 +243,10 @@ impl<'d> Camera<'d> {
mclk: impl Peripheral<P = MCLK> + 'd, mclk: impl Peripheral<P = MCLK> + 'd,
) -> Self { ) -> Self {
crate::into_mapped_ref!(mclk); crate::into_mapped_ref!(mclk);
mclk.set_to_push_pull_output(crate::private::Internal); 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 self
} }
@ -256,7 +258,7 @@ impl<'d> Camera<'d> {
crate::into_mapped_ref!(pclk); crate::into_mapped_ref!(pclk);
pclk.init_input(Pull::None, crate::private::Internal); 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 self
} }
@ -271,9 +273,9 @@ impl<'d> Camera<'d> {
crate::into_mapped_ref!(vsync, h_enable); crate::into_mapped_ref!(vsync, h_enable);
vsync.init_input(Pull::None, crate::private::Internal); 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.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 self.lcd_cam
.cam_ctrl1() .cam_ctrl1()
@ -297,11 +299,11 @@ impl<'d> Camera<'d> {
crate::into_mapped_ref!(vsync, hsync, h_enable); crate::into_mapped_ref!(vsync, hsync, h_enable);
vsync.init_input(Pull::None, crate::private::Internal); 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.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.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 self.lcd_cam
.cam_ctrl1() .cam_ctrl1()
@ -514,9 +516,9 @@ impl RxEightBits {
(pin_7, InputSignal::CAM_DATA_7), (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.init_input(Pull::None, crate::private::Internal);
pin.connect_input_to_peripheral(signal, crate::private::Internal); signal.connect_to(pin);
} }
Self { _pins: () } Self { _pins: () }
@ -591,9 +593,9 @@ impl RxSixteenBits {
(pin_15, InputSignal::CAM_DATA_15), (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.init_input(Pull::None, crate::private::Internal);
pin.connect_input_to_peripheral(signal, crate::private::Internal); signal.connect_to(pin);
} }
Self { _pins: () } Self { _pins: () }

View File

@ -239,7 +239,7 @@ impl<'d, DM: Mode> I8080<'d, DM> {
pub fn with_cs<CS: PeripheralOutput>(self, cs: impl Peripheral<P = CS> + 'd) -> Self { pub fn with_cs<CS: PeripheralOutput>(self, cs: impl Peripheral<P = CS> + 'd) -> Self {
crate::into_mapped_ref!(cs); crate::into_mapped_ref!(cs);
cs.set_to_push_pull_output(crate::private::Internal); 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 self
} }
@ -253,10 +253,10 @@ impl<'d, DM: Mode> I8080<'d, DM> {
crate::into_mapped_ref!(dc, wrx); crate::into_mapped_ref!(dc, wrx);
dc.set_to_push_pull_output(crate::private::Internal); 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.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 self
} }
@ -628,9 +628,9 @@ impl<'d> TxPins for TxEightBits<'d> {
OutputSignal::LCD_DATA_7, 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.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, 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.set_to_push_pull_output(crate::private::Internal);
pin.connect_peripheral_to_output(*signal, crate::private::Internal); signal.connect_to(pin);
} }
} }
} }

View File

@ -610,8 +610,7 @@ where
Number::Channel7 => OutputSignal::LEDC_LS_SIG7, Number::Channel7 => OutputSignal::LEDC_LS_SIG7,
}; };
self.output_pin signal.connect_to(&mut self.output_pin);
.connect_peripheral_to_output(signal, crate::private::Internal);
} else { } else {
return Err(Error::Timer); return Err(Error::Timer);
} }

View File

@ -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)] #[doc(hidden)]
/// Shorthand to define enums with From implementations. /// Shorthand to define enums with From implementations.
#[macro_export] #[macro_export]

View File

@ -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_actions(config.actions);
pin.set_update_method(config.update_method); pin.set_update_method(config.update_method);
let output_signal = PWM::output_signal::<OP, IS_A>(); PWM::output_signal::<OP, IS_A>().connect_to(&mut pin.pin);
pin.pin
.connect_peripheral_to_output(output_signal, private::Internal);
pin.pin.enable_output(true, private::Internal); pin.pin.enable_output(true, private::Internal);
pin pin

View File

@ -43,7 +43,6 @@ use crate::{
gpio::InputSignal, gpio::InputSignal,
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals, peripherals,
private::Internal,
system::{Peripheral as PeripheralEnable, PeripheralClockControl}, system::{Peripheral as PeripheralEnable, PeripheralClockControl},
}; };
@ -99,10 +98,10 @@ impl<'d> Usb<'d> {
use crate::gpio::Level; use crate::gpio::Level;
Level::High.connect_input_to_peripheral(InputSignal::USB_OTG_IDDIG, Internal); // connected connector is mini-B side InputSignal::USB_OTG_IDDIG.connect_to(Level::High); // connected connector is mini-B side
Level::High.connect_input_to_peripheral(InputSignal::USB_SRP_BVALID, Internal); // HIGH to force USB device mode InputSignal::USB_SRP_BVALID.connect_to(Level::High); // HIGH to force USB device mode
Level::High.connect_input_to_peripheral(InputSignal::USB_OTG_VBUSVALID, Internal); // receiving a valid Vbus from device InputSignal::USB_OTG_VBUSVALID.connect_to(Level::High); // receiving a valid Vbus from device
Level::Low.connect_input_to_peripheral(InputSignal::USB_OTG_AVALID, Internal); InputSignal::USB_OTG_AVALID.connect_to(Level::Low);
} }
} }

View File

@ -292,10 +292,7 @@ impl<'d> ClkOutPin<'d> {
impl TxClkPin for ClkOutPin<'_> { impl TxClkPin for ClkOutPin<'_> {
fn configure(&mut self) { fn configure(&mut self) {
self.pin.set_to_push_pull_output(crate::private::Internal); self.pin.set_to_push_pull_output(crate::private::Internal);
self.pin.connect_peripheral_to_output( crate::gpio::OutputSignal::PARL_TX_CLK.connect_to(&mut self.pin);
crate::gpio::OutputSignal::PARL_TX_CLK,
crate::private::Internal,
);
} }
} }
@ -318,10 +315,7 @@ impl TxClkPin for ClkInPin<'_> {
self.pin self.pin
.init_input(crate::gpio::Pull::None, crate::private::Internal); .init_input(crate::gpio::Pull::None, crate::private::Internal);
self.pin.connect_input_to_peripheral( crate::gpio::InputSignal::PARL_TX_CLK.connect_to(&mut self.pin);
crate::gpio::InputSignal::PARL_TX_CLK,
crate::private::Internal,
);
} }
} }
@ -348,10 +342,7 @@ impl RxClkPin for RxClkInPin<'_> {
self.pin self.pin
.init_input(crate::gpio::Pull::None, crate::private::Internal); .init_input(crate::gpio::Pull::None, crate::private::Internal);
self.pin.connect_input_to_peripheral( crate::gpio::InputSignal::PARL_RX_CLK.connect_to(&mut self.pin);
crate::gpio::InputSignal::PARL_RX_CLK,
crate::private::Internal,
);
Instance::set_rx_clk_edge_sel(self.sample_edge); Instance::set_rx_clk_edge_sel(self.sample_edge);
} }
@ -390,10 +381,7 @@ where
self.tx_pins.configure()?; self.tx_pins.configure()?;
self.valid_pin self.valid_pin
.set_to_push_pull_output(crate::private::Internal); .set_to_push_pull_output(crate::private::Internal);
self.valid_pin.connect_peripheral_to_output( Instance::tx_valid_pin_signal().connect_to(&mut self.valid_pin);
Instance::tx_valid_pin_signal(),
crate::private::Internal,
);
Instance::set_tx_hw_valid_en(true); Instance::set_tx_hw_valid_en(true);
Ok(()) Ok(())
} }
@ -464,7 +452,7 @@ macro_rules! tx_pins {
fn configure(&mut self) -> Result<(), Error>{ fn configure(&mut self) -> Result<(), Error>{
$( $(
self.[< pin_ $pin:lower >].set_to_push_pull_output(crate::private::Internal); 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 >]); private::Instance::set_tx_bit_width( private::WidSel::[< Bits $width >]);
@ -584,8 +572,7 @@ where
self.rx_pins.configure()?; self.rx_pins.configure()?;
self.valid_pin self.valid_pin
.init_input(crate::gpio::Pull::None, crate::private::Internal); .init_input(crate::gpio::Pull::None, crate::private::Internal);
self.valid_pin Instance::rx_valid_pin_signal().connect_to(&mut self.valid_pin);
.connect_input_to_peripheral(Instance::rx_valid_pin_signal(), crate::private::Internal);
Instance::set_rx_sw_en(false); Instance::set_rx_sw_en(false);
if let Some(sel) = self.enable_mode.pulse_submode_sel() { if let Some(sel) = self.enable_mode.pulse_submode_sel() {
Instance::set_rx_pulse_submode_sel(sel); Instance::set_rx_pulse_submode_sel(sel);
@ -684,7 +671,7 @@ macro_rules! rx_pins {
fn configure(&mut self) -> Result<(), Error> { fn configure(&mut self) -> Result<(), Error> {
$( $(
self.[< pin_ $pin:lower >].init_input(crate::gpio::Pull::None, crate::private::Internal); 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 >]); private::Instance::set_rx_bit_width( private::WidSel::[< Bits $width >]);

View File

@ -118,7 +118,7 @@ impl<const UNIT: usize, const NUM: usize> Channel<'_, UNIT, NUM> {
if (signal as usize) <= crate::gpio::INPUT_SIGNAL_MAX as usize { if (signal as usize) <= crate::gpio::INPUT_SIGNAL_MAX as usize {
crate::into_mapped_ref!(source); crate::into_mapped_ref!(source);
source.enable_input(true, crate::private::Internal); source.enable_input(true, crate::private::Internal);
source.connect_input_to_peripheral(signal, crate::private::Internal); signal.connect_to(source);
} }
self self
} }
@ -176,7 +176,7 @@ impl<const UNIT: usize, const NUM: usize> Channel<'_, UNIT, NUM> {
if (signal as usize) <= crate::gpio::INPUT_SIGNAL_MAX as usize { if (signal as usize) <= crate::gpio::INPUT_SIGNAL_MAX as usize {
crate::into_mapped_ref!(source); crate::into_mapped_ref!(source);
source.enable_input(true, crate::private::Internal); source.enable_input(true, crate::private::Internal);
source.connect_input_to_peripheral(signal, crate::private::Internal); signal.connect_to(source);
} }
self self
} }

View File

@ -312,8 +312,8 @@ fn configure_rx_channel<'d, P: PeripheralInput, T: RxChannelInternal<M>, M: crat
} }
crate::into_mapped_ref!(pin); crate::into_mapped_ref!(pin);
pin.init_input(crate::gpio::Pull::None, crate::Internal); pin.init_input(crate::gpio::Pull::None, crate::private::Internal);
pin.connect_input_to_peripheral(T::input_signal(), crate::Internal); T::input_signal().connect_to(pin);
T::set_divider(config.clk_divider); T::set_divider(config.clk_divider);
T::set_carrier( T::set_carrier(
@ -333,8 +333,8 @@ fn configure_tx_channel<'d, P: PeripheralOutput, T: TxChannelInternal<M>, M: cra
config: TxChannelConfig, config: TxChannelConfig,
) -> Result<T, Error> { ) -> Result<T, Error> {
crate::into_mapped_ref!(pin); crate::into_mapped_ref!(pin);
pin.set_to_push_pull_output(crate::Internal); pin.set_to_push_pull_output(crate::private::Internal);
pin.connect_peripheral_to_output(T::output_signal(), crate::Internal); T::output_signal().connect_to(pin);
T::set_divider(config.clk_divider); T::set_divider(config.clk_divider);
T::set_carrier( T::set_carrier(

View File

@ -53,6 +53,7 @@ pub const NUM_PINS: usize = 40;
pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0;
pub(crate) type InputSignalType = u16;
pub(crate) type OutputSignalType = u16; pub(crate) type OutputSignalType = u16;
pub(crate) const OUTPUT_SIGNAL_MAX: u16 = 548; pub(crate) const OUTPUT_SIGNAL_MAX: u16 = 548;
pub(crate) const INPUT_SIGNAL_MAX: u16 = 539; 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 /// Peripheral input signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum InputSignal { pub enum InputSignal {
SPICLK = 0, SPICLK = 0,
@ -310,7 +312,8 @@ pub enum InputSignal {
/// Peripheral output signals for the GPIO mux /// Peripheral output signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum OutputSignal { pub enum OutputSignal {
SPICLK = 0, SPICLK = 0,

View File

@ -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 use chip;
pub(crate) mod constants { pub(crate) mod constants {

View File

@ -45,6 +45,7 @@ pub const NUM_PINS: usize = 21;
pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0;
pub(crate) type InputSignalType = u8;
pub(crate) type OutputSignalType = u8; pub(crate) type OutputSignalType = u8;
pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128; pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128;
pub(crate) const INPUT_SIGNAL_MAX: u8 = 100; 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 /// Peripheral input signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum InputSignal { pub enum InputSignal {
SPIQ = 0, SPIQ = 0,
@ -104,7 +106,8 @@ pub enum InputSignal {
/// Peripheral output signals for the GPIO mux /// Peripheral output signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum OutputSignal { pub enum OutputSignal {
SPIQ = 0, SPIQ = 0,

View File

@ -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; pub use chip;
#[allow(unused)] #[allow(unused)]

View File

@ -46,6 +46,7 @@ pub const NUM_PINS: usize = 22;
pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0;
pub(crate) type InputSignalType = u8;
pub(crate) type OutputSignalType = u8; pub(crate) type OutputSignalType = u8;
pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128; pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128;
pub(crate) const INPUT_SIGNAL_MAX: u8 = 100; 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 /// Peripheral input signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum InputSignal { pub enum InputSignal {
SPIQ = 0, SPIQ = 0,
@ -114,7 +116,8 @@ pub enum InputSignal {
/// Peripheral output signals for the GPIO mux /// Peripheral output signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone, Copy, PartialEq)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum OutputSignal { pub enum OutputSignal {
SPIQ = 0, SPIQ = 0,

View File

@ -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; pub use chip;
#[allow(unused)] #[allow(unused)]

View File

@ -46,6 +46,7 @@ pub const NUM_PINS: usize = 31;
pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0;
pub(crate) type InputSignalType = u8;
pub(crate) type OutputSignalType = u8; pub(crate) type OutputSignalType = u8;
pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128; pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128;
pub(crate) const INPUT_SIGNAL_MAX: u8 = 124; 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 /// Peripheral input signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum InputSignal { pub enum InputSignal {
EXT_ADC_START = 0, EXT_ADC_START = 0,
@ -169,7 +171,8 @@ pub enum InputSignal {
/// Peripheral input signals for the GPIO mux /// Peripheral input signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum OutputSignal { pub enum OutputSignal {
LEDC_LS_SIG0 = 0, LEDC_LS_SIG0 = 0,

View File

@ -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; pub use chip;
#[allow(unused)] #[allow(unused)]

View File

@ -47,6 +47,7 @@ pub const NUM_PINS: usize = 28;
pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0;
pub(crate) type InputSignalType = u8;
pub(crate) type OutputSignalType = u8; pub(crate) type OutputSignalType = u8;
pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128; pub(crate) const OUTPUT_SIGNAL_MAX: u8 = 128;
pub(crate) const INPUT_SIGNAL_MAX: u8 = 124; 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 /// Peripheral input signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum InputSignal { pub enum InputSignal {
EXT_ADC_START = 0, EXT_ADC_START = 0,
@ -151,7 +153,8 @@ pub enum InputSignal {
/// Peripheral input signals for the GPIO mux /// Peripheral input signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum OutputSignal { pub enum OutputSignal {
LEDC_LS_SIG0 = 0, LEDC_LS_SIG0 = 0,

View File

@ -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; pub use chip;
#[allow(unused)] #[allow(unused)]

View File

@ -59,6 +59,7 @@ pub const NUM_PINS: usize = 47;
pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0;
pub(crate) type InputSignalType = u16;
pub(crate) type OutputSignalType = u16; pub(crate) type OutputSignalType = u16;
pub(crate) const OUTPUT_SIGNAL_MAX: u16 = 256; pub(crate) const OUTPUT_SIGNAL_MAX: u16 = 256;
pub(crate) const INPUT_SIGNAL_MAX: u16 = 204; 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 /// Peripheral input signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum InputSignal { pub enum InputSignal {
SPIQ = 0, SPIQ = 0,
@ -212,7 +214,8 @@ pub enum InputSignal {
/// Peripheral output signals for the GPIO mux /// Peripheral output signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum OutputSignal { pub enum OutputSignal {
SPIQ = 0, SPIQ = 0,

View File

@ -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 use chip;
pub(crate) mod constants { pub(crate) mod constants {

View File

@ -46,6 +46,7 @@ pub const NUM_PINS: usize = 49;
pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0; pub(crate) const FUNC_IN_SEL_OFFSET: usize = 0;
pub(crate) type InputSignalType = u16;
pub(crate) type OutputSignalType = u16; pub(crate) type OutputSignalType = u16;
pub(crate) const OUTPUT_SIGNAL_MAX: u16 = 256; pub(crate) const OUTPUT_SIGNAL_MAX: u16 = 256;
pub(crate) const INPUT_SIGNAL_MAX: u16 = 189; 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 /// Peripheral input signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[doc(hidden)] #[doc(hidden)]
pub enum InputSignal { pub enum InputSignal {
SPIQ = 0, SPIQ = 0,
@ -203,8 +205,10 @@ pub enum InputSignal {
/// Peripheral output signals for the GPIO mux /// Peripheral output signals for the GPIO mux
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[doc(hidden)] #[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 { pub enum OutputSignal {
SPIQ = 0, SPIQ = 0,
SPID = 1, SPID = 1,

View File

@ -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 use chip;
pub(crate) mod constants { pub(crate) mod constants {

View File

@ -90,12 +90,7 @@ use crate::{
Rx, Rx,
Tx, Tx,
}, },
gpio::{ gpio::{interconnect::PeripheralOutput, InputSignal, NoPin, OutputSignal},
interconnect::{OutputConnection, PeripheralOutput},
InputSignal,
NoPin,
OutputSignal,
},
interrupt::InterruptHandler, interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::spi2::RegisterBlock, peripherals::spi2::RegisterBlock,
@ -608,20 +603,10 @@ where
let is_qspi = this.driver().sio2_input.is_some(); let is_qspi = this.driver().sio2_input.is_some();
if is_qspi { if is_qspi {
let mut signal = OutputConnection::from(NoPin); unwrap!(this.driver().sio2_input).connect_to(NoPin);
unwrap!(this.driver().sio2_output).connect_to(NoPin);
signal unwrap!(this.driver().sio3_input).connect_to(NoPin);
.connect_input_to_peripheral(unwrap!(this.driver().sio2_input), private::Internal); unwrap!(this.driver().sio3_output).connect_to(NoPin);
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,
);
} }
this this
@ -634,10 +619,10 @@ where
pub fn with_mosi<MOSI: PeripheralOutput>(self, mosi: impl Peripheral<P = MOSI> + 'd) -> Self { pub fn with_mosi<MOSI: PeripheralOutput>(self, mosi: impl Peripheral<P = MOSI> + 'd) -> Self {
crate::into_mapped_ref!(mosi); crate::into_mapped_ref!(mosi);
mosi.enable_output(true, private::Internal); mosi.enable_output(true, private::Internal);
mosi.connect_peripheral_to_output(self.driver().mosi, private::Internal);
mosi.enable_input(true, 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 self
} }
@ -649,10 +634,10 @@ where
pub fn with_miso<MISO: PeripheralOutput>(self, miso: impl Peripheral<P = MISO> + 'd) -> Self { pub fn with_miso<MISO: PeripheralOutput>(self, miso: impl Peripheral<P = MISO> + 'd) -> Self {
crate::into_mapped_ref!(miso); crate::into_mapped_ref!(miso);
miso.enable_input(true, private::Internal); miso.enable_input(true, private::Internal);
miso.connect_input_to_peripheral(self.driver().miso, private::Internal);
miso.enable_output(true, 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 self
} }
@ -664,7 +649,7 @@ where
pub fn with_sck<SCK: PeripheralOutput>(self, sclk: impl Peripheral<P = SCK> + 'd) -> Self { pub fn with_sck<SCK: PeripheralOutput>(self, sclk: impl Peripheral<P = SCK> + 'd) -> Self {
crate::into_mapped_ref!(sclk); crate::into_mapped_ref!(sclk);
sclk.set_to_push_pull_output(private::Internal); 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 self
} }
@ -676,7 +661,7 @@ where
pub fn with_cs<CS: PeripheralOutput>(self, cs: impl Peripheral<P = CS> + 'd) -> Self { pub fn with_cs<CS: PeripheralOutput>(self, cs: impl Peripheral<P = CS> + 'd) -> Self {
crate::into_mapped_ref!(cs); crate::into_mapped_ref!(cs);
cs.set_to_push_pull_output(private::Internal); 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 self
} }
@ -716,8 +701,8 @@ where
sio2.enable_input(true, private::Internal); sio2.enable_input(true, private::Internal);
sio2.enable_output(true, private::Internal); sio2.enable_output(true, private::Internal);
sio2.connect_input_to_peripheral(unwrap!(self.driver().sio2_input), private::Internal); unwrap!(self.driver().sio2_input).connect_to(&mut sio2);
sio2.connect_peripheral_to_output(unwrap!(self.driver().sio2_output), private::Internal); unwrap!(self.driver().sio2_output).connect_to(&mut sio2);
self self
} }
@ -734,8 +719,8 @@ where
sio3.enable_input(true, private::Internal); sio3.enable_input(true, private::Internal);
sio3.enable_output(true, private::Internal); sio3.enable_output(true, private::Internal);
sio3.connect_input_to_peripheral(unwrap!(self.driver().sio3_input), private::Internal); unwrap!(self.driver().sio3_input).connect_to(&mut sio3);
sio3.connect_peripheral_to_output(unwrap!(self.driver().sio3_output), private::Internal); unwrap!(self.driver().sio3_output).connect_to(&mut sio3);
self self
} }

View File

@ -144,16 +144,16 @@ where
// TODO: with_pins et. al. // TODO: with_pins et. al.
sclk.enable_input(true, private::Internal); 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.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.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.enable_input(true, private::Internal);
cs.connect_input_to_peripheral(this.spi.cs_signal(), private::Internal); this.spi.cs_signal().connect_to(cs);
this this
} }

View File

@ -806,13 +806,13 @@ where
tx_pin.set_to_push_pull_output(crate::private::Internal); tx_pin.set_to_push_pull_output(crate::private::Internal);
Pull::None 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. // 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 // `set_to_push_pull_output` disables input, here we re-enable it if rx_pin
// uses the same GPIO. // uses the same GPIO.
rx_pin.init_input(rx_pull, crate::private::Internal); 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 // Freeze REC by changing to LOM mode
this.set_mode(TwaiMode::ListenOnly); this.set_mode(TwaiMode::ListenOnly);

View File

@ -460,7 +460,7 @@ where
fn with_rx(self, rx: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self { fn with_rx(self, rx: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self {
crate::into_mapped_ref!(rx); crate::into_mapped_ref!(rx);
rx.init_input(Pull::Up, Internal); 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 self
} }
@ -470,7 +470,7 @@ where
// Make sure we don't cause an unexpected low pulse on the pin. // Make sure we don't cause an unexpected low pulse on the pin.
tx.set_output_high(true, Internal); tx.set_output_high(true, Internal);
tx.set_to_push_pull_output(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 self
} }
@ -558,7 +558,7 @@ where
pub fn with_rts(self, rts: impl Peripheral<P = impl PeripheralOutput> + 'd) -> Self { pub fn with_rts(self, rts: impl Peripheral<P = impl PeripheralOutput> + 'd) -> Self {
crate::into_mapped_ref!(rts); crate::into_mapped_ref!(rts);
rts.set_to_push_pull_output(Internal); 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 self
} }
@ -766,7 +766,7 @@ where
pub fn with_cts(self, cts: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self { pub fn with_cts(self, cts: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self {
crate::into_mapped_ref!(cts); crate::into_mapped_ref!(cts);
cts.init_input(Pull::None, Internal); 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 self
} }

View File

@ -11,10 +11,8 @@
use esp_hal::{ use esp_hal::{
dma::{Dma, DmaPriority}, dma::{Dma, DmaPriority},
dma_buffers, dma_buffers,
gpio::{ gpio::{Input, Io, Level, Output, Pull},
interconnect::{InputSignal, OutputSignal}, peripheral::Peripheral,
Io,
},
spi::{slave::Spi, SpiMode}, spi::{slave::Spi, SpiMode},
Blocking, Blocking,
}; };
@ -35,32 +33,19 @@ struct Context {
} }
struct BitbangSpi { struct BitbangSpi {
sclk: OutputSignal, sclk: Output<'static>,
mosi: OutputSignal, mosi: Output<'static>,
miso: InputSignal, miso: Input<'static>,
cs: OutputSignal, cs: Output<'static>,
} }
impl BitbangSpi { impl BitbangSpi {
fn new( fn new(
mut sclk: OutputSignal, sclk: Output<'static>,
mut mosi: OutputSignal, mosi: Output<'static>,
mut miso: InputSignal, miso: Input<'static>,
mut cs: OutputSignal, cs: Output<'static>,
) -> Self { ) -> 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 { Self {
sclk, sclk,
mosi, mosi,
@ -70,29 +55,22 @@ impl BitbangSpi {
} }
fn assert_cs(&mut self) { fn assert_cs(&mut self) {
self.sclk self.sclk.set_level(Level::Low);
.set_output_high(false, unsafe { esp_hal::Internal::conjure() }); self.cs.set_level(Level::Low);
self.cs
.set_output_high(false, unsafe { esp_hal::Internal::conjure() });
} }
fn deassert_cs(&mut self) { fn deassert_cs(&mut self) {
self.sclk self.sclk.set_level(Level::Low);
.set_output_high(false, unsafe { esp_hal::Internal::conjure() }); self.cs.set_level(Level::High);
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. // Mode 1, so sampled on the rising edge and set on the falling edge.
fn shift_bit(&mut self, bit: bool) -> bool { fn shift_bit(&mut self, bit: bool) -> bool {
self.mosi self.mosi.set_level(Level::from(bit));
.set_output_high(bit, unsafe { esp_hal::Internal::conjure() }); self.sclk.set_level(Level::High);
self.sclk
.set_output_high(true, unsafe { esp_hal::Internal::conjure() });
let miso = self.miso.get_level().into(); let miso = self.miso.get_level().into();
self.sclk self.sclk.set_level(Level::Low);
.set_output_high(false, unsafe { esp_hal::Internal::conjure() });
miso miso
} }
@ -141,21 +119,19 @@ mod tests {
} }
} }
let (cs, cs_pin) = cs_pin.split(); let mosi_gpio = Output::new(mosi_pin, Level::Low);
let (mosi, mosi_pin) = mosi_pin.split(); let cs_gpio = Output::new(cs_pin, Level::High);
let (miso, miso_pin) = miso_pin.split(); let sclk_gpio = Output::new(sclk_pin, Level::Low);
let (sclk_signal, sclk_pin) = sclk_pin.split(); 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 { Context {
spi: Spi::new( spi: Spi::new(peripherals.SPI2, sclk, mosi, miso, cs, SpiMode::Mode1),
peripherals.SPI2, bitbang_spi: BitbangSpi::new(sclk_gpio, mosi_gpio, miso_gpio, cs_gpio),
sclk_signal,
mosi,
miso_pin,
cs,
SpiMode::Mode1,
),
bitbang_spi: BitbangSpi::new(sclk_pin, mosi_pin, miso, cs_pin),
dma_channel, dma_channel,
} }
} }