From 2ac47868f79fa39ed24d788974f2d2131f110062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 24 Oct 2024 09:22:21 +0200 Subject: [PATCH] Remove FullDuplexMode and HalfDuplexMode type params (#2373) * Remove duplex type param * Rename dma_ functions --- esp-hal/CHANGELOG.md | 7 + esp-hal/MIGRATING-0.21.md | 57 + esp-hal/src/dma/mod.rs | 5 +- esp-hal/src/spi/master.rs | 982 ++++++------------ esp-hal/src/spi/mod.rs | 13 - esp-hal/src/spi/slave.rs | 27 +- examples/src/bin/embassy_spi.rs | 5 +- examples/src/bin/qspi_flash.rs | 19 +- .../spi_halfduplex_read_manufacturer_id.rs | 17 +- examples/src/bin/spi_loopback.rs | 11 +- examples/src/bin/spi_loopback_dma.rs | 7 +- examples/src/bin/spi_loopback_dma_psram.rs | 14 +- examples/src/bin/spi_slave_dma.rs | 14 +- hil-test/tests/embassy_interrupt_spi_dma.rs | 3 +- hil-test/tests/qspi.rs | 60 +- hil-test/tests/spi_full_duplex.rs | 42 +- hil-test/tests/spi_half_duplex_read.rs | 15 +- hil-test/tests/spi_half_duplex_write.rs | 15 +- hil-test/tests/spi_half_duplex_write_psram.rs | 15 +- hil-test/tests/spi_slave.rs | 6 +- 20 files changed, 511 insertions(+), 823 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index abf3eb35f..2adb516bf 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `AnyTwai`. (#2359) - `Pins::steal()` to unsafely obtain GPIO. (#2335) - `I2c::with_timeout` (#2361) +- `Spi::half_duplex_read` and `Spi::half_duplex_write` (#2373) ### Changed @@ -25,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Peripheral type erasure for I2S (#2367) - Peripheral type erasure for I2C (#2361) - Peripheral type erasure for TWAI (#2359) +- The SPI driver has been rewritten to allow using half-duplex and full-duplex functionality on the same bus. See the migration guide for details. (#2373) +- Renamed `SpiDma` functions: `dma_transfer` to `transfer`, `dma_write` to `write`, `dma_read` to `read`. (#2373) ### Fixed @@ -36,6 +39,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `i2s::{I2sWrite, I2sWriteDma, I2sRead, I2sReadDma, I2sWriteDmaAsync, I2sReadDmaAsync}` traits have been removed. (#2316) - The `ledc::ChannelHW` trait is no longer generic. (#2387) - The `I2c::new_with_timeout` constructors have been removed (#2361) +- The `spi::master::HalfDuplexReadWrite` trait has been removed. (#2373) +- The `Spi::with_pins` methods have been removed. (#2373) +- The `Spi::new_half_duplex` constructor have been removed. (#2373) +- The `HalfDuplexMode` and `FullDuplexMode` parameters have been removed from `Spi`. (#2373) ## [0.21.1] diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index ec2480937..38dc75374 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -60,3 +60,60 @@ The `with_timeout` constructors have been removed in favour of `set_timeout` or -let i2c = I2c::new_with_timeout(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 100.kHz(), timeout); +let i2c = I2c::new(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 100.kHz()).with_timeout(timeout); ``` + +## Changes to half-duplex SPI + +The `HalfDuplexMode` and `FullDuplexMode` type parameters have been removed from SPI master and slave +drivers. It is now possible to execute half-duplex and full-duplex operations on the same SPI bus. + +### Driver construction + +- The `Spi::new_half_duplex` constructor has been removed. Use `new` (or `new_typed`) instead. +- The `with_pins` methods have been removed. Use the individual `with_*` functions instead. +- The `with_mosi` and `with_miso` functions now take input-output peripheral signals to support half-duplex mode. + > TODO(danielb): this means they are currently only usable with GPIO pins, but upcoming GPIO changes should allow using any output signal. + +```diff +- let mut spi = Spi::new_half_duplex(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) +- .with_pins(sck, mosi, miso, sio2, sio3, cs); ++ let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) ++ .with_sck(sck) ++ .with_cs(cs) ++ .with_mosi(mosi) ++ .with_miso(miso) ++ .with_sio2(sio2) ++ .with_sio3(sio3); +``` + +### Transfer functions + +The `Spi<'_, SPI, HalfDuplexMode>::read` and `Spi<'_, SPI, HalfDuplexMode>::write` functions have been replaced by +`half_duplex_read` and `half_duplex_write`. + +```diff + let mut data = [0u8; 2]; + let transfer = spi +- .read( ++ .half_duplex_read( + SpiDataMode::Single, + Command::Command8(0x90, SpiDataMode::Single), + Address::Address24(0x000000, SpiDataMode::Single), + 0, + &mut data, + ) + .unwrap(); + + let transfer = spi +- .write( ++ .half_duplex_write( + SpiDataMode::Quad, + Command::Command8(write as u16, command_data_mode), + Address::Address24( + write as u32 | (write as u32) << 8 | (write as u32) << 16, + SpiDataMode::Quad, + ), + 0, + dma_tx_buf, + ) + .unwrap(); +``` diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index 8e9114ae3..c228517e6 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -35,7 +35,10 @@ //! 100.kHz(), //! SpiMode::Mode0, //! ) -//! .with_pins(sclk, mosi, miso, cs) +//! .with_sck(sclk) +//! .with_mosi(mosi) +//! .with_miso(miso) +//! .with_cs(cs) //! .with_dma(dma_channel.configure( //! false, //! DmaPriority::Priority0, diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 170506a89..c8f10a97d 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -51,15 +51,16 @@ //! 100.kHz(), //! SpiMode::Mode0, //! ) -//! .with_pins(sclk, mosi, miso, cs); +//! .with_sck(sclk) +//! .with_mosi(mosi) +//! .with_miso(miso) +//! .with_cs(cs); //! # } //! ``` //! //! [`embedded-hal-bus`]: https://docs.rs/embedded-hal-bus/latest/embedded_hal_bus/spi/index.html //! [`embassy-embedded-hal`]: https://docs.embassy.dev/embassy-embedded-hal/git/default/shared_bus/index.html -use core::marker::PhantomData; - pub use dma::*; #[cfg(gdma)] use enumset::EnumSet; @@ -69,16 +70,7 @@ use fugit::HertzU32; #[cfg(place_spi_driver_in_ram)] use procmacros::ram; -use super::{ - DmaError, - DuplexMode, - Error, - FullDuplexMode, - HalfDuplexMode, - SpiBitOrder, - SpiDataMode, - SpiMode, -}; +use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode}; use crate::{ clock::Clocks, dma::{DmaChannelConvert, DmaEligible, DmaRxBuffer, DmaTxBuffer, PeripheralMarker, Rx, Tx}, @@ -425,92 +417,14 @@ impl Address { } } -/// Read and Write in half duplex mode. -pub trait HalfDuplexReadWrite { - /// The associated error type that will be returned in the event of a - /// failure. - type Error; - - /// Half-duplex read. - fn read( - &mut self, - data_mode: SpiDataMode, - cmd: Command, - address: Address, - dummy: u8, - buffer: &mut [u8], - ) -> Result<(), Self::Error>; - - /// Half-duplex write. - fn write( - &mut self, - data_mode: SpiDataMode, - cmd: Command, - address: Address, - dummy: u8, - buffer: &[u8], - ) -> Result<(), Self::Error>; -} - /// SPI peripheral driver -pub struct Spi<'d, M, T = AnySpi> { +pub struct Spi<'d, T = AnySpi> { spi: PeripheralRef<'d, T>, - _mode: PhantomData, } -impl<'d, M, T> Spi<'d, M, T> -where - T: Instance, -{ - fn new_internal( - spi: impl Peripheral

+ 'd, - frequency: HertzU32, - mode: SpiMode, - ) -> Spi<'d, M, T> { - crate::into_ref!(spi); - - let mut spi = Spi { - spi, - _mode: PhantomData, - }; - spi.spi.reset_peripheral(); - spi.spi.enable_peripheral(); - spi.spi.setup(frequency); - spi.spi.init(); - spi.spi.set_data_mode(mode); - - spi - } - - /// Assign the SCK (Serial Clock) pin for the SPI instance. - /// - /// Sets the specified pin to push-pull output and connects it to the SPI - /// clock signal. - pub fn with_sck(self, sclk: impl Peripheral

+ 'd) -> Self { - crate::into_ref!(sclk); - sclk.set_to_push_pull_output(private::Internal); - sclk.connect_peripheral_to_output(self.spi.sclk_signal(), private::Internal); - - self - } - - /// Assign the CS (Chip Select) pin for the SPI instance. - /// - /// Sets the specified pin to push-pull output and connects it to the SPI CS - /// signal. - pub fn with_cs(self, cs: impl Peripheral

+ 'd) -> Self { - crate::into_ref!(cs); - cs.set_to_push_pull_output(private::Internal); - cs.connect_peripheral_to_output(self.spi.cs_signal(), private::Internal); - - self - } -} - -impl<'d, M, T> Spi<'d, M, T> +impl<'d, T> Spi<'d, T> where T: InstanceDma, - M: DuplexMode, { /// Configures the SPI instance to use DMA with the specified channel. /// @@ -520,7 +434,7 @@ where pub fn with_dma( self, channel: crate::dma::Channel<'d, CH, DmaMode>, - ) -> SpiDma<'d, M, DmaMode, T> + ) -> SpiDma<'d, DmaMode, T> where CH: DmaChannelConvert, DmaMode: Mode, @@ -529,7 +443,7 @@ where } } -impl<'d, T> Spi<'d, FullDuplexMode, T> +impl<'d, T> Spi<'d, T> where T: Instance, { @@ -565,137 +479,67 @@ where } } -impl<'d> Spi<'d, FullDuplexMode> { +impl<'d> Spi<'d> { /// Constructs an SPI instance in 8bit dataframe mode. - /// - /// All pins are optional. Setup these pins using - /// [with_pins](Self::with_pins) or individual methods for each pin. pub fn new( spi: impl Peripheral

+ 'd, frequency: HertzU32, mode: SpiMode, - ) -> Spi<'d, FullDuplexMode> { + ) -> Spi<'d> { Self::new_typed(spi.map_into(), frequency, mode) } } -impl<'d, T> Spi<'d, FullDuplexMode, T> +impl<'d, T> Spi<'d, T> where T: Instance, { /// Constructs an SPI instance in 8bit dataframe mode. - /// - /// All pins are optional. Setup these pins using - /// [with_pins](Self::with_pins) or individual methods for each pin. pub fn new_typed( spi: impl Peripheral

+ 'd, frequency: HertzU32, mode: SpiMode, - ) -> Spi<'d, FullDuplexMode, T> { - let spi = Spi::::new_internal(spi, frequency, mode); + ) -> Spi<'d, T> { + crate::into_ref!(spi); - // Disconnect any lingering connections - spi.with_pins(NoPin, NoPin, NoPin, NoPin) + let mut spi = Spi { spi }; + spi.spi.reset_peripheral(); + spi.spi.enable_peripheral(); + spi.spi.setup(frequency); + spi.spi.init(); + spi.spi.set_data_mode(mode); + + let spi = spi + .with_mosi(NoPin) + .with_miso(NoPin) + .with_sck(NoPin) + .with_cs(NoPin); + + let is_qspi = spi.spi.sio2_input_signal().is_some(); + if is_qspi { + NoPin.connect_input_to_peripheral( + unwrap!(spi.spi.sio2_input_signal()), + private::Internal, + ); + NoPin.connect_peripheral_to_output( + unwrap!(spi.spi.sio2_output_signal()), + private::Internal, + ); + NoPin.connect_input_to_peripheral( + unwrap!(spi.spi.sio3_input_signal()), + private::Internal, + ); + NoPin.connect_peripheral_to_output( + unwrap!(spi.spi.sio3_output_signal()), + private::Internal, + ); + } + + spi } /// Assign the MOSI (Master Out Slave In) pin for the SPI instance. /// - /// Sets the specified pin to push-pull output and connects it to the SPI - /// MOSI signal. - pub fn with_mosi(self, mosi: impl Peripheral

+ 'd) -> Self { - crate::into_ref!(mosi); - mosi.set_to_push_pull_output(private::Internal); - mosi.connect_peripheral_to_output(self.spi.mosi_signal(), private::Internal); - - self - } - - /// Assign the MISO (Master In Slave Out) pin for the SPI instance. - /// - /// Sets the specified pin to input and connects it to the SPI MISO signal. - pub fn with_miso(self, miso: impl Peripheral

+ 'd) -> Self { - crate::into_ref!(miso); - miso.init_input(crate::gpio::Pull::None, private::Internal); - miso.connect_input_to_peripheral(self.spi.miso_signal(), private::Internal); - - self - } - - /// Set the bit order for the SPI instance. - /// - /// The default is MSB first for both read and write. - pub fn with_bit_order(mut self, read_order: SpiBitOrder, write_order: SpiBitOrder) -> Self { - self.spi.set_bit_order(read_order, write_order); - self - } - - /// Setup pins for this SPI instance. - /// - /// All pins are optional. Pass [crate::gpio::NoPin] if you don't need the - /// given pin. - pub fn with_pins< - SCK: PeripheralOutput, - MOSI: PeripheralOutput, - MISO: PeripheralInput, - CS: PeripheralOutput, - >( - self, - sck: impl Peripheral

+ 'd, - mosi: impl Peripheral

+ 'd, - miso: impl Peripheral

+ 'd, - cs: impl Peripheral

+ 'd, - ) -> Self { - self.with_sck(sck) - .with_mosi(mosi) - .with_miso(miso) - .with_cs(cs) - } - - /// Change the bus frequency of the SPI instance. - /// - /// This method allows user to update the bus frequency for the SPI - /// communication after the instance has been created. - pub fn change_bus_frequency(&mut self, frequency: HertzU32) { - self.spi.ch_bus_freq(frequency); - } -} - -impl<'d> Spi<'d, HalfDuplexMode> { - /// Constructs an SPI instance in half-duplex mode. - /// - /// All pins are optional. Setup these pins using - /// [with_pins](Self::with_pins) or individual methods for each pin. - pub fn new_half_duplex( - spi: impl Peripheral

+ 'd, - frequency: HertzU32, - mode: SpiMode, - ) -> Spi<'d, HalfDuplexMode> { - Self::new_half_duplex_typed(spi.map_into(), frequency, mode) - } -} - -impl<'d, T> Spi<'d, HalfDuplexMode, T> -where - T: ExtendedInstance, -{ - /// Constructs an SPI instance in half-duplex mode. - /// - /// All pins are optional. Setup these pins using - /// [with_pins](Self::with_pins) or individual methods for each pin. - pub fn new_half_duplex_typed( - spi: impl Peripheral

+ 'd, - frequency: HertzU32, - mode: SpiMode, - ) -> Spi<'d, HalfDuplexMode, T> { - let spi = Spi::::new_internal(spi, frequency, mode); - - // Disconnect any lingering connections - spi.with_pins(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin) - } - - /// Assign the MOSI (Master Out Slave In) pin for the SPI instance in - /// half-duplex mode. - /// /// Enables both input and output functionality for the pin, and connects it /// to the MOSI signal and SIO0 input signal. pub fn with_mosi( @@ -703,17 +547,17 @@ where mosi: impl Peripheral

+ 'd, ) -> Self { crate::into_ref!(mosi); - mosi.enable_input(true, private::Internal); - mosi.enable_output(true, private::Internal); - mosi.connect_input_to_peripheral(self.spi.sio0_input_signal(), private::Internal); + mosi.enable_output(true, private::Internal); mosi.connect_peripheral_to_output(self.spi.mosi_signal(), private::Internal); + mosi.enable_input(true, private::Internal); + mosi.connect_input_to_peripheral(self.spi.sio0_input_signal(), private::Internal); + self } - /// Assign the MISO (Master In Slave Out) pin for the SPI instance in - /// half-duplex mode. + /// Assign the MISO (Master In Slave Out) pin for the SPI instance. /// /// Enables both input and output functionality for the pin, and connects it /// to the MISO signal and SIO1 input signal. @@ -722,78 +566,40 @@ where miso: impl Peripheral

+ 'd, ) -> Self { crate::into_ref!(miso); - miso.enable_input(true, private::Internal); - miso.enable_output(true, private::Internal); + miso.enable_input(true, private::Internal); miso.connect_input_to_peripheral(self.spi.miso_signal(), private::Internal); + + miso.enable_output(true, private::Internal); miso.connect_peripheral_to_output(self.spi.sio1_output_signal(), private::Internal); self } - /// Assign the SIO2 pin for the SPI instance. + /// Assign the SCK (Serial Clock) pin for the SPI instance. /// - /// Enables both input and output functionality for the pin, and connects it - /// to the SIO2 output and input signals. - pub fn with_sio2( - self, - sio2: impl Peripheral

+ 'd, - ) -> Self { - crate::into_ref!(sio2); - sio2.enable_input(true, private::Internal); - sio2.enable_output(true, private::Internal); - - sio2.connect_input_to_peripheral(self.spi.sio2_input_signal(), private::Internal); - sio2.connect_peripheral_to_output(self.spi.sio2_output_signal(), private::Internal); + /// Sets the specified pin to push-pull output and connects it to the SPI + /// clock signal. + pub fn with_sck(self, sclk: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(sclk); + sclk.set_to_push_pull_output(private::Internal); + sclk.connect_peripheral_to_output(self.spi.sclk_signal(), private::Internal); self } - /// Assign the SIO3 pin for the SPI instance. + /// Assign the CS (Chip Select) pin for the SPI instance. /// - /// Enables both input and output functionality for the pin, and connects it - /// to the SIO3 output and input signals. - pub fn with_sio3( - self, - sio3: impl Peripheral

+ 'd, - ) -> Self { - crate::into_ref!(sio3); - sio3.enable_input(true, private::Internal); - sio3.enable_output(true, private::Internal); - - sio3.connect_input_to_peripheral(self.spi.sio3_input_signal(), private::Internal); - sio3.connect_peripheral_to_output(self.spi.sio3_output_signal(), private::Internal); + /// Sets the specified pin to push-pull output and connects it to the SPI CS + /// signal. + pub fn with_cs(self, cs: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(cs); + cs.set_to_push_pull_output(private::Internal); + cs.connect_peripheral_to_output(self.spi.cs_signal(), private::Internal); self } - /// Setup pins for this SPI instance. - /// - /// All pins are optional. Pass [crate::gpio::NoPin] if you don't need the - /// given pin. - pub fn with_pins< - SCK: PeripheralOutput, - MOSI: PeripheralOutput + PeripheralInput, - MISO: PeripheralOutput + PeripheralInput, - SIO2: PeripheralOutput + PeripheralInput, - SIO3: PeripheralOutput + PeripheralInput, - CS: PeripheralOutput, - >( - self, - sck: impl Peripheral

+ 'd, - mosi: impl Peripheral

+ 'd, - miso: impl Peripheral

+ 'd, - sio2: impl Peripheral

+ 'd, - sio3: impl Peripheral

+ 'd, - cs: impl Peripheral

+ 'd, - ) -> Self { - self.with_sck(sck) - .with_mosi(mosi) - .with_miso(miso) - .with_sio2(sio2) - .with_sio3(sio3) - .with_cs(cs) - } /// Change the bus frequency of the SPI instance in half-duplex mode. /// /// This method allows you to update the bus frequency for the SPI @@ -811,20 +617,72 @@ where } } -impl HalfDuplexReadWrite for Spi<'_, HalfDuplexMode, T> +impl<'d, T> Spi<'d, T> +where + T: QspiInstance, +{ + /// Assign the SIO2 pin for the SPI instance. + /// + /// Enables both input and output functionality for the pin, and connects it + /// to the SIO2 output and input signals. + pub fn with_sio2( + self, + sio2: impl Peripheral

+ 'd, + ) -> Self + where + T: QspiInstance, + { + crate::into_ref!(sio2); + sio2.enable_input(true, private::Internal); + sio2.enable_output(true, private::Internal); + + sio2.connect_input_to_peripheral(unwrap!(self.spi.sio2_input_signal()), private::Internal); + sio2.connect_peripheral_to_output( + unwrap!(self.spi.sio2_output_signal()), + private::Internal, + ); + + self + } + + /// Assign the SIO3 pin for the SPI instance. + /// + /// Enables both input and output functionality for the pin, and connects it + /// to the SIO3 output and input signals. + pub fn with_sio3( + self, + sio3: impl Peripheral

+ 'd, + ) -> Self + where + T: QspiInstance, + { + crate::into_ref!(sio3); + sio3.enable_input(true, private::Internal); + sio3.enable_output(true, private::Internal); + + sio3.connect_input_to_peripheral(unwrap!(self.spi.sio3_input_signal()), private::Internal); + sio3.connect_peripheral_to_output( + unwrap!(self.spi.sio3_output_signal()), + private::Internal, + ); + + self + } +} + +impl Spi<'_, T> where T: Instance, { - type Error = Error; - - fn read( + /// Half-duplex read. + pub fn half_duplex_read( &mut self, data_mode: SpiDataMode, cmd: Command, address: Address, dummy: u8, buffer: &mut [u8], - ) -> Result<(), Self::Error> { + ) -> Result<(), Error> { if buffer.len() > FIFO_SIZE { return Err(Error::FifoSizeExeeded); } @@ -849,14 +707,15 @@ where self.spi.read_bytes_from_fifo(buffer) } - fn write( + /// Half-duplex write. + pub fn half_duplex_write( &mut self, data_mode: SpiDataMode, cmd: Command, address: Address, dummy: u8, buffer: &[u8], - ) -> Result<(), Self::Error> { + ) -> Result<(), Error> { if buffer.len() > FIFO_SIZE { return Err(Error::FifoSizeExeeded); } @@ -902,7 +761,7 @@ where } } -impl embedded_hal_02::spi::FullDuplex for Spi<'_, FullDuplexMode, T> +impl embedded_hal_02::spi::FullDuplex for Spi<'_, T> where T: Instance, { @@ -917,7 +776,7 @@ where } } -impl embedded_hal_02::blocking::spi::Transfer for Spi<'_, FullDuplexMode, T> +impl embedded_hal_02::blocking::spi::Transfer for Spi<'_, T> where T: Instance, { @@ -928,7 +787,7 @@ where } } -impl embedded_hal_02::blocking::spi::Write for Spi<'_, FullDuplexMode, T> +impl embedded_hal_02::blocking::spi::Write for Spi<'_, T> where T: Instance, { @@ -971,10 +830,9 @@ mod dma { /// [`SpiDmaBus`] via `with_buffers` to get access /// to a DMA capable SPI bus that implements the /// embedded-hal traits. - pub struct SpiDma<'d, D, M, T = AnySpi> + pub struct SpiDma<'d, M, T = AnySpi> where T: InstanceDma, - D: DuplexMode, M: Mode, { pub(crate) spi: PeripheralRef<'d, T>, @@ -983,22 +841,19 @@ mod dma { rx_transfer_in_progress: bool, #[cfg(all(esp32, spi_address_workaround))] address_buffer: DmaTxBuf, - _mode: PhantomData, } #[cfg(all(esp32, spi_address_workaround))] - unsafe impl<'d, D, M, T> Send for SpiDma<'d, D, M, T> + unsafe impl<'d, M, T> Send for SpiDma<'d, M, T> where T: InstanceDma, - D: DuplexMode, M: Mode, { } - impl<'d, D, M, T> core::fmt::Debug for SpiDma<'d, D, M, T> + impl<'d, M, T> core::fmt::Debug for SpiDma<'d, M, T> where T: InstanceDma, - D: DuplexMode, M: Mode, { /// Formats the `SpiDma` instance for debugging purposes. @@ -1010,10 +865,9 @@ mod dma { } } - impl<'d, D, M, T> SpiDma<'d, D, M, T> + impl<'d, M, T> SpiDma<'d, M, T> where T: InstanceDma, - D: DuplexMode, M: Mode, { pub(super) fn new(spi: PeripheralRef<'d, T>, channel: Channel<'d, CH, M>) -> Self @@ -1044,7 +898,6 @@ mod dma { address_buffer, tx_transfer_in_progress: false, rx_transfer_in_progress: false, - _mode: PhantomData, } } @@ -1218,18 +1071,16 @@ mod dma { } } - impl<'d, D, M, T> crate::private::Sealed for SpiDma<'d, D, M, T> + impl<'d, M, T> crate::private::Sealed for SpiDma<'d, M, T> where T: InstanceDma, - D: DuplexMode, M: Mode, { } - impl<'d, D, M, T> InterruptConfigurable for SpiDma<'d, D, M, T> + impl<'d, M, T> InterruptConfigurable for SpiDma<'d, M, T> where T: InstanceDma, - D: DuplexMode, M: Mode, { /// Configures the interrupt handler for the DMA-enabled SPI instance. @@ -1238,10 +1089,9 @@ mod dma { } } - impl<'d, D, M, T> SpiDma<'d, D, M, T> + impl<'d, M, T> SpiDma<'d, M, T> where T: InstanceDma, - D: DuplexMode, M: Mode, { /// Changes the SPI bus frequency for the DMA-enabled SPI instance. @@ -1258,7 +1108,7 @@ mod dma { self, dma_rx_buf: DmaRxBuf, dma_tx_buf: DmaTxBuf, - ) -> SpiDmaBus<'d, D, M, T> { + ) -> SpiDmaBus<'d, M, T> { SpiDmaBus::new(self, dma_rx_buf, dma_tx_buf) } } @@ -1267,23 +1117,21 @@ mod dma { /// /// This structure holds references to the SPI instance, DMA buffers, and /// transfer status. - pub struct SpiDmaTransfer<'d, D, M, Buf, T = AnySpi> + pub struct SpiDmaTransfer<'d, M, Buf, T = AnySpi> where T: InstanceDma, - D: DuplexMode, M: Mode, { - spi_dma: ManuallyDrop>, + spi_dma: ManuallyDrop>, dma_buf: ManuallyDrop, } - impl<'d, D, M, T, Buf> SpiDmaTransfer<'d, D, M, Buf, T> + impl<'d, M, T, Buf> SpiDmaTransfer<'d, M, Buf, T> where T: InstanceDma, - D: DuplexMode, M: Mode, { - fn new(spi_dma: SpiDma<'d, D, M, T>, dma_buf: Buf) -> Self { + fn new(spi_dma: SpiDma<'d, M, T>, dma_buf: Buf) -> Self { Self { spi_dma: ManuallyDrop::new(spi_dma), dma_buf: ManuallyDrop::new(dma_buf), @@ -1302,7 +1150,7 @@ mod dma { /// /// This method blocks until the transfer is finished and returns the /// `SpiDma` instance and the associated buffer. - pub fn wait(mut self) -> (SpiDma<'d, D, M, T>, Buf) { + pub fn wait(mut self) -> (SpiDma<'d, M, T>, Buf) { self.spi_dma.wait_for_idle(); let retval = unsafe { ( @@ -1322,10 +1170,9 @@ mod dma { } } - impl<'d, D, M, T, Buf> Drop for SpiDmaTransfer<'d, D, M, Buf, T> + impl<'d, M, T, Buf> Drop for SpiDmaTransfer<'d, M, Buf, T> where T: InstanceDma, - D: DuplexMode, M: Mode, { fn drop(&mut self) { @@ -1341,10 +1188,9 @@ mod dma { } } - impl<'d, T, D, Buf> SpiDmaTransfer<'d, D, crate::Async, Buf, T> + impl<'d, T, Buf> SpiDmaTransfer<'d, crate::Async, Buf, T> where T: InstanceDma, - D: DuplexMode, { /// Waits for the DMA transfer to complete asynchronously. /// @@ -1354,7 +1200,7 @@ mod dma { } } - impl<'d, M, T> SpiDma<'d, FullDuplexMode, M, T> + impl<'d, M, T> SpiDma<'d, M, T> where T: InstanceDma, M: Mode, @@ -1386,10 +1232,10 @@ mod dma { /// bytes. #[allow(clippy::type_complexity)] #[cfg_attr(place_spi_driver_in_ram, ram)] - pub fn dma_write( + pub fn write( mut self, mut buffer: TX, - ) -> Result, (Error, Self, TX)> { + ) -> Result, (Error, Self, TX)> { self.wait_for_idle(); match unsafe { self.start_dma_write(&mut buffer) } { @@ -1425,10 +1271,10 @@ mod dma { /// received is 32736 bytes. #[allow(clippy::type_complexity)] #[cfg_attr(place_spi_driver_in_ram, ram)] - pub fn dma_read( + pub fn read( mut self, mut buffer: RX, - ) -> Result, (Error, Self, RX)> { + ) -> Result, (Error, Self, RX)> { self.wait_for_idle(); match unsafe { self.start_dma_read(&mut buffer) } { Ok(_) => Ok(SpiDmaTransfer::new(self, buffer)), @@ -1463,12 +1309,11 @@ mod dma { /// sent/received is 32736 bytes. #[allow(clippy::type_complexity)] #[cfg_attr(place_spi_driver_in_ram, ram)] - pub fn dma_transfer( + pub fn transfer( mut self, mut rx_buffer: RX, mut tx_buffer: TX, - ) -> Result, (Error, Self, RX, TX)> - { + ) -> Result, (Error, Self, RX, TX)> { self.wait_for_idle(); match unsafe { self.start_dma_transfer(&mut rx_buffer, &mut tx_buffer) } { Ok(_) => Ok(SpiDmaTransfer::new(self, (rx_buffer, tx_buffer))), @@ -1477,7 +1322,7 @@ mod dma { } } - impl<'d, M, T> SpiDma<'d, HalfDuplexMode, M, T> + impl<'d, M, T> SpiDma<'d, M, T> where T: InstanceDma, M: Mode, @@ -1522,14 +1367,14 @@ mod dma { /// Perform a half-duplex read operation using DMA. #[allow(clippy::type_complexity)] #[cfg_attr(place_spi_driver_in_ram, ram)] - pub fn read( + pub fn half_duplex_read( mut self, data_mode: SpiDataMode, cmd: Command, address: Address, dummy: u8, mut buffer: RX, - ) -> Result, (Error, Self, RX)> { + ) -> Result, (Error, Self, RX)> { self.wait_for_idle(); match unsafe { @@ -1589,14 +1434,14 @@ mod dma { /// Perform a half-duplex write operation using DMA. #[allow(clippy::type_complexity)] #[cfg_attr(place_spi_driver_in_ram, ram)] - pub fn write( + pub fn half_duplex_write( mut self, data_mode: SpiDataMode, cmd: Command, address: Address, dummy: u8, mut buffer: TX, - ) -> Result, (Error, Self, TX)> { + ) -> Result, (Error, Self, TX)> { self.wait_for_idle(); match unsafe { @@ -1612,26 +1457,25 @@ mod dma { /// /// This structure is responsible for managing SPI transfers using DMA /// buffers. - pub struct SpiDmaBus<'d, D, M, T = AnySpi> + pub struct SpiDmaBus<'d, M, T = AnySpi> where T: InstanceDma, - D: DuplexMode, + M: Mode, { - spi_dma: SpiDma<'d, D, M, T>, + spi_dma: SpiDma<'d, M, T>, rx_buf: DmaRxBuf, tx_buf: DmaTxBuf, } - impl<'d, D, M, T> SpiDmaBus<'d, D, M, T> + impl<'d, M, T> SpiDmaBus<'d, M, T> where T: InstanceDma, - D: DuplexMode, M: Mode, { /// Creates a new `SpiDmaBus` with the specified SPI instance and DMA /// buffers. - pub fn new(spi_dma: SpiDma<'d, D, M, T>, rx_buf: DmaRxBuf, tx_buf: DmaTxBuf) -> Self { + pub fn new(spi_dma: SpiDma<'d, M, T>, rx_buf: DmaRxBuf, tx_buf: DmaTxBuf) -> Self { Self { spi_dma, rx_buf, @@ -1680,10 +1524,9 @@ mod dma { } } - impl<'d, D, M, T> InterruptConfigurable for SpiDmaBus<'d, D, M, T> + impl<'d, M, T> InterruptConfigurable for SpiDmaBus<'d, M, T> where T: InstanceDma, - D: DuplexMode, M: Mode, { /// Configures the interrupt handler for the DMA-enabled SPI instance. @@ -1692,15 +1535,14 @@ mod dma { } } - impl<'d, D, M, T> crate::private::Sealed for SpiDmaBus<'d, D, M, T> + impl<'d, M, T> crate::private::Sealed for SpiDmaBus<'d, M, T> where T: InstanceDma, - D: DuplexMode, M: Mode, { } - impl<'d, M, T> SpiDmaBus<'d, FullDuplexMode, M, T> + impl<'d, M, T> SpiDmaBus<'d, M, T> where T: InstanceDma, M: Mode, @@ -1800,22 +1642,20 @@ mod dma { } } - impl<'d, M, T> HalfDuplexReadWrite for SpiDmaBus<'d, HalfDuplexMode, M, T> + impl<'d, M, T> SpiDmaBus<'d, M, T> where T: InstanceDma, M: Mode, { - type Error = Error; - /// Half-duplex read. - fn read( + pub fn half_duplex_read( &mut self, data_mode: SpiDataMode, cmd: Command, address: Address, dummy: u8, buffer: &mut [u8], - ) -> Result<(), Self::Error> { + ) -> Result<(), Error> { if buffer.len() > self.rx_buf.capacity() { return Err(Error::DmaError(DmaError::Overflow)); } @@ -1841,14 +1681,14 @@ mod dma { } /// Half-duplex write. - fn write( + pub fn half_duplex_write( &mut self, data_mode: SpiDataMode, cmd: Command, address: Address, dummy: u8, buffer: &[u8], - ) -> Result<(), Self::Error> { + ) -> Result<(), Error> { if buffer.len() > self.tx_buf.capacity() { return Err(Error::DmaError(DmaError::Overflow)); } @@ -1871,8 +1711,7 @@ mod dma { } } - impl<'d, T> embedded_hal_02::blocking::spi::Transfer - for SpiDmaBus<'d, FullDuplexMode, crate::Blocking, T> + impl<'d, T> embedded_hal_02::blocking::spi::Transfer for SpiDmaBus<'d, crate::Blocking, T> where T: InstanceDma, { @@ -1884,8 +1723,7 @@ mod dma { } } - impl<'d, T> embedded_hal_02::blocking::spi::Write - for SpiDmaBus<'d, FullDuplexMode, crate::Blocking, T> + impl<'d, T> embedded_hal_02::blocking::spi::Write for SpiDmaBus<'d, crate::Blocking, T> where T: InstanceDma, { @@ -1944,7 +1782,7 @@ mod dma { } } - impl<'d, T> SpiDmaBus<'d, FullDuplexMode, crate::Async, T> + impl<'d, T> SpiDmaBus<'d, crate::Async, T> where T: InstanceDma, { @@ -2058,7 +1896,7 @@ mod dma { } } - impl<'d, T> embedded_hal_async::spi::SpiBus for SpiDmaBus<'d, FullDuplexMode, crate::Async, T> + impl<'d, T> embedded_hal_async::spi::SpiBus for SpiDmaBus<'d, crate::Async, T> where T: InstanceDma, { @@ -2090,7 +1928,7 @@ mod dma { use super::*; - impl<'d, M, T> ErrorType for SpiDmaBus<'d, FullDuplexMode, M, T> + impl<'d, M, T> ErrorType for SpiDmaBus<'d, M, T> where T: InstanceDma, M: Mode, @@ -2098,7 +1936,7 @@ mod dma { type Error = Error; } - impl<'d, M, T> SpiBus for SpiDmaBus<'d, FullDuplexMode, M, T> + impl<'d, M, T> SpiBus for SpiDmaBus<'d, M, T> where T: InstanceDma, M: Mode, @@ -2133,11 +1971,11 @@ mod ehal1 { use super::*; - impl embedded_hal::spi::ErrorType for Spi<'_, M, T> { + impl embedded_hal::spi::ErrorType for Spi<'_, T> { type Error = Error; } - impl FullDuplex for Spi<'_, FullDuplexMode, T> + impl FullDuplex for Spi<'_, T> where T: Instance, { @@ -2150,7 +1988,7 @@ mod ehal1 { } } - impl SpiBus for Spi<'_, FullDuplexMode, T> + impl SpiBus for Spi<'_, T> where T: Instance, { @@ -2356,33 +2194,22 @@ impl InstanceDma for crate::peripherals::SPI2 {} #[cfg(spi3)] impl InstanceDma for crate::peripherals::SPI3 {} -#[doc(hidden)] -pub trait ExtendedInstance: Instance { - fn sio0_input_signal(&self) -> InputSignal; - - fn sio1_output_signal(&self) -> OutputSignal; - - fn sio2_output_signal(&self) -> OutputSignal; - - fn sio2_input_signal(&self) -> InputSignal; - - fn sio3_output_signal(&self) -> OutputSignal; - - fn sio3_input_signal(&self) -> InputSignal; -} - #[doc(hidden)] pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static { fn register_block(&self) -> &RegisterBlock; fn sclk_signal(&self) -> OutputSignal; - fn mosi_signal(&self) -> OutputSignal; - fn miso_signal(&self) -> InputSignal; - fn cs_signal(&self) -> OutputSignal; + fn sio0_input_signal(&self) -> InputSignal; + fn sio1_output_signal(&self) -> OutputSignal; + fn sio2_output_signal(&self) -> Option; + fn sio2_input_signal(&self) -> Option; + fn sio3_output_signal(&self) -> Option; + fn sio3_input_signal(&self) -> Option; + #[inline(always)] fn enable_peripheral(&self) { PeripheralClockControl::enable(self.peripheral()); @@ -3011,6 +2838,9 @@ pub trait Instance: private::Sealed + PeripheralMarker + Into + 'static } } +#[doc(hidden)] +pub trait QspiInstance: Instance {} + fn set_up_common_phases(reg_block: &RegisterBlock, cmd: Command, address: Address, dummy: u8) { if !cmd.is_none() { reg_block.user2().modify(|_, w| unsafe { @@ -3040,269 +2870,118 @@ fn set_up_common_phases(reg_block: &RegisterBlock, cmd: Command, address: Addres } } -#[cfg(spi2)] -impl Instance for crate::peripherals::SPI2 { - #[inline(always)] - fn register_block(&self) -> &RegisterBlock { - self - } +macro_rules! spi_instance { + (@ignore $sio2:ident) => {}; - #[inline(always)] - fn spi_num(&self) -> u8 { - 2 - } + ($num:literal, $sclk:ident, $mosi:ident, $miso:ident, $cs:ident $(, $sio2:ident, $sio3:ident)?) => { + paste::paste! { + impl Instance for crate::peripherals::[] { + #[inline(always)] + fn register_block(&self) -> &RegisterBlock { + self + } - #[inline(always)] - fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - self.bind_spi2_interrupt(handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::SPI2, handler.priority()).unwrap(); - } + #[inline(always)] + fn spi_num(&self) -> u8 { + $num + } - #[inline(always)] - fn sclk_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::HSPICLK - } else if #[cfg(any(esp32s2, esp32s3))] { - OutputSignal::FSPICLK - } else { - OutputSignal::FSPICLK_MUX + #[inline(always)] + fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + self.[](handler.handler()); + crate::interrupt::enable(crate::peripherals::Interrupt::[], handler.priority()).unwrap(); + } + + #[inline(always)] + fn sclk_signal(&self) -> OutputSignal { + OutputSignal::$sclk + } + + #[inline(always)] + fn mosi_signal(&self) -> OutputSignal { + OutputSignal::$mosi + } + + #[inline(always)] + fn miso_signal(&self) -> InputSignal { + InputSignal::$miso + } + + #[inline(always)] + fn cs_signal(&self) -> OutputSignal { + OutputSignal::$cs + } + + #[inline(always)] + fn sio0_input_signal(&self) -> InputSignal { + InputSignal::$mosi + } + + #[inline(always)] + fn sio1_output_signal(&self) -> OutputSignal { + OutputSignal::$miso + } + + #[inline(always)] + fn sio2_output_signal(&self) -> Option { + if_set!($(Some(OutputSignal::$sio2))?, None) + } + + #[inline(always)] + fn sio2_input_signal(&self) -> Option { + if_set!($(Some(InputSignal::$sio2))?, None) + } + + #[inline(always)] + fn sio3_output_signal(&self) -> Option { + if_set!($(Some(OutputSignal::$sio3))?, None) + } + + #[inline(always)] + fn sio3_input_signal(&self) -> Option { + if_set!($(Some(InputSignal::$sio3))?, None) + } } - } - } - #[inline(always)] - fn mosi_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::HSPID - } else { - OutputSignal::FSPID - } - } - } - - #[inline(always)] - fn miso_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::HSPIQ - } else { - InputSignal::FSPIQ - } - } - } - - #[inline(always)] - fn cs_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::HSPICS0 - } else { - OutputSignal::FSPICS0 - } + $( + // If the extra pins are set, implement QspiInstance + spi_instance!(@ignore $sio2); + impl QspiInstance for crate::peripherals::[] {} + )? } } } +/// Macro to choose between two expressions. Useful for implementing "else" for +/// `$()?` macro syntax. +macro_rules! if_set { + (, $not_set:expr) => { + $not_set + }; + ($set:expr, $not_set:expr) => { + $set + }; +} + #[cfg(spi2)] -impl ExtendedInstance for crate::peripherals::SPI2 { - #[inline(always)] - fn sio0_input_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::HSPID - } else { - InputSignal::FSPID - } - } - } - - #[inline(always)] - fn sio1_output_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::HSPIQ - } else { - OutputSignal::FSPIQ - } - } - } - - #[inline(always)] - fn sio2_output_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::HSPIWP - } else { - OutputSignal::FSPIWP - } - } - } - - #[inline(always)] - fn sio2_input_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::HSPIWP - } else { - InputSignal::FSPIWP - } - } - } - - #[inline(always)] - fn sio3_output_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::HSPIHD - } else { - OutputSignal::FSPIHD - } - } - } - - #[inline(always)] - fn sio3_input_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::HSPIHD - } else { - InputSignal::FSPIHD - } - } +cfg_if::cfg_if! { + if #[cfg(esp32)] { + spi_instance!(2, HSPICLK, HSPID, HSPIQ, HSPICS0, HSPIWP, HSPIHD); + } else if #[cfg(any(esp32s2, esp32s3))] { + spi_instance!(2, FSPICLK, FSPID, FSPIQ, FSPICS0, FSPIWP, FSPIHD); + } else { + spi_instance!(2, FSPICLK_MUX, FSPID, FSPIQ, FSPICS0, FSPIWP, FSPIHD); } } #[cfg(spi3)] -impl Instance for crate::peripherals::SPI3 { - #[inline(always)] - fn register_block(&self) -> &RegisterBlock { - self - } - - #[inline(always)] - fn spi_num(&self) -> u8 { - 3 - } - - #[inline(always)] - fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - self.bind_spi3_interrupt(handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::SPI3, handler.priority()).unwrap(); - } - - #[inline(always)] - fn sclk_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::VSPICLK - } else { - OutputSignal::SPI3_CLK - } - } - } - - #[inline(always)] - fn mosi_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::VSPID - } else { - OutputSignal::SPI3_D - } - } - } - - #[inline(always)] - fn miso_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::VSPIQ - } else { - InputSignal::SPI3_Q - } - } - } - - #[inline(always)] - fn cs_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::VSPICS0 - } else { - OutputSignal::SPI3_CS0 - } - } - } -} - -#[cfg(all(spi3, any(esp32, esp32s3)))] -impl ExtendedInstance for crate::peripherals::SPI3 { - #[inline(always)] - fn sio0_input_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::HSPID - } else { - InputSignal::SPI3_D - } - } - } - - #[inline(always)] - fn sio1_output_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::HSPIQ - } else { - OutputSignal::SPI3_Q - } - } - } - - #[inline(always)] - fn sio2_output_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::HSPIWP - } else { - OutputSignal::SPI3_WP - } - } - } - - #[inline(always)] - fn sio2_input_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::HSPIWP - } else { - InputSignal::SPI3_WP - } - } - } - - #[inline(always)] - fn sio3_output_signal(&self) -> OutputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - OutputSignal::HSPIHD - } else { - OutputSignal::SPI3_HD - } - } - } - - #[inline(always)] - fn sio3_input_signal(&self) -> InputSignal { - cfg_if::cfg_if! { - if #[cfg(esp32)] { - InputSignal::HSPIHD - } else { - InputSignal::SPI3_HD - } - } +cfg_if::cfg_if! { + if #[cfg(esp32)] { + spi_instance!(3, VSPICLK, VSPID, VSPIQ, VSPICS0, HSPIWP, HSPIHD); + } else if #[cfg(esp32s3)] { + spi_instance!(3, SPI3_CLK, SPI3_D, SPI3_Q, SPI3_CS0, SPI3_WP, SPI3_HD); + } else { + spi_instance!(3, SPI3_CLK, SPI3_D, SPI3_Q, SPI3_CS0); } } @@ -3319,6 +2998,13 @@ impl Instance for super::AnySpi { fn mosi_signal(&self) -> OutputSignal; fn miso_signal(&self) -> InputSignal; fn cs_signal(&self) -> OutputSignal; + + fn sio0_input_signal(&self) -> InputSignal; + fn sio1_output_signal(&self) -> OutputSignal; + fn sio2_output_signal(&self) -> Option; + fn sio2_input_signal(&self) -> Option; + fn sio3_output_signal(&self) -> Option; + fn sio3_input_signal(&self) -> Option; } } delegate::delegate! { @@ -3332,79 +3018,7 @@ impl Instance for super::AnySpi { } } -impl ExtendedInstance for super::AnySpi { - fn sio0_input_signal(&self) -> InputSignal { - match &self.0 { - super::AnySpiInner::Spi2(spi) => spi.sio0_input_signal(), - - #[cfg(all(spi3, any(esp32, esp32s3)))] - super::AnySpiInner::Spi3(spi) => spi.sio0_input_signal(), - - #[cfg(all(spi3, not(any(esp32, esp32s3))))] - super::AnySpiInner::Spi3(_) => unimplemented!("SPI3 is does not support QSPI"), - } - } - - fn sio1_output_signal(&self) -> OutputSignal { - match &self.0 { - super::AnySpiInner::Spi2(spi) => spi.sio1_output_signal(), - - #[cfg(all(spi3, any(esp32, esp32s3)))] - super::AnySpiInner::Spi3(spi) => spi.sio1_output_signal(), - - #[cfg(all(spi3, not(any(esp32, esp32s3))))] - super::AnySpiInner::Spi3(_) => unimplemented!("SPI3 is does not support QSPI"), - } - } - - fn sio2_output_signal(&self) -> OutputSignal { - match &self.0 { - super::AnySpiInner::Spi2(spi) => spi.sio2_output_signal(), - - #[cfg(all(spi3, any(esp32, esp32s3)))] - super::AnySpiInner::Spi3(spi) => spi.sio2_output_signal(), - - #[cfg(all(spi3, not(any(esp32, esp32s3))))] - super::AnySpiInner::Spi3(_) => unimplemented!("SPI3 is does not support QSPI"), - } - } - - fn sio2_input_signal(&self) -> InputSignal { - match &self.0 { - super::AnySpiInner::Spi2(spi) => spi.sio2_input_signal(), - - #[cfg(all(spi3, any(esp32, esp32s3)))] - super::AnySpiInner::Spi3(spi) => spi.sio2_input_signal(), - - #[cfg(all(spi3, not(any(esp32, esp32s3))))] - super::AnySpiInner::Spi3(_) => unimplemented!("SPI3 is does not support QSPI"), - } - } - - fn sio3_output_signal(&self) -> OutputSignal { - match &self.0 { - super::AnySpiInner::Spi2(spi) => spi.sio3_output_signal(), - - #[cfg(all(spi3, any(esp32, esp32s3)))] - super::AnySpiInner::Spi3(spi) => spi.sio3_output_signal(), - - #[cfg(all(spi3, not(any(esp32, esp32s3))))] - super::AnySpiInner::Spi3(_) => unimplemented!("SPI3 is does not support QSPI"), - } - } - - fn sio3_input_signal(&self) -> InputSignal { - match &self.0 { - super::AnySpiInner::Spi2(spi) => spi.sio3_input_signal(), - - #[cfg(all(spi3, any(esp32, esp32s3)))] - super::AnySpiInner::Spi3(spi) => spi.sio3_input_signal(), - - #[cfg(all(spi3, not(any(esp32, esp32s3))))] - super::AnySpiInner::Spi3(_) => unimplemented!("SPI3 is does not support QSPI"), - } - } -} +impl QspiInstance for super::AnySpi {} impl InstanceDma for super::AnySpi { delegate::delegate! { diff --git a/esp-hal/src/spi/mod.rs b/esp-hal/src/spi/mod.rs index ff5305901..7ac8b313a 100644 --- a/esp-hal/src/spi/mod.rs +++ b/esp-hal/src/spi/mod.rs @@ -76,9 +76,6 @@ pub enum SpiBitOrder { LSBFirst, } -/// Trait marker for defining SPI duplex modes. -pub trait DuplexMode: crate::private::Sealed {} - /// SPI data mode #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -91,16 +88,6 @@ pub enum SpiDataMode { Quad, } -/// Full-duplex operation -pub struct FullDuplexMode {} -impl DuplexMode for FullDuplexMode {} -impl crate::private::Sealed for FullDuplexMode {} - -/// Half-duplex operation -pub struct HalfDuplexMode {} -impl DuplexMode for HalfDuplexMode {} -impl crate::private::Sealed for HalfDuplexMode {} - crate::any_peripheral! { /// Any SPI peripheral. pub peripheral AnySpi { diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index bd0bc183b..c49e2372a 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -48,7 +48,7 @@ //! let mut send = tx_buffer; //! //! let transfer = spi -//! .dma_transfer(&mut receive, &mut send) +//! .transfer(&mut receive, &mut send) //! .unwrap(); //! //! transfer.wait().unwrap(); @@ -69,9 +69,8 @@ //! `is_done()`. //! //! See [tracking issue](https://github.com/esp-rs/esp-hal/issues/469) for more information. -use core::marker::PhantomData; -use super::{Error, FullDuplexMode, SpiMode}; +use super::{Error, SpiMode}; use crate::{ dma::{DescriptorChain, DmaChannelConvert, DmaEligible, PeripheralMarker, Rx, Tx}, gpio::{InputSignal, OutputSignal, PeripheralInput, PeripheralOutput}, @@ -87,14 +86,13 @@ const MAX_DMA_SIZE: usize = 32768 - 32; /// SPI peripheral driver. /// /// See the [module-level documentation][self] for more details. -pub struct Spi<'d, M, T = AnySpi> { +pub struct Spi<'d, T = AnySpi> { spi: PeripheralRef<'d, T>, #[allow(dead_code)] data_mode: SpiMode, - _mode: PhantomData, } -impl<'d> Spi<'d, FullDuplexMode> { +impl<'d> Spi<'d> { /// Constructs an SPI instance in 8bit dataframe mode. pub fn new< SCK: PeripheralInput, @@ -108,12 +106,12 @@ impl<'d> Spi<'d, FullDuplexMode> { miso: impl Peripheral

+ 'd, cs: impl Peripheral

+ 'd, mode: SpiMode, - ) -> Spi<'d, FullDuplexMode> { + ) -> Spi<'d> { Self::new_typed(spi, sclk, mosi, miso, cs, mode) } } -impl<'d, T> Spi<'d, FullDuplexMode, T> +impl<'d, T> Spi<'d, T> where T: Instance, { @@ -130,7 +128,7 @@ where miso: impl Peripheral

+ 'd, cs: impl Peripheral

+ 'd, mode: SpiMode, - ) -> Spi<'d, FullDuplexMode, T> { + ) -> Spi<'d, T> { crate::into_ref!(sclk, mosi, miso, cs); let this = Self::new_internal(spi, mode); @@ -154,13 +152,12 @@ where pub(crate) fn new_internal( spi: impl Peripheral

+ 'd> + 'd, mode: SpiMode, - ) -> Spi<'d, FullDuplexMode, T> { + ) -> Spi<'d, T> { crate::into_ref!(spi); let mut spi = Spi { spi: spi.map_into(), data_mode: mode, - _mode: PhantomData, }; spi.spi.reset_peripheral(); spi.spi.enable_peripheral(); @@ -193,7 +190,7 @@ pub mod dma { Mode, }; - impl<'d, T> Spi<'d, FullDuplexMode, T> + impl<'d, T> Spi<'d, T> where T: InstanceDma, { @@ -316,7 +313,7 @@ pub mod dma { /// sent is 32736 bytes. /// /// The write is driven by the SPI master's sclk signal and cs line. - pub fn dma_write<'t, TXBUF>( + pub fn write<'t, TXBUF>( &'t mut self, words: &'t TXBUF, ) -> Result, Error> @@ -351,7 +348,7 @@ pub mod dma { /// received is 32736 bytes. /// /// The read is driven by the SPI master's sclk signal and cs line. - pub fn dma_read<'t, RXBUF>( + pub fn read<'t, RXBUF>( &'t mut self, words: &'t mut RXBUF, ) -> Result, Error> @@ -387,7 +384,7 @@ pub mod dma { /// /// The data transfer is driven by the SPI master's sclk signal and cs /// line. - pub fn dma_transfer<'t, RXBUF, TXBUF>( + pub fn transfer<'t, RXBUF, TXBUF>( &'t mut self, read_buffer: &'t mut RXBUF, words: &'t TXBUF, diff --git a/examples/src/bin/embassy_spi.rs b/examples/src/bin/embassy_spi.rs index 4187226fe..334cd7137 100644 --- a/examples/src/bin/embassy_spi.rs +++ b/examples/src/bin/embassy_spi.rs @@ -59,7 +59,10 @@ async fn main(_spawner: Spawner) { let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_pins(sclk, mosi, miso, cs) + .with_sck(sclk) + .with_mosi(mosi) + .with_miso(miso) + .with_cs(cs) .with_dma(dma_channel.configure_for_async(false, DmaPriority::Priority0)) .with_buffers(dma_rx_buf, dma_tx_buf); diff --git a/examples/src/bin/qspi_flash.rs b/examples/src/bin/qspi_flash.rs index 036a17d39..687b28ba1 100644 --- a/examples/src/bin/qspi_flash.rs +++ b/examples/src/bin/qspi_flash.rs @@ -79,8 +79,13 @@ fn main() -> ! { let mut dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap(); let mut dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); - let mut spi = Spi::new_half_duplex(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_pins(sclk, mosi, miso, sio2, sio3, cs) + let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) + .with_sck(sclk) + .with_mosi(mosi) + .with_miso(miso) + .with_sio2(sio2) + .with_sio3(sio3) + .with_cs(cs) .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); let delay = Delay::new(); @@ -88,7 +93,7 @@ fn main() -> ! { // write enable dma_tx_buf.set_length(0); let transfer = spi - .write( + .half_duplex_write( SpiDataMode::Single, Command::Command8(0x06, SpiDataMode::Single), Address::None, @@ -102,7 +107,7 @@ fn main() -> ! { // erase sector let transfer = spi - .write( + .half_duplex_write( SpiDataMode::Single, Command::Command8(0x20, SpiDataMode::Single), Address::Address24(0x000000, SpiDataMode::Single), @@ -116,7 +121,7 @@ fn main() -> ! { // write enable let transfer = spi - .write( + .half_duplex_write( SpiDataMode::Single, Command::Command8(0x06, SpiDataMode::Single), Address::None, @@ -133,7 +138,7 @@ fn main() -> ! { dma_tx_buf.as_mut_slice().fill(b'!'); dma_tx_buf.as_mut_slice()[0..][..5].copy_from_slice(&b"Hello"[..]); let transfer = spi - .write( + .half_duplex_write( SpiDataMode::Quad, Command::Command8(0x32, SpiDataMode::Single), Address::Address24(0x000000, SpiDataMode::Single), @@ -148,7 +153,7 @@ fn main() -> ! { loop { // quad fast read let transfer = spi - .read( + .half_duplex_read( SpiDataMode::Quad, Command::Command8(0xeb, SpiDataMode::Single), Address::Address32(0x000000 << 8, SpiDataMode::Quad), diff --git a/examples/src/bin/spi_halfduplex_read_manufacturer_id.rs b/examples/src/bin/spi_halfduplex_read_manufacturer_id.rs index 4bd361517..c6dba002a 100644 --- a/examples/src/bin/spi_halfduplex_read_manufacturer_id.rs +++ b/examples/src/bin/spi_halfduplex_read_manufacturer_id.rs @@ -33,7 +33,7 @@ use esp_hal::{ gpio::Io, prelude::*, spi::{ - master::{Address, Command, HalfDuplexReadWrite, Spi}, + master::{Address, Command, Spi}, SpiDataMode, SpiMode, }, @@ -63,15 +63,20 @@ fn main() -> ! { } } - let mut spi = Spi::new_half_duplex(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_pins(sclk, mosi, miso, sio2, sio3, cs); + let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) + .with_sck(sclk) + .with_mosi(mosi) + .with_miso(miso) + .with_sio2(sio2) + .with_sio3(sio3) + .with_cs(cs); let delay = Delay::new(); loop { // READ MANUFACTURER ID FROM FLASH CHIP let mut data = [0u8; 2]; - spi.read( + spi.half_duplex_read( SpiDataMode::Single, Command::Command8(0x90, SpiDataMode::Single), Address::Address24(0x000000, SpiDataMode::Single), @@ -84,7 +89,7 @@ fn main() -> ! { // READ MANUFACTURER ID FROM FLASH CHIP let mut data = [0u8; 2]; - spi.read( + spi.half_duplex_read( SpiDataMode::Dual, Command::Command8(0x92, SpiDataMode::Single), Address::Address32(0x000000_00, SpiDataMode::Dual), @@ -97,7 +102,7 @@ fn main() -> ! { // READ MANUFACTURER ID FROM FLASH CHIP let mut data = [0u8; 2]; - spi.read( + spi.half_duplex_read( SpiDataMode::Quad, Command::Command8(0x94, SpiDataMode::Single), Address::Address32(0x000000_00, SpiDataMode::Quad), diff --git a/examples/src/bin/spi_loopback.rs b/examples/src/bin/spi_loopback.rs index 613cbacec..0900d031d 100644 --- a/examples/src/bin/spi_loopback.rs +++ b/examples/src/bin/spi_loopback.rs @@ -19,6 +19,7 @@ use esp_backtrace as _; use esp_hal::{ delay::Delay, gpio::Io, + peripheral::Peripheral, prelude::*, spi::{master::Spi, SpiMode}, }; @@ -33,11 +34,13 @@ fn main() -> ! { let miso_mosi = io.pins.gpio2; let cs = io.pins.gpio5; - let miso = miso_mosi.peripheral_input(); - let mosi = miso_mosi.into_peripheral_output(); + let miso = unsafe { miso_mosi.clone_unchecked() }; - let mut spi = - Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0).with_pins(sclk, mosi, miso, cs); + let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) + .with_sck(sclk) + .with_mosi(miso_mosi) + .with_miso(miso) + .with_cs(cs); let delay = Delay::new(); diff --git a/examples/src/bin/spi_loopback_dma.rs b/examples/src/bin/spi_loopback_dma.rs index 50faea729..f081478da 100644 --- a/examples/src/bin/spi_loopback_dma.rs +++ b/examples/src/bin/spi_loopback_dma.rs @@ -54,7 +54,10 @@ fn main() -> ! { let mut dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_pins(sclk, mosi, miso, cs) + .with_sck(sclk) + .with_mosi(mosi) + .with_miso(miso) + .with_cs(cs) .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); let delay = Delay::new(); @@ -71,7 +74,7 @@ fn main() -> ! { i = i.wrapping_add(1); let transfer = spi - .dma_transfer(dma_rx_buf, dma_tx_buf) + .transfer(dma_rx_buf, dma_tx_buf) .map_err(|e| e.0) .unwrap(); // here we could do something else while DMA transfer is in progress diff --git a/examples/src/bin/spi_loopback_dma_psram.rs b/examples/src/bin/spi_loopback_dma_psram.rs index 250123752..1ae304085 100644 --- a/examples/src/bin/spi_loopback_dma_psram.rs +++ b/examples/src/bin/spi_loopback_dma_psram.rs @@ -2,7 +2,7 @@ //! //! The following wiring is assumed: //! - SCLK => GPIO42 -//! - MISO => (loopback to MOSI via peripheral_input()) +//! - MISO => (looped back to MOSI via the GPIO MUX) //! - MOSI => GPIO48 //! - CS => GPIO38 //! @@ -27,6 +27,7 @@ use esp_hal::{ delay::Delay, dma::{Dma, DmaBufBlkSize, DmaPriority, DmaRxBuf, DmaTxBuf}, gpio::Io, + peripheral::Peripheral, prelude::*, spi::{master::Spi, SpiMode}, }; @@ -62,7 +63,7 @@ fn main() -> ! { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let sclk = io.pins.gpio42; let mosi = io.pins.gpio48; - let miso = mosi.peripheral_input(); + let miso = unsafe { mosi.clone_unchecked() }; let cs = io.pins.gpio38; let dma = Dma::new(peripherals.DMA); @@ -87,8 +88,13 @@ fn main() -> ! { rx_descriptors.len() ); let mut dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap(); + // Need to set miso first so that mosi can overwrite the + // output connection (because we are using the same pin to loop back) let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_pins(sclk, mosi, miso, cs) + .with_sck(sclk) + .with_miso(miso) + .with_mosi(mosi) + .with_cs(cs) .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); delay.delay_millis(100); // delay to let the above messages display @@ -105,7 +111,7 @@ fn main() -> ! { i = i.wrapping_add(1); let transfer = spi - .dma_transfer(dma_rx_buf, dma_tx_buf) + .transfer(dma_rx_buf, dma_tx_buf) .map_err(|e| e.0) .unwrap(); diff --git a/examples/src/bin/spi_slave_dma.rs b/examples/src/bin/spi_slave_dma.rs index 93d35ca38..5352c71db 100644 --- a/examples/src/bin/spi_slave_dma.rs +++ b/examples/src/bin/spi_slave_dma.rs @@ -107,11 +107,9 @@ fn main() -> ! { println!("Iteration {i}"); - println!("Do `dma_transfer`"); + println!("Do `transfer`"); - let transfer = spi - .dma_transfer(&mut slave_receive, &mut slave_send) - .unwrap(); + let transfer = spi.transfer(&mut slave_receive, &mut slave_send).unwrap(); bitbang_master( master_send, @@ -133,9 +131,9 @@ fn main() -> ! { delay.delay_millis(250); - println!("Do `dma_read`"); + println!("Do `read`"); slave_receive.fill(0xff); - let transfer = spi.dma_read(&mut slave_receive).unwrap(); + let transfer = spi.read(&mut slave_receive).unwrap(); bitbang_master( master_send, @@ -155,8 +153,8 @@ fn main() -> ! { delay.delay_millis(250); - println!("Do `dma_write`"); - let transfer = spi.dma_write(&mut slave_send).unwrap(); + println!("Do `write`"); + let transfer = spi.write(&mut slave_send).unwrap(); master_receive.fill(0); diff --git a/hil-test/tests/embassy_interrupt_spi_dma.rs b/hil-test/tests/embassy_interrupt_spi_dma.rs index 9821c35f4..65499ab4a 100644 --- a/hil-test/tests/embassy_interrupt_spi_dma.rs +++ b/hil-test/tests/embassy_interrupt_spi_dma.rs @@ -15,7 +15,6 @@ use esp_hal::{ prelude::*, spi::{ master::{Spi, SpiDma}, - FullDuplexMode, SpiMode, }, timer::{timg::TimerGroup, AnyTimer}, @@ -34,7 +33,7 @@ macro_rules! mk_static { } #[embassy_executor::task] -async fn interrupt_driven_task(spi: SpiDma<'static, FullDuplexMode, Async>) { +async fn interrupt_driven_task(spi: SpiDma<'static, Async>) { let mut ticker = Ticker::every(Duration::from_millis(1)); let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(128); diff --git a/hil-test/tests/qspi.rs b/hil-test/tests/qspi.rs index fa0d18196..641098f1a 100644 --- a/hil-test/tests/qspi.rs +++ b/hil-test/tests/qspi.rs @@ -10,11 +10,10 @@ use esp_hal::pcnt::{channel::EdgeMode, unit::Unit, Pcnt}; use esp_hal::{ dma::{Channel, Dma, DmaPriority, DmaRxBuf, DmaTxBuf}, dma_buffers, - gpio::{AnyPin, Input, Io, Level, NoPin, Output, Pull}, + gpio::{AnyPin, Input, Io, Level, Output, Pull}, prelude::*, spi::{ master::{Address, Command, Spi, SpiDma}, - HalfDuplexMode, SpiDataMode, SpiMode, }, @@ -38,7 +37,7 @@ cfg_if::cfg_if! { } } -type SpiUnderTest = SpiDma<'static, HalfDuplexMode, Blocking>; +type SpiUnderTest = SpiDma<'static, Blocking>; struct Context { spi: esp_hal::peripherals::SPI2, @@ -54,7 +53,7 @@ fn transfer_read( command: Command, ) -> (SpiUnderTest, DmaRxBuf) { let transfer = spi - .read(SpiDataMode::Quad, command, Address::None, 0, dma_rx_buf) + .half_duplex_read(SpiDataMode::Quad, command, Address::None, 0, dma_rx_buf) .map_err(|e| e.0) .unwrap(); transfer.wait() @@ -67,7 +66,7 @@ fn transfer_write( command_data_mode: SpiDataMode, ) -> (SpiUnderTest, DmaTxBuf) { let transfer = spi - .write( + .half_duplex_write( SpiDataMode::Quad, Command::Command8(write as u16, command_data_mode), Address::Address24( @@ -226,8 +225,8 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new_half_duplex(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_pins(NoPin, pin, NoPin, NoPin, NoPin, NoPin) + let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + .with_mosi(pin) .with_dma(ctx.dma_channel); super::execute_read(spi, pin_mirror, 0b0001_0001); @@ -239,8 +238,8 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new_half_duplex(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_pins(NoPin, NoPin, pin, NoPin, NoPin, NoPin) + let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + .with_miso(pin) .with_dma(ctx.dma_channel); super::execute_read(spi, pin_mirror, 0b0010_0010); @@ -252,8 +251,8 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new_half_duplex(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_pins(NoPin, NoPin, NoPin, pin, NoPin, NoPin) + let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + .with_sio2(pin) .with_dma(ctx.dma_channel); super::execute_read(spi, pin_mirror, 0b0100_0100); @@ -265,8 +264,8 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new_half_duplex(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_pins(NoPin, NoPin, NoPin, NoPin, pin, NoPin) + let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + .with_sio3(pin) .with_dma(ctx.dma_channel); super::execute_read(spi, pin_mirror, 0b1000_1000); @@ -278,8 +277,8 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new_half_duplex(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_pins(NoPin, pin, NoPin, NoPin, NoPin, NoPin) + let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + .with_mosi(pin) .with_dma(ctx.dma_channel); super::execute_write_read(spi, pin_mirror, 0b0001_0001); @@ -291,8 +290,8 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new_half_duplex(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_pins(NoPin, NoPin, pin, NoPin, NoPin, NoPin) + let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + .with_miso(pin) .with_dma(ctx.dma_channel); super::execute_write_read(spi, pin_mirror, 0b0010_0010); @@ -304,8 +303,8 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new_half_duplex(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_pins(NoPin, NoPin, NoPin, pin, NoPin, NoPin) + let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + .with_sio2(pin) .with_dma(ctx.dma_channel); super::execute_write_read(spi, pin_mirror, 0b0100_0100); @@ -317,8 +316,8 @@ mod tests { let [pin, pin_mirror, _] = ctx.gpios; let pin_mirror = Output::new(pin_mirror, Level::High); - let spi = Spi::new_half_duplex(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_pins(NoPin, NoPin, NoPin, NoPin, pin, NoPin) + let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + .with_sio3(pin) .with_dma(ctx.dma_channel); super::execute_write_read(spi, pin_mirror, 0b1000_1000); @@ -341,8 +340,8 @@ mod tests { .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - let spi = Spi::new_half_duplex(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_pins(NoPin, mosi, NoPin, NoPin, NoPin, NoPin) + let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + .with_mosi(mosi) .with_dma(ctx.dma_channel); super::execute_write(unit0, unit1, spi, 0b0000_0001, false); @@ -370,8 +369,9 @@ mod tests { .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - let spi = Spi::new_half_duplex(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_pins(NoPin, mosi, gpio, NoPin, NoPin, NoPin) + let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + .with_mosi(mosi) + .with_miso(gpio) .with_dma(ctx.dma_channel); super::execute_write(unit0, unit1, spi, 0b0000_0010, true); @@ -399,8 +399,9 @@ mod tests { .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - let spi = Spi::new_half_duplex(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_pins(NoPin, mosi, NoPin, gpio, NoPin, NoPin) + let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + .with_mosi(mosi) + .with_sio2(gpio) .with_dma(ctx.dma_channel); super::execute_write(unit0, unit1, spi, 0b0000_0100, true); @@ -428,8 +429,9 @@ mod tests { .channel0 .set_input_mode(EdgeMode::Hold, EdgeMode::Increment); - let spi = Spi::new_half_duplex(ctx.spi, 100.kHz(), SpiMode::Mode0) - .with_pins(NoPin, mosi, NoPin, NoPin, gpio, NoPin) + let spi = Spi::new(ctx.spi, 100.kHz(), SpiMode::Mode0) + .with_mosi(mosi) + .with_sio3(gpio) .with_dma(ctx.dma_channel); super::execute_write(unit0, unit1, spi, 0b0000_1000, true); diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs index b8ab6153b..1af4146ff 100644 --- a/hil-test/tests/spi_full_duplex.rs +++ b/hil-test/tests/spi_full_duplex.rs @@ -15,8 +15,9 @@ use esp_hal::{ dma::{Dma, DmaDescriptor, DmaPriority, DmaRxBuf, DmaTxBuf}, dma_buffers, gpio::{Io, Level, NoPin}, + peripheral::Peripheral, prelude::*, - spi::{master::Spi, FullDuplexMode, SpiMode}, + spi::{master::Spi, SpiMode}, }; #[cfg(pcnt)] use esp_hal::{ @@ -34,7 +35,7 @@ cfg_if::cfg_if! { } struct Context { - spi: Spi<'static, FullDuplexMode>, + spi: Spi<'static>, dma_channel: DmaChannelCreator, // Reuse the really large buffer so we don't run out of DRAM with many tests rx_buffer: &'static mut [u8], @@ -72,11 +73,12 @@ mod tests { #[cfg(pcnt)] let mosi_loopback_pcnt = mosi.peripheral_input(); - let mosi_loopback = mosi.peripheral_input(); + // Need to set miso first so that mosi can overwrite the + // output connection (because we are using the same pin to loop back) let spi = Spi::new(peripherals.SPI2, 10000.kHz(), SpiMode::Mode0) .with_sck(sclk) - .with_mosi(mosi) - .with_miso(mosi_loopback); + .with_miso(unsafe { mosi.clone_unchecked() }) + .with_mosi(mosi); let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(32000); @@ -209,11 +211,11 @@ mod tests { for i in 1..4 { dma_rx_buf.as_mut_slice().copy_from_slice(&[5, 5, 5, 5, 5]); - let transfer = spi.dma_read(dma_rx_buf).map_err(|e| e.0).unwrap(); + let transfer = spi.read(dma_rx_buf).map_err(|e| e.0).unwrap(); (spi, dma_rx_buf) = transfer.wait(); assert_eq!(dma_rx_buf.as_slice(), &[0, 0, 0, 0, 0]); - let transfer = spi.dma_write(dma_tx_buf).map_err(|e| e.0).unwrap(); + let transfer = spi.write(dma_tx_buf).map_err(|e| e.0).unwrap(); (spi, dma_tx_buf) = transfer.wait(); assert_eq!(unit.get_value(), (i * 3 * DMA_BUFFER_SIZE) as _); } @@ -242,12 +244,12 @@ mod tests { for i in 1..4 { dma_rx_buf.as_mut_slice().copy_from_slice(&[5, 5, 5, 5, 5]); - let transfer = spi.dma_read(dma_rx_buf).map_err(|e| e.0).unwrap(); + let transfer = spi.read(dma_rx_buf).map_err(|e| e.0).unwrap(); (spi, dma_rx_buf) = transfer.wait(); assert_eq!(dma_rx_buf.as_slice(), &[0, 0, 0, 0, 0]); let transfer = spi - .dma_transfer(dma_rx_buf, dma_tx_buf) + .transfer(dma_rx_buf, dma_tx_buf) .map_err(|e| e.0) .unwrap(); (spi, (dma_rx_buf, dma_tx_buf)) = transfer.wait(); @@ -274,7 +276,7 @@ mod tests { dma_tx_buf.as_mut_slice()[0] = i as u8; *dma_tx_buf.as_mut_slice().last_mut().unwrap() = i as u8; let transfer = spi - .dma_transfer(dma_rx_buf, dma_tx_buf) + .transfer(dma_rx_buf, dma_tx_buf) .map_err(|e| e.0) .unwrap(); @@ -300,7 +302,7 @@ mod tests { .spi .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)); let transfer = spi - .dma_transfer(dma_rx_buf, dma_tx_buf) + .transfer(dma_rx_buf, dma_tx_buf) .map_err(|e| e.0) .unwrap(); let (spi, (dma_rx_buf, mut dma_tx_buf)) = transfer.wait(); @@ -311,7 +313,7 @@ mod tests { dma_tx_buf.fill(&[0xaa, 0xdd, 0xef, 0xbe]); let transfer = spi - .dma_transfer(dma_rx_buf, dma_tx_buf) + .transfer(dma_rx_buf, dma_tx_buf) .map_err(|e| e.0) .unwrap(); let (_, (dma_rx_buf, dma_tx_buf)) = transfer.wait(); @@ -469,18 +471,18 @@ mod tests { dma_tx_buf.fill(&[0xde, 0xad, 0xbe, 0xef]); - let transfer = spi.dma_write(dma_tx_buf).map_err(|e| e.0).unwrap(); + let transfer = spi.write(dma_tx_buf).map_err(|e| e.0).unwrap(); let (spi, dma_tx_buf) = transfer.wait(); dma_rx_buf.as_mut_slice().fill(0); - let transfer = spi.dma_read(dma_rx_buf).map_err(|e| e.0).unwrap(); + let transfer = spi.read(dma_rx_buf).map_err(|e| e.0).unwrap(); let (spi, mut dma_rx_buf) = transfer.wait(); - let transfer = spi.dma_write(dma_tx_buf).map_err(|e| e.0).unwrap(); + let transfer = spi.write(dma_tx_buf).map_err(|e| e.0).unwrap(); let (spi, _dma_tx_buf) = transfer.wait(); dma_rx_buf.as_mut_slice().fill(0); - let transfer = spi.dma_read(dma_rx_buf).map_err(|e| e.0).unwrap(); + let transfer = spi.read(dma_rx_buf).map_err(|e| e.0).unwrap(); let (_, dma_rx_buf) = transfer.wait(); assert_eq!(&[0xff, 0xff, 0xff, 0xff], dma_rx_buf.as_slice()); @@ -503,7 +505,7 @@ mod tests { .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)); let mut transfer = spi - .dma_transfer(dma_rx_buf, dma_tx_buf) + .transfer(dma_rx_buf, dma_tx_buf) .map_err(|e| e.0) .unwrap(); @@ -526,7 +528,7 @@ mod tests { .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)); let mut transfer = spi - .dma_transfer(dma_rx_buf, dma_tx_buf) + .transfer(dma_rx_buf, dma_tx_buf) .map_err(|e| e.0) .unwrap(); @@ -536,7 +538,7 @@ mod tests { spi.change_bus_frequency(10000.kHz()); let transfer = spi - .dma_transfer(dma_rx_buf, dma_tx_buf) + .transfer(dma_rx_buf, dma_tx_buf) .map_err(|e| e.0) .unwrap(); @@ -561,7 +563,7 @@ mod tests { ); let mut transfer = spi - .dma_transfer(dma_rx_buf, dma_tx_buf) + .transfer(dma_rx_buf, dma_tx_buf) .map_err(|e| e.0) .unwrap(); diff --git a/hil-test/tests/spi_half_duplex_read.rs b/hil-test/tests/spi_half_duplex_read.rs index 63d786a9c..a50fa0dc8 100644 --- a/hil-test/tests/spi_half_duplex_read.rs +++ b/hil-test/tests/spi_half_duplex_read.rs @@ -11,8 +11,7 @@ use esp_hal::{ gpio::{Io, Level, Output}, prelude::*, spi::{ - master::{Address, Command, HalfDuplexReadWrite, Spi, SpiDma}, - HalfDuplexMode, + master::{Address, Command, Spi, SpiDma}, SpiDataMode, SpiMode, }, @@ -21,7 +20,7 @@ use esp_hal::{ use hil_test as _; struct Context { - spi: SpiDma<'static, HalfDuplexMode, Blocking>, + spi: SpiDma<'static, Blocking>, miso_mirror: Output<'static>, } @@ -50,7 +49,7 @@ mod tests { } } - let spi = Spi::new_half_duplex(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) + let spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) .with_sck(sclk) .with_miso(miso) .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); @@ -72,7 +71,7 @@ mod tests { let mut spi = ctx.spi; let transfer = spi - .read( + .half_duplex_read( SpiDataMode::Single, Command::None, Address::None, @@ -89,7 +88,7 @@ mod tests { ctx.miso_mirror.set_high(); let transfer = spi - .read( + .half_duplex_read( SpiDataMode::Single, Command::None, Address::None, @@ -120,7 +119,7 @@ mod tests { ctx.miso_mirror.set_low(); let mut buffer = [0xAA; DMA_BUFFER_SIZE]; - spi.read( + spi.half_duplex_read( SpiDataMode::Single, Command::None, Address::None, @@ -134,7 +133,7 @@ mod tests { // SPI should read '1's from the MISO pin ctx.miso_mirror.set_high(); - spi.read( + spi.half_duplex_read( SpiDataMode::Single, Command::None, Address::None, diff --git a/hil-test/tests/spi_half_duplex_write.rs b/hil-test/tests/spi_half_duplex_write.rs index 75b8a8957..a44dda260 100644 --- a/hil-test/tests/spi_half_duplex_write.rs +++ b/hil-test/tests/spi_half_duplex_write.rs @@ -12,8 +12,7 @@ use esp_hal::{ pcnt::{channel::EdgeMode, unit::Unit, Pcnt}, prelude::*, spi::{ - master::{Address, Command, HalfDuplexReadWrite, Spi, SpiDma}, - HalfDuplexMode, + master::{Address, Command, Spi, SpiDma}, SpiDataMode, SpiMode, }, @@ -22,7 +21,7 @@ use esp_hal::{ use hil_test as _; struct Context { - spi: SpiDma<'static, HalfDuplexMode, Blocking>, + spi: SpiDma<'static, Blocking>, pcnt_unit: Unit<'static, 0>, pcnt_source: InputSignal, } @@ -53,7 +52,7 @@ mod tests { let mosi_loopback = mosi.peripheral_input(); - let spi = Spi::new_half_duplex(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) + let spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) .with_sck(sclk) .with_mosi(mosi) .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); @@ -84,7 +83,7 @@ mod tests { dma_tx_buf.fill(&[0b0110_1010; DMA_BUFFER_SIZE]); let transfer = spi - .write( + .half_duplex_write( SpiDataMode::Single, Command::None, Address::None, @@ -98,7 +97,7 @@ mod tests { assert_eq!(unit.get_value(), (3 * DMA_BUFFER_SIZE) as _); let transfer = spi - .write( + .half_duplex_write( SpiDataMode::Single, Command::None, Address::None, @@ -130,7 +129,7 @@ mod tests { let buffer = [0b0110_1010; DMA_BUFFER_SIZE]; // Write the buffer where each byte has 3 pos edges. - spi.write( + spi.half_duplex_write( SpiDataMode::Single, Command::None, Address::None, @@ -141,7 +140,7 @@ mod tests { assert_eq!(unit.get_value(), (3 * DMA_BUFFER_SIZE) as _); - spi.write( + spi.half_duplex_write( SpiDataMode::Single, Command::None, Address::None, diff --git a/hil-test/tests/spi_half_duplex_write_psram.rs b/hil-test/tests/spi_half_duplex_write_psram.rs index d0f9e3cdc..eea6b6254 100644 --- a/hil-test/tests/spi_half_duplex_write_psram.rs +++ b/hil-test/tests/spi_half_duplex_write_psram.rs @@ -14,8 +14,7 @@ use esp_hal::{ pcnt::{channel::EdgeMode, unit::Unit, Pcnt}, prelude::*, spi::{ - master::{Address, Command, HalfDuplexReadWrite, Spi, SpiDma}, - HalfDuplexMode, + master::{Address, Command, Spi, SpiDma}, SpiDataMode, SpiMode, }, @@ -39,7 +38,7 @@ macro_rules! dma_alloc_buffer { } struct Context { - spi: SpiDma<'static, HalfDuplexMode, Blocking>, + spi: SpiDma<'static, Blocking>, pcnt_unit: Unit<'static, 0>, pcnt_source: InputSignal, } @@ -65,7 +64,7 @@ mod tests { let mosi_loopback = mosi.peripheral_input(); - let spi = Spi::new_half_duplex(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) + let spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) .with_sck(sclk) .with_mosi(mosi) .with_dma(dma_channel.configure(false, DmaPriority::Priority0)); @@ -99,7 +98,7 @@ mod tests { // Fill the buffer where each byte has 3 pos edges. dma_tx_buf.fill(&[0b0110_1010; DMA_BUFFER_SIZE]); let transfer = spi - .write( + .half_duplex_write( SpiDataMode::Single, Command::None, Address::None, @@ -113,7 +112,7 @@ mod tests { assert_eq!(unit.get_value(), (3 * DMA_BUFFER_SIZE) as _); let transfer = spi - .write( + .half_duplex_write( SpiDataMode::Single, Command::None, Address::None, @@ -151,7 +150,7 @@ mod tests { let buffer = [0b0110_1010; DMA_BUFFER_SIZE]; // Write the buffer where each byte has 3 pos edges. - spi.write( + spi.half_duplex_write( SpiDataMode::Single, Command::None, Address::None, @@ -162,7 +161,7 @@ mod tests { assert_eq!(unit.get_value(), (3 * DMA_BUFFER_SIZE) as _); - spi.write( + spi.half_duplex_write( SpiDataMode::Single, Command::None, Address::None, diff --git a/hil-test/tests/spi_slave.rs b/hil-test/tests/spi_slave.rs index 08870aea1..aced1f2bc 100644 --- a/hil-test/tests/spi_slave.rs +++ b/hil-test/tests/spi_slave.rs @@ -12,7 +12,7 @@ use esp_hal::{ dma::{Dma, DmaPriority}, dma_buffers, gpio::{interconnect::InputSignal, Io, Level, Output, PeripheralInput}, - spi::{slave::Spi, FullDuplexMode, SpiMode}, + spi::{slave::Spi, SpiMode}, }; use hil_test as _; @@ -25,7 +25,7 @@ cfg_if::cfg_if! { } struct Context { - spi: Spi<'static, FullDuplexMode>, + spi: Spi<'static>, dma_channel: DmaChannelCreator, bitbang_spi: BitbangSpi, } @@ -170,7 +170,7 @@ mod tests { } slave_receive.fill(0xFF); - let transfer = spi.dma_transfer(slave_receive, &slave_send).unwrap(); + let transfer = spi.transfer(slave_receive, &slave_send).unwrap(); ctx.bitbang_spi.transfer_buf(master_receive, master_send);