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) - 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) - Add burst transfer support to DMA buffers (#2336)
- `AnyPin` now implements `From<GpioPin<N>>`. (#2326) - `AnyPin` now implements `From<GpioPin<N>>`. (#2326)
- Added `AnySpi` and `AnySpiDmaChannel`. (#2334)
- `Pins::steal()` to unsafely obtain GPIO. (#2335) - `Pins::steal()` to unsafely obtain GPIO. (#2335)
### Changed ### Changed
- Peripheral type erasure for SPI (#2334)
### Fixed ### Fixed
### Removed ### 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>] {} impl $crate::private::Sealed for [<Spi $num DmaChannel>] {}
#[doc = concat!("Creates a channel for SPI", $num)] #[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 { impl RegBlock for I2S0 {
fn register_block(&self) -> &RegisterBlock { fn register_block(&self) -> &RegisterBlock {
unsafe { &*I2S0::PTR.cast::<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)] #[cfg(i2s1)]
impl RegBlock for I2S1 { impl RegBlock for I2S1 {
fn register_block(&self) -> &RegisterBlock { fn register_block(&self) -> &RegisterBlock {

View File

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

View File

@ -142,7 +142,6 @@ mod fmt;
#[cfg(riscv)] #[cfg(riscv)]
pub use esp_riscv_rt::{self, entry, riscv}; pub use esp_riscv_rt::{self, entry, riscv};
pub use procmacros as macros;
#[cfg(xtensa)] #[cfg(xtensa)]
pub use xtensa_lx; pub use xtensa_lx;
#[cfg(xtensa)] #[cfg(xtensa)]
@ -241,6 +240,8 @@ pub mod debugger;
#[doc(hidden)] #[doc(hidden)]
pub mod sync; pub mod sync;
pub mod macros;
/// State of the CPU saved when entering exception or interrupt /// State of the CPU saved when entering exception or interrupt
pub mod trapframe { pub mod trapframe {
#[cfg(riscv)] #[cfg(riscv)]
@ -449,26 +450,6 @@ unsafe extern "C" fn stack_chk_fail() {
panic!("Stack corruption detected"); 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::{ use crate::{
clock::{Clocks, CpuClock}, clock::{Clocks, CpuClock},
config::{WatchdogConfig, WatchdogStatus}, 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 { 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)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! peripherals { 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`] /// Contains the generated peripherals which implement [`Peripheral`]
mod peripherals { mod peripherals {
pub use super::pac::*; 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)] #[allow(non_snake_case)]
pub struct Peripherals { pub struct Peripherals {
$( $(
$(#[$cfg])?
/// Each field represents a hardware peripheral. /// Each field represents a hardware peripheral.
pub $name: peripherals::$name, pub $name: peripherals::$name,
)* )*
@ -245,9 +262,7 @@ mod peripheral_macros {
Self::steal() Self::steal()
}) })
} }
}
impl Peripherals {
/// Unsafely create an instance of this peripheral out of thin air. /// Unsafely create an instance of this peripheral out of thin air.
/// ///
/// # Safety /// # Safety
@ -257,7 +272,6 @@ mod peripheral_macros {
pub unsafe fn steal() -> Self { pub unsafe fn steal() -> Self {
Self { Self {
$( $(
$(#[$cfg])?
$name: peripherals::$name::steal(), $name: peripherals::$name::steal(),
)* )*
} }
@ -313,8 +327,7 @@ mod peripheral_macros {
#[macro_export] #[macro_export]
/// Macro to create a peripheral structure. /// Macro to create a peripheral structure.
macro_rules! create_peripheral { macro_rules! create_peripheral {
($(#[$cfg:meta])? $name:ident <= virtual) => { ($([$enum_variant:ident])? $name:ident <= virtual) => {
$(#[$cfg])?
#[derive(Debug)] #[derive(Debug)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
/// Represents a virtual peripheral with no associated hardware. /// Represents a virtual peripheral with no associated hardware.
@ -323,7 +336,6 @@ mod peripheral_macros {
/// is defined as virtual. /// is defined as virtual.
pub struct $name { _inner: () } pub struct $name { _inner: () }
$(#[$cfg])?
impl $name { impl $name {
/// Unsafely create an instance of this peripheral out of thin air. /// Unsafely create an instance of this peripheral out of thin air.
/// ///
@ -346,29 +358,21 @@ mod peripheral_macros {
} }
impl $crate::private::Sealed for $name {} 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 { impl $crate::dma::PeripheralMarker for $crate::peripherals::$name {
/// Unsafely create an instance of this peripheral out of thin air. #[inline(always)]
/// fn peripheral(&self) -> $crate::system::Peripheral {
/// # Safety $crate::system::Peripheral::$enum_variant
/// }
/// You must ensure that you're only using one instance of this type at a time.
#[inline]
pub unsafe fn steal() -> Self {
Self { _inner: () }
} }
)?
};
($([$enum_variant:ident])? $name:ident <= $base:ident) => {
$crate::create_peripheral!($([$enum_variant])? $name <= virtual);
impl $name {
#[doc = r"Pointer to the register block"] #[doc = r"Pointer to the register block"]
pub const PTR: *const <super::pac::$base as core::ops::Deref>::Target = super::pac::$base::PTR; 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 { impl core::ops::DerefMut for $name {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(Self::PTR as *mut _) } 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, HINF <= HINF,
I2C0 <= I2C0, I2C0 <= I2C0,
I2C1 <= I2C1, I2C1 <= I2C1,
I2S0 <= I2S0 (I2S0), [I2s0] I2S0 <= I2S0 (I2S0),
I2S1 <= I2S1 (I2S1), [I2s1] I2S1 <= I2S1 (I2S1),
IO_MUX <= IO_MUX, IO_MUX <= IO_MUX,
LEDC <= LEDC, LEDC <= LEDC,
MCPWM0 <= MCPWM0, MCPWM0 <= MCPWM0,
@ -60,8 +60,8 @@ crate::peripherals! {
SLCHOST <= SLCHOST, SLCHOST <= SLCHOST,
SPI0 <= SPI0, SPI0 <= SPI0,
SPI1 <= SPI1, SPI1 <= SPI1,
SPI2 <= SPI2 (SPI2_DMA, SPI2), [Spi2] SPI2 <= SPI2 (SPI2_DMA, SPI2),
SPI3 <= SPI3 (SPI3_DMA, SPI3), [Spi3] SPI3 <= SPI3 (SPI3_DMA, SPI3),
SYSTEM <= DPORT, SYSTEM <= DPORT,
SW_INTERRUPT <= virtual, SW_INTERRUPT <= virtual,
TIMG0 <= TIMG0, TIMG0 <= TIMG0,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -87,6 +87,7 @@ use crate::{
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::spi2::RegisterBlock, peripherals::spi2::RegisterBlock,
private, private,
spi::AnySpi,
system::PeripheralClockControl, system::PeripheralClockControl,
Mode, Mode,
}; };
@ -452,15 +453,35 @@ pub trait HalfDuplexReadWrite {
} }
/// SPI peripheral driver /// SPI peripheral driver
pub struct Spi<'d, T, M> { pub struct Spi<'d, M, T = AnySpi> {
spi: PeripheralRef<'d, T>, spi: PeripheralRef<'d, T>,
_mode: PhantomData<M>, _mode: PhantomData<M>,
} }
impl<'d, T, M> Spi<'d, T, M> impl<'d, M, T> Spi<'d, M, T>
where where
T: Instance, 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. /// Assign the SCK (Serial Clock) pin for the SPI instance.
/// ///
/// Sets the specified pin to push-pull output and connects it to the SPI /// 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 where
T: InstanceDma, T: InstanceDma,
M: DuplexMode, M: DuplexMode,
@ -499,7 +520,7 @@ where
pub fn with_dma<CH, DmaMode>( pub fn with_dma<CH, DmaMode>(
self, self,
channel: crate::dma::Channel<'d, CH, DmaMode>, channel: crate::dma::Channel<'d, CH, DmaMode>,
) -> SpiDma<'d, T, M, DmaMode> ) -> SpiDma<'d, M, DmaMode, T>
where where
CH: DmaChannelConvert<T::Dma>, CH: DmaChannelConvert<T::Dma>,
DmaMode: Mode, DmaMode: Mode,
@ -508,7 +529,7 @@ where
} }
} }
impl<'d, T> Spi<'d, T, FullDuplexMode> impl<'d, T> Spi<'d, FullDuplexMode, T>
where where
T: Instance, 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 where
T: Instance, T: Instance,
{ {
@ -552,13 +587,15 @@ where
/// ///
/// All pins are optional. Setup these pins using /// All pins are optional. Setup these pins using
/// [with_pins](Self::with_pins) or individual methods for each pin. /// [with_pins](Self::with_pins) or individual methods for each pin.
pub fn new( pub fn new_typed(
spi: impl Peripheral<P = T> + 'd, spi: impl Peripheral<P = impl Into<T> + 'd> + 'd,
frequency: HertzU32, frequency: HertzU32,
mode: SpiMode, mode: SpiMode,
) -> Spi<'d, T, FullDuplexMode> { ) -> Spi<'d, FullDuplexMode, T> {
crate::into_ref!(spi); let spi = Spi::<FullDuplexMode, T>::new_internal(spi, frequency, mode);
Self::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. /// Assign the MOSI (Master Out Slave In) pin for the SPI instance.
@ -614,26 +651,6 @@ where
.with_cs(cs) .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. /// Change the bus frequency of the SPI instance.
/// ///
/// This method allows user to update the bus frequency for the SPI /// 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 where
T: ExtendedInstance, T: ExtendedInstance,
{ {
@ -651,13 +682,15 @@ where
/// ///
/// All pins are optional. Setup these pins using /// All pins are optional. Setup these pins using
/// [with_pins](Self::with_pins) or individual methods for each pin. /// [with_pins](Self::with_pins) or individual methods for each pin.
pub fn new_half_duplex( pub fn new_half_duplex_typed(
spi: impl Peripheral<P = T> + 'd, spi: impl Peripheral<P = impl Into<T> + 'd> + 'd,
frequency: HertzU32, frequency: HertzU32,
mode: SpiMode, mode: SpiMode,
) -> Spi<'d, T, HalfDuplexMode> { ) -> Spi<'d, HalfDuplexMode, T> {
crate::into_ref!(spi); let spi = Spi::<HalfDuplexMode, T>::new_internal(spi, frequency, mode);
Self::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 /// Assign the MOSI (Master Out Slave In) pin for the SPI instance in
@ -761,27 +794,6 @@ where
.with_sio3(sio3) .with_sio3(sio3)
.with_cs(cs) .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. /// Change the bus frequency of the SPI instance in half-duplex mode.
/// ///
/// This method allows you to update the bus frequency for the SPI /// 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 where
T: Instance, 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 where
T: Instance, 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 where
T: Instance, 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 where
T: Instance, T: Instance,
{ {
@ -959,7 +971,7 @@ mod dma {
/// [`SpiDmaBus`] via `with_buffers` to get access /// [`SpiDmaBus`] via `with_buffers` to get access
/// to a DMA capable SPI bus that implements the /// to a DMA capable SPI bus that implements the
/// embedded-hal traits. /// embedded-hal traits.
pub struct SpiDma<'d, T, D, M> pub struct SpiDma<'d, D, M, T = AnySpi>
where where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, D: DuplexMode,
@ -975,7 +987,7 @@ mod dma {
} }
#[cfg(all(esp32, spi_address_workaround))] #[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 where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, 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 where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, 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 where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, 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 where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, 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 where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, 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 where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, D: DuplexMode,
@ -1246,7 +1258,7 @@ mod dma {
self, self,
dma_rx_buf: DmaRxBuf, dma_rx_buf: DmaRxBuf,
dma_tx_buf: DmaTxBuf, dma_tx_buf: DmaTxBuf,
) -> SpiDmaBus<'d, T, D, M> { ) -> SpiDmaBus<'d, D, M, T> {
SpiDmaBus::new(self, dma_rx_buf, dma_tx_buf) 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 /// This structure holds references to the SPI instance, DMA buffers, and
/// transfer status. /// transfer status.
pub struct SpiDmaTransfer<'d, T, D, M, Buf> pub struct SpiDmaTransfer<'d, D, M, Buf, T = AnySpi>
where where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, D: DuplexMode,
M: Mode, M: Mode,
{ {
spi_dma: ManuallyDrop<SpiDma<'d, T, D, M>>, spi_dma: ManuallyDrop<SpiDma<'d, D, M, T>>,
dma_buf: ManuallyDrop<Buf>, 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 where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, D: DuplexMode,
M: Mode, 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 { Self {
spi_dma: ManuallyDrop::new(spi_dma), spi_dma: ManuallyDrop::new(spi_dma),
dma_buf: ManuallyDrop::new(dma_buf), dma_buf: ManuallyDrop::new(dma_buf),
@ -1290,7 +1302,7 @@ mod dma {
/// ///
/// This method blocks until the transfer is finished and returns the /// This method blocks until the transfer is finished and returns the
/// `SpiDma` instance and the associated buffer. /// `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(); self.spi_dma.wait_for_idle();
let retval = unsafe { 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 where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, 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 where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, 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 where
T: InstanceDma, T: InstanceDma,
M: Mode, M: Mode,
@ -1377,7 +1389,7 @@ mod dma {
pub fn dma_write<TX: DmaTxBuffer>( pub fn dma_write<TX: DmaTxBuffer>(
mut self, mut self,
mut buffer: TX, 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(); self.wait_for_idle();
match unsafe { self.start_dma_write(&mut buffer) } { match unsafe { self.start_dma_write(&mut buffer) } {
@ -1416,7 +1428,7 @@ mod dma {
pub fn dma_read<RX: DmaRxBuffer>( pub fn dma_read<RX: DmaRxBuffer>(
mut self, mut self,
mut buffer: RX, 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(); self.wait_for_idle();
match unsafe { self.start_dma_read(&mut buffer) } { match unsafe { self.start_dma_read(&mut buffer) } {
Ok(_) => Ok(SpiDmaTransfer::new(self, buffer)), Ok(_) => Ok(SpiDmaTransfer::new(self, buffer)),
@ -1455,7 +1467,7 @@ mod dma {
mut self, mut self,
mut rx_buffer: RX, mut rx_buffer: RX,
mut tx_buffer: TX, 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(); self.wait_for_idle();
match unsafe { self.start_dma_transfer(&mut rx_buffer, &mut tx_buffer) } { 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 where
T: InstanceDma, T: InstanceDma,
M: Mode, M: Mode,
@ -1517,7 +1529,7 @@ mod dma {
address: Address, address: Address,
dummy: u8, dummy: u8,
mut buffer: RX, 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(); self.wait_for_idle();
match unsafe { match unsafe {
@ -1584,7 +1596,7 @@ mod dma {
address: Address, address: Address,
dummy: u8, dummy: u8,
mut buffer: TX, 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(); self.wait_for_idle();
match unsafe { match unsafe {
@ -1600,18 +1612,18 @@ mod dma {
/// ///
/// This structure is responsible for managing SPI transfers using DMA /// This structure is responsible for managing SPI transfers using DMA
/// buffers. /// buffers.
pub struct SpiDmaBus<'d, T, D, M> pub struct SpiDmaBus<'d, D, M, T = AnySpi>
where where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, D: DuplexMode,
M: Mode, M: Mode,
{ {
spi_dma: SpiDma<'d, T, D, M>, spi_dma: SpiDma<'d, D, M, T>,
rx_buf: DmaRxBuf, rx_buf: DmaRxBuf,
tx_buf: DmaTxBuf, tx_buf: DmaTxBuf,
} }
impl<'d, T, D, M> SpiDmaBus<'d, T, D, M> impl<'d, D, M, T> SpiDmaBus<'d, D, M, T>
where where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, D: DuplexMode,
@ -1619,7 +1631,7 @@ mod dma {
{ {
/// Creates a new `SpiDmaBus` with the specified SPI instance and DMA /// Creates a new `SpiDmaBus` with the specified SPI instance and DMA
/// buffers. /// 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 { Self {
spi_dma, spi_dma,
rx_buf, 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 where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, 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 where
T: InstanceDma, T: InstanceDma,
D: DuplexMode, 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 where
T: InstanceDma, T: InstanceDma,
M: Mode, 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 where
T: InstanceDma, T: InstanceDma,
M: Mode, M: Mode,
@ -1860,7 +1872,7 @@ mod dma {
} }
impl<'d, T> embedded_hal_02::blocking::spi::Transfer<u8> 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 where
T: InstanceDma, T: InstanceDma,
{ {
@ -1873,7 +1885,7 @@ mod dma {
} }
impl<'d, T> embedded_hal_02::blocking::spi::Write<u8> 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 where
T: InstanceDma, 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 where
T: InstanceDma, 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 where
T: InstanceDma, T: InstanceDma,
{ {
@ -2078,7 +2090,7 @@ mod dma {
use super::*; 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 where
T: InstanceDma, T: InstanceDma,
M: Mode, M: Mode,
@ -2086,7 +2098,7 @@ mod dma {
type Error = Error; 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 where
T: InstanceDma, T: InstanceDma,
M: Mode, M: Mode,
@ -2121,11 +2133,11 @@ mod ehal1 {
use super::*; 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; type Error = Error;
} }
impl<T> FullDuplex for Spi<'_, T, FullDuplexMode> impl<T> FullDuplex for Spi<'_, FullDuplexMode, T>
where where
T: Instance, T: Instance,
{ {
@ -2138,7 +2150,7 @@ mod ehal1 {
} }
} }
impl<T> SpiBus for Spi<'_, T, FullDuplexMode> impl<T> SpiBus for Spi<'_, FullDuplexMode, T>
where where
T: Instance, T: Instance,
{ {
@ -2680,24 +2692,21 @@ pub trait Instance: private::Sealed + PeripheralMarker {
} }
fn ch_bus_freq(&mut self, frequency: HertzU32) { fn ch_bus_freq(&mut self, frequency: HertzU32) {
// Disable clock source fn enable_clocks(_reg_block: &RegisterBlock, _enable: bool) {
#[cfg(gdma)] #[cfg(gdma)]
self.register_block().clk_gate().modify(|_, w| { _reg_block.clk_gate().modify(|_, w| {
w.clk_en().clear_bit(); w.clk_en().bit(_enable);
w.mst_clk_active().clear_bit(); w.mst_clk_active().bit(_enable);
w.mst_clk_sel().clear_bit() w.mst_clk_sel().bit(_enable)
}); });
}
enable_clocks(self.register_block(), false);
// Change clock frequency // Change clock frequency
self.setup(frequency); self.setup(frequency);
// Enable clock source enable_clocks(self.register_block(), true);
#[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()
});
} }
#[cfg(not(any(esp32, esp32c3, esp32s2)))] #[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 //! more information on these modes, please refer to the documentation in their
//! respective modules. //! respective modules.
use crate::dma::{DmaError, PeripheralMarker}; use crate::dma::{DmaEligible, DmaError};
pub mod master; pub mod master;
pub mod slave; pub mod slave;
@ -101,18 +101,28 @@ pub struct HalfDuplexMode {}
impl DuplexMode for HalfDuplexMode {} impl DuplexMode for HalfDuplexMode {}
impl crate::private::Sealed for HalfDuplexMode {} impl crate::private::Sealed for HalfDuplexMode {}
#[cfg(spi2)] crate::any_peripheral! {
impl PeripheralMarker for crate::peripherals::SPI2 { /// Any SPI peripheral.
#[inline(always)] pub peripheral AnySpi {
fn peripheral(&self) -> crate::system::Peripheral { #[cfg(spi2)]
crate::system::Peripheral::Spi2 Spi2(crate::peripherals::SPI2),
#[cfg(spi3)]
Spi3(crate::peripherals::SPI3),
} }
} }
#[cfg(spi3)] impl DmaEligible for AnySpi {
impl PeripheralMarker for crate::peripherals::SPI3 { #[cfg(gdma)]
#[inline(always)] type Dma = crate::dma::AnyGdmaChannel;
fn peripheral(&self) -> crate::system::Peripheral { #[cfg(pdma)]
crate::system::Peripheral::Spi3 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}, peripheral::{Peripheral, PeripheralRef},
peripherals::spi2::RegisterBlock, peripherals::spi2::RegisterBlock,
private, private,
spi::AnySpi,
system::PeripheralClockControl, system::PeripheralClockControl,
}; };
@ -86,17 +87,14 @@ const MAX_DMA_SIZE: usize = 32768 - 32;
/// SPI peripheral driver. /// SPI peripheral driver.
/// ///
/// See the [module-level documentation][self] for more details. /// 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>, spi: PeripheralRef<'d, T>,
#[allow(dead_code)] #[allow(dead_code)]
data_mode: SpiMode, data_mode: SpiMode,
_mode: PhantomData<M>, _mode: PhantomData<M>,
} }
impl<'d, T> Spi<'d, T, FullDuplexMode> impl<'d> Spi<'d, FullDuplexMode> {
where
T: Instance,
{
/// Constructs an SPI instance in 8bit dataframe mode. /// Constructs an SPI instance in 8bit dataframe mode.
pub fn new< pub fn new<
SCK: PeripheralInput, SCK: PeripheralInput,
@ -104,42 +102,68 @@ where
MISO: PeripheralOutput, MISO: PeripheralOutput,
CS: PeripheralInput, CS: PeripheralInput,
>( >(
spi: impl Peripheral<P = T> + 'd, spi: impl Peripheral<P = impl Into<AnySpi> + 'd> + 'd,
sclk: impl Peripheral<P = SCK> + 'd, sclk: impl Peripheral<P = SCK> + 'd,
mosi: impl Peripheral<P = MOSI> + 'd, mosi: impl Peripheral<P = MOSI> + 'd,
miso: impl Peripheral<P = MISO> + 'd, miso: impl Peripheral<P = MISO> + 'd,
cs: impl Peripheral<P = CS> + 'd, cs: impl Peripheral<P = CS> + 'd,
mode: SpiMode, mode: SpiMode,
) -> Spi<'d, T, FullDuplexMode> { ) -> Spi<'d, FullDuplexMode> {
crate::into_ref!(spi, sclk, mosi, miso, cs); 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.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.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.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.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( pub(crate) fn new_internal(
spi: PeripheralRef<'d, T>, spi: impl Peripheral<P = impl Into<T> + 'd> + 'd,
mode: SpiMode, mode: SpiMode,
) -> Spi<'d, T, FullDuplexMode> { ) -> Spi<'d, FullDuplexMode, T> {
spi.reset_peripheral(); crate::into_ref!(spi);
spi.enable_peripheral();
let mut spi = Spi { let mut spi = Spi {
spi, spi: spi.map_into(),
data_mode: mode, data_mode: mode,
_mode: PhantomData, _mode: PhantomData,
}; };
spi.spi.reset_peripheral();
spi.spi.enable_peripheral();
spi.spi.init(); spi.spi.init();
spi.spi.set_data_mode(mode, false); spi.spi.set_data_mode(mode, false);
@ -169,7 +193,7 @@ pub mod dma {
Mode, Mode,
}; };
impl<'d, T> Spi<'d, T, FullDuplexMode> impl<'d, T> Spi<'d, FullDuplexMode, T>
where where
T: InstanceDma, T: InstanceDma,
{ {
@ -181,7 +205,7 @@ pub mod dma {
channel: Channel<'d, CH, DmaMode>, channel: Channel<'d, CH, DmaMode>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> SpiDma<'d, T, DmaMode> ) -> SpiDma<'d, DmaMode, T>
where where
CH: DmaChannelConvert<T::Dma>, CH: DmaChannelConvert<T::Dma>,
DmaMode: Mode, DmaMode: Mode,
@ -192,7 +216,7 @@ pub mod dma {
} }
/// A DMA capable SPI instance. /// A DMA capable SPI instance.
pub struct SpiDma<'d, T, DmaMode> pub struct SpiDma<'d, DmaMode, T = AnySpi>
where where
T: InstanceDma, T: InstanceDma,
DmaMode: Mode, DmaMode: Mode,
@ -203,7 +227,7 @@ pub mod dma {
tx_chain: DescriptorChain, 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 where
T: InstanceDma, T: InstanceDma,
DmaMode: Mode, 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 where
T: InstanceDma, T: InstanceDma,
DmaMode: Mode, 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 where
T: InstanceDma, T: InstanceDma,
DmaMode: Mode, 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 where
T: InstanceDma, T: InstanceDma,
DmaMode: Mode, 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 where
T: InstanceDma, T: InstanceDma,
DmaMode: Mode, DmaMode: Mode,
@ -566,8 +590,6 @@ pub trait Instance: private::Sealed + PeripheralMarker {
PeripheralClockControl::enable(self.peripheral()); PeripheralClockControl::enable(self.peripheral());
} }
fn spi_num(&self) -> u8;
#[cfg(esp32)] #[cfg(esp32)]
fn prepare_length_and_lines(&self, rx_len: usize, tx_len: usize) { fn prepare_length_and_lines(&self, rx_len: usize, tx_len: usize) {
let reg_block = self.register_block(); let reg_block = self.register_block();
@ -728,11 +750,6 @@ impl Instance for crate::peripherals::SPI2 {
self self
} }
#[inline(always)]
fn spi_num(&self) -> u8 {
2
}
#[inline(always)] #[inline(always)]
fn sclk_signal(&self) -> InputSignal { fn sclk_signal(&self) -> InputSignal {
cfg_if::cfg_if! { cfg_if::cfg_if! {
@ -785,11 +802,6 @@ impl Instance for crate::peripherals::SPI3 {
self self
} }
#[inline(always)]
fn spi_num(&self) -> u8 {
3
}
#[inline(always)] #[inline(always)]
fn sclk_signal(&self) -> InputSignal { fn sclk_signal(&self) -> InputSignal {
cfg_if::cfg_if! { 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::{Dma, DmaPriority, DmaRxBuf, DmaTxBuf},
dma_buffers, dma_buffers,
interrupt::{software::SoftwareInterruptControl, Priority}, interrupt::{software::SoftwareInterruptControl, Priority},
peripherals::SPI3,
prelude::*, prelude::*,
spi::{ spi::{
master::{Spi, SpiDma}, master::{Spi, SpiDma},
@ -35,7 +34,7 @@ macro_rules! mk_static {
} }
#[embassy_executor::task] #[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 mut ticker = Ticker::every(Duration::from_millis(1));
let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(128); 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 { struct Context {
spi: esp_hal::peripherals::SPI2, spi: esp_hal::peripherals::SPI2,

View File

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

View File

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

View File

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

View File

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

View File

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