SPI type erasure (#2334)

* Move SPI peripheral type to the last position

* Implement AnySpi

* Convert peripheral types

* Add new_typed constructors

* Implement PDMA

* Fix conditional

* Clean up constructors

* Fix test

* Move stuff to utils

* Extract any macros

* Merge PeripheralMarker defs into peripherals macro

* Changelogs

* Implement fn degrade

* Changelog num

* Fix typo

* Rename type-erased dma channel

* Remove degrade fn

* Remove utils

* Explain peripherals macro
This commit is contained in:
Dániel Buga 2024-10-21 16:03:14 +02:00 committed by GitHub
parent f2aa3f9863
commit a754e411b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 573 additions and 279 deletions

View File

@ -13,10 +13,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- A new config option `PLACE_ANON_IN_RAM` to improve performance (especially for interrupts) at the cost of RAM usage (#2331)
- Add burst transfer support to DMA buffers (#2336)
- `AnyPin` now implements `From<GpioPin<N>>`. (#2326)
- Added `AnySpi` and `AnySpiDmaChannel`. (#2334)
- `Pins::steal()` to unsafely obtain GPIO. (#2335)
### Changed
- Peripheral type erasure for SPI (#2334)
### Fixed
### Removed

View File

@ -22,3 +22,26 @@ For example:
// ...
}
```
## Peripheral types are now optional
You no longer have to specify the peripheral instance in the driver's type for the following
peripherals:
- SPI (both master and slave)
```diff
-Spi<'static, SPI2, FullDuplexMode>
+Spi<'static, FullDuplexMode>
-SpiDma<'static, SPI2, HalfDuplexMode, Blocking>
+SpiDma<'static, HalfDuplexMode, Blocking>
```
Note that you may still specify the instance if you need to. To do this, we provide `_typed`
versions of the constructors (for example: `new_typed`, `new_half_duplex_typed`). Please note that
the peripheral instance has been moved to the last generic parameter position.
```rust
let spi: Spi<'static, FullDuplexMode, SPI2> = Spi::new_typed(peripherals.SPI2, 1.MHz(), SpiMode::Mode0);
```

View File

@ -366,6 +366,15 @@ macro_rules! ImplSpiChannel {
}
}
impl DmaChannelConvert<AnySpiDmaChannel> for [<Spi $num DmaChannel>] {
fn degrade_rx(rx: SpiDmaRxChannelImpl<Self>) -> SpiDmaRxChannelImpl<AnySpiDmaChannelInner> {
SpiDmaRxChannelImpl(rx.0.into())
}
fn degrade_tx(tx: SpiDmaTxChannelImpl<Self>) -> SpiDmaTxChannelImpl<AnySpiDmaChannelInner> {
SpiDmaTxChannelImpl(tx.0.into())
}
}
impl $crate::private::Sealed for [<Spi $num DmaChannel>] {}
#[doc = concat!("Creates a channel for SPI", $num)]
@ -897,3 +906,39 @@ where
);
}
}
/// A marker for SPI-compatible type-erased DMA channels.
pub struct AnySpiDmaChannel;
impl crate::private::Sealed for AnySpiDmaChannel {}
impl DmaChannel for AnySpiDmaChannel {
type Rx = SpiDmaRxChannelImpl<AnySpiDmaChannelInner>;
type Tx = SpiDmaTxChannelImpl<AnySpiDmaChannelInner>;
}
crate::any_enum! {
#[doc(hidden)]
pub enum AnySpiDmaChannelInner {
Spi2(Spi2DmaChannel),
Spi3(Spi3DmaChannel),
}
}
impl crate::private::Sealed for AnySpiDmaChannelInner {}
impl PdmaChannel for AnySpiDmaChannelInner {
type RegisterBlock = SpiRegisterBlock;
delegate::delegate! {
to match self {
AnySpiDmaChannelInner::Spi2(channel) => channel,
AnySpiDmaChannelInner::Spi3(channel) => channel,
} {
fn register_block(&self) -> &SpiRegisterBlock;
fn tx_waker(&self) -> &'static AtomicWaker;
fn rx_waker(&self) -> &'static AtomicWaker;
fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool;
}
}
}

View File

@ -1545,12 +1545,6 @@ mod private {
}
}
impl PeripheralMarker for I2S0 {
fn peripheral(&self) -> crate::system::Peripheral {
crate::system::Peripheral::I2s0
}
}
impl RegBlock for I2S0 {
fn register_block(&self) -> &RegisterBlock {
unsafe { &*I2S0::PTR.cast::<RegisterBlock>() }
@ -1650,13 +1644,6 @@ mod private {
}
}
#[cfg(i2s1)]
impl PeripheralMarker for I2S1 {
fn peripheral(&self) -> crate::system::Peripheral {
crate::system::Peripheral::I2s1
}
}
#[cfg(i2s1)]
impl RegBlock for I2S1 {
fn register_block(&self) -> &RegisterBlock {

View File

@ -136,13 +136,7 @@ pub mod asynch {
}
mod private {
use crate::{dma::PeripheralMarker, peripherals::LCD_CAM};
impl PeripheralMarker for LCD_CAM {
fn peripheral(&self) -> crate::system::Peripheral {
crate::system::Peripheral::LcdCam
}
}
use crate::peripherals::LCD_CAM;
pub(crate) struct Instance;

View File

@ -142,7 +142,6 @@ mod fmt;
#[cfg(riscv)]
pub use esp_riscv_rt::{self, entry, riscv};
pub use procmacros as macros;
#[cfg(xtensa)]
pub use xtensa_lx;
#[cfg(xtensa)]
@ -241,6 +240,8 @@ pub mod debugger;
#[doc(hidden)]
pub mod sync;
pub mod macros;
/// State of the CPU saved when entering exception or interrupt
pub mod trapframe {
#[cfg(riscv)]
@ -449,26 +450,6 @@ unsafe extern "C" fn stack_chk_fail() {
panic!("Stack corruption detected");
}
#[doc(hidden)]
/// Helper macro for checking doctest code snippets
#[macro_export]
macro_rules! before_snippet {
() => {
r#"
# #![no_std]
# use esp_hal::prelude::*;
# use procmacros::handler;
# use esp_hal::interrupt;
# #[panic_handler]
# fn panic(_ : &core::panic::PanicInfo) -> ! {
# loop {}
# }
# fn main() {
# let mut peripherals = esp_hal::init(esp_hal::Config::default());
"#
};
}
use crate::{
clock::{Clocks, CpuClock},
config::{WatchdogConfig, WatchdogStatus},

115
esp-hal/src/macros.rs Normal file
View File

@ -0,0 +1,115 @@
//! Macros used by the HAL.
//!
//! Most of the macros in this module are hidden and intended for internal use
//! only. For the list of public macros, see the [procmacros](https://docs.rs/esp-hal-procmacros/latest/esp_hal_procmacros/)
//! documentation.
pub use procmacros::*;
#[doc(hidden)]
/// Helper macro for checking doctest code snippets
#[macro_export]
macro_rules! before_snippet {
() => {
r#"
# #![no_std]
# use esp_hal::prelude::*;
# use procmacros::handler;
# use esp_hal::interrupt;
# #[panic_handler]
# fn panic(_ : &core::panic::PanicInfo) -> ! {
# loop {}
# }
# fn main() {
# let mut peripherals = esp_hal::init(esp_hal::Config::default());
"#
};
}
#[doc(hidden)]
/// Shorthand to define enums with From implementations.
#[macro_export]
macro_rules! any_enum {
($(#[$meta:meta])* $vis:vis enum $name:ident {
$(
$(#[$variant_meta:meta])*
$variant:ident($inner:ty)
),* $(,)?
}) => {
$(#[$meta])*
$vis enum $name {
$(
$(#[$variant_meta])*
$variant($inner),
)*
}
$(
$(#[$variant_meta])*
impl From<$inner> for $name {
fn from(inner: $inner) -> Self {
$name::$variant(inner)
}
}
)*
};
}
#[doc(hidden)]
/// Shorthand to define AnyPeripheral instances.
#[macro_export]
macro_rules! any_peripheral {
($(#[$meta:meta])* $vis:vis peripheral $name:ident {
$(
$(#[cfg($variant_meta:meta)])*
$variant:ident($inner:ty)
),* $(,)?
}) => {
paste::paste! {
$(#[$meta])*
$vis struct $name([< $name Inner >]);
impl $crate::private::Sealed for $name {}
impl $crate::dma::PeripheralMarker for $name {
#[inline(always)]
fn peripheral(&self) -> $crate::system::Peripheral {
match &self.0 {
$(
$(#[cfg($variant_meta)])*
[<$name Inner>]::$variant(inner) => inner.peripheral(),
)*
}
}
}
impl $crate::peripheral::Peripheral for $name {
type P = $name;
unsafe fn clone_unchecked(&self) -> Self::P {
match &self.0 {
$(
$(#[cfg($variant_meta)])*
[<$name Inner>]::$variant(inner) => $name::from(inner.clone_unchecked()),
)*
}
}
}
enum [< $name Inner >] {
$(
$(#[cfg($variant_meta)])*
$variant($inner),
)*
}
$(
$(#[cfg($variant_meta)])*
impl From<$inner> for $name {
fn from(inner: $inner) -> Self {
Self([< $name Inner >]::$variant(inner))
}
}
)*
}
};
}

View File

@ -207,16 +207,34 @@ impl<T: Peripheral> Peripheral for PeripheralRef<'_, T> {
}
mod peripheral_macros {
/// Creates a new `Peripherals` struct and its associated methods.
///
/// The macro has a few fields doing different things, in the form of
/// `[first] second <= third (fourth)`.
/// - The first field is the name of the `Peripherals` enum variant. This is
/// optional and used to create `PeripheralMarker` implementations for
/// DMA-eligible peripherals.
/// - The second field is the name of the peripheral, as it appears in the
/// `Peripherals` struct.
/// - The third field is the name of the peripheral as it appears in the
/// PAC. This may be `virtual` if the peripheral is not present in the
/// PAC.
/// - The fourth field is an optional list of interrupts that can be bound
/// to the peripheral.
#[doc(hidden)]
#[macro_export]
macro_rules! peripherals {
($($(#[$cfg:meta])? $name:ident <= $from_pac:tt $(($($interrupt:ident),*))? ),*$(,)?) => {
(
$(
$([$enum_variant:ident])? $name:ident <= $from_pac:tt $(($($interrupt:ident),*))?
), *$(,)?
) => {
/// Contains the generated peripherals which implement [`Peripheral`]
mod peripherals {
pub use super::pac::*;
$(
$crate::create_peripheral!($(#[$cfg])? $name <= $from_pac);
$crate::create_peripheral!($([$enum_variant])? $name <= $from_pac);
)*
}
@ -224,7 +242,6 @@ mod peripheral_macros {
#[allow(non_snake_case)]
pub struct Peripherals {
$(
$(#[$cfg])?
/// Each field represents a hardware peripheral.
pub $name: peripherals::$name,
)*
@ -245,9 +262,7 @@ mod peripheral_macros {
Self::steal()
})
}
}
impl Peripherals {
/// Unsafely create an instance of this peripheral out of thin air.
///
/// # Safety
@ -257,7 +272,6 @@ mod peripheral_macros {
pub unsafe fn steal() -> Self {
Self {
$(
$(#[$cfg])?
$name: peripherals::$name::steal(),
)*
}
@ -313,8 +327,7 @@ mod peripheral_macros {
#[macro_export]
/// Macro to create a peripheral structure.
macro_rules! create_peripheral {
($(#[$cfg:meta])? $name:ident <= virtual) => {
$(#[$cfg])?
($([$enum_variant:ident])? $name:ident <= virtual) => {
#[derive(Debug)]
#[allow(non_camel_case_types)]
/// Represents a virtual peripheral with no associated hardware.
@ -323,7 +336,6 @@ mod peripheral_macros {
/// is defined as virtual.
pub struct $name { _inner: () }
$(#[$cfg])?
impl $name {
/// Unsafely create an instance of this peripheral out of thin air.
///
@ -346,29 +358,21 @@ mod peripheral_macros {
}
impl $crate::private::Sealed for $name {}
};
($(#[$cfg:meta])? $name:ident <= $base:ident) => {
$(#[$cfg])?
#[derive(Debug)]
#[allow(non_camel_case_types)]
/// Represents a concrete hardware peripheral.
///
/// This struct is generated by the `create_peripheral!` macro when the peripheral
/// is tied to an actual hardware device.
pub struct $name { _inner: () }
$(#[$cfg])?
impl $name {
/// Unsafely create an instance of this peripheral out of thin air.
///
/// # Safety
///
/// You must ensure that you're only using one instance of this type at a time.
#[inline]
pub unsafe fn steal() -> Self {
Self { _inner: () }
$(
impl $crate::dma::PeripheralMarker for $crate::peripherals::$name {
#[inline(always)]
fn peripheral(&self) -> $crate::system::Peripheral {
$crate::system::Peripheral::$enum_variant
}
}
)?
};
($([$enum_variant:ident])? $name:ident <= $base:ident) => {
$crate::create_peripheral!($([$enum_variant])? $name <= virtual);
impl $name {
#[doc = r"Pointer to the register block"]
pub const PTR: *const <super::pac::$base as core::ops::Deref>::Target = super::pac::$base::PTR;
@ -388,22 +392,10 @@ mod peripheral_macros {
}
impl core::ops::DerefMut for $name {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(Self::PTR as *mut _) }
}
}
impl $crate::peripheral::Peripheral for $name {
type P = $name;
#[inline]
unsafe fn clone_unchecked(&self) -> Self::P {
Self::steal()
}
}
impl $crate::private::Sealed for $name {}
};
}
}

View File

@ -38,8 +38,8 @@ crate::peripherals! {
HINF <= HINF,
I2C0 <= I2C0,
I2C1 <= I2C1,
I2S0 <= I2S0 (I2S0),
I2S1 <= I2S1 (I2S1),
[I2s0] I2S0 <= I2S0 (I2S0),
[I2s1] I2S1 <= I2S1 (I2S1),
IO_MUX <= IO_MUX,
LEDC <= LEDC,
MCPWM0 <= MCPWM0,
@ -60,8 +60,8 @@ crate::peripherals! {
SLCHOST <= SLCHOST,
SPI0 <= SPI0,
SPI1 <= SPI1,
SPI2 <= SPI2 (SPI2_DMA, SPI2),
SPI3 <= SPI3 (SPI3_DMA, SPI3),
[Spi2] SPI2 <= SPI2 (SPI2_DMA, SPI2),
[Spi3] SPI3 <= SPI3 (SPI3_DMA, SPI3),
SYSTEM <= DPORT,
SW_INTERRUPT <= virtual,
TIMG0 <= TIMG0,

View File

@ -40,7 +40,7 @@ crate::peripherals! {
SHA <= SHA,
SPI0 <= SPI0,
SPI1 <= SPI1,
SPI2 <= SPI2 (SPI2),
[Spi2] SPI2 <= SPI2 (SPI2),
SYSTEM <= SYSTEM,
SYSTIMER <= SYSTIMER,
SW_INTERRUPT <= virtual,

View File

@ -34,7 +34,7 @@ crate::peripherals! {
GPIO_SD <= GPIO_SD,
HMAC <= HMAC,
I2C0 <= I2C0,
I2S0 <= I2S0 (I2S0),
[I2s0] I2S0 <= I2S0 (I2S0),
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
IO_MUX <= IO_MUX,
LEDC <= LEDC,
@ -47,7 +47,7 @@ crate::peripherals! {
SHA <= SHA,
SPI0 <= SPI0,
SPI1 <= SPI1,
SPI2 <= SPI2 (SPI2),
[Spi2] SPI2 <= SPI2 (SPI2),
SYSTEM <= SYSTEM,
SYSTIMER <= SYSTIMER,
SW_INTERRUPT <= virtual,

View File

@ -37,7 +37,7 @@ crate::peripherals! {
HP_APM <= HP_APM,
HP_SYS <= HP_SYS,
I2C0 <= I2C0,
I2S0 <= I2S0 (I2S0),
[I2s0] I2S0 <= I2S0 (I2S0),
IEEE802154 <= IEEE802154,
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
INTPRI <= INTPRI,
@ -73,7 +73,7 @@ crate::peripherals! {
SOC_ETM <= SOC_ETM,
SPI0 <= SPI0,
SPI1 <= SPI1,
SPI2 <= SPI2 (SPI2),
[Spi2] SPI2 <= SPI2 (SPI2),
SYSTEM <= PCR,
SYSTIMER <= SYSTIMER,
SW_INTERRUPT <= virtual,

View File

@ -35,7 +35,7 @@ crate::peripherals! {
HP_SYS <= HP_SYS,
I2C0 <= I2C0,
I2C1 <= I2C1,
I2S0 <= I2S0 (I2S0),
[I2s0] I2S0 <= I2S0 (I2S0),
IEEE802154 <= IEEE802154,
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
INTPRI <= INTPRI,
@ -65,7 +65,7 @@ crate::peripherals! {
SOC_ETM <= SOC_ETM,
SPI0 <= SPI0,
SPI1 <= SPI1,
SPI2 <= SPI2 (SPI2),
[Spi2] SPI2 <= SPI2 (SPI2),
SYSTEM <= PCR,
SYSTIMER <= SYSTIMER,
SW_INTERRUPT <= virtual,

View File

@ -35,7 +35,7 @@ crate::peripherals! {
HMAC <= HMAC,
I2C0 <= I2C0,
I2C1 <= I2C1,
I2S0 <= I2S0 (I2S0),
[I2s0] I2S0 <= I2S0 (I2S0),
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
IO_MUX <= IO_MUX,
LEDC <= LEDC,
@ -52,9 +52,8 @@ crate::peripherals! {
SHA <= SHA,
SPI0 <= SPI0,
SPI1 <= SPI1,
SPI2 <= SPI2 (SPI2_DMA, SPI2),
SPI3 <= SPI3 (SPI3_DMA, SPI3),
SPI4 <= SPI4,
[Spi2] SPI2 <= SPI2 (SPI2_DMA, SPI2),
[Spi3] SPI3 <= SPI3 (SPI3_DMA, SPI3),
SYSCON <= SYSCON,
SYSTEM <= SYSTEM,
SYSTIMER <= SYSTIMER,

View File

@ -36,12 +36,12 @@ crate::peripherals! {
HMAC <= HMAC,
I2C0 <= I2C0,
I2C1 <= I2C1,
I2S0 <= I2S0 (I2S0),
I2S1 <= I2S1 (I2S1),
[I2s0] I2S0 <= I2S0 (I2S0),
[I2s1] I2S1 <= I2S1 (I2S1),
INTERRUPT_CORE0 <= INTERRUPT_CORE0,
INTERRUPT_CORE1 <= INTERRUPT_CORE1,
IO_MUX <= IO_MUX,
LCD_CAM <= LCD_CAM,
[LcdCam] LCD_CAM <= LCD_CAM,
LEDC <= LEDC,
LPWR <= RTC_CNTL,
PCNT <= PCNT,
@ -59,8 +59,8 @@ crate::peripherals! {
SHA <= SHA,
SPI0 <= SPI0,
SPI1 <= SPI1,
SPI2 <= SPI2 (SPI2),
SPI3 <= SPI3 (SPI3),
[Spi2] SPI2 <= SPI2 (SPI2),
[Spi3] SPI3 <= SPI3 (SPI3),
SYSTEM <= SYSTEM,
SYSTIMER <= SYSTIMER,
SW_INTERRUPT <= virtual,

View File

@ -87,6 +87,7 @@ use crate::{
peripheral::{Peripheral, PeripheralRef},
peripherals::spi2::RegisterBlock,
private,
spi::AnySpi,
system::PeripheralClockControl,
Mode,
};
@ -452,15 +453,35 @@ pub trait HalfDuplexReadWrite {
}
/// SPI peripheral driver
pub struct Spi<'d, T, M> {
pub struct Spi<'d, M, T = AnySpi> {
spi: PeripheralRef<'d, T>,
_mode: PhantomData<M>,
}
impl<'d, T, M> Spi<'d, T, M>
impl<'d, M, T> Spi<'d, M, T>
where
T: Instance,
{
fn new_internal(
spi: impl Peripheral<P = impl Into<T> + 'd> + 'd,
frequency: HertzU32,
mode: SpiMode,
) -> Spi<'d, M, T> {
crate::into_ref!(spi);
let mut spi = Spi {
spi: spi.map_into(),
_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
@ -486,7 +507,7 @@ where
}
}
impl<'d, T, M> Spi<'d, T, M>
impl<'d, M, T> Spi<'d, M, T>
where
T: InstanceDma,
M: DuplexMode,
@ -499,7 +520,7 @@ where
pub fn with_dma<CH, DmaMode>(
self,
channel: crate::dma::Channel<'d, CH, DmaMode>,
) -> SpiDma<'d, T, M, DmaMode>
) -> SpiDma<'d, M, DmaMode, T>
where
CH: DmaChannelConvert<T::Dma>,
DmaMode: Mode,
@ -508,7 +529,7 @@ where
}
}
impl<'d, T> Spi<'d, T, FullDuplexMode>
impl<'d, T> Spi<'d, FullDuplexMode, T>
where
T: Instance,
{
@ -544,7 +565,21 @@ where
}
}
impl<'d, T> Spi<'d, T, FullDuplexMode>
impl<'d> Spi<'d, FullDuplexMode> {
/// 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<P = impl Into<AnySpi> + 'd> + 'd,
frequency: HertzU32,
mode: SpiMode,
) -> Spi<'d, FullDuplexMode> {
Self::new_typed(spi, frequency, mode)
}
}
impl<'d, T> Spi<'d, FullDuplexMode, T>
where
T: Instance,
{
@ -552,13 +587,15 @@ where
///
/// 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<P = T> + 'd,
pub fn new_typed(
spi: impl Peripheral<P = impl Into<T> + 'd> + 'd,
frequency: HertzU32,
mode: SpiMode,
) -> Spi<'d, T, FullDuplexMode> {
crate::into_ref!(spi);
Self::new_internal(spi, frequency, mode)
) -> Spi<'d, FullDuplexMode, T> {
let spi = Spi::<FullDuplexMode, T>::new_internal(spi, frequency, mode);
// Disconnect any lingering connections
spi.with_pins(NoPin, NoPin, NoPin, NoPin)
}
/// Assign the MOSI (Master Out Slave In) pin for the SPI instance.
@ -614,26 +651,6 @@ where
.with_cs(cs)
}
pub(crate) fn new_internal(
spi: PeripheralRef<'d, T>,
frequency: HertzU32,
mode: SpiMode,
) -> Spi<'d, T, FullDuplexMode> {
spi.reset_peripheral();
spi.enable_peripheral();
let mut spi = Spi {
spi,
_mode: PhantomData,
};
spi.spi.setup(frequency);
spi.spi.init();
spi.spi.set_data_mode(mode);
// Disconnect any lingering connections
spi.with_pins(NoPin, NoPin, NoPin, NoPin)
}
/// Change the bus frequency of the SPI instance.
///
/// This method allows user to update the bus frequency for the SPI
@ -643,7 +660,21 @@ where
}
}
impl<'d, T> Spi<'d, T, HalfDuplexMode>
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<P = impl Into<AnySpi> + 'd> + 'd,
frequency: HertzU32,
mode: SpiMode,
) -> Spi<'d, HalfDuplexMode> {
Self::new_half_duplex_typed(spi, frequency, mode)
}
}
impl<'d, T> Spi<'d, HalfDuplexMode, T>
where
T: ExtendedInstance,
{
@ -651,13 +682,15 @@ where
///
/// 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<P = T> + 'd,
pub fn new_half_duplex_typed(
spi: impl Peripheral<P = impl Into<T> + 'd> + 'd,
frequency: HertzU32,
mode: SpiMode,
) -> Spi<'d, T, HalfDuplexMode> {
crate::into_ref!(spi);
Self::new_internal(spi, frequency, mode)
) -> Spi<'d, HalfDuplexMode, T> {
let spi = Spi::<HalfDuplexMode, T>::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
@ -761,27 +794,6 @@ where
.with_sio3(sio3)
.with_cs(cs)
}
pub(crate) fn new_internal(
spi: PeripheralRef<'d, T>,
frequency: HertzU32,
mode: SpiMode,
) -> Spi<'d, T, HalfDuplexMode> {
spi.reset_peripheral();
spi.enable_peripheral();
let mut spi = Spi {
spi,
_mode: PhantomData::<HalfDuplexMode>,
};
spi.spi.setup(frequency);
spi.spi.init();
spi.spi.set_data_mode(mode);
// Disconnect any lingering connections
spi.with_pins(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin)
}
/// Change the bus frequency of the SPI instance in half-duplex mode.
///
/// This method allows you to update the bus frequency for the SPI
@ -799,7 +811,7 @@ where
}
}
impl<T> HalfDuplexReadWrite for Spi<'_, T, HalfDuplexMode>
impl<T> HalfDuplexReadWrite for Spi<'_, HalfDuplexMode, T>
where
T: Instance,
{
@ -890,7 +902,7 @@ where
}
}
impl<T> embedded_hal_02::spi::FullDuplex<u8> for Spi<'_, T, FullDuplexMode>
impl<T> embedded_hal_02::spi::FullDuplex<u8> for Spi<'_, FullDuplexMode, T>
where
T: Instance,
{
@ -905,7 +917,7 @@ where
}
}
impl<T> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'_, T, FullDuplexMode>
impl<T> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'_, FullDuplexMode, T>
where
T: Instance,
{
@ -916,7 +928,7 @@ where
}
}
impl<T> embedded_hal_02::blocking::spi::Write<u8> for Spi<'_, T, FullDuplexMode>
impl<T> embedded_hal_02::blocking::spi::Write<u8> for Spi<'_, FullDuplexMode, T>
where
T: Instance,
{
@ -959,7 +971,7 @@ 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, T, D, M>
pub struct SpiDma<'d, D, M, T = AnySpi>
where
T: InstanceDma,
D: DuplexMode,
@ -975,7 +987,7 @@ mod dma {
}
#[cfg(all(esp32, spi_address_workaround))]
unsafe impl<'d, T, D, M> Send for SpiDma<'d, T, D, M>
unsafe impl<'d, D, M, T> Send for SpiDma<'d, D, M, T>
where
T: InstanceDma,
D: DuplexMode,
@ -983,7 +995,7 @@ mod dma {
{
}
impl<'d, T, D, M> core::fmt::Debug for SpiDma<'d, T, D, M>
impl<'d, D, M, T> core::fmt::Debug for SpiDma<'d, D, M, T>
where
T: InstanceDma,
D: DuplexMode,
@ -998,7 +1010,7 @@ mod dma {
}
}
impl<'d, T, D, M> SpiDma<'d, T, D, M>
impl<'d, D, M, T> SpiDma<'d, D, M, T>
where
T: InstanceDma,
D: DuplexMode,
@ -1206,7 +1218,7 @@ mod dma {
}
}
impl<'d, T, D, M> crate::private::Sealed for SpiDma<'d, T, D, M>
impl<'d, D, M, T> crate::private::Sealed for SpiDma<'d, D, M, T>
where
T: InstanceDma,
D: DuplexMode,
@ -1214,7 +1226,7 @@ mod dma {
{
}
impl<'d, T, D, M> InterruptConfigurable for SpiDma<'d, T, D, M>
impl<'d, D, M, T> InterruptConfigurable for SpiDma<'d, D, M, T>
where
T: InstanceDma,
D: DuplexMode,
@ -1226,7 +1238,7 @@ mod dma {
}
}
impl<'d, T, D, M> SpiDma<'d, T, D, M>
impl<'d, D, M, T> SpiDma<'d, D, M, T>
where
T: InstanceDma,
D: DuplexMode,
@ -1246,7 +1258,7 @@ mod dma {
self,
dma_rx_buf: DmaRxBuf,
dma_tx_buf: DmaTxBuf,
) -> SpiDmaBus<'d, T, D, M> {
) -> SpiDmaBus<'d, D, M, T> {
SpiDmaBus::new(self, dma_rx_buf, dma_tx_buf)
}
}
@ -1255,23 +1267,23 @@ mod dma {
///
/// This structure holds references to the SPI instance, DMA buffers, and
/// transfer status.
pub struct SpiDmaTransfer<'d, T, D, M, Buf>
pub struct SpiDmaTransfer<'d, D, M, Buf, T = AnySpi>
where
T: InstanceDma,
D: DuplexMode,
M: Mode,
{
spi_dma: ManuallyDrop<SpiDma<'d, T, D, M>>,
spi_dma: ManuallyDrop<SpiDma<'d, D, M, T>>,
dma_buf: ManuallyDrop<Buf>,
}
impl<'d, T, D, M, Buf> SpiDmaTransfer<'d, T, D, M, Buf>
impl<'d, D, M, T, Buf> SpiDmaTransfer<'d, D, M, Buf, T>
where
T: InstanceDma,
D: DuplexMode,
M: Mode,
{
fn new(spi_dma: SpiDma<'d, T, D, M>, dma_buf: Buf) -> Self {
fn new(spi_dma: SpiDma<'d, D, M, T>, dma_buf: Buf) -> Self {
Self {
spi_dma: ManuallyDrop::new(spi_dma),
dma_buf: ManuallyDrop::new(dma_buf),
@ -1290,7 +1302,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, T, D, M>, Buf) {
pub fn wait(mut self) -> (SpiDma<'d, D, M, T>, Buf) {
self.spi_dma.wait_for_idle();
let retval = unsafe {
(
@ -1310,7 +1322,7 @@ mod dma {
}
}
impl<'d, T, D, M, Buf> Drop for SpiDmaTransfer<'d, T, D, M, Buf>
impl<'d, D, M, T, Buf> Drop for SpiDmaTransfer<'d, D, M, Buf, T>
where
T: InstanceDma,
D: DuplexMode,
@ -1329,7 +1341,7 @@ mod dma {
}
}
impl<'d, T, D, Buf> SpiDmaTransfer<'d, T, D, crate::Async, Buf>
impl<'d, T, D, Buf> SpiDmaTransfer<'d, D, crate::Async, Buf, T>
where
T: InstanceDma,
D: DuplexMode,
@ -1342,7 +1354,7 @@ mod dma {
}
}
impl<'d, T, M> SpiDma<'d, T, FullDuplexMode, M>
impl<'d, M, T> SpiDma<'d, FullDuplexMode, M, T>
where
T: InstanceDma,
M: Mode,
@ -1377,7 +1389,7 @@ mod dma {
pub fn dma_write<TX: DmaTxBuffer>(
mut self,
mut buffer: TX,
) -> Result<SpiDmaTransfer<'d, T, FullDuplexMode, M, TX>, (Error, Self, TX)> {
) -> Result<SpiDmaTransfer<'d, FullDuplexMode, M, TX, T>, (Error, Self, TX)> {
self.wait_for_idle();
match unsafe { self.start_dma_write(&mut buffer) } {
@ -1416,7 +1428,7 @@ mod dma {
pub fn dma_read<RX: DmaRxBuffer>(
mut self,
mut buffer: RX,
) -> Result<SpiDmaTransfer<'d, T, FullDuplexMode, M, RX>, (Error, Self, RX)> {
) -> Result<SpiDmaTransfer<'d, FullDuplexMode, M, RX, T>, (Error, Self, RX)> {
self.wait_for_idle();
match unsafe { self.start_dma_read(&mut buffer) } {
Ok(_) => Ok(SpiDmaTransfer::new(self, buffer)),
@ -1455,7 +1467,7 @@ mod dma {
mut self,
mut rx_buffer: RX,
mut tx_buffer: TX,
) -> Result<SpiDmaTransfer<'d, T, FullDuplexMode, M, (RX, TX)>, (Error, Self, RX, TX)>
) -> Result<SpiDmaTransfer<'d, FullDuplexMode, M, (RX, TX), T>, (Error, Self, RX, TX)>
{
self.wait_for_idle();
match unsafe { self.start_dma_transfer(&mut rx_buffer, &mut tx_buffer) } {
@ -1465,7 +1477,7 @@ mod dma {
}
}
impl<'d, T, M> SpiDma<'d, T, HalfDuplexMode, M>
impl<'d, M, T> SpiDma<'d, HalfDuplexMode, M, T>
where
T: InstanceDma,
M: Mode,
@ -1517,7 +1529,7 @@ mod dma {
address: Address,
dummy: u8,
mut buffer: RX,
) -> Result<SpiDmaTransfer<'d, T, HalfDuplexMode, M, RX>, (Error, Self, RX)> {
) -> Result<SpiDmaTransfer<'d, HalfDuplexMode, M, RX, T>, (Error, Self, RX)> {
self.wait_for_idle();
match unsafe {
@ -1584,7 +1596,7 @@ mod dma {
address: Address,
dummy: u8,
mut buffer: TX,
) -> Result<SpiDmaTransfer<'d, T, HalfDuplexMode, M, TX>, (Error, Self, TX)> {
) -> Result<SpiDmaTransfer<'d, HalfDuplexMode, M, TX, T>, (Error, Self, TX)> {
self.wait_for_idle();
match unsafe {
@ -1600,18 +1612,18 @@ mod dma {
///
/// This structure is responsible for managing SPI transfers using DMA
/// buffers.
pub struct SpiDmaBus<'d, T, D, M>
pub struct SpiDmaBus<'d, D, M, T = AnySpi>
where
T: InstanceDma,
D: DuplexMode,
M: Mode,
{
spi_dma: SpiDma<'d, T, D, M>,
spi_dma: SpiDma<'d, D, M, T>,
rx_buf: DmaRxBuf,
tx_buf: DmaTxBuf,
}
impl<'d, T, D, M> SpiDmaBus<'d, T, D, M>
impl<'d, D, M, T> SpiDmaBus<'d, D, M, T>
where
T: InstanceDma,
D: DuplexMode,
@ -1619,7 +1631,7 @@ mod dma {
{
/// Creates a new `SpiDmaBus` with the specified SPI instance and DMA
/// buffers.
pub fn new(spi_dma: SpiDma<'d, T, D, M>, rx_buf: DmaRxBuf, tx_buf: DmaTxBuf) -> Self {
pub fn new(spi_dma: SpiDma<'d, D, M, T>, rx_buf: DmaRxBuf, tx_buf: DmaTxBuf) -> Self {
Self {
spi_dma,
rx_buf,
@ -1668,7 +1680,7 @@ mod dma {
}
}
impl<'d, T, D, M> InterruptConfigurable for SpiDmaBus<'d, T, D, M>
impl<'d, D, M, T> InterruptConfigurable for SpiDmaBus<'d, D, M, T>
where
T: InstanceDma,
D: DuplexMode,
@ -1680,7 +1692,7 @@ mod dma {
}
}
impl<'d, T, D, M> crate::private::Sealed for SpiDmaBus<'d, T, D, M>
impl<'d, D, M, T> crate::private::Sealed for SpiDmaBus<'d, D, M, T>
where
T: InstanceDma,
D: DuplexMode,
@ -1688,7 +1700,7 @@ mod dma {
{
}
impl<'d, T, M> SpiDmaBus<'d, T, FullDuplexMode, M>
impl<'d, M, T> SpiDmaBus<'d, FullDuplexMode, M, T>
where
T: InstanceDma,
M: Mode,
@ -1788,7 +1800,7 @@ mod dma {
}
}
impl<'d, T, M> HalfDuplexReadWrite for SpiDmaBus<'d, T, HalfDuplexMode, M>
impl<'d, M, T> HalfDuplexReadWrite for SpiDmaBus<'d, HalfDuplexMode, M, T>
where
T: InstanceDma,
M: Mode,
@ -1860,7 +1872,7 @@ mod dma {
}
impl<'d, T> embedded_hal_02::blocking::spi::Transfer<u8>
for SpiDmaBus<'d, T, FullDuplexMode, crate::Blocking>
for SpiDmaBus<'d, FullDuplexMode, crate::Blocking, T>
where
T: InstanceDma,
{
@ -1873,7 +1885,7 @@ mod dma {
}
impl<'d, T> embedded_hal_02::blocking::spi::Write<u8>
for SpiDmaBus<'d, T, FullDuplexMode, crate::Blocking>
for SpiDmaBus<'d, FullDuplexMode, crate::Blocking, T>
where
T: InstanceDma,
{
@ -1932,7 +1944,7 @@ mod dma {
}
}
impl<'d, T> SpiDmaBus<'d, T, FullDuplexMode, crate::Async>
impl<'d, T> SpiDmaBus<'d, FullDuplexMode, crate::Async, T>
where
T: InstanceDma,
{
@ -2046,7 +2058,7 @@ mod dma {
}
}
impl<'d, T> embedded_hal_async::spi::SpiBus for SpiDmaBus<'d, T, FullDuplexMode, crate::Async>
impl<'d, T> embedded_hal_async::spi::SpiBus for SpiDmaBus<'d, FullDuplexMode, crate::Async, T>
where
T: InstanceDma,
{
@ -2078,7 +2090,7 @@ mod dma {
use super::*;
impl<'d, T, M> ErrorType for SpiDmaBus<'d, T, FullDuplexMode, M>
impl<'d, M, T> ErrorType for SpiDmaBus<'d, FullDuplexMode, M, T>
where
T: InstanceDma,
M: Mode,
@ -2086,7 +2098,7 @@ mod dma {
type Error = Error;
}
impl<'d, T, M> SpiBus for SpiDmaBus<'d, T, FullDuplexMode, M>
impl<'d, M, T> SpiBus for SpiDmaBus<'d, FullDuplexMode, M, T>
where
T: InstanceDma,
M: Mode,
@ -2121,11 +2133,11 @@ mod ehal1 {
use super::*;
impl<T, M> embedded_hal::spi::ErrorType for Spi<'_, T, M> {
impl<T, M> embedded_hal::spi::ErrorType for Spi<'_, M, T> {
type Error = Error;
}
impl<T> FullDuplex for Spi<'_, T, FullDuplexMode>
impl<T> FullDuplex for Spi<'_, FullDuplexMode, T>
where
T: Instance,
{
@ -2138,7 +2150,7 @@ mod ehal1 {
}
}
impl<T> SpiBus for Spi<'_, T, FullDuplexMode>
impl<T> SpiBus for Spi<'_, FullDuplexMode, T>
where
T: Instance,
{
@ -2680,24 +2692,21 @@ pub trait Instance: private::Sealed + PeripheralMarker {
}
fn ch_bus_freq(&mut self, frequency: HertzU32) {
// Disable clock source
#[cfg(gdma)]
self.register_block().clk_gate().modify(|_, w| {
w.clk_en().clear_bit();
w.mst_clk_active().clear_bit();
w.mst_clk_sel().clear_bit()
});
fn enable_clocks(_reg_block: &RegisterBlock, _enable: bool) {
#[cfg(gdma)]
_reg_block.clk_gate().modify(|_, w| {
w.clk_en().bit(_enable);
w.mst_clk_active().bit(_enable);
w.mst_clk_sel().bit(_enable)
});
}
enable_clocks(self.register_block(), false);
// Change clock frequency
self.setup(frequency);
// Enable clock source
#[cfg(gdma)]
self.register_block().clk_gate().modify(|_, w| {
w.clk_en().set_bit();
w.mst_clk_active().set_bit();
w.mst_clk_sel().set_bit()
});
enable_clocks(self.register_block(), true);
}
#[cfg(not(any(esp32, esp32c3, esp32s2)))]
@ -3296,3 +3305,115 @@ impl ExtendedInstance for crate::peripherals::SPI3 {
}
}
}
impl Instance for super::AnySpi {
delegate::delegate! {
to match &self.0 {
super::AnySpiInner::Spi2(spi) => spi,
#[cfg(spi3)]
super::AnySpiInner::Spi3(spi) => spi,
} {
fn register_block(&self) -> &RegisterBlock;
fn spi_num(&self) -> u8;
fn sclk_signal(&self) -> OutputSignal;
fn mosi_signal(&self) -> OutputSignal;
fn miso_signal(&self) -> InputSignal;
fn cs_signal(&self) -> OutputSignal;
}
}
delegate::delegate! {
to match &mut self.0 {
super::AnySpiInner::Spi2(spi) => spi,
#[cfg(spi3)]
super::AnySpiInner::Spi3(spi) => spi,
} {
fn set_interrupt_handler(&mut self, handler: InterruptHandler);
}
}
}
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 InstanceDma for super::AnySpi {
delegate::delegate! {
to match &self.0 {
super::AnySpiInner::Spi2(spi) => spi,
#[cfg(spi3)]
super::AnySpiInner::Spi3(spi) => spi,
} {
fn clear_dma_interrupts(&self);
}
}
}

View File

@ -9,7 +9,7 @@
//! more information on these modes, please refer to the documentation in their
//! respective modules.
use crate::dma::{DmaError, PeripheralMarker};
use crate::dma::{DmaEligible, DmaError};
pub mod master;
pub mod slave;
@ -101,18 +101,28 @@ pub struct HalfDuplexMode {}
impl DuplexMode for HalfDuplexMode {}
impl crate::private::Sealed for HalfDuplexMode {}
#[cfg(spi2)]
impl PeripheralMarker for crate::peripherals::SPI2 {
#[inline(always)]
fn peripheral(&self) -> crate::system::Peripheral {
crate::system::Peripheral::Spi2
crate::any_peripheral! {
/// Any SPI peripheral.
pub peripheral AnySpi {
#[cfg(spi2)]
Spi2(crate::peripherals::SPI2),
#[cfg(spi3)]
Spi3(crate::peripherals::SPI3),
}
}
#[cfg(spi3)]
impl PeripheralMarker for crate::peripherals::SPI3 {
#[inline(always)]
fn peripheral(&self) -> crate::system::Peripheral {
crate::system::Peripheral::Spi3
impl DmaEligible for AnySpi {
#[cfg(gdma)]
type Dma = crate::dma::AnyGdmaChannel;
#[cfg(pdma)]
type Dma = crate::dma::AnySpiDmaChannel;
fn dma_peripheral(&self) -> crate::dma::DmaPeripheral {
match &self.0 {
#[cfg(spi2)]
AnySpiInner::Spi2(_) => crate::dma::DmaPeripheral::Spi2,
#[cfg(spi3)]
AnySpiInner::Spi3(_) => crate::dma::DmaPeripheral::Spi3,
}
}
}

View File

@ -78,6 +78,7 @@ use crate::{
peripheral::{Peripheral, PeripheralRef},
peripherals::spi2::RegisterBlock,
private,
spi::AnySpi,
system::PeripheralClockControl,
};
@ -86,17 +87,14 @@ const MAX_DMA_SIZE: usize = 32768 - 32;
/// SPI peripheral driver.
///
/// See the [module-level documentation][self] for more details.
pub struct Spi<'d, T, M> {
pub struct Spi<'d, M, T = AnySpi> {
spi: PeripheralRef<'d, T>,
#[allow(dead_code)]
data_mode: SpiMode,
_mode: PhantomData<M>,
}
impl<'d, T> Spi<'d, T, FullDuplexMode>
where
T: Instance,
{
impl<'d> Spi<'d, FullDuplexMode> {
/// Constructs an SPI instance in 8bit dataframe mode.
pub fn new<
SCK: PeripheralInput,
@ -104,42 +102,68 @@ where
MISO: PeripheralOutput,
CS: PeripheralInput,
>(
spi: impl Peripheral<P = T> + 'd,
spi: impl Peripheral<P = impl Into<AnySpi> + 'd> + 'd,
sclk: impl Peripheral<P = SCK> + 'd,
mosi: impl Peripheral<P = MOSI> + 'd,
miso: impl Peripheral<P = MISO> + 'd,
cs: impl Peripheral<P = CS> + 'd,
mode: SpiMode,
) -> Spi<'d, T, FullDuplexMode> {
crate::into_ref!(spi, sclk, mosi, miso, cs);
) -> Spi<'d, FullDuplexMode> {
Self::new_typed(spi, sclk, mosi, miso, cs, mode)
}
}
impl<'d, T> Spi<'d, FullDuplexMode, T>
where
T: Instance,
{
/// Constructs an SPI instance in 8bit dataframe mode.
pub fn new_typed<
SCK: PeripheralInput,
MOSI: PeripheralInput,
MISO: PeripheralOutput,
CS: PeripheralInput,
>(
spi: impl Peripheral<P = impl Into<T> + 'd> + 'd,
sclk: impl Peripheral<P = SCK> + 'd,
mosi: impl Peripheral<P = MOSI> + 'd,
miso: impl Peripheral<P = MISO> + 'd,
cs: impl Peripheral<P = CS> + 'd,
mode: SpiMode,
) -> Spi<'d, FullDuplexMode, T> {
crate::into_ref!(sclk, mosi, miso, cs);
let this = Self::new_internal(spi, mode);
// TODO: with_pins et. al.
sclk.enable_input(true, private::Internal);
sclk.connect_input_to_peripheral(spi.sclk_signal(), private::Internal);
sclk.connect_input_to_peripheral(this.spi.sclk_signal(), private::Internal);
mosi.enable_input(true, private::Internal);
mosi.connect_input_to_peripheral(spi.mosi_signal(), private::Internal);
mosi.connect_input_to_peripheral(this.spi.mosi_signal(), private::Internal);
miso.set_to_push_pull_output(private::Internal);
miso.connect_peripheral_to_output(spi.miso_signal(), private::Internal);
miso.connect_peripheral_to_output(this.spi.miso_signal(), private::Internal);
cs.enable_input(true, private::Internal);
cs.connect_input_to_peripheral(spi.cs_signal(), private::Internal);
cs.connect_input_to_peripheral(this.spi.cs_signal(), private::Internal);
Self::new_internal(spi, mode)
this
}
pub(crate) fn new_internal(
spi: PeripheralRef<'d, T>,
spi: impl Peripheral<P = impl Into<T> + 'd> + 'd,
mode: SpiMode,
) -> Spi<'d, T, FullDuplexMode> {
spi.reset_peripheral();
spi.enable_peripheral();
) -> Spi<'d, FullDuplexMode, T> {
crate::into_ref!(spi);
let mut spi = Spi {
spi,
spi: spi.map_into(),
data_mode: mode,
_mode: PhantomData,
};
spi.spi.reset_peripheral();
spi.spi.enable_peripheral();
spi.spi.init();
spi.spi.set_data_mode(mode, false);
@ -169,7 +193,7 @@ pub mod dma {
Mode,
};
impl<'d, T> Spi<'d, T, FullDuplexMode>
impl<'d, T> Spi<'d, FullDuplexMode, T>
where
T: InstanceDma,
{
@ -181,7 +205,7 @@ pub mod dma {
channel: Channel<'d, CH, DmaMode>,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
) -> SpiDma<'d, T, DmaMode>
) -> SpiDma<'d, DmaMode, T>
where
CH: DmaChannelConvert<T::Dma>,
DmaMode: Mode,
@ -192,7 +216,7 @@ pub mod dma {
}
/// A DMA capable SPI instance.
pub struct SpiDma<'d, T, DmaMode>
pub struct SpiDma<'d, DmaMode, T = AnySpi>
where
T: InstanceDma,
DmaMode: Mode,
@ -203,7 +227,7 @@ pub mod dma {
tx_chain: DescriptorChain,
}
impl<'d, T, DmaMode> core::fmt::Debug for SpiDma<'d, T, DmaMode>
impl<'d, DmaMode, T> core::fmt::Debug for SpiDma<'d, DmaMode, T>
where
T: InstanceDma,
DmaMode: Mode,
@ -213,7 +237,7 @@ pub mod dma {
}
}
impl<'d, T, DmaMode> DmaSupport for SpiDma<'d, T, DmaMode>
impl<'d, DmaMode, T> DmaSupport for SpiDma<'d, DmaMode, T>
where
T: InstanceDma,
DmaMode: Mode,
@ -232,7 +256,7 @@ pub mod dma {
}
}
impl<'d, T, DmaMode> DmaSupportTx for SpiDma<'d, T, DmaMode>
impl<'d, DmaMode, T> DmaSupportTx for SpiDma<'d, DmaMode, T>
where
T: InstanceDma,
DmaMode: Mode,
@ -248,7 +272,7 @@ pub mod dma {
}
}
impl<'d, T, DmaMode> DmaSupportRx for SpiDma<'d, T, DmaMode>
impl<'d, DmaMode, T> DmaSupportRx for SpiDma<'d, DmaMode, T>
where
T: InstanceDma,
DmaMode: Mode,
@ -264,7 +288,7 @@ pub mod dma {
}
}
impl<'d, T, DmaMode> SpiDma<'d, T, DmaMode>
impl<'d, DmaMode, T> SpiDma<'d, DmaMode, T>
where
T: InstanceDma,
DmaMode: Mode,
@ -566,8 +590,6 @@ pub trait Instance: private::Sealed + PeripheralMarker {
PeripheralClockControl::enable(self.peripheral());
}
fn spi_num(&self) -> u8;
#[cfg(esp32)]
fn prepare_length_and_lines(&self, rx_len: usize, tx_len: usize) {
let reg_block = self.register_block();
@ -728,11 +750,6 @@ impl Instance for crate::peripherals::SPI2 {
self
}
#[inline(always)]
fn spi_num(&self) -> u8 {
2
}
#[inline(always)]
fn sclk_signal(&self) -> InputSignal {
cfg_if::cfg_if! {
@ -785,11 +802,6 @@ impl Instance for crate::peripherals::SPI3 {
self
}
#[inline(always)]
fn spi_num(&self) -> u8 {
3
}
#[inline(always)]
fn sclk_signal(&self) -> InputSignal {
cfg_if::cfg_if! {
@ -834,3 +846,21 @@ impl Instance for crate::peripherals::SPI3 {
}
}
}
impl Instance for super::AnySpi {
delegate::delegate! {
to match &self.0 {
super::AnySpiInner::Spi2(spi) => spi,
#[cfg(spi3)]
super::AnySpiInner::Spi3(spi) => spi,
} {
fn register_block(&self) -> &RegisterBlock;
fn sclk_signal(&self) -> InputSignal;
fn mosi_signal(&self) -> InputSignal;
fn miso_signal(&self) -> OutputSignal;
fn cs_signal(&self) -> InputSignal;
}
}
}
impl InstanceDma for super::AnySpi {}

View File

@ -12,7 +12,6 @@ use esp_hal::{
dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf},
dma_buffers,
interrupt::{software::SoftwareInterruptControl, Priority},
peripherals::SPI3,
prelude::*,
spi::{
master::{Spi, SpiDma},
@ -35,7 +34,7 @@ macro_rules! mk_static {
}
#[embassy_executor::task]
async fn interrupt_driven_task(spi: SpiDma<'static, SPI3, FullDuplexMode, Async>) {
async fn interrupt_driven_task(spi: SpiDma<'static, FullDuplexMode, Async>) {
let mut ticker = Ticker::every(Duration::from_millis(1));
let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(128);

View File

@ -38,7 +38,7 @@ cfg_if::cfg_if! {
}
}
type SpiUnderTest = SpiDma<'static, esp_hal::peripherals::SPI2, HalfDuplexMode, Blocking>;
type SpiUnderTest = SpiDma<'static, HalfDuplexMode, Blocking>;
struct Context {
spi: esp_hal::peripherals::SPI2,

View File

@ -15,7 +15,6 @@ use esp_hal::{
dma::{Dma, DmaDescriptor, DmaPriority, DmaRxBuf, DmaTxBuf},
dma_buffers,
gpio::{Io, Level, NoPin},
peripherals::SPI2,
prelude::*,
spi::{master::Spi, FullDuplexMode, SpiMode},
};
@ -35,7 +34,7 @@ cfg_if::cfg_if! {
}
struct Context {
spi: Spi<'static, SPI2, FullDuplexMode>,
spi: Spi<'static, FullDuplexMode>,
dma_channel: DmaChannelCreator,
// Reuse the really large buffer so we don't run out of DRAM with many tests
rx_buffer: &'static mut [u8],

View File

@ -9,7 +9,6 @@ use esp_hal::{
dma::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf},
dma_buffers,
gpio::{Io, Level, Output},
peripherals::SPI2,
prelude::*,
spi::{
master::{Address, Command, HalfDuplexReadWrite, Spi, SpiDma},
@ -22,7 +21,7 @@ use esp_hal::{
use hil_test as _;
struct Context {
spi: SpiDma<'static, SPI2, HalfDuplexMode, Blocking>,
spi: SpiDma<'static, HalfDuplexMode, Blocking>,
miso_mirror: Output<'static>,
}

View File

@ -10,7 +10,6 @@ use esp_hal::{
dma_buffers,
gpio::{interconnect::InputSignal, Io},
pcnt::{channel::EdgeMode, unit::Unit, Pcnt},
peripherals::SPI2,
prelude::*,
spi::{
master::{Address, Command, HalfDuplexReadWrite, Spi, SpiDma},
@ -23,7 +22,7 @@ use esp_hal::{
use hil_test as _;
struct Context {
spi: SpiDma<'static, SPI2, HalfDuplexMode, Blocking>,
spi: SpiDma<'static, HalfDuplexMode, Blocking>,
pcnt_unit: Unit<'static, 0>,
pcnt_source: InputSignal,
}

View File

@ -12,7 +12,6 @@ use esp_hal::{
dma_descriptors_chunk_size,
gpio::{interconnect::InputSignal, Io},
pcnt::{channel::EdgeMode, unit::Unit, Pcnt},
peripherals::SPI2,
prelude::*,
spi::{
master::{Address, Command, HalfDuplexReadWrite, Spi, SpiDma},
@ -40,7 +39,7 @@ macro_rules! dma_alloc_buffer {
}
struct Context {
spi: SpiDma<'static, SPI2, HalfDuplexMode, Blocking>,
spi: SpiDma<'static, HalfDuplexMode, Blocking>,
pcnt_unit: Unit<'static, 0>,
pcnt_source: InputSignal,
}

View File

@ -12,7 +12,6 @@ use esp_hal::{
dma::{Dma, DmaPriority},
dma_buffers,
gpio::{interconnect::InputSignal, Io, Level, Output, PeripheralInput},
peripherals::SPI2,
spi::{slave::Spi, FullDuplexMode, SpiMode},
};
use hil_test as _;
@ -26,7 +25,7 @@ cfg_if::cfg_if! {
}
struct Context {
spi: Spi<'static, SPI2, FullDuplexMode>,
spi: Spi<'static, FullDuplexMode>,
dma_channel: DmaChannelCreator,
bitbang_spi: BitbangSpi,
}