Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPI pins are no longer optional #2133

Merged
merged 4 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Introduce traits for the DMA buffer objects (#1976)
- Implement `embedded-hal` output pin traits for `DummyPin` (#2019)
- Implement `embedded-hal` output pin traits for `NoPin` (#2019, #2133)
- Added `esp_hal::init` to simplify HAL initialisation (#1970, #1999)
- Added GpioPin::degrade to create ErasePins easily. Same for AnyPin by accident. (#2075)
- Added missing functions to `Flex`: `unlisten`, `is_interrupt_set`, `wakeup_enable`, `wait_for_high`, `wait_for_low`, `wait_for_rising_edge`, `wait_for_falling_edge`, `wait_for_any_edge`. (#2075)
Expand All @@ -39,6 +39,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- ESP32: Added support for touch sensing on GPIO32 and 33 (#2109)
- Replaced `AnyPin` with `InputSignal` and `OutputSignal` and renamed `ErasedPin` to `AnyPin` (#2128)
- Replaced the `ErasedTimer` enum with the `AnyTimer` struct. (#?)
- Changed the parameters of `Spi::with_pins` to no longer be optional (#2133)
- Renamed `DummyPin` to `NoPin` and removed all internal logic from it. (#2133)
- The `NO_PIN` constant has been removed. (#2133)

### Fixed

Expand Down
13 changes: 13 additions & 0 deletions esp-hal/MIGRATING-0.20.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,16 @@ configure an input pin, and pass it to `set_edge_signal` or `set_ctrl_signal`.
- ));
+ ch0.set_edge_signal(Input::new(io.pins.gpio5, Pull::Down));
```

## SPI pins and `NO_PIN`

Use `NoPin` in place of the now-removed `NO_PIN` constant.

SPI pins, when using the `with_pin` function, are no longer optional.
You can pass `NoPin` or `Level` as inputs, and `NoPin` as output if you don't need a particular pin.

```diff
let spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0)
- .with_pins(Some(sclk), Some(mosi), NO_PIN, NO_PIN);
+ .with_pins(sclk, mosi, Level::Low, NoPin);
```
2 changes: 1 addition & 1 deletion esp-hal/src/dma/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
//! 100.kHz(),
//! SpiMode::Mode0,
//! )
//! .with_pins(Some(sclk), Some(mosi), Some(miso), Some(cs))
//! .with_pins(sclk, mosi, miso, cs)
//! .with_dma(dma_channel.configure(
//! false,
//! DmaPriority::Priority0,
Expand Down
8 changes: 4 additions & 4 deletions esp-hal/src/gpio/interconnect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use crate::{
self,
AlternateFunction,
AnyPin,
DummyPin,
GpioPin,
GpioProperties,
InputPin,
Level,
NoPin,
OutputSignalType,
PeripheralInput,
PeripheralOutput,
Expand Down Expand Up @@ -331,7 +331,7 @@ impl PeripheralOutput for OutputSignal {
enum AnyInputSignalInner {
Input(InputSignal),
Constant(Level),
Dummy(DummyPin),
Dummy(NoPin),
}

/// A type-erased input signal.
Expand All @@ -358,8 +358,8 @@ impl From<Level> for AnyInputSignal {
}
}

impl From<DummyPin> for AnyInputSignal {
fn from(pin: DummyPin) -> Self {
impl From<NoPin> for AnyInputSignal {
fn from(pin: NoPin) -> Self {
Self(AnyInputSignalInner::Dummy(pin))
}
}
Expand Down
17 changes: 12 additions & 5 deletions esp-hal/src/gpio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
//! - [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.
//! - [DummyPin] is a useful for cases where peripheral driver requires a pin,
//! but real pin cannot be used.
//! - [NoPin] is a useful for cases where peripheral driver requires a pin, but
//! real pin cannot be used.
//!
//! ### GPIO interconnect
//!
Expand Down Expand Up @@ -77,10 +77,10 @@ use crate::{
InterruptConfigurable,
};

mod dummy_pin;
pub mod interconnect;
mod placeholder;

pub use dummy_pin::DummyPin;
pub use placeholder::NoPin;

#[cfg(soc_etm)]
pub mod etm;
Expand All @@ -90,7 +90,6 @@ pub mod lp_io;
pub mod rtc_io;

/// Convenience constant for `Option::None` pin
pub const NO_PIN: Option<DummyPin> = None;

static USER_INTERRUPT_HANDLER: CFnPtr = CFnPtr::NULL;

Expand Down Expand Up @@ -147,6 +146,14 @@ pub enum WakeEvent {
}

/// Digital input or output level.
///
/// `Level` can be used to control a GPIO output, and it can act as a peripheral
/// signal and be connected to peripheral inputs and outputs.
///
/// When connected to a peripheral
/// input, the peripheral will read the corresponding level from that signal.
///
/// When connected to a peripheral output, the level will be ignored.
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Level {
Expand Down
152 changes: 77 additions & 75 deletions esp-hal/src/gpio/dummy_pin.rs → esp-hal/src/gpio/placeholder.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,17 @@
//! Placeholder pins.
//! Placeholder pins/signals.
//!
//! These are useful to pass them into peripheral drivers where you don't want
//! an actual pin but one is required.
// This module also contains peripheral signal impls for `Level` to avoid
// polluting the main module.

use super::*;

/// DummyPin, not useful everywhere as it panics if number() is called
#[derive(Default, Clone)]
pub struct DummyPin {
value: bool,
}

impl DummyPin {
/// Create a dummy pin.
pub fn new() -> Self {
Self { value: false }
}
}

impl crate::peripheral::Peripheral for DummyPin {
type P = Self;

unsafe fn clone_unchecked(&mut self) -> Self::P {
Self { value: self.value }
}
impl PeripheralSignal for Level {
fn pull_direction(&self, _pull: Pull, _internal: private::Internal) {}
}

impl private::Sealed for DummyPin {}

impl PeripheralInput for DummyPin {
impl PeripheralInput for Level {
fn input_signals(&self, _: private::Internal) -> [Option<InputSignal>; 6] {
[None; 6]
}
Expand All @@ -40,11 +23,14 @@ impl PeripheralInput for DummyPin {
fn enable_input_in_sleep_mode(&mut self, _on: bool, _: private::Internal) {}

fn is_input_high(&self, _: private::Internal) -> bool {
self.value
*self == Level::High
}

fn connect_input_to_peripheral(&mut self, signal: InputSignal, _: private::Internal) {
let value = if self.value { ONE_INPUT } else { ZERO_INPUT };
let value = match self {
Level::High => ONE_INPUT,
Level::Low => ZERO_INPUT,
};

unsafe { &*GPIO::PTR }
.func_in_sel_cfg(signal as usize - FUNC_IN_SEL_OFFSET)
Expand All @@ -61,48 +47,14 @@ impl PeripheralInput for DummyPin {
fn disconnect_input_from_peripheral(&mut self, _signal: InputSignal, _: private::Internal) {}
}

impl PeripheralSignal for Level {
delegate::delegate! {
to match self {
Level::High => DummyPin { value: true },
Level::Low => DummyPin { value: false },
} {
fn pull_direction(&self, pull: Pull, _internal: private::Internal);
}
}
}

impl PeripheralInput for Level {
delegate::delegate! {
to match self {
Level::High => DummyPin { value: true },
Level::Low => DummyPin { value: false },
} {
fn init_input(&self, _pull: Pull, _internal: private::Internal);
fn enable_input(&mut self, _on: bool, _internal: private::Internal);
fn enable_input_in_sleep_mode(&mut self, _on: bool, _internal: private::Internal);
fn is_input_high(&self, _internal: private::Internal) -> bool;
fn connect_input_to_peripheral(&mut self, _signal: InputSignal, _internal: private::Internal);
fn disconnect_input_from_peripheral(&mut self, _signal: InputSignal, _internal: private::Internal);
fn input_signals(&self, _internal: private::Internal) -> [Option<InputSignal>; 6];
}
}
}

impl PeripheralSignal for DummyPin {
fn pull_direction(&self, _pull: Pull, _internal: private::Internal) {}
}

impl PeripheralOutput for DummyPin {
impl PeripheralOutput for Level {
fn set_to_open_drain_output(&mut self, _: private::Internal) {}

fn set_to_push_pull_output(&mut self, _: private::Internal) {}

fn enable_output(&mut self, _on: bool, _: private::Internal) {}

fn set_output_high(&mut self, on: bool, _: private::Internal) {
self.value = on;
}
fn set_output_high(&mut self, _on: bool, _: private::Internal) {}

fn set_drive_strength(&mut self, _strength: DriveStrength, _: private::Internal) {}

Expand All @@ -115,7 +67,7 @@ impl PeripheralOutput for DummyPin {
fn internal_pull_down_in_sleep_mode(&mut self, _on: bool, _: private::Internal) {}

fn is_set_high(&self, _: private::Internal) -> bool {
self.value
false
}

fn output_signals(&self, _: private::Internal) -> [Option<OutputSignal>; 6] {
Expand All @@ -127,49 +79,99 @@ impl PeripheralOutput for DummyPin {
fn disconnect_from_peripheral_output(&mut self, _signal: OutputSignal, _: private::Internal) {}
}

impl embedded_hal_02::digital::v2::OutputPin for DummyPin {
/// Placeholder pin, used when no pin is required when using a peripheral.
///
/// When used as a peripheral signal, `NoPin` is equivalent to [`Level::Low`].
#[derive(Default, Clone, Copy)]
pub struct NoPin;

impl crate::peripheral::Peripheral for NoPin {
type P = Self;

unsafe fn clone_unchecked(&mut self) -> Self::P {
Self
}
}

impl private::Sealed for NoPin {}

impl PeripheralSignal for NoPin {
fn pull_direction(&self, _pull: Pull, _internal: private::Internal) {}
}

impl PeripheralInput for NoPin {
delegate::delegate! {
to Level::Low {
fn init_input(&self, _pull: Pull, _internal: private::Internal);
fn enable_input(&mut self, _on: bool, _internal: private::Internal);
fn enable_input_in_sleep_mode(&mut self, _on: bool, _internal: private::Internal);
fn is_input_high(&self, _internal: private::Internal) -> bool;
fn connect_input_to_peripheral(&mut self, _signal: InputSignal, _internal: private::Internal);
fn disconnect_input_from_peripheral(&mut self, _signal: InputSignal, _internal: private::Internal);
fn input_signals(&self, _internal: private::Internal) -> [Option<InputSignal>; 6];
}
}
}

impl PeripheralOutput for NoPin {
delegate::delegate! {
to Level::Low {
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: DriveStrength, _internal: private::Internal);
fn enable_open_drain(&mut self, _on: bool, _internal: private::Internal);
fn enable_output_in_sleep_mode(&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;
fn output_signals(&self, _internal: private::Internal) -> [Option<OutputSignal>; 6];
fn connect_peripheral_to_output(&mut self, _signal: OutputSignal, _internal: private::Internal);
fn disconnect_from_peripheral_output(&mut self, _signal: OutputSignal, _internal: private::Internal);
}
}
}

impl embedded_hal_02::digital::v2::OutputPin for NoPin {
type Error = core::convert::Infallible;

fn set_high(&mut self) -> Result<(), Self::Error> {
self.set_output_high(true, private::Internal);
Ok(())
}
fn set_low(&mut self) -> Result<(), Self::Error> {
self.set_output_high(false, private::Internal);
Ok(())
}
}
impl embedded_hal_02::digital::v2::StatefulOutputPin for DummyPin {
impl embedded_hal_02::digital::v2::StatefulOutputPin for NoPin {
fn is_set_high(&self) -> Result<bool, Self::Error> {
Ok(PeripheralOutput::is_set_high(self, private::Internal))
Ok(false)
}
fn is_set_low(&self) -> Result<bool, Self::Error> {
Ok(!PeripheralOutput::is_set_high(self, private::Internal))
Ok(false)
}
}

impl embedded_hal::digital::ErrorType for DummyPin {
impl embedded_hal::digital::ErrorType for NoPin {
type Error = core::convert::Infallible;
}

impl embedded_hal::digital::OutputPin for DummyPin {
impl embedded_hal::digital::OutputPin for NoPin {
fn set_low(&mut self) -> Result<(), Self::Error> {
self.set_output_high(true, private::Internal);
Ok(())
}

fn set_high(&mut self) -> Result<(), Self::Error> {
self.set_output_high(false, private::Internal);
Ok(())
}
}

impl embedded_hal::digital::StatefulOutputPin for DummyPin {
impl embedded_hal::digital::StatefulOutputPin for NoPin {
fn is_set_high(&mut self) -> Result<bool, Self::Error> {
Ok(PeripheralOutput::is_set_high(self, private::Internal))
Ok(false)
}

fn is_set_low(&mut self) -> Result<bool, Self::Error> {
Ok(!PeripheralOutput::is_set_high(self, private::Internal))
Ok(false)
}
}
Loading
Loading