into_async (#2430)

* Remove configure_for_async

* Add into_async and into_blocking to I2c

* Add into_async and into_blocking to UsbSerialJtag

* Rework LCD_CAM

* Rmt

* RSA

* TWAI

* Uart

* Documentation

* Disable interrupts set on other core

* Move configure into RegisterAccess

* Disable interrupts on the other core

* Use EnumSet in RMT
This commit is contained in:
Dániel Buga 2024-11-04 10:32:12 +01:00 committed by GitHub
parent c717f04d4d
commit 40c0a6944e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
54 changed files with 3044 additions and 2908 deletions

View File

@ -1,2 +1,3 @@
[alias] [alias]
xtask = "run --package xtask --" xtask = "run --package xtask --"
xfmt = "xtask fmt-packages"

View File

@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- I2S Parallel output driver for ESP32. (#2348, #2436) - I2S Parallel output driver for ESP32. (#2348, #2436)
- Add an option to configure `WDT` action (#2330) - Add an option to configure `WDT` action (#2330)
- `DmaDescriptor` is now `Send` (#2456) - `DmaDescriptor` is now `Send` (#2456)
- `into_async` and `into_blocking` functions for most peripherals (#2430)
- API mode type parameter (currently always `Blocking`) to `master::Spi` and `slave::Spi` (#2430)
### Changed ### Changed
@ -39,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Interrupt listen/unlisten/clear functions now accept any type that converts into `EnumSet` (i.e. single interrupt flags). (#2442) - Interrupt listen/unlisten/clear functions now accept any type that converts into `EnumSet` (i.e. single interrupt flags). (#2442)
- SPI interrupt listening is now only available in Blocking mode. The `set_interrupt_handler` is available via `InterruptConfigurable` (#2442) - SPI interrupt listening is now only available in Blocking mode. The `set_interrupt_handler` is available via `InterruptConfigurable` (#2442)
- Allow users to create DMA `Preparation`s (#2455) - Allow users to create DMA `Preparation`s (#2455)
- The `rmt::asynch::RxChannelAsync` and `rmt::asynch::TxChannelAsync` traits have been moved to `rmt` (#2430)
### Fixed ### Fixed
@ -64,6 +67,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Removed the pin type parameters from `parl_io::{RxOneBit, RxTwoBits, RxFourBits, RxEightBits, RxSixteenBits}` (#2388) - Removed the pin type parameters from `parl_io::{RxOneBit, RxTwoBits, RxFourBits, RxEightBits, RxSixteenBits}` (#2388)
- Removed the pin type parameters from `lcd_cam::lcd::i8080::{TxEightBits, TxSixteenBits}` (#2388) - Removed the pin type parameters from `lcd_cam::lcd::i8080::{TxEightBits, TxSixteenBits}` (#2388)
- Removed the pin type parameters from `lcd_cam::cam::{RxEightBits, RxSixteenBits}` (#2388) - Removed the pin type parameters from `lcd_cam::cam::{RxEightBits, RxSixteenBits}` (#2388)
- Most of the async-specific constructors (`new_async`, `new_async_no_transceiver`) have been removed. (#2430)
- The `configure_for_async` DMA functions have been removed (#2430)
## [0.21.1] ## [0.21.1]

View File

@ -23,6 +23,41 @@ For example:
} }
``` ```
## Removed `async`-specific constructors
The following async-specific constuctors have been removed:
- `configure_for_async` DMA channel constructors
- `TwaiConfiguration::new_async` and `TwaiConfiguration::new_async_no_transceiver`
- `I2c::new_async`
- `LcdCam::new_async`
- `UsbSerialJtag::new_async`
- `Rsa::new_async`
- `Rmt::new_async`
- `Uart::new_async`, `Uart::new_async_with_config`
- `UartRx::new_async`, `UartRx::new_async_with_config`
- `UartTx::new_async`, `UartTx::new_async_with_config`
You can use the blocking counterparts, then call `into_async` on the returned peripheral instead.
```diff
-let mut config = twai::TwaiConfiguration::new_async(
+let mut config = twai::TwaiConfiguration::new(
peripherals.TWAI0,
loopback_pin.peripheral_input(),
loopback_pin,
twai::BaudRate::B1000K,
TwaiMode::SelfTest,
-);
+).into_async();
```
Some drivers were implicitly configured to the asyncness of the DMA channel used to construct them.
This is no longer the case, and the following drivers will always be created in blocking mode:
- `I2s`
- `master::SpiDma` and `master::SpiDmaBus`
## Peripheral types are now optional ## Peripheral types are now optional
You no longer have to specify the peripheral instance in the driver's type for the following You no longer have to specify the peripheral instance in the driver's type for the following

View File

@ -250,6 +250,7 @@ pub mod dma {
WriteBuffer, WriteBuffer,
}, },
peripherals::AES, peripherals::AES,
Blocking,
}; };
const ALIGN_SIZE: usize = core::mem::size_of::<u32>(); const ALIGN_SIZE: usize = core::mem::size_of::<u32>();
@ -275,7 +276,7 @@ pub mod dma {
/// The underlying [`Aes`](super::Aes) driver /// The underlying [`Aes`](super::Aes) driver
pub aes: super::Aes<'d>, pub aes: super::Aes<'d>,
channel: Channel<'d, <AES as DmaEligible>::Dma, crate::Blocking>, channel: Channel<'d, <AES as DmaEligible>::Dma, Blocking>,
rx_chain: DescriptorChain, rx_chain: DescriptorChain,
tx_chain: DescriptorChain, tx_chain: DescriptorChain,
} }
@ -284,12 +285,11 @@ pub mod dma {
/// Enable DMA for the current instance of the AES driver /// Enable DMA for the current instance of the AES driver
pub fn with_dma<C>( pub fn with_dma<C>(
self, self,
channel: Channel<'d, C, crate::Blocking>, channel: Channel<'d, C, Blocking>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> AesDma<'d> ) -> AesDma<'d>
where where
Self: Sized,
C: DmaChannelConvert<<AES as DmaEligible>::Dma>, C: DmaChannelConvert<<AES as DmaEligible>::Dma>,
{ {
AesDma { AesDma {

View File

@ -26,7 +26,7 @@
use crate::{ use crate::{
interrupt::InterruptHandler, interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::ASSIST_DEBUG, peripherals::{Interrupt, ASSIST_DEBUG},
InterruptConfigurable, InterruptConfigurable,
}; };
@ -51,17 +51,14 @@ impl crate::private::Sealed for DebugAssist<'_> {}
impl InterruptConfigurable for DebugAssist<'_> { impl InterruptConfigurable for DebugAssist<'_> {
fn set_interrupt_handler(&mut self, handler: InterruptHandler) { fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
unsafe { for core in crate::Cpu::other() {
crate::interrupt::bind_interrupt( crate::interrupt::disable(core, Interrupt::ASSIST_DEBUG);
crate::peripherals::Interrupt::ASSIST_DEBUG,
handler.handler(),
);
crate::interrupt::enable(
crate::peripherals::Interrupt::ASSIST_DEBUG,
handler.priority(),
)
.unwrap();
} }
unsafe { crate::interrupt::bind_interrupt(Interrupt::ASSIST_DEBUG, handler.handler()) };
unwrap!(crate::interrupt::enable(
Interrupt::ASSIST_DEBUG,
handler.priority()
));
} }
} }

View File

@ -17,7 +17,9 @@
use crate::{ use crate::{
dma::*, dma::*,
peripheral::PeripheralRef, peripheral::PeripheralRef,
peripherals::Interrupt,
system::{Peripheral, PeripheralClockControl}, system::{Peripheral, PeripheralClockControl},
Blocking,
}; };
#[doc(hidden)] #[doc(hidden)]
@ -33,6 +35,36 @@ impl crate::private::Sealed for AnyGdmaChannel {}
impl DmaChannel for AnyGdmaChannel { impl DmaChannel for AnyGdmaChannel {
type Rx = ChannelRxImpl<Self>; type Rx = ChannelRxImpl<Self>;
type Tx = ChannelTxImpl<Self>; type Tx = ChannelTxImpl<Self>;
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler {
match ch.tx.tx_impl.0.number() {
0 => DmaChannel0::handler(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::handler(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::handler(),
#[cfg(esp32s3)]
3 => DmaChannel3::handler(),
#[cfg(esp32s3)]
4 => DmaChannel4::handler(),
_ => unreachable!(),
}
}
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
match ch.tx.tx_impl.0.number() {
0 => DmaChannel0::isrs(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::isrs(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::isrs(),
#[cfg(esp32s3)]
3 => DmaChannel3::isrs(),
#[cfg(esp32s3)]
4 => DmaChannel4::isrs(),
_ => unreachable!(),
}
}
} }
#[non_exhaustive] #[non_exhaustive]
@ -460,9 +492,27 @@ macro_rules! impl_channel {
impl crate::private::Sealed for [<DmaChannel $num>] {} impl crate::private::Sealed for [<DmaChannel $num>] {}
impl [<DmaChannel $num>] {
fn handler() -> InterruptHandler {
$async_handler
}
fn isrs() -> &'static [Interrupt] {
&[$(Interrupt::$interrupt),*]
}
}
impl DmaChannel for [<DmaChannel $num>] { impl DmaChannel for [<DmaChannel $num>] {
type Rx = ChannelRxImpl<SpecificGdmaChannel<$num>>; type Rx = ChannelRxImpl<SpecificGdmaChannel<$num>>;
type Tx = ChannelTxImpl<SpecificGdmaChannel<$num>>; type Tx = ChannelTxImpl<SpecificGdmaChannel<$num>>;
fn async_handler<M: Mode>(_ch: &Channel<'_, Self, M>) -> InterruptHandler {
Self::handler()
}
fn interrupts<M: Mode>(_ch: &Channel<'_, Self, M>,) -> &'static [Interrupt] {
Self::isrs()
}
} }
impl DmaChannelConvert<AnyGdmaChannel> for [<DmaChannel $num>] { impl DmaChannelConvert<AnyGdmaChannel> for [<DmaChannel $num>] {
@ -482,64 +532,22 @@ macro_rules! impl_channel {
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> { fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
ChannelTxImpl(SpecificGdmaChannel::<$num> {}) ChannelTxImpl(SpecificGdmaChannel::<$num> {})
} }
fn set_isr(handler: $crate::interrupt::InterruptHandler) {
let mut dma = unsafe { crate::peripherals::DMA::steal() };
$(
dma.[< bind_ $interrupt:lower _interrupt >](handler.handler());
$crate::interrupt::enable($crate::peripherals::Interrupt::$interrupt, handler.priority()).unwrap();
)*
}
} }
impl ChannelCreator<$num> { impl ChannelCreator<$num> {
fn do_configure<'a, M: crate::Mode>(
self,
burst_mode: bool,
priority: DmaPriority,
) -> crate::dma::Channel<'a, [<DmaChannel $num>], M> {
let tx_impl = ChannelTxImpl(SpecificGdmaChannel::<$num> {});
tx_impl.set_burst_mode(burst_mode);
tx_impl.set_priority(priority);
let rx_impl = ChannelRxImpl(SpecificGdmaChannel::<$num> {});
rx_impl.set_burst_mode(burst_mode);
rx_impl.set_priority(priority);
// clear the mem2mem mode to avoid failed DMA if this
// channel was previously used for a mem2mem transfer.
rx_impl.set_mem2mem_mode(false);
crate::dma::Channel {
tx: ChannelTx::new(tx_impl, burst_mode),
rx: ChannelRx::new(rx_impl, burst_mode),
phantom: PhantomData,
}
}
/// Configure the channel for use with blocking APIs /// Configure the channel for use with blocking APIs
///
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
pub fn configure<'a>( pub fn configure<'a>(
self, self,
burst_mode: bool, burst_mode: bool,
priority: DmaPriority, priority: DmaPriority,
) -> crate::dma::Channel<'a, [<DmaChannel $num>], crate::Blocking> { ) -> Channel<'a, [<DmaChannel $num>], Blocking> {
self.do_configure(burst_mode, priority) let mut this = Channel {
} tx: ChannelTx::new(ChannelTxImpl(SpecificGdmaChannel::<$num> {})),
rx: ChannelRx::new(ChannelRxImpl(SpecificGdmaChannel::<$num> {})),
phantom: PhantomData,
};
/// Configure the channel for use with async APIs this.configure(burst_mode, priority);
///
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
pub fn configure_for_async<'a>(
self,
burst_mode: bool,
priority: DmaPriority,
) -> crate::dma::Channel<'a, [<DmaChannel $num>], $crate::Async> {
let this = self.do_configure(burst_mode, priority);
[<DmaChannel $num>]::set_isr($async_handler);
this this
} }

View File

@ -18,6 +18,8 @@ use crate::{
Tx, Tx,
WriteBuffer, WriteBuffer,
}, },
Async,
Blocking,
Mode, Mode,
}; };
@ -36,19 +38,18 @@ where
peripheral: DmaPeripheral, peripheral: DmaPeripheral,
} }
impl<'d, M> Mem2Mem<'d, M> impl<'d> Mem2Mem<'d, Blocking> {
where
M: Mode,
{
/// Create a new Mem2Mem instance. /// Create a new Mem2Mem instance.
pub fn new<CH>( pub fn new<CH, DM>(
channel: Channel<'d, CH, M>, channel: Channel<'d, CH, DM>,
peripheral: impl DmaEligible, peripheral: impl DmaEligible,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> Result<Self, DmaError> ) -> Result<Self, DmaError>
where where
CH: DmaChannelConvert<AnyGdmaChannel>, CH: DmaChannelConvert<AnyGdmaChannel>,
DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
{ {
unsafe { unsafe {
Self::new_unsafe( Self::new_unsafe(
@ -62,8 +63,8 @@ where
} }
/// Create a new Mem2Mem instance with specific chunk size. /// Create a new Mem2Mem instance with specific chunk size.
pub fn new_with_chunk_size<CH>( pub fn new_with_chunk_size<CH, DM>(
channel: Channel<'d, CH, M>, channel: Channel<'d, CH, DM>,
peripheral: impl DmaEligible, peripheral: impl DmaEligible,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
@ -71,6 +72,8 @@ where
) -> Result<Self, DmaError> ) -> Result<Self, DmaError>
where where
CH: DmaChannelConvert<AnyGdmaChannel>, CH: DmaChannelConvert<AnyGdmaChannel>,
DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
{ {
unsafe { unsafe {
Self::new_unsafe( Self::new_unsafe(
@ -89,8 +92,8 @@ where
/// ///
/// You must ensure that your not using DMA for the same peripheral and /// You must ensure that your not using DMA for the same peripheral and
/// that your the only one using the DmaPeripheral. /// that your the only one using the DmaPeripheral.
pub unsafe fn new_unsafe<CH>( pub unsafe fn new_unsafe<CH, DM>(
channel: Channel<'d, CH, M>, channel: Channel<'d, CH, DM>,
peripheral: DmaPeripheral, peripheral: DmaPeripheral,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
@ -98,6 +101,8 @@ where
) -> Result<Self, DmaError> ) -> Result<Self, DmaError>
where where
CH: DmaChannelConvert<AnyGdmaChannel>, CH: DmaChannelConvert<AnyGdmaChannel>,
DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
{ {
if !(1..=4092).contains(&chunk_size) { if !(1..=4092).contains(&chunk_size) {
return Err(DmaError::InvalidChunkSize); return Err(DmaError::InvalidChunkSize);
@ -106,13 +111,28 @@ where
return Err(DmaError::OutOfDescriptors); return Err(DmaError::OutOfDescriptors);
} }
Ok(Mem2Mem { Ok(Mem2Mem {
channel: channel.degrade(), channel: Channel::<_, Blocking>::from(channel).degrade(),
peripheral, peripheral,
rx_chain: DescriptorChain::new_with_chunk_size(rx_descriptors, chunk_size), rx_chain: DescriptorChain::new_with_chunk_size(rx_descriptors, chunk_size),
tx_chain: DescriptorChain::new_with_chunk_size(tx_descriptors, chunk_size), tx_chain: DescriptorChain::new_with_chunk_size(tx_descriptors, chunk_size),
}) })
} }
/// Convert Mem2Mem to an async Mem2Mem.
pub fn into_async(self) -> Mem2Mem<'d, Async> {
Mem2Mem {
channel: self.channel.into_async(),
rx_chain: self.rx_chain,
tx_chain: self.tx_chain,
peripheral: self.peripheral,
}
}
}
impl<'d, M> Mem2Mem<'d, M>
where
M: Mode,
{
/// Start a memory to memory transfer. /// Start a memory to memory transfer.
pub fn start_transfer<'t, TXBUF, RXBUF>( pub fn start_transfer<'t, TXBUF, RXBUF>(
&mut self, &mut self,

View File

@ -58,6 +58,25 @@
use core::{cmp::min, fmt::Debug, marker::PhantomData, sync::atomic::compiler_fence}; use core::{cmp::min, fmt::Debug, marker::PhantomData, sync::atomic::compiler_fence};
use enumset::{EnumSet, EnumSetType};
pub use self::buffers::*;
#[cfg(gdma)]
pub use self::gdma::*;
#[cfg(gdma)]
pub use self::m2m::*;
#[cfg(pdma)]
pub use self::pdma::*;
use crate::{
interrupt::InterruptHandler,
peripherals::Interrupt,
soc::is_slice_in_dram,
Async,
Blocking,
Cpu,
Mode,
};
trait Word: crate::private::Sealed {} trait Word: crate::private::Sealed {}
macro_rules! impl_word { macro_rules! impl_word {
@ -356,17 +375,6 @@ impl DmaDescriptor {
// Send (where the compiler sees fit). // Send (where the compiler sees fit).
unsafe impl Send for DmaDescriptor {} unsafe impl Send for DmaDescriptor {}
use enumset::{EnumSet, EnumSetType};
pub use self::buffers::*;
#[cfg(gdma)]
pub use self::gdma::*;
#[cfg(gdma)]
pub use self::m2m::*;
#[cfg(pdma)]
pub use self::pdma::*;
use crate::{interrupt::InterruptHandler, soc::is_slice_in_dram, Mode};
mod buffers; mod buffers;
#[cfg(gdma)] #[cfg(gdma)]
mod gdma; mod gdma;
@ -1562,21 +1570,24 @@ impl RxCircularState {
} }
/// A description of a DMA Channel. /// A description of a DMA Channel.
pub trait DmaChannel: crate::private::Sealed { pub trait DmaChannel: crate::private::Sealed + Sized {
/// A description of the RX half of a DMA Channel. /// A description of the RX half of a DMA Channel.
type Rx: RxRegisterAccess + InterruptAccess<DmaRxInterrupt>; type Rx: RxRegisterAccess + InterruptAccess<DmaRxInterrupt>;
/// A description of the TX half of a DMA Channel. /// A description of the TX half of a DMA Channel.
type Tx: TxRegisterAccess + InterruptAccess<DmaTxInterrupt>; type Tx: TxRegisterAccess + InterruptAccess<DmaTxInterrupt>;
/// Returns the async interrupt handler.
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler;
/// Returns the interrupt.
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt];
} }
#[doc(hidden)] #[doc(hidden)]
pub trait DmaChannelExt: DmaChannel { pub trait DmaChannelExt: DmaChannel {
fn get_rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt>; fn get_rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt>;
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt>; fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt>;
#[doc(hidden)]
fn set_isr(handler: InterruptHandler);
} }
#[doc(hidden)] #[doc(hidden)]
@ -1668,9 +1679,14 @@ impl<'a, CH> ChannelRx<'a, CH>
where where
CH: DmaChannel, CH: DmaChannel,
{ {
fn new(rx_impl: CH::Rx, burst_mode: bool) -> Self { fn new(rx_impl: CH::Rx) -> Self {
#[cfg(gdma)]
// clear the mem2mem mode to avoid failed DMA if this
// channel was previously used for a mem2mem transfer.
rx_impl.set_mem2mem_mode(false);
Self { Self {
burst_mode, burst_mode: false,
rx_impl, rx_impl,
_phantom: PhantomData, _phantom: PhantomData,
} }
@ -1688,6 +1704,12 @@ where
_phantom: PhantomData, _phantom: PhantomData,
} }
} }
/// Configure the channel.
pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) {
self.burst_mode = burst_mode;
self.rx_impl.configure(burst_mode, priority);
}
} }
impl<CH> crate::private::Sealed for ChannelRx<'_, CH> where CH: DmaChannel {} impl<CH> crate::private::Sealed for ChannelRx<'_, CH> where CH: DmaChannel {}
@ -1886,9 +1908,9 @@ impl<'a, CH> ChannelTx<'a, CH>
where where
CH: DmaChannel, CH: DmaChannel,
{ {
fn new(tx_impl: CH::Tx, burst_mode: bool) -> Self { fn new(tx_impl: CH::Tx) -> Self {
Self { Self {
burst_mode, burst_mode: false,
tx_impl, tx_impl,
_phantom: PhantomData, _phantom: PhantomData,
} }
@ -1906,6 +1928,12 @@ where
_phantom: PhantomData, _phantom: PhantomData,
} }
} }
/// Configure the channel.
pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) {
self.burst_mode = burst_mode;
self.tx_impl.configure(burst_mode, priority);
}
} }
impl<CH> crate::private::Sealed for ChannelTx<'_, CH> where CH: DmaChannel {} impl<CH> crate::private::Sealed for ChannelTx<'_, CH> where CH: DmaChannel {}
@ -2076,6 +2104,12 @@ pub trait RegisterAccess: crate::private::Sealed {
#[cfg(pdma)] #[cfg(pdma)]
fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool; fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool;
/// Configure the channel.
fn configure(&self, burst_mode: bool, priority: DmaPriority) {
self.set_burst_mode(burst_mode);
self.set_priority(priority);
}
} }
#[doc(hidden)] #[doc(hidden)]
@ -2114,31 +2148,38 @@ pub trait InterruptAccess<T: EnumSetType>: crate::private::Sealed {
} }
/// DMA Channel /// DMA Channel
pub struct Channel<'d, CH, MODE> pub struct Channel<'d, CH, M>
where where
CH: DmaChannel, CH: DmaChannel,
MODE: Mode, M: Mode,
{ {
/// RX half of the channel /// RX half of the channel
pub rx: ChannelRx<'d, CH>, pub rx: ChannelRx<'d, CH>,
/// TX half of the channel /// TX half of the channel
pub tx: ChannelTx<'d, CH>, pub tx: ChannelTx<'d, CH>,
phantom: PhantomData<MODE>, pub(crate) phantom: PhantomData<M>,
} }
impl<C> Channel<'_, C, crate::Blocking> impl<'d, C> Channel<'d, C, Blocking>
where where
C: DmaChannel, C: DmaChannel,
{ {
/// Sets the interrupt handler for RX and TX interrupts, enables them /// Sets the interrupt handler for RX and TX interrupts.
/// with [crate::interrupt::Priority::max()]
/// ///
/// Interrupts are not enabled at the peripheral level here. /// Interrupts are not enabled at the peripheral level here.
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) pub fn set_interrupt_handler(&mut self, handler: InterruptHandler)
where where
C: DmaChannelExt, C: DmaChannel,
{ {
C::set_isr(handler); self.unlisten(EnumSet::all());
self.clear_interrupts(EnumSet::all());
for interrupt in C::interrupts(self).iter().copied() {
for core in crate::Cpu::other() {
crate::interrupt::disable(core, interrupt);
}
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
}
} }
/// Listen for the given interrupts /// Listen for the given interrupts
@ -2182,6 +2223,53 @@ where
} }
} }
} }
/// Configure the channel.
pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) {
self.tx.configure(burst_mode, priority);
self.rx.configure(burst_mode, priority);
}
/// Converts a blocking channel to an async channel.
pub fn into_async(mut self) -> Channel<'d, C, Async> {
self.set_interrupt_handler(C::async_handler(&self));
Channel {
tx: self.tx,
rx: self.rx,
phantom: PhantomData,
}
}
}
impl<'d, C> Channel<'d, C, Async>
where
C: DmaChannel,
{
/// Converts an async channel to a blocking channel.
pub fn into_blocking(self) -> Channel<'d, C, Blocking> {
for interrupt in C::interrupts(&self).iter().copied() {
crate::interrupt::disable(Cpu::current(), interrupt);
}
Channel {
tx: self.tx,
rx: self.rx,
phantom: PhantomData,
}
}
}
impl<'d, C: DmaChannel> From<Channel<'d, C, Blocking>> for Channel<'d, C, Async> {
fn from(channel: Channel<'d, C, Blocking>) -> Self {
channel.into_async()
}
}
impl<'d, C: DmaChannel> From<Channel<'d, C, Async>> for Channel<'d, C, Blocking> {
fn from(channel: Channel<'d, C, Async>) -> Self {
channel.into_blocking()
}
} }
impl<'d, CH, M: Mode> Channel<'d, CH, M> impl<'d, CH, M: Mode> Channel<'d, CH, M>
@ -2906,13 +2994,13 @@ pub(crate) mod asynch {
#[cfg(i2s0)] #[cfg(i2s0)]
#[handler(priority = crate::interrupt::Priority::max())] #[handler(priority = crate::interrupt::Priority::max())]
pub(crate) fn interrupt_handler_i2s0() { pub(crate) fn interrupt_handler_i2s0_dma() {
handle_interrupt::<I2s0DmaChannel>(); handle_interrupt::<I2s0DmaChannel>();
} }
#[cfg(i2s1)] #[cfg(i2s1)]
#[handler(priority = crate::interrupt::Priority::max())] #[handler(priority = crate::interrupt::Priority::max())]
pub(crate) fn interrupt_handler_i2s1() { pub(crate) fn interrupt_handler_i2s1_dma() {
handle_interrupt::<I2s1DmaChannel>(); handle_interrupt::<I2s1DmaChannel>();
} }
} }

View File

@ -16,7 +16,9 @@ use embassy_sync::waitqueue::AtomicWaker;
use crate::{ use crate::{
dma::*, dma::*,
peripheral::PeripheralRef, peripheral::PeripheralRef,
peripherals::Interrupt,
system::{Peripheral, PeripheralClockControl}, system::{Peripheral, PeripheralClockControl},
Blocking,
}; };
type SpiRegisterBlock = crate::peripherals::spi2::RegisterBlock; type SpiRegisterBlock = crate::peripherals::spi2::RegisterBlock;
@ -341,9 +343,27 @@ macro_rules! ImplSpiChannel {
#[non_exhaustive] #[non_exhaustive]
pub struct [<Spi $num DmaChannel>] {} pub struct [<Spi $num DmaChannel>] {}
impl [<Spi $num DmaChannel>] {
fn handler() -> InterruptHandler {
super::asynch::interrupt::[< interrupt_handler_spi $num _dma >]
}
fn isrs() -> &'static [Interrupt] {
&[Interrupt::[< SPI $num _DMA >]]
}
}
impl DmaChannel for [<Spi $num DmaChannel>] { impl DmaChannel for [<Spi $num DmaChannel>] {
type Rx = SpiDmaRxChannelImpl<Self>; type Rx = SpiDmaRxChannelImpl<Self>;
type Tx = SpiDmaTxChannelImpl<Self>; type Tx = SpiDmaTxChannelImpl<Self>;
fn async_handler<M: Mode>(_ch: &Channel<'_, Self, M>) -> InterruptHandler {
Self::handler()
}
fn interrupts<M: Mode>(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
Self::isrs()
}
} }
impl DmaChannelExt for [<Spi $num DmaChannel>] { impl DmaChannelExt for [<Spi $num DmaChannel>] {
@ -353,14 +373,6 @@ macro_rules! ImplSpiChannel {
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> { fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
SpiDmaTxChannelImpl(Self {}) SpiDmaTxChannelImpl(Self {})
} }
fn set_isr(handler: InterruptHandler) {
let interrupt = $crate::peripherals::Interrupt::[< SPI $num _DMA >];
unsafe {
crate::interrupt::bind_interrupt(interrupt, handler.handler());
}
crate::interrupt::enable(interrupt, handler.priority()).unwrap();
}
} }
impl PdmaChannel for [<Spi $num DmaChannel>] { impl PdmaChannel for [<Spi $num DmaChannel>] {
@ -399,59 +411,19 @@ macro_rules! ImplSpiChannel {
pub struct [<Spi $num DmaChannelCreator>] {} pub struct [<Spi $num DmaChannelCreator>] {}
impl [<Spi $num DmaChannelCreator>] { impl [<Spi $num DmaChannelCreator>] {
fn do_configure<'a, M: $crate::Mode>(
self,
burst_mode: bool,
priority: DmaPriority,
) -> Channel<'a, [<Spi $num DmaChannel>], M> {
#[cfg(esp32)]
{
// (only) on ESP32 we need to configure DPORT for the SPI DMA channels
let dport = unsafe { &*crate::peripherals::DPORT::PTR };
dport
.spi_dma_chan_sel()
.modify(|_, w| unsafe { w.[< spi $num _dma_chan_sel>]().bits($num - 1) });
}
let tx_impl = SpiDmaTxChannelImpl([<Spi $num DmaChannel>] {});
tx_impl.set_burst_mode(burst_mode);
tx_impl.set_priority(priority);
let rx_impl = SpiDmaRxChannelImpl([<Spi $num DmaChannel>] {});
rx_impl.set_burst_mode(burst_mode);
rx_impl.set_priority(priority);
Channel {
tx: ChannelTx::new(tx_impl, burst_mode),
rx: ChannelRx::new(rx_impl, burst_mode),
phantom: PhantomData,
}
}
/// Configure the channel for use with blocking APIs /// Configure the channel for use with blocking APIs
///
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
pub fn configure<'a>( pub fn configure<'a>(
self, self,
burst_mode: bool, burst_mode: bool,
priority: DmaPriority, priority: DmaPriority,
) -> Channel<'a, [<Spi $num DmaChannel>], $crate::Blocking> { ) -> Channel<'a, [<Spi $num DmaChannel>], Blocking> {
Self::do_configure(self, burst_mode, priority) let mut this = Channel {
} tx: ChannelTx::new(SpiDmaTxChannelImpl([<Spi $num DmaChannel>] {})),
rx: ChannelRx::new(SpiDmaRxChannelImpl([<Spi $num DmaChannel>] {})),
phantom: PhantomData,
};
/// Configure the channel for use with async APIs this.configure(burst_mode, priority);
///
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
pub fn configure_for_async<'a>(
self,
burst_mode: bool,
priority: DmaPriority,
) -> Channel<'a, [<Spi $num DmaChannel>], $crate::Async> {
let this = Self::do_configure(self, burst_mode, priority);
[<Spi $num DmaChannel>]::set_isr(super::asynch::interrupt::[< interrupt_handler_spi $num _dma >]);
this this
} }
@ -784,9 +756,27 @@ macro_rules! ImplI2sChannel {
impl $crate::private::Sealed for [<I2s $num DmaChannel>] {} impl $crate::private::Sealed for [<I2s $num DmaChannel>] {}
impl [<I2s $num DmaChannel>] {
fn handler() -> InterruptHandler {
super::asynch::interrupt::[< interrupt_handler_i2s $num _dma >]
}
fn isrs() -> &'static [Interrupt] {
&[Interrupt::[< I2S $num >]]
}
}
impl DmaChannel for [<I2s $num DmaChannel>] { impl DmaChannel for [<I2s $num DmaChannel>] {
type Rx = I2sDmaRxChannelImpl<Self>; type Rx = I2sDmaRxChannelImpl<Self>;
type Tx = I2sDmaTxChannelImpl<Self>; type Tx = I2sDmaTxChannelImpl<Self>;
fn async_handler<M: Mode>(_ch: &Channel<'_, Self, M>) -> InterruptHandler {
Self::handler()
}
fn interrupts<M: Mode>(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
Self::isrs()
}
} }
impl DmaChannelExt for [<I2s $num DmaChannel>] { impl DmaChannelExt for [<I2s $num DmaChannel>] {
@ -796,14 +786,6 @@ macro_rules! ImplI2sChannel {
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> { fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
I2sDmaTxChannelImpl(Self {}) I2sDmaTxChannelImpl(Self {})
} }
fn set_isr(handler: InterruptHandler) {
let interrupt = $crate::peripherals::Interrupt::[< I2S $num >];
unsafe {
crate::interrupt::bind_interrupt(interrupt, handler.handler());
}
crate::interrupt::enable(interrupt, handler.priority()).unwrap();
}
} }
impl PdmaChannel for [<I2s $num DmaChannel>] { impl PdmaChannel for [<I2s $num DmaChannel>] {
@ -838,50 +820,19 @@ macro_rules! ImplI2sChannel {
pub struct [<I2s $num DmaChannelCreator>] {} pub struct [<I2s $num DmaChannelCreator>] {}
impl [<I2s $num DmaChannelCreator>] { impl [<I2s $num DmaChannelCreator>] {
fn do_configure<'a, M: $crate::Mode>(
self,
burst_mode: bool,
priority: DmaPriority,
) -> Channel<'a, [<I2s $num DmaChannel>], M> {
let tx_impl = I2sDmaTxChannelImpl([<I2s $num DmaChannel>] {});
tx_impl.set_burst_mode(burst_mode);
tx_impl.set_priority(priority);
let rx_impl = I2sDmaRxChannelImpl([<I2s $num DmaChannel>] {});
rx_impl.set_burst_mode(burst_mode);
rx_impl.set_priority(priority);
Channel {
tx: ChannelTx::new(tx_impl, burst_mode),
rx: ChannelRx::new(rx_impl, burst_mode),
phantom: PhantomData,
}
}
/// Configure the channel for use with blocking APIs /// Configure the channel for use with blocking APIs
///
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
pub fn configure<'a>( pub fn configure<'a>(
self, self,
burst_mode: bool, burst_mode: bool,
priority: DmaPriority, priority: DmaPriority,
) -> Channel<'a, [<I2s $num DmaChannel>], $crate::Blocking> { ) -> Channel<'a, [<I2s $num DmaChannel>], Blocking> {
Self::do_configure(self, burst_mode, priority) let mut this = Channel {
} tx: ChannelTx::new(I2sDmaTxChannelImpl([<I2s $num DmaChannel>] {})),
rx: ChannelRx::new(I2sDmaRxChannelImpl([<I2s $num DmaChannel>] {})),
phantom: PhantomData,
};
/// Configure the channel for use with async APIs this.configure(burst_mode, priority);
///
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
pub fn configure_for_async<'a>(
self,
burst_mode: bool,
priority: DmaPriority,
) -> Channel<'a, [<I2s $num DmaChannel>], $crate::Async> {
let this = Self::do_configure(self, burst_mode, priority);
[<I2s $num DmaChannel>]::set_isr(super::asynch::interrupt::[< interrupt_handler_i2s $num >]);
this this
} }
@ -929,6 +880,19 @@ impl<'d> Dma<'d> {
) -> Dma<'d> { ) -> Dma<'d> {
PeripheralClockControl::enable(Peripheral::Dma); PeripheralClockControl::enable(Peripheral::Dma);
#[cfg(esp32)]
{
// (only) on ESP32 we need to configure DPORT for the SPI DMA channels
// This assignes the DMA channels to the SPI peripherals, which is more
// restrictive than necessary but we currently support the same
// number of SPI peripherals as SPI DMA channels so it's not a big
// deal.
let dport = unsafe { &*crate::peripherals::DPORT::PTR };
dport.spi_dma_chan_sel().modify(|_, w| unsafe {
w.spi2_dma_chan_sel().bits(1).spi3_dma_chan_sel().bits(2)
});
}
Dma { Dma {
_inner: dma.into_ref(), _inner: dma.into_ref(),
spi2channel: Spi2DmaChannelCreator {}, spi2channel: Spi2DmaChannelCreator {},
@ -962,6 +926,20 @@ impl crate::private::Sealed for AnySpiDmaChannel {}
impl DmaChannel for AnySpiDmaChannel { impl DmaChannel for AnySpiDmaChannel {
type Rx = SpiDmaRxChannelImpl<AnySpiDmaChannelInner>; type Rx = SpiDmaRxChannelImpl<AnySpiDmaChannelInner>;
type Tx = SpiDmaTxChannelImpl<AnySpiDmaChannelInner>; type Tx = SpiDmaTxChannelImpl<AnySpiDmaChannelInner>;
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler {
match &ch.tx.tx_impl.0 {
AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::handler(),
AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::handler(),
}
}
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
match &ch.tx.tx_impl.0 {
AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::isrs(),
AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::isrs(),
}
}
} }
crate::any_enum! { crate::any_enum! {
@ -998,6 +976,22 @@ impl crate::private::Sealed for AnyI2sDmaChannel {}
impl DmaChannel for AnyI2sDmaChannel { impl DmaChannel for AnyI2sDmaChannel {
type Rx = I2sDmaRxChannelImpl<AnyI2sDmaChannelInner>; type Rx = I2sDmaRxChannelImpl<AnyI2sDmaChannelInner>;
type Tx = I2sDmaTxChannelImpl<AnyI2sDmaChannelInner>; type Tx = I2sDmaTxChannelImpl<AnyI2sDmaChannelInner>;
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler {
match &ch.tx.tx_impl.0 {
AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::handler(),
#[cfg(i2s1)]
AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::handler(),
}
}
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
match &ch.tx.tx_impl.0 {
AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::isrs(),
#[cfg(i2s1)]
AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::isrs(),
}
}
} }
crate::any_enum! { crate::any_enum! {

View File

@ -30,7 +30,7 @@ use core::marker::PhantomData;
use crate::{ use crate::{
interrupt::InterruptHandler, interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::ECC, peripherals::{Interrupt, ECC},
reg_access::{AlignmentHelper, SocDependentEndianess}, reg_access::{AlignmentHelper, SocDependentEndianess},
system::{Peripheral as PeripheralEnable, PeripheralClockControl}, system::{Peripheral as PeripheralEnable, PeripheralClockControl},
InterruptConfigurable, InterruptConfigurable,
@ -117,11 +117,11 @@ impl crate::private::Sealed for Ecc<'_, crate::Blocking> {}
impl InterruptConfigurable for Ecc<'_, crate::Blocking> { impl InterruptConfigurable for Ecc<'_, crate::Blocking> {
fn set_interrupt_handler(&mut self, handler: InterruptHandler) { fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
unsafe { for core in crate::Cpu::other() {
crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::ECC, handler.handler()); crate::interrupt::disable(core, Interrupt::ECC);
crate::interrupt::enable(crate::peripherals::Interrupt::ECC, handler.priority())
.unwrap();
} }
unsafe { crate::interrupt::bind_interrupt(Interrupt::ECC, handler.handler()) };
unwrap!(crate::interrupt::enable(Interrupt::ECC, handler.priority()));
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -107,6 +107,8 @@ use crate::{
interrupt::InterruptHandler, interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
system::PeripheralClockControl, system::PeripheralClockControl,
Async,
Blocking,
InterruptConfigurable, InterruptConfigurable,
Mode, Mode,
}; };
@ -253,16 +255,16 @@ impl DataFormat {
} }
/// Instance of the I2S peripheral driver /// Instance of the I2S peripheral driver
pub struct I2s<'d, DmaMode, T = AnyI2s> pub struct I2s<'d, M, T = AnyI2s>
where where
T: RegisterAccess, T: RegisterAccess,
DmaMode: Mode, M: Mode,
{ {
/// Handles the reception (RX) side of the I2S peripheral. /// Handles the reception (RX) side of the I2S peripheral.
pub i2s_rx: RxCreator<'d, DmaMode, T>, pub i2s_rx: RxCreator<'d, M, T>,
/// Handles the transmission (TX) side of the I2S peripheral. /// Handles the transmission (TX) side of the I2S peripheral.
pub i2s_tx: TxCreator<'d, DmaMode, T>, pub i2s_tx: TxCreator<'d, M, T>,
phantom: PhantomData<DmaMode>, phantom: PhantomData<M>,
} }
impl<'d, DmaMode, T> I2s<'d, DmaMode, T> impl<'d, DmaMode, T> I2s<'d, DmaMode, T>
@ -369,24 +371,23 @@ where
} }
} }
impl<'d, DmaMode> I2s<'d, DmaMode> impl<'d> I2s<'d, Blocking> {
where
DmaMode: Mode,
{
/// Construct a new I2S peripheral driver instance for the first I2S /// Construct a new I2S peripheral driver instance for the first I2S
/// peripheral /// peripheral
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn new<CH>( pub fn new<CH, DM>(
i2s: impl Peripheral<P = impl RegisterAccess> + 'd, i2s: impl Peripheral<P = impl RegisterAccess> + 'd,
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<'d, CH, DmaMode>, channel: Channel<'d, CH, DM>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> Self ) -> Self
where where
CH: DmaChannelConvert<<AnyI2s as DmaEligible>::Dma>, CH: DmaChannelConvert<<AnyI2s as DmaEligible>::Dma>,
DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
{ {
Self::new_typed( Self::new_typed(
i2s.map_into(), i2s.map_into(),
@ -400,25 +401,26 @@ where
} }
} }
impl<'d, DmaMode, T> I2s<'d, DmaMode, T> impl<'d, T> I2s<'d, Blocking, T>
where where
T: RegisterAccess, T: RegisterAccess,
DmaMode: Mode,
{ {
/// Construct a new I2S peripheral driver instance for the first I2S /// Construct a new I2S peripheral driver instance for the first I2S
/// peripheral /// peripheral
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn new_typed<CH>( pub fn new_typed<CH, DM>(
i2s: impl Peripheral<P = T> + 'd, i2s: impl Peripheral<P = T> + 'd,
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<'d, CH, DmaMode>, channel: Channel<'d, CH, DM>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> Self ) -> Self
where where
CH: DmaChannelConvert<T::Dma>, CH: DmaChannelConvert<T::Dma>,
DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
{ {
crate::into_ref!(i2s); crate::into_ref!(i2s);
Self::new_internal( Self::new_internal(
@ -426,12 +428,43 @@ where
standard, standard,
data_format, data_format,
sample_rate, sample_rate,
channel, channel.into(),
rx_descriptors, rx_descriptors,
tx_descriptors, tx_descriptors,
) )
} }
/// Converts the SPI instance into async mode.
pub fn into_async(self) -> I2s<'d, Async, T> {
let channel = Channel {
rx: self.i2s_rx.rx_channel,
tx: self.i2s_tx.tx_channel,
phantom: PhantomData::<Blocking>,
};
let channel = channel.into_async();
I2s {
i2s_rx: RxCreator {
i2s: self.i2s_rx.i2s,
rx_channel: channel.rx,
descriptors: self.i2s_rx.descriptors,
phantom: PhantomData,
},
i2s_tx: TxCreator {
i2s: self.i2s_tx.i2s,
tx_channel: channel.tx,
descriptors: self.i2s_tx.descriptors,
phantom: PhantomData,
},
phantom: PhantomData,
}
}
}
impl<'d, M, T> I2s<'d, M, T>
where
T: RegisterAccess,
M: Mode,
{
/// Configures the I2S peripheral to use a master clock (MCLK) output pin. /// Configures the I2S peripheral to use a master clock (MCLK) output pin.
pub fn with_mclk<P: PeripheralOutput>(self, pin: impl Peripheral<P = P> + 'd) -> Self { pub fn with_mclk<P: PeripheralOutput>(self, pin: impl Peripheral<P = P> + 'd) -> Self {
crate::into_mapped_ref!(pin); crate::into_mapped_ref!(pin);
@ -757,20 +790,20 @@ mod private {
}, },
interrupt::InterruptHandler, interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::I2S0, peripherals::{Interrupt, I2S0},
private, private,
Mode, Mode,
}; };
pub struct TxCreator<'d, DmaMode, T> pub struct TxCreator<'d, M, T>
where where
T: RegisterAccess, T: RegisterAccess,
DmaMode: Mode, M: Mode,
{ {
pub i2s: PeripheralRef<'d, T>, pub i2s: PeripheralRef<'d, T>,
pub tx_channel: ChannelTx<'d, T::Dma>, pub tx_channel: ChannelTx<'d, T::Dma>,
pub descriptors: &'static mut [DmaDescriptor], pub descriptors: &'static mut [DmaDescriptor],
pub(crate) phantom: PhantomData<DmaMode>, pub(crate) phantom: PhantomData<M>,
} }
impl<'d, DmaMode, T> TxCreator<'d, DmaMode, T> impl<'d, DmaMode, T> TxCreator<'d, DmaMode, T>
@ -821,23 +854,23 @@ mod private {
} }
} }
pub struct RxCreator<'d, DmaMode, T> pub struct RxCreator<'d, M, T>
where where
T: RegisterAccess, T: RegisterAccess,
DmaMode: Mode, M: Mode,
{ {
pub i2s: PeripheralRef<'d, T>, pub i2s: PeripheralRef<'d, T>,
pub rx_channel: ChannelRx<'d, T::Dma>, pub rx_channel: ChannelRx<'d, T::Dma>,
pub descriptors: &'static mut [DmaDescriptor], pub descriptors: &'static mut [DmaDescriptor],
pub(crate) phantom: PhantomData<DmaMode>, pub(crate) phantom: PhantomData<M>,
} }
impl<'d, DmaMode, T> RxCreator<'d, DmaMode, T> impl<'d, M, T> RxCreator<'d, M, T>
where where
T: RegisterAccess, T: RegisterAccess,
DmaMode: Mode, M: Mode,
{ {
pub fn build(self) -> I2sRx<'d, DmaMode, T> { pub fn build(self) -> I2sRx<'d, M, T> {
I2sRx { I2sRx {
i2s: self.i2s, i2s: self.i2s,
rx_channel: self.rx_channel, rx_channel: self.rx_channel,
@ -1582,9 +1615,14 @@ mod private {
impl RegisterAccessPrivate for I2S0 { impl RegisterAccessPrivate for I2S0 {
fn set_interrupt_handler(&self, handler: InterruptHandler) { fn set_interrupt_handler(&self, handler: InterruptHandler) {
for core in crate::Cpu::other() {
crate::interrupt::disable(core, Interrupt::I2S0);
}
unsafe { crate::peripherals::I2S0::steal() }.bind_i2s0_interrupt(handler.handler()); unsafe { crate::peripherals::I2S0::steal() }.bind_i2s0_interrupt(handler.handler());
crate::interrupt::enable(crate::peripherals::Interrupt::I2S0, handler.priority()) unwrap!(crate::interrupt::enable(
.unwrap(); Interrupt::I2S0,
handler.priority()
));
} }
} }
@ -1682,9 +1720,14 @@ mod private {
#[cfg(i2s1)] #[cfg(i2s1)]
impl RegisterAccessPrivate for I2S1 { impl RegisterAccessPrivate for I2S1 {
fn set_interrupt_handler(&self, handler: InterruptHandler) { fn set_interrupt_handler(&self, handler: InterruptHandler) {
for core in crate::Cpu::other() {
crate::interrupt::disable(core, Interrupt::I2S1);
}
unsafe { crate::peripherals::I2S1::steal() }.bind_i2s1_interrupt(handler.handler()); unsafe { crate::peripherals::I2S1::steal() }.bind_i2s1_interrupt(handler.handler());
crate::interrupt::enable(crate::peripherals::Interrupt::I2S1, handler.priority()) unwrap!(crate::interrupt::enable(
.unwrap(); Interrupt::I2S1,
handler.priority()
));
} }
} }

View File

@ -62,10 +62,11 @@ impl<const NUM: u8> SoftwareInterrupt<NUM> {
_ => unreachable!(), _ => unreachable!(),
}; };
unsafe { for core in crate::Cpu::other() {
crate::interrupt::bind_interrupt(interrupt, handler.handler()); crate::interrupt::disable(core, interrupt);
crate::interrupt::enable(interrupt, handler.priority()).unwrap();
} }
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
} }
/// Trigger this software-interrupt /// Trigger this software-interrupt

View File

@ -81,7 +81,7 @@ use crate::{
OutputSignal, OutputSignal,
Pull, Pull,
}, },
lcd_cam::{cam::private::RxPins, private::calculate_clkm, BitOrder, ByteOrder}, lcd_cam::{calculate_clkm, BitOrder, ByteOrder},
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::LCD_CAM, peripherals::LCD_CAM,
}; };
@ -604,8 +604,7 @@ impl RxPins for RxSixteenBits {
const BUS_WIDTH: usize = 2; const BUS_WIDTH: usize = 2;
} }
mod private { #[doc(hidden)]
pub trait RxPins { pub trait RxPins {
const BUS_WIDTH: usize; const BUS_WIDTH: usize;
}
} }

View File

@ -75,12 +75,13 @@ use crate::{
OutputSignal, OutputSignal,
}, },
lcd_cam::{ lcd_cam::{
asynch::LCD_DONE_WAKER, calculate_clkm,
lcd::{i8080::private::TxPins, ClockMode, DelayMode, Phase, Polarity}, lcd::{ClockMode, DelayMode, Phase, Polarity},
private::{calculate_clkm, Instance},
BitOrder, BitOrder,
ByteOrder, ByteOrder,
Instance,
Lcd, Lcd,
LCD_DONE_WAKER,
}, },
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::LCD_CAM, peripherals::LCD_CAM,
@ -703,8 +704,7 @@ impl<'d> TxPins for TxSixteenBits<'d> {
} }
} }
mod private { #[doc(hidden)]
pub trait TxPins { pub trait TxPins {
fn configure(&mut self); fn configure(&mut self);
}
} }

View File

@ -10,12 +10,18 @@ pub mod lcd;
use core::marker::PhantomData; use core::marker::PhantomData;
use embassy_sync::waitqueue::AtomicWaker;
use crate::{ use crate::{
interrupt::InterruptHandler, interrupt::InterruptHandler,
lcd_cam::{cam::Cam, lcd::Lcd}, lcd_cam::{cam::Cam, lcd::Lcd},
macros::handler,
peripheral::Peripheral, peripheral::Peripheral,
peripherals::LCD_CAM, peripherals::{Interrupt, LCD_CAM},
system::{self, PeripheralClockControl}, system::{self, PeripheralClockControl},
Async,
Blocking,
Cpu,
InterruptConfigurable, InterruptConfigurable,
}; };
@ -27,7 +33,7 @@ pub struct LcdCam<'d, DM: crate::Mode> {
pub cam: Cam<'d>, pub cam: Cam<'d>,
} }
impl<'d> LcdCam<'d, crate::Blocking> { impl<'d> LcdCam<'d, Blocking> {
/// Creates a new `LcdCam` instance. /// Creates a new `LcdCam` instance.
pub fn new(lcd_cam: impl Peripheral<P = LCD_CAM> + 'd) -> Self { pub fn new(lcd_cam: impl Peripheral<P = LCD_CAM> + 'd) -> Self {
crate::into_ref!(lcd_cam); crate::into_ref!(lcd_cam);
@ -40,56 +46,49 @@ impl<'d> LcdCam<'d, crate::Blocking> {
lcd_cam: unsafe { lcd_cam.clone_unchecked() }, lcd_cam: unsafe { lcd_cam.clone_unchecked() },
_mode: PhantomData, _mode: PhantomData,
}, },
cam: Cam { cam: Cam { lcd_cam },
lcd_cam: unsafe { lcd_cam.clone_unchecked() },
},
} }
} }
}
impl<'d> crate::private::Sealed for LcdCam<'d, crate::Blocking> {} /// Reconfigures the peripheral for asynchronous operation.
// TODO: This interrupt is shared with the Camera module, we should handle this pub fn into_async(mut self) -> LcdCam<'d, Async> {
// in a similar way to the gpio::IO self.set_interrupt_handler(interrupt_handler);
impl<'d> InterruptConfigurable for LcdCam<'d, crate::Blocking> { LcdCam {
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::LCD_CAM,
handler.handler(),
);
crate::interrupt::enable(crate::peripherals::Interrupt::LCD_CAM, handler.priority())
.unwrap();
}
}
}
impl<'d> LcdCam<'d, crate::Async> {
/// Creates a new `LcdCam` instance for asynchronous operation.
pub fn new_async(lcd_cam: impl Peripheral<P = LCD_CAM> + 'd) -> Self {
crate::into_ref!(lcd_cam);
PeripheralClockControl::enable(system::Peripheral::LcdCam);
unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::LCD_CAM,
asynch::interrupt_handler.handler(),
);
}
crate::interrupt::enable(
crate::peripherals::Interrupt::LCD_CAM,
asynch::interrupt_handler.priority(),
)
.unwrap();
Self {
lcd: Lcd { lcd: Lcd {
lcd_cam: unsafe { lcd_cam.clone_unchecked() }, lcd_cam: self.lcd.lcd_cam,
_mode: PhantomData, _mode: PhantomData,
}, },
cam: Cam { cam: self.cam,
lcd_cam: unsafe { lcd_cam.clone_unchecked() }, }
}
}
impl crate::private::Sealed for LcdCam<'_, Blocking> {}
// TODO: This interrupt is shared with the Camera module, we should handle this
// in a similar way to the gpio::IO
impl InterruptConfigurable for LcdCam<'_, Blocking> {
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
for core in crate::Cpu::other() {
crate::interrupt::disable(core, Interrupt::LCD_CAM);
}
unsafe { crate::interrupt::bind_interrupt(Interrupt::LCD_CAM, handler.handler()) };
unwrap!(crate::interrupt::enable(
Interrupt::LCD_CAM,
handler.priority()
));
}
}
impl<'d> LcdCam<'d, Async> {
/// Reconfigures the peripheral for blocking operation.
pub fn into_blocking(self) -> LcdCam<'d, Blocking> {
crate::interrupt::disable(Cpu::current(), Interrupt::LCD_CAM);
LcdCam {
lcd: Lcd {
lcd_cam: self.lcd.lcd_cam,
_mode: PhantomData,
}, },
cam: self.cam,
} }
} }
} }
@ -116,205 +115,193 @@ pub enum ByteOrder {
Inverted = 1, Inverted = 1,
} }
#[doc(hidden)] pub(crate) static LCD_DONE_WAKER: AtomicWaker = AtomicWaker::new();
pub mod asynch {
use embassy_sync::waitqueue::AtomicWaker;
use procmacros::handler;
use super::private::Instance; #[handler]
fn interrupt_handler() {
pub(crate) static LCD_DONE_WAKER: AtomicWaker = AtomicWaker::new(); // TODO: this is a shared interrupt with Camera and here we ignore that!
if Instance::is_lcd_done_set() {
#[handler] Instance::unlisten_lcd_done();
pub(crate) fn interrupt_handler() { LCD_DONE_WAKER.wake()
// TODO: this is a shared interrupt with Camera and here we ignore that!
if Instance::is_lcd_done_set() {
Instance::unlisten_lcd_done();
LCD_DONE_WAKER.wake()
}
} }
} }
mod private { pub(crate) struct Instance;
use crate::peripherals::LCD_CAM;
pub(crate) struct Instance; // NOTE: the LCD_CAM interrupt registers are shared between LCD and Camera and
// this is only implemented for the LCD side, when the Camera is implemented a
// NOTE: the LCD_CAM interrupt registers are shared between LCD and Camera and // CriticalSection will be needed to protect these shared registers.
// this is only implemented for the LCD side, when the Camera is implemented a impl Instance {
// CriticalSection will be needed to protect these shared registers. pub(crate) fn listen_lcd_done() {
impl Instance { let lcd_cam = unsafe { LCD_CAM::steal() };
pub(crate) fn listen_lcd_done() { lcd_cam
let lcd_cam = unsafe { LCD_CAM::steal() }; .lc_dma_int_ena()
lcd_cam .modify(|_, w| w.lcd_trans_done_int_ena().set_bit());
.lc_dma_int_ena()
.modify(|_, w| w.lcd_trans_done_int_ena().set_bit());
}
pub(crate) fn unlisten_lcd_done() {
let lcd_cam = unsafe { LCD_CAM::steal() };
lcd_cam
.lc_dma_int_ena()
.modify(|_, w| w.lcd_trans_done_int_ena().clear_bit());
}
pub(crate) fn is_lcd_done_set() -> bool {
let lcd_cam = unsafe { LCD_CAM::steal() };
lcd_cam
.lc_dma_int_raw()
.read()
.lcd_trans_done_int_raw()
.bit()
}
}
pub struct ClockDivider {
// Integral LCD clock divider value. (8 bits)
// Value 0 is treated as 256
// Value 1 is treated as 2
// Value N is treated as N
pub div_num: usize,
// Fractional clock divider numerator value. (6 bits)
pub div_b: usize,
// Fractional clock divider denominator value. (6 bits)
pub div_a: usize,
} }
pub fn calculate_clkm( pub(crate) fn unlisten_lcd_done() {
desired_frequency: usize, let lcd_cam = unsafe { LCD_CAM::steal() };
source_frequencies: &[usize], lcd_cam
) -> (usize, ClockDivider) { .lc_dma_int_ena()
let mut result_freq = 0; .modify(|_, w| w.lcd_trans_done_int_ena().clear_bit());
let mut result = None; }
for (i, &source_frequency) in source_frequencies.iter().enumerate() { pub(crate) fn is_lcd_done_set() -> bool {
let div = calculate_closest_divider(source_frequency, desired_frequency); let lcd_cam = unsafe { LCD_CAM::steal() };
if let Some(div) = div { lcd_cam
let freq = calculate_output_frequency(source_frequency, &div); .lc_dma_int_raw()
if result.is_none() || freq > result_freq { .read()
result = Some((i, div)); .lcd_trans_done_int_raw()
result_freq = freq; .bit()
} }
}
pub(crate) struct ClockDivider {
// Integral LCD clock divider value. (8 bits)
// Value 0 is treated as 256
// Value 1 is treated as 2
// Value N is treated as N
pub div_num: usize,
// Fractional clock divider numerator value. (6 bits)
pub div_b: usize,
// Fractional clock divider denominator value. (6 bits)
pub div_a: usize,
}
pub(crate) fn calculate_clkm(
desired_frequency: usize,
source_frequencies: &[usize],
) -> (usize, ClockDivider) {
let mut result_freq = 0;
let mut result = None;
for (i, &source_frequency) in source_frequencies.iter().enumerate() {
let div = calculate_closest_divider(source_frequency, desired_frequency);
if let Some(div) = div {
let freq = calculate_output_frequency(source_frequency, &div);
if result.is_none() || freq > result_freq {
result = Some((i, div));
result_freq = freq;
} }
} }
result.expect("Desired frequency was too low for the dividers to divide to")
} }
fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize { result.expect("Desired frequency was too low for the dividers to divide to")
let n = match divider.div_num { }
0 => 256,
1 => 2,
_ => divider.div_num.min(256),
};
if divider.div_b != 0 && divider.div_a != 0 { fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize {
// OUTPUT = SOURCE / (N + B/A) let n = match divider.div_num {
// OUTPUT = SOURCE / ((NA + B)/A) 0 => 256,
// OUTPUT = (SOURCE * A) / (NA + B) 1 => 2,
_ => divider.div_num.min(256),
};
// u64 is required to fit the numbers from this arithmetic. if divider.div_b != 0 && divider.div_a != 0 {
// OUTPUT = SOURCE / (N + B/A)
// OUTPUT = SOURCE / ((NA + B)/A)
// OUTPUT = (SOURCE * A) / (NA + B)
let source = source_frequency as u64; // u64 is required to fit the numbers from this arithmetic.
let n = n as u64;
let a = divider.div_b as u64;
let b = divider.div_a as u64;
((source * a) / (n * a + b)) as _ let source = source_frequency as u64;
} else { let n = n as u64;
source_frequency / n let a = divider.div_b as u64;
} let b = divider.div_a as u64;
((source * a) / (n * a + b)) as _
} else {
source_frequency / n
}
}
fn calculate_closest_divider(
source_frequency: usize,
desired_frequency: usize,
) -> Option<ClockDivider> {
let div_num = source_frequency / desired_frequency;
if div_num < 2 {
// Source clock isn't fast enough to reach the desired frequency.
// Return max output.
return Some(ClockDivider {
div_num: 1,
div_b: 0,
div_a: 0,
});
}
if div_num > 256 {
// Source is too fast to divide to the desired frequency. Return None.
return None;
} }
fn calculate_closest_divider( let div_num = if div_num == 256 { 0 } else { div_num };
source_frequency: usize,
desired_frequency: usize, let div_fraction = {
) -> Option<ClockDivider> { let div_remainder = source_frequency % desired_frequency;
let div_num = source_frequency / desired_frequency; let gcd = hcf(div_remainder, desired_frequency);
if div_num < 2 { Fraction {
// Source clock isn't fast enough to reach the desired frequency. numerator: div_remainder / gcd,
// Return max output. denominator: desired_frequency / gcd,
return Some(ClockDivider {
div_num: 1,
div_b: 0,
div_a: 0,
});
} }
if div_num > 256 { };
// Source is too fast to divide to the desired frequency. Return None.
let divider = if div_fraction.numerator == 0 {
ClockDivider {
div_num,
div_b: 0,
div_a: 0,
}
} else {
let target = div_fraction;
let closest = farey_sequence(63)
.find(|curr| {
// https://en.wikipedia.org/wiki/Fraction#Adding_unlike_quantities
let new_curr_num = curr.numerator * target.denominator;
let new_target_num = target.numerator * curr.denominator;
new_curr_num >= new_target_num
})
.expect("The fraction must be between 0 and 1");
ClockDivider {
div_num,
div_b: closest.numerator,
div_a: closest.denominator,
}
};
Some(divider)
}
// https://en.wikipedia.org/wiki/Euclidean_algorithm
const fn hcf(a: usize, b: usize) -> usize {
if b != 0 {
hcf(b, a % b)
} else {
a
}
}
struct Fraction {
pub numerator: usize,
pub denominator: usize,
}
// https://en.wikipedia.org/wiki/Farey_sequence#Next_term
fn farey_sequence(denominator: usize) -> impl Iterator<Item = Fraction> {
let mut a = 0;
let mut b = 1;
let mut c = 1;
let mut d = denominator;
core::iter::from_fn(move || {
if a > denominator {
return None; return None;
} }
let next = Fraction {
let div_num = if div_num == 256 { 0 } else { div_num }; numerator: a,
denominator: b,
let div_fraction = {
let div_remainder = source_frequency % desired_frequency;
let gcd = hcf(div_remainder, desired_frequency);
Fraction {
numerator: div_remainder / gcd,
denominator: desired_frequency / gcd,
}
}; };
let k = (denominator + b) / d;
let divider = if div_fraction.numerator == 0 { (a, b, c, d) = (c, d, k * c - a, k * d - b);
ClockDivider { Some(next)
div_num, })
div_b: 0,
div_a: 0,
}
} else {
let target = div_fraction;
let closest = farey_sequence(63)
.find(|curr| {
// https://en.wikipedia.org/wiki/Fraction#Adding_unlike_quantities
let new_curr_num = curr.numerator * target.denominator;
let new_target_num = target.numerator * curr.denominator;
new_curr_num >= new_target_num
})
.expect("The fraction must be between 0 and 1");
ClockDivider {
div_num,
div_b: closest.numerator,
div_a: closest.denominator,
}
};
Some(divider)
}
// https://en.wikipedia.org/wiki/Euclidean_algorithm
const fn hcf(a: usize, b: usize) -> usize {
if b != 0 {
hcf(b, a % b)
} else {
a
}
}
struct Fraction {
pub numerator: usize,
pub denominator: usize,
}
// https://en.wikipedia.org/wiki/Farey_sequence#Next_term
fn farey_sequence(denominator: usize) -> impl Iterator<Item = Fraction> {
let mut a = 0;
let mut b = 1;
let mut c = 1;
let mut d = denominator;
core::iter::from_fn(move || {
if a > denominator {
return None;
}
let next = Fraction {
numerator: a,
denominator: b,
};
let k = (denominator + b) / d;
(a, b, c, d) = (c, d, k * c - a, k * d - b);
Some(next)
})
}
} }

View File

@ -374,6 +374,21 @@ impl Cpu {
pub fn current() -> Self { pub fn current() -> Self {
get_core() get_core()
} }
/// Returns an iterator over the "other" cores.
#[inline(always)]
pub fn other() -> impl Iterator<Item = Self> {
cfg_if::cfg_if! {
if #[cfg(multi_core)] {
match get_core() {
Cpu::ProCpu => [Cpu::AppCpu].into_iter(),
Cpu::AppCpu => [Cpu::ProCpu].into_iter(),
}
} else {
[].into_iter()
}
}
}
} }
/// Which core the application is currently executing on /// Which core the application is currently executing on

View File

@ -52,7 +52,7 @@ use crate::{
gpio::interconnect::{InputConnection, OutputConnection, PeripheralInput, PeripheralOutput}, gpio::interconnect::{InputConnection, OutputConnection, PeripheralInput, PeripheralOutput},
interrupt::InterruptHandler, interrupt::InterruptHandler,
peripheral::{self, Peripheral}, peripheral::{self, Peripheral},
peripherals::{self, PARL_IO}, peripherals::{self, Interrupt, PARL_IO},
system::PeripheralClockControl, system::PeripheralClockControl,
Blocking, Blocking,
InterruptConfigurable, InterruptConfigurable,
@ -923,42 +923,52 @@ where
fn internal_set_interrupt_handler(handler: InterruptHandler) { fn internal_set_interrupt_handler(handler: InterruptHandler) {
#[cfg(esp32c6)] #[cfg(esp32c6)]
{ {
for core in crate::Cpu::other() {
crate::interrupt::disable(core, Interrupt::PARL_IO);
}
internal_listen(EnumSet::all(), false);
internal_clear_interrupts(EnumSet::all());
unsafe { PARL_IO::steal() }.bind_parl_io_interrupt(handler.handler()); unsafe { PARL_IO::steal() }.bind_parl_io_interrupt(handler.handler());
crate::interrupt::enable(crate::peripherals::Interrupt::PARL_IO, handler.priority()) unwrap!(crate::interrupt::enable(
.unwrap(); Interrupt::PARL_IO,
handler.priority()
));
} }
#[cfg(esp32h2)] #[cfg(esp32h2)]
{ {
for core in crate::Cpu::other() {
crate::interrupt::disable(core, Interrupt::PARL_IO_RX);
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
}
internal_listen(EnumSet::all(), false);
internal_clear_interrupts(EnumSet::all());
unsafe { PARL_IO::steal() }.bind_parl_io_tx_interrupt(handler.handler()); unsafe { PARL_IO::steal() }.bind_parl_io_tx_interrupt(handler.handler());
unsafe { PARL_IO::steal() }.bind_parl_io_rx_interrupt(handler.handler()); unsafe { PARL_IO::steal() }.bind_parl_io_rx_interrupt(handler.handler());
crate::interrupt::enable( unwrap!(crate::interrupt::enable(
crate::peripherals::Interrupt::PARL_IO_TX, Interrupt::PARL_IO_TX,
handler.priority(), handler.priority(),
) ));
.unwrap(); unwrap!(crate::interrupt::enable(
crate::interrupt::enable( Interrupt::PARL_IO_RX,
crate::peripherals::Interrupt::PARL_IO_RX,
handler.priority(), handler.priority(),
) ));
.unwrap();
} }
} }
fn internal_listen(interrupts: EnumSet<ParlIoInterrupt>, enable: bool) { fn internal_listen(interrupts: EnumSet<ParlIoInterrupt>, enable: bool) {
let parl_io = unsafe { PARL_IO::steal() }; let parl_io = unsafe { PARL_IO::steal() };
for interrupt in interrupts { parl_io.int_ena().write(|w| {
match interrupt { for interrupt in interrupts {
ParlIoInterrupt::TxFifoReEmpty => parl_io match interrupt {
.int_ena() ParlIoInterrupt::TxFifoReEmpty => w.tx_fifo_rempty().bit(enable),
.modify(|_, w| w.tx_fifo_rempty().bit(enable)), ParlIoInterrupt::RxFifoWOvf => w.rx_fifo_wovf().bit(enable),
ParlIoInterrupt::RxFifoWOvf => parl_io ParlIoInterrupt::TxEof => w.tx_eof().bit(enable),
.int_ena() };
.modify(|_, w| w.rx_fifo_wovf().bit(enable)),
ParlIoInterrupt::TxEof => parl_io.int_ena().write(|w| w.tx_eof().bit(enable)),
} }
} w
});
} }
fn internal_interrupts() -> EnumSet<ParlIoInterrupt> { fn internal_interrupts() -> EnumSet<ParlIoInterrupt> {
@ -980,17 +990,16 @@ fn internal_interrupts() -> EnumSet<ParlIoInterrupt> {
fn internal_clear_interrupts(interrupts: EnumSet<ParlIoInterrupt>) { fn internal_clear_interrupts(interrupts: EnumSet<ParlIoInterrupt>) {
let parl_io = unsafe { PARL_IO::steal() }; let parl_io = unsafe { PARL_IO::steal() };
for interrupt in interrupts { parl_io.int_clr().write(|w| {
match interrupt { for interrupt in interrupts {
ParlIoInterrupt::TxFifoReEmpty => parl_io match interrupt {
.int_clr() ParlIoInterrupt::TxFifoReEmpty => w.tx_fifo_rempty().clear_bit_by_one(),
.write(|w| w.tx_fifo_rempty().clear_bit_by_one()), ParlIoInterrupt::RxFifoWOvf => w.rx_fifo_wovf().clear_bit_by_one(),
ParlIoInterrupt::RxFifoWOvf => parl_io ParlIoInterrupt::TxEof => w.tx_eof().clear_bit_by_one(),
.int_clr() };
.write(|w| w.rx_fifo_wovf().clear_bit_by_one()),
ParlIoInterrupt::TxEof => parl_io.int_clr().write(|w| w.tx_eof().clear_bit_by_one()),
} }
} w
});
} }
/// Parallel IO in full duplex mode /// Parallel IO in full duplex mode

View File

@ -113,9 +113,10 @@ impl crate::private::Sealed for Pcnt<'_> {}
impl InterruptConfigurable for Pcnt<'_> { impl InterruptConfigurable for Pcnt<'_> {
fn set_interrupt_handler(&mut self, handler: InterruptHandler) { fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
unsafe { for core in crate::Cpu::other() {
interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()); crate::interrupt::disable(core, Interrupt::PCNT);
interrupt::enable(Interrupt::PCNT, handler.priority()).unwrap();
} }
unsafe { interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()) };
unwrap!(interrupt::enable(Interrupt::PCNT, handler.priority()));
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -26,8 +26,11 @@ use core::{marker::PhantomData, ptr::copy_nonoverlapping};
use crate::{ use crate::{
interrupt::InterruptHandler, interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::RSA, peripherals::{Interrupt, RSA},
system::{Peripheral as PeripheralEnable, PeripheralClockControl}, system::{Peripheral as PeripheralEnable, PeripheralClockControl},
Async,
Blocking,
Cpu,
InterruptConfigurable, InterruptConfigurable,
}; };
@ -47,29 +50,44 @@ pub struct Rsa<'d, DM: crate::Mode> {
phantom: PhantomData<DM>, phantom: PhantomData<DM>,
} }
impl<'d> Rsa<'d, crate::Blocking> { impl<'d> Rsa<'d, Blocking> {
/// Create a new instance in [crate::Blocking] mode. /// Create a new instance in [crate::Blocking] mode.
/// ///
/// Optionally an interrupt handler can be bound. /// Optionally an interrupt handler can be bound.
pub fn new(rsa: impl Peripheral<P = RSA> + 'd) -> Self { pub fn new(rsa: impl Peripheral<P = RSA> + 'd) -> Self {
Self::new_internal(rsa) Self::new_internal(rsa)
} }
}
impl crate::private::Sealed for Rsa<'_, crate::Blocking> {} /// Reconfigures the RSA driver to operate in asynchronous mode.
pub fn into_async(mut self) -> Rsa<'d, Async> {
impl InterruptConfigurable for Rsa<'_, crate::Blocking> { self.set_interrupt_handler(asynch::rsa_interrupt_handler);
fn set_interrupt_handler(&mut self, handler: InterruptHandler) { Rsa {
self.internal_set_interrupt_handler(handler); rsa: self.rsa,
phantom: PhantomData,
}
} }
} }
impl<'d> Rsa<'d, crate::Async> { impl crate::private::Sealed for Rsa<'_, Blocking> {}
impl InterruptConfigurable for Rsa<'_, Blocking> {
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
for core in crate::Cpu::other() {
crate::interrupt::disable(core, Interrupt::RSA);
}
unsafe { crate::interrupt::bind_interrupt(Interrupt::RSA, handler.handler()) };
unwrap!(crate::interrupt::enable(Interrupt::RSA, handler.priority()));
}
}
impl<'d> Rsa<'d, Async> {
/// Create a new instance in [crate::Blocking] mode. /// Create a new instance in [crate::Blocking] mode.
pub fn new_async(rsa: impl Peripheral<P = RSA> + 'd) -> Self { pub fn into_blocking(self) -> Rsa<'d, Blocking> {
let mut this = Self::new_internal(rsa); crate::interrupt::disable(Cpu::current(), Interrupt::RSA);
this.internal_set_interrupt_handler(asynch::rsa_interrupt_handler); Rsa {
this rsa: self.rsa,
phantom: PhantomData,
}
} }
} }
@ -129,15 +147,6 @@ impl<'d, DM: crate::Mode> Rsa<'d, DM> {
); );
} }
} }
fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) {
unsafe {
crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::RSA, handler.handler());
crate::interrupt::enable(crate::peripherals::Interrupt::RSA, handler.priority())
.unwrap();
}
}
fn wait_for_idle(&mut self) { fn wait_for_idle(&mut self) {
while !self.is_idle() {} while !self.is_idle() {}
self.clear_interrupt(); self.clear_interrupt();

View File

@ -434,23 +434,18 @@ impl crate::private::Sealed for Rtc<'_> {}
impl InterruptConfigurable for Rtc<'_> { impl InterruptConfigurable for Rtc<'_> {
fn set_interrupt_handler(&mut self, handler: InterruptHandler) { fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
unsafe { cfg_if::cfg_if! {
interrupt::bind_interrupt( if #[cfg(any(esp32c6, esp32h2))] {
#[cfg(any(esp32c6, esp32h2))] let interrupt = Interrupt::LP_WDT;
Interrupt::LP_WDT, } else {
#[cfg(not(any(esp32c6, esp32h2)))] let interrupt = Interrupt::RTC_CORE;
Interrupt::RTC_CORE, }
handler.handler(),
);
interrupt::enable(
#[cfg(any(esp32c6, esp32h2))]
Interrupt::LP_WDT,
#[cfg(not(any(esp32c6, esp32h2)))]
Interrupt::RTC_CORE,
handler.priority(),
)
.unwrap();
} }
for core in crate::Cpu::other() {
crate::interrupt::disable(core, interrupt);
}
unsafe { interrupt::bind_interrupt(interrupt, handler.handler()) };
unwrap!(interrupt::enable(interrupt, handler.priority()));
} }
} }

View File

@ -62,6 +62,8 @@ use core::{borrow::BorrowMut, convert::Infallible, marker::PhantomData, mem::siz
#[cfg(feature = "digest")] #[cfg(feature = "digest")]
pub use digest::Digest; pub use digest::Digest;
#[cfg(not(esp32))]
use crate::peripherals::Interrupt;
use crate::{ use crate::{
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
peripherals::SHA, peripherals::SHA,
@ -103,11 +105,11 @@ impl crate::private::Sealed for Sha<'_> {}
#[cfg(not(esp32))] #[cfg(not(esp32))]
impl crate::InterruptConfigurable for Sha<'_> { impl crate::InterruptConfigurable for Sha<'_> {
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
unsafe { for core in crate::Cpu::other() {
crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::SHA, handler.handler()); crate::interrupt::disable(core, Interrupt::SHA);
crate::interrupt::enable(crate::peripherals::Interrupt::SHA, handler.priority())
.unwrap();
} }
unsafe { crate::interrupt::bind_interrupt(Interrupt::SHA, handler.handler()) };
unwrap!(crate::interrupt::enable(Interrupt::SHA, handler.priority()));
} }
} }

View File

@ -61,6 +61,8 @@
//! [`embedded-hal-bus`]: https://docs.rs/embedded-hal-bus/latest/embedded_hal_bus/spi/index.html //! [`embedded-hal-bus`]: https://docs.rs/embedded-hal-bus/latest/embedded_hal_bus/spi/index.html
//! [`embassy-embedded-hal`]: https://docs.embassy.dev/embassy-embedded-hal/git/default/shared_bus/index.html //! [`embassy-embedded-hal`]: https://docs.embassy.dev/embassy-embedded-hal/git/default/shared_bus/index.html
use core::marker::PhantomData;
pub use dma::*; pub use dma::*;
#[cfg(gdma)] #[cfg(gdma)]
use enumset::EnumSet; use enumset::EnumSet;
@ -73,7 +75,16 @@ use procmacros::ram;
use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode}; use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode};
use crate::{ use crate::{
clock::Clocks, clock::Clocks,
dma::{DmaChannelConvert, DmaEligible, DmaRxBuffer, DmaTxBuffer, PeripheralMarker, Rx, Tx}, dma::{
Channel,
DmaChannelConvert,
DmaEligible,
DmaRxBuffer,
DmaTxBuffer,
PeripheralMarker,
Rx,
Tx,
},
gpio::{ gpio::{
interconnect::{OutputConnection, PeripheralOutput}, interconnect::{OutputConnection, PeripheralOutput},
InputSignal, InputSignal,
@ -86,6 +97,8 @@ use crate::{
private, private,
spi::AnySpi, spi::AnySpi,
system::PeripheralClockControl, system::PeripheralClockControl,
Async,
Blocking,
Mode, Mode,
}; };
@ -423,12 +436,14 @@ impl Address {
} }
/// SPI peripheral driver /// SPI peripheral driver
pub struct Spi<'d, T = AnySpi> { pub struct Spi<'d, M, T = AnySpi> {
spi: PeripheralRef<'d, T>, spi: PeripheralRef<'d, T>,
_mode: PhantomData<M>,
} }
impl<'d, T> Spi<'d, T> impl<'d, M, T> Spi<'d, M, T>
where where
M: Mode,
T: InstanceDma, T: InstanceDma,
{ {
/// Configures the SPI instance to use DMA with the specified channel. /// Configures the SPI instance to use DMA with the specified channel.
@ -436,19 +451,17 @@ where
/// This method prepares the SPI instance for DMA transfers using SPI /// This method prepares the SPI instance for DMA transfers using SPI
/// and returns an instance of `SpiDma` that supports DMA /// and returns an instance of `SpiDma` that supports DMA
/// operations. /// operations.
pub fn with_dma<CH, DmaMode>( pub fn with_dma<CH, DM>(self, channel: Channel<'d, CH, DM>) -> SpiDma<'d, M, T>
self,
channel: crate::dma::Channel<'d, CH, DmaMode>,
) -> SpiDma<'d, DmaMode, T>
where where
CH: DmaChannelConvert<T::Dma>, CH: DmaChannelConvert<T::Dma>,
DmaMode: Mode, DM: Mode,
Channel<'d, CH, M>: From<Channel<'d, CH, DM>>,
{ {
SpiDma::new(self.spi, channel) SpiDma::new(self.spi, channel.into())
} }
} }
impl<T> Spi<'_, T> impl<M, T> Spi<'_, M, T>
where where
T: Instance, T: Instance,
{ {
@ -484,18 +497,36 @@ where
} }
} }
impl<'d> Spi<'d> { impl<'d> Spi<'d, Blocking> {
/// Constructs an SPI instance in 8bit dataframe mode. /// Constructs an SPI instance in 8bit dataframe mode.
pub fn new( pub fn new(
spi: impl Peripheral<P = impl Instance> + 'd, spi: impl Peripheral<P = impl Instance> + 'd,
frequency: HertzU32, frequency: HertzU32,
mode: SpiMode, mode: SpiMode,
) -> Spi<'d> { ) -> Spi<'d, Blocking> {
Self::new_typed(spi.map_into(), frequency, mode) Self::new_typed(spi.map_into(), frequency, mode)
} }
/// Converts the SPI instance into async mode.
pub fn into_async(self) -> Spi<'d, Async> {
Spi {
spi: self.spi,
_mode: PhantomData,
}
}
} }
impl<'d, T> Spi<'d, T> impl<'d> Spi<'d, Async> {
/// Converts the SPI instance into blocking mode.
pub fn into_blocking(self) -> Spi<'d, Blocking> {
Spi {
spi: self.spi,
_mode: PhantomData,
}
}
}
impl<'d, M, T> Spi<'d, M, T>
where where
T: Instance, T: Instance,
{ {
@ -504,10 +535,13 @@ where
spi: impl Peripheral<P = T> + 'd, spi: impl Peripheral<P = T> + 'd,
frequency: HertzU32, frequency: HertzU32,
mode: SpiMode, mode: SpiMode,
) -> Spi<'d, T> { ) -> Spi<'d, M, T> {
crate::into_ref!(spi); crate::into_ref!(spi);
let mut spi = Spi { spi }; let mut spi = Spi {
spi,
_mode: PhantomData,
};
spi.spi.reset_peripheral(); spi.spi.reset_peripheral();
spi.spi.enable_peripheral(); spi.spi.enable_peripheral();
spi.spi.setup(frequency); spi.spi.setup(frequency);
@ -616,7 +650,7 @@ where
} }
} }
impl<'d, T> Spi<'d, T> impl<'d, M, T> Spi<'d, M, T>
where where
T: QspiInstance, T: QspiInstance,
{ {
@ -663,7 +697,7 @@ where
} }
} }
impl<T> Spi<'_, T> impl<M, T> Spi<'_, M, T>
where where
T: Instance, T: Instance,
{ {
@ -754,7 +788,7 @@ where
} }
} }
impl<T> embedded_hal_02::spi::FullDuplex<u8> for Spi<'_, T> impl<M, T> embedded_hal_02::spi::FullDuplex<u8> for Spi<'_, M, T>
where where
T: Instance, T: Instance,
{ {
@ -769,7 +803,7 @@ where
} }
} }
impl<T> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'_, T> impl<M, T> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'_, M, T>
where where
T: Instance, T: Instance,
{ {
@ -780,7 +814,7 @@ where
} }
} }
impl<T> embedded_hal_02::blocking::spi::Write<u8> for Spi<'_, T> impl<M, T> embedded_hal_02::blocking::spi::Write<u8> for Spi<'_, M, T>
where where
T: Instance, T: Instance,
{ {
@ -812,9 +846,7 @@ mod dma {
Rx, Rx,
Tx, Tx,
}, },
Blocking,
InterruptConfigurable, InterruptConfigurable,
Mode,
}; };
/// A DMA capable SPI instance. /// A DMA capable SPI instance.
@ -837,6 +869,40 @@ mod dma {
address_buffer: DmaTxBuf, address_buffer: DmaTxBuf,
} }
impl<'d, T> SpiDma<'d, Blocking, T>
where
T: InstanceDma,
{
/// Converts the SPI instance into async mode.
pub fn into_async(self) -> SpiDma<'d, Async, T> {
SpiDma {
spi: self.spi,
channel: self.channel.into_async(),
tx_transfer_in_progress: self.tx_transfer_in_progress,
rx_transfer_in_progress: self.rx_transfer_in_progress,
#[cfg(all(esp32, spi_address_workaround))]
address_buffer: self.address_buffer,
}
}
}
impl<'d, T> SpiDma<'d, Async, T>
where
T: InstanceDma,
{
/// Converts the SPI instance into async mode.
pub fn into_blocking(self) -> SpiDma<'d, Blocking, T> {
SpiDma {
spi: self.spi,
channel: self.channel.into_blocking(),
tx_transfer_in_progress: self.tx_transfer_in_progress,
rx_transfer_in_progress: self.rx_transfer_in_progress,
#[cfg(all(esp32, spi_address_workaround))]
address_buffer: self.address_buffer,
}
}
}
#[cfg(all(esp32, spi_address_workaround))] #[cfg(all(esp32, spi_address_workaround))]
unsafe impl<'d, M, T> Send for SpiDma<'d, M, T> unsafe impl<'d, M, T> Send for SpiDma<'d, M, T>
where where
@ -868,6 +934,9 @@ mod dma {
/// Interrupts are not enabled at the peripheral level here. /// Interrupts are not enabled at the peripheral level here.
fn set_interrupt_handler(&mut self, handler: InterruptHandler) { fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
let interrupt = self.spi.interrupt(); let interrupt = self.spi.interrupt();
for core in crate::Cpu::other() {
crate::interrupt::disable(core, interrupt);
}
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) }; unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
unwrap!(crate::interrupt::enable(interrupt, handler.priority())); unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
} }
@ -1180,7 +1249,7 @@ mod dma {
} }
} }
impl<T, Buf> SpiDmaTransfer<'_, crate::Async, Buf, T> impl<T, Buf> SpiDmaTransfer<'_, Async, Buf, T>
where where
T: InstanceDma, T: InstanceDma,
{ {
@ -1460,6 +1529,34 @@ mod dma {
tx_buf: DmaTxBuf, tx_buf: DmaTxBuf,
} }
impl<'d, T> SpiDmaBus<'d, Blocking, T>
where
T: InstanceDma,
{
/// Converts the SPI instance into async mode.
pub fn into_async(self) -> SpiDmaBus<'d, Async, T> {
SpiDmaBus {
spi_dma: self.spi_dma.into_async(),
rx_buf: self.rx_buf,
tx_buf: self.tx_buf,
}
}
}
impl<'d, T> SpiDmaBus<'d, Async, T>
where
T: InstanceDma,
{
/// Converts the SPI instance into async mode.
pub fn into_blocking(self) -> SpiDmaBus<'d, Blocking, T> {
SpiDmaBus {
spi_dma: self.spi_dma.into_blocking(),
rx_buf: self.rx_buf,
tx_buf: self.tx_buf,
}
}
}
impl<'d, M, T> SpiDmaBus<'d, M, T> impl<'d, M, T> SpiDmaBus<'d, M, T>
where where
T: InstanceDma, T: InstanceDma,
@ -1699,7 +1796,7 @@ mod dma {
} }
} }
impl<T> embedded_hal_02::blocking::spi::Transfer<u8> for SpiDmaBus<'_, crate::Blocking, T> impl<T> embedded_hal_02::blocking::spi::Transfer<u8> for SpiDmaBus<'_, Blocking, T>
where where
T: InstanceDma, T: InstanceDma,
{ {
@ -1711,7 +1808,7 @@ mod dma {
} }
} }
impl<T> embedded_hal_02::blocking::spi::Write<u8> for SpiDmaBus<'_, crate::Blocking, T> impl<T> embedded_hal_02::blocking::spi::Write<u8> for SpiDmaBus<'_, Blocking, T>
where where
T: InstanceDma, T: InstanceDma,
{ {
@ -1731,6 +1828,7 @@ mod dma {
}; };
use super::*; use super::*;
use crate::Async;
struct DropGuard<I, F: FnOnce(I)> { struct DropGuard<I, F: FnOnce(I)> {
inner: ManuallyDrop<I>, inner: ManuallyDrop<I>,
@ -1770,7 +1868,7 @@ mod dma {
} }
} }
impl<T> SpiDmaBus<'_, crate::Async, T> impl<T> SpiDmaBus<'_, Async, T>
where where
T: InstanceDma, T: InstanceDma,
{ {
@ -1884,7 +1982,7 @@ mod dma {
} }
} }
impl<T> embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, crate::Async, T> impl<T> embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, Async, T>
where where
T: InstanceDma, T: InstanceDma,
{ {
@ -1959,11 +2057,11 @@ mod ehal1 {
use super::*; use super::*;
impl<T> embedded_hal::spi::ErrorType for Spi<'_, T> { impl<M, T> embedded_hal::spi::ErrorType for Spi<'_, M, T> {
type Error = Error; type Error = Error;
} }
impl<T> FullDuplex for Spi<'_, T> impl<M, T> FullDuplex for Spi<'_, M, T>
where where
T: Instance, T: Instance,
{ {
@ -1976,7 +2074,7 @@ mod ehal1 {
} }
} }
impl<T> SpiBus for Spi<'_, T> impl<M, T> SpiBus for Spi<'_, M, T>
where where
T: Instance, T: Instance,
{ {

View File

@ -70,6 +70,8 @@
//! //!
//! See [tracking issue](https://github.com/esp-rs/esp-hal/issues/469) for more information. //! See [tracking issue](https://github.com/esp-rs/esp-hal/issues/469) for more information.
use core::marker::PhantomData;
use super::{Error, SpiMode}; use super::{Error, SpiMode};
use crate::{ use crate::{
dma::{DescriptorChain, DmaChannelConvert, DmaEligible, PeripheralMarker, Rx, Tx}, dma::{DescriptorChain, DmaChannelConvert, DmaEligible, PeripheralMarker, Rx, Tx},
@ -83,6 +85,7 @@ use crate::{
private, private,
spi::AnySpi, spi::AnySpi,
system::PeripheralClockControl, system::PeripheralClockControl,
Blocking,
}; };
const MAX_DMA_SIZE: usize = 32768 - 32; const MAX_DMA_SIZE: usize = 32768 - 32;
@ -90,13 +93,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 = AnySpi> { 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>,
} }
impl<'d> Spi<'d> { impl<'d> Spi<'d, Blocking> {
/// 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,
@ -110,12 +114,12 @@ impl<'d> Spi<'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> { ) -> Spi<'d, Blocking> {
Self::new_typed(spi.map_into(), sclk, mosi, miso, cs, mode) Self::new_typed(spi.map_into(), sclk, mosi, miso, cs, mode)
} }
} }
impl<'d, T> Spi<'d, T> impl<'d, M, T> Spi<'d, M, T>
where where
T: Instance, T: Instance,
{ {
@ -132,7 +136,7 @@ where
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> { ) -> Spi<'d, M, T> {
crate::into_mapped_ref!(sclk, mosi, miso, cs); crate::into_mapped_ref!(sclk, mosi, miso, cs);
let this = Self::new_internal(spi, mode); let this = Self::new_internal(spi, mode);
@ -153,12 +157,13 @@ where
this this
} }
pub(crate) fn new_internal(spi: impl Peripheral<P = T> + 'd, mode: SpiMode) -> Spi<'d, T> { pub(crate) fn new_internal(spi: impl Peripheral<P = T> + 'd, mode: SpiMode) -> Spi<'d, M, T> {
crate::into_ref!(spi); crate::into_ref!(spi);
let mut spi = Spi { let mut spi = Spi {
spi, spi,
data_mode: mode, data_mode: mode,
_mode: PhantomData,
}; };
PeripheralClockControl::reset(spi.spi.peripheral()); PeripheralClockControl::reset(spi.spi.peripheral());
@ -193,36 +198,38 @@ pub mod dma {
Mode, Mode,
}; };
impl<'d, T> Spi<'d, T> impl<'d, M, T> Spi<'d, M, T>
where where
T: InstanceDma, T: InstanceDma,
M: Mode,
{ {
/// Configures the SPI3 peripheral with the provided DMA channel and /// Configures the SPI3 peripheral with the provided DMA channel and
/// descriptors. /// descriptors.
#[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")] #[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")]
pub fn with_dma<CH, DmaMode>( pub fn with_dma<CH, DM>(
mut self, mut self,
channel: Channel<'d, CH, DmaMode>, channel: Channel<'d, CH, DM>,
rx_descriptors: &'static mut [DmaDescriptor], rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor],
) -> SpiDma<'d, DmaMode, T> ) -> SpiDma<'d, M, T>
where where
CH: DmaChannelConvert<T::Dma>, CH: DmaChannelConvert<T::Dma>,
DmaMode: Mode, DM: Mode,
Channel<'d, CH, M>: From<Channel<'d, CH, DM>>,
{ {
self.spi.set_data_mode(self.data_mode, true); self.spi.set_data_mode(self.data_mode, true);
SpiDma::new(self.spi, channel, rx_descriptors, tx_descriptors) SpiDma::new(self.spi, channel.into(), rx_descriptors, tx_descriptors)
} }
} }
/// A DMA capable SPI instance. /// A DMA capable SPI instance.
pub struct SpiDma<'d, DmaMode, T = AnySpi> pub struct SpiDma<'d, M, T = AnySpi>
where where
T: InstanceDma, T: InstanceDma,
DmaMode: Mode, M: Mode,
{ {
pub(crate) spi: PeripheralRef<'d, T>, pub(crate) spi: PeripheralRef<'d, T>,
pub(crate) channel: Channel<'d, T::Dma, DmaMode>, pub(crate) channel: Channel<'d, T::Dma, M>,
rx_chain: DescriptorChain, rx_chain: DescriptorChain,
tx_chain: DescriptorChain, tx_chain: DescriptorChain,
} }

View File

@ -549,6 +549,10 @@ pub trait Comparator {
_ => unreachable!(), _ => unreachable!(),
}; };
for core in crate::Cpu::other() {
crate::interrupt::disable(core, interrupt);
}
#[cfg(not(esp32s2))] #[cfg(not(esp32s2))]
unsafe { unsafe {
interrupt::bind_interrupt(interrupt, handler.handler()); interrupt::bind_interrupt(interrupt, handler.handler());

View File

@ -553,10 +553,11 @@ where
_ => unreachable!(), _ => unreachable!(),
}; };
unsafe { for core in crate::Cpu::other() {
interrupt::bind_interrupt(interrupt, handler.handler()); crate::interrupt::disable(core, interrupt);
} }
interrupt::enable(interrupt, handler.priority()).unwrap(); unsafe { interrupt::bind_interrupt(interrupt, handler.handler()) };
unwrap!(interrupt::enable(interrupt, handler.priority()));
} }
fn is_interrupt_set(&self) -> bool { fn is_interrupt_set(&self) -> bool {

View File

@ -840,10 +840,15 @@ where
} }
fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) { fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) {
unsafe { for core in crate::Cpu::other() {
crate::interrupt::bind_interrupt(self.twai.interrupt(), handler.handler()); crate::interrupt::disable(core, self.twai.interrupt());
crate::interrupt::enable(self.twai.interrupt(), handler.priority()).unwrap();
} }
unsafe { crate::interrupt::bind_interrupt(self.twai.interrupt(), handler.handler()) };
unwrap!(crate::interrupt::enable(
self.twai.interrupt(),
handler.priority()
));
} }
/// Set the bitrate of the bus. /// Set the bitrate of the bus.
@ -1027,17 +1032,6 @@ where
phantom: PhantomData, phantom: PhantomData,
} }
} }
/// Convert the configuration into an async configuration.
fn into_async(self) -> TwaiConfiguration<'d, Async, T> {
let mut this = TwaiConfiguration {
twai: self.twai,
phantom: PhantomData,
mode: self.mode,
};
this.internal_set_interrupt_handler(this.twai.async_handler());
this
}
} }
impl<'d> TwaiConfiguration<'d, Blocking> { impl<'d> TwaiConfiguration<'d, Blocking> {
@ -1101,35 +1095,15 @@ where
) -> Self { ) -> Self {
Self::new_internal(peripheral, rx_pin, tx_pin, baud_rate, true, mode) Self::new_internal(peripheral, rx_pin, tx_pin, baud_rate, true, mode)
} }
}
impl<'d> TwaiConfiguration<'d, Async> { /// Convert the configuration into an async configuration.
/// Create a new instance of [TwaiConfiguration] pub fn into_async(mut self) -> TwaiConfiguration<'d, Async, T> {
/// self.set_interrupt_handler(self.twai.async_handler());
/// You will need to use a transceiver to connect to the TWAI bus TwaiConfiguration {
pub fn new_async<RX: PeripheralInput, TX: PeripheralOutput>( twai: self.twai,
peripheral: impl Peripheral<P = impl Instance> + 'd, phantom: PhantomData,
rx_pin: impl Peripheral<P = RX> + 'd, mode: self.mode,
tx_pin: impl Peripheral<P = TX> + 'd, }
baud_rate: BaudRate,
mode: TwaiMode,
) -> Self {
Self::new_async_typed(peripheral.map_into(), rx_pin, tx_pin, baud_rate, mode)
}
/// Create a new instance of [TwaiConfiguration] meant to connect two ESP32s
/// directly
///
/// You don't need a transceiver by following the description in the
/// `twai.rs` example
pub fn new_async_no_transceiver<RX: PeripheralInput, TX: PeripheralOutput>(
peripheral: impl Peripheral<P = impl Instance> + 'd,
rx_pin: impl Peripheral<P = RX> + 'd,
tx_pin: impl Peripheral<P = TX> + 'd,
baud_rate: BaudRate,
mode: TwaiMode,
) -> Self {
Self::new_async_no_transceiver_typed(peripheral.map_into(), rx_pin, tx_pin, baud_rate, mode)
} }
} }
@ -1137,33 +1111,18 @@ impl<'d, T> TwaiConfiguration<'d, Async, T>
where where
T: Instance, T: Instance,
{ {
/// Create a new instance of [TwaiConfiguration] in async mode /// Convert the configuration into a blocking configuration.
/// pub fn into_blocking(self) -> TwaiConfiguration<'d, Blocking, T> {
/// You will need to use a transceiver to connect to the TWAI bus use crate::{interrupt, Cpu};
pub fn new_async_typed<RX: PeripheralInput, TX: PeripheralOutput>(
peripheral: impl Peripheral<P = T> + 'd,
rx_pin: impl Peripheral<P = RX> + 'd,
tx_pin: impl Peripheral<P = TX> + 'd,
baud_rate: BaudRate,
mode: TwaiMode,
) -> Self {
TwaiConfiguration::new_typed(peripheral, rx_pin, tx_pin, baud_rate, mode).into_async()
}
/// Create a new instance of [TwaiConfiguration] meant to connect two ESP32s interrupt::disable(Cpu::current(), self.twai.interrupt());
/// directly in async mode
/// // Re-create in blocking mode
/// You don't need a transceiver by following the description in the TwaiConfiguration {
/// `twai.rs` example twai: self.twai,
pub fn new_async_no_transceiver_typed<RX: PeripheralInput, TX: PeripheralOutput>( phantom: PhantomData,
peripheral: impl Peripheral<P = T> + 'd, mode: self.mode,
rx_pin: impl Peripheral<P = RX> + 'd, }
tx_pin: impl Peripheral<P = TX> + 'd,
baud_rate: BaudRate,
mode: TwaiMode,
) -> Self {
TwaiConfiguration::new_no_transceiver_typed(peripheral, rx_pin, tx_pin, baud_rate, mode)
.into_async()
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -75,14 +75,18 @@
//! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/ //! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/
//! [embedded-io-async]: https://docs.rs/embedded-io-async/latest/embedded_io_async/ //! [embedded-io-async]: https://docs.rs/embedded-io-async/latest/embedded_io_async/
use core::{convert::Infallible, marker::PhantomData}; use core::{convert::Infallible, marker::PhantomData, task::Poll};
use embassy_sync::waitqueue::AtomicWaker;
use procmacros::handler;
use crate::{ use crate::{
interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef},
peripheral::Peripheral,
peripherals::{usb_device::RegisterBlock, Interrupt, USB_DEVICE}, peripherals::{usb_device::RegisterBlock, Interrupt, USB_DEVICE},
system::PeripheralClockControl, system::PeripheralClockControl,
Async,
Blocking, Blocking,
Cpu,
InterruptConfigurable, InterruptConfigurable,
Mode, Mode,
}; };
@ -98,20 +102,24 @@ pub struct UsbSerialJtag<'d, M> {
/// USB Serial/JTAG (Transmit) /// USB Serial/JTAG (Transmit)
pub struct UsbSerialJtagTx<'d, M> { pub struct UsbSerialJtagTx<'d, M> {
phantom: PhantomData<(&'d mut USB_DEVICE, M)>, peripheral: PeripheralRef<'d, USB_DEVICE>,
phantom: PhantomData<M>,
} }
/// USB Serial/JTAG (Receive) /// USB Serial/JTAG (Receive)
pub struct UsbSerialJtagRx<'d, M> { pub struct UsbSerialJtagRx<'d, M> {
phantom: PhantomData<(&'d mut USB_DEVICE, M)>, peripheral: PeripheralRef<'d, USB_DEVICE>,
phantom: PhantomData<M>,
} }
impl<M> UsbSerialJtagTx<'_, M> impl<'d, M> UsbSerialJtagTx<'d, M>
where where
M: Mode, M: Mode,
{ {
fn new_inner() -> Self { fn new_inner(peripheral: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
crate::into_ref!(peripheral);
Self { Self {
peripheral,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -183,12 +191,14 @@ where
} }
} }
impl<M> UsbSerialJtagRx<'_, M> impl<'d, M> UsbSerialJtagRx<'d, M>
where where
M: Mode, M: Mode,
{ {
fn new_inner() -> Self { fn new_inner(peripheral: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
crate::into_ref!(peripheral);
Self { Self {
peripheral,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -263,13 +273,37 @@ impl<'d> UsbSerialJtag<'d, Blocking> {
pub fn new(usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self { pub fn new(usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
Self::new_inner(usb_device) Self::new_inner(usb_device)
} }
/// Reconfigure the USB Serial JTAG peripheral to operate in asynchronous
/// mode.
pub fn into_async(mut self) -> UsbSerialJtag<'d, Async> {
self.set_interrupt_handler(async_interrupt_handler);
UsbSerialJtag {
rx: UsbSerialJtagRx {
peripheral: self.rx.peripheral,
phantom: PhantomData,
},
tx: UsbSerialJtagTx {
peripheral: self.tx.peripheral,
phantom: PhantomData,
},
}
}
} }
impl crate::private::Sealed for UsbSerialJtag<'_, Blocking> {} impl crate::private::Sealed for UsbSerialJtag<'_, Blocking> {}
impl InterruptConfigurable for UsbSerialJtag<'_, Blocking> { impl InterruptConfigurable for UsbSerialJtag<'_, Blocking> {
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
self.inner_set_interrupt_handler(handler); for core in crate::Cpu::other() {
crate::interrupt::disable(core, Interrupt::USB_DEVICE);
}
unsafe { crate::interrupt::bind_interrupt(Interrupt::USB_DEVICE, handler.handler()) };
unwrap!(crate::interrupt::enable(
Interrupt::USB_DEVICE,
handler.priority()
));
} }
} }
@ -277,7 +311,7 @@ impl<'d, M> UsbSerialJtag<'d, M>
where where
M: Mode, M: Mode,
{ {
fn new_inner(_usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self { fn new_inner(usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
// Do NOT reset the peripheral. Doing so will result in a broken USB JTAG // Do NOT reset the peripheral. Doing so will result in a broken USB JTAG
// connection. // connection.
PeripheralClockControl::enable(crate::system::Peripheral::UsbDevice); PeripheralClockControl::enable(crate::system::Peripheral::UsbDevice);
@ -293,29 +327,20 @@ where
// doesn't swap the pullups too, this works around that. // doesn't swap the pullups too, this works around that.
if Efuse::read_bit(USB_EXCHG_PINS) { if Efuse::read_bit(USB_EXCHG_PINS) {
USB_DEVICE::register_block().conf0().modify(|_, w| { USB_DEVICE::register_block().conf0().modify(|_, w| {
w.pad_pull_override() w.pad_pull_override().set_bit();
.set_bit() w.dm_pullup().clear_bit();
.dm_pullup() w.dp_pullup().set_bit()
.clear_bit()
.dp_pullup()
.set_bit()
}); });
} }
} }
crate::into_ref!(usb_device);
Self { Self {
rx: UsbSerialJtagRx::new_inner(), rx: UsbSerialJtagRx::new_inner(unsafe { usb_device.clone_unchecked() }),
tx: UsbSerialJtagTx::new_inner(), tx: UsbSerialJtagTx::new_inner(usb_device),
} }
} }
fn inner_set_interrupt_handler(&mut self, handler: InterruptHandler) {
unsafe {
crate::interrupt::bind_interrupt(Interrupt::USB_DEVICE, handler.handler());
crate::interrupt::enable(Interrupt::USB_DEVICE, handler.priority()).unwrap();
}
}
/// Split the USB Serial JTAG peripheral into a transmitter and receiver, /// Split the USB Serial JTAG peripheral into a transmitter and receiver,
/// which is particularly useful when having two tasks correlating to /// which is particularly useful when having two tasks correlating to
/// transmitting and receiving. /// transmitting and receiving.
@ -652,224 +677,221 @@ where
} }
} }
mod asynch { // Static instance of the waker for each component of the peripheral:
use core::{marker::PhantomData, task::Poll}; static WAKER_TX: AtomicWaker = AtomicWaker::new();
static WAKER_RX: AtomicWaker = AtomicWaker::new();
use embassy_sync::waitqueue::AtomicWaker; #[must_use = "futures do nothing unless you `.await` or poll them"]
use procmacros::handler; struct UsbSerialJtagWriteFuture<'d> {
_peripheral: PeripheralRef<'d, USB_DEVICE>,
}
use super::{Error, Instance, UsbSerialJtag, UsbSerialJtagRx, UsbSerialJtagTx}; impl<'d> UsbSerialJtagWriteFuture<'d> {
use crate::{peripheral::Peripheral, peripherals::USB_DEVICE, Async}; fn new(_peripheral: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
crate::into_ref!(_peripheral);
// Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT
// interrupt
USB_DEVICE::register_block()
.int_ena()
.modify(|_, w| w.serial_in_empty().set_bit());
// Static instance of the waker for each component of the peripheral: Self { _peripheral }
static WAKER_TX: AtomicWaker = AtomicWaker::new();
static WAKER_RX: AtomicWaker = AtomicWaker::new();
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub(crate) struct UsbSerialJtagWriteFuture<'d> {
phantom: PhantomData<&'d mut USB_DEVICE>,
} }
impl UsbSerialJtagWriteFuture<'_> { fn event_bit_is_clear(&self) -> bool {
pub fn new() -> Self { USB_DEVICE::register_block()
// Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT .int_ena()
// interrupt .read()
USB_DEVICE::register_block() .serial_in_empty()
.int_ena() .bit_is_clear()
.modify(|_, w| w.serial_in_empty().set_bit());
Self {
phantom: PhantomData,
}
}
fn event_bit_is_clear(&self) -> bool {
USB_DEVICE::register_block()
.int_ena()
.read()
.serial_in_empty()
.bit_is_clear()
}
} }
}
impl core::future::Future for UsbSerialJtagWriteFuture<'_> { impl core::future::Future for UsbSerialJtagWriteFuture<'_> {
type Output = (); type Output = ();
fn poll( fn poll(
self: core::pin::Pin<&mut Self>, self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>, cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> { ) -> core::task::Poll<Self::Output> {
WAKER_TX.register(cx.waker()); WAKER_TX.register(cx.waker());
if self.event_bit_is_clear() { if self.event_bit_is_clear() {
Poll::Ready(()) Poll::Ready(())
} else { } else {
Poll::Pending Poll::Pending
}
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub(crate) struct UsbSerialJtagReadFuture<'d> {
phantom: PhantomData<&'d mut USB_DEVICE>,
}
impl UsbSerialJtagReadFuture<'_> {
pub fn new() -> Self {
// Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT
// interrupt
USB_DEVICE::register_block()
.int_ena()
.modify(|_, w| w.serial_out_recv_pkt().set_bit());
Self {
phantom: PhantomData,
}
}
fn event_bit_is_clear(&self) -> bool {
USB_DEVICE::register_block()
.int_ena()
.read()
.serial_out_recv_pkt()
.bit_is_clear()
}
}
impl core::future::Future for UsbSerialJtagReadFuture<'_> {
type Output = ();
fn poll(
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
WAKER_RX.register(cx.waker());
if self.event_bit_is_clear() {
Poll::Ready(())
} else {
Poll::Pending
}
}
}
impl<'d> UsbSerialJtag<'d, Async> {
/// Create a new USB serial/JTAG instance in asynchronous mode
pub fn new_async(usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
let mut this = Self::new_inner(usb_device);
this.inner_set_interrupt_handler(async_interrupt_handler);
this
}
}
impl UsbSerialJtagTx<'_, Async> {
async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> {
let reg_block = USB_DEVICE::register_block();
for chunk in words.chunks(64) {
for byte in chunk {
reg_block
.ep1()
.write(|w| unsafe { w.rdwr_byte().bits(*byte) });
}
reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit());
UsbSerialJtagWriteFuture::new().await;
}
Ok(())
}
async fn flush_tx_async(&mut self) -> Result<(), Error> {
if USB_DEVICE::register_block()
.jfifo_st()
.read()
.out_fifo_empty()
.bit_is_clear()
{
UsbSerialJtagWriteFuture::new().await;
}
Ok(())
}
}
impl UsbSerialJtagRx<'_, Async> {
async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
if buf.is_empty() {
return Ok(0);
}
loop {
let read_bytes = self.drain_rx_fifo(buf);
if read_bytes > 0 {
return Ok(read_bytes);
}
UsbSerialJtagReadFuture::new().await;
}
}
}
impl embedded_io_async::Write for UsbSerialJtag<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
embedded_io_async::Write::write(&mut self.tx, buf).await
}
async fn flush(&mut self) -> Result<(), Self::Error> {
embedded_io_async::Write::flush(&mut self.tx).await
}
}
impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_bytes_async(buf).await?;
Ok(buf.len())
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush_tx_async().await
}
}
impl embedded_io_async::Read for UsbSerialJtag<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
embedded_io_async::Read::read(&mut self.rx, buf).await
}
}
impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_bytes_async(buf).await
}
}
#[handler]
fn async_interrupt_handler() {
let usb = USB_DEVICE::register_block();
let interrupts = usb.int_st().read();
let tx = interrupts.serial_in_empty().bit_is_set();
let rx = interrupts.serial_out_recv_pkt().bit_is_set();
if tx {
usb.int_ena().modify(|_, w| w.serial_in_empty().clear_bit());
}
if rx {
usb.int_ena()
.modify(|_, w| w.serial_out_recv_pkt().clear_bit());
}
usb.int_clr().write(|w| {
w.serial_in_empty()
.clear_bit_by_one()
.serial_out_recv_pkt()
.clear_bit_by_one()
});
if rx {
WAKER_RX.wake();
}
if tx {
WAKER_TX.wake();
} }
} }
} }
#[must_use = "futures do nothing unless you `.await` or poll them"]
struct UsbSerialJtagReadFuture<'d> {
_peripheral: PeripheralRef<'d, USB_DEVICE>,
}
impl<'d> UsbSerialJtagReadFuture<'d> {
fn new(_peripheral: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
crate::into_ref!(_peripheral);
// Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT
// interrupt
USB_DEVICE::register_block()
.int_ena()
.modify(|_, w| w.serial_out_recv_pkt().set_bit());
Self { _peripheral }
}
fn event_bit_is_clear(&self) -> bool {
USB_DEVICE::register_block()
.int_ena()
.read()
.serial_out_recv_pkt()
.bit_is_clear()
}
}
impl core::future::Future for UsbSerialJtagReadFuture<'_> {
type Output = ();
fn poll(
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
WAKER_RX.register(cx.waker());
if self.event_bit_is_clear() {
Poll::Ready(())
} else {
Poll::Pending
}
}
}
impl<'d> UsbSerialJtag<'d, Async> {
/// Reconfigure the USB Serial JTAG peripheral to operate in blocking
/// mode.
pub fn into_blocking(self) -> UsbSerialJtag<'d, Blocking> {
crate::interrupt::disable(Cpu::current(), Interrupt::USB_DEVICE);
UsbSerialJtag {
rx: UsbSerialJtagRx {
peripheral: self.rx.peripheral,
phantom: PhantomData,
},
tx: UsbSerialJtagTx {
peripheral: self.tx.peripheral,
phantom: PhantomData,
},
}
}
}
impl UsbSerialJtagTx<'_, Async> {
async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> {
let reg_block = USB_DEVICE::register_block();
for chunk in words.chunks(64) {
for byte in chunk {
reg_block
.ep1()
.write(|w| unsafe { w.rdwr_byte().bits(*byte) });
}
reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit());
UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await;
}
Ok(())
}
async fn flush_tx_async(&mut self) -> Result<(), Error> {
if USB_DEVICE::register_block()
.jfifo_st()
.read()
.out_fifo_empty()
.bit_is_clear()
{
UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await;
}
Ok(())
}
}
impl UsbSerialJtagRx<'_, Async> {
async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
if buf.is_empty() {
return Ok(0);
}
loop {
let read_bytes = self.drain_rx_fifo(buf);
if read_bytes > 0 {
return Ok(read_bytes);
}
UsbSerialJtagReadFuture::new(self.peripheral.reborrow()).await;
}
}
}
impl embedded_io_async::Write for UsbSerialJtag<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
embedded_io_async::Write::write(&mut self.tx, buf).await
}
async fn flush(&mut self) -> Result<(), Self::Error> {
embedded_io_async::Write::flush(&mut self.tx).await
}
}
impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_bytes_async(buf).await?;
Ok(buf.len())
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush_tx_async().await
}
}
impl embedded_io_async::Read for UsbSerialJtag<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
embedded_io_async::Read::read(&mut self.rx, buf).await
}
}
impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_bytes_async(buf).await
}
}
#[handler]
fn async_interrupt_handler() {
let usb = USB_DEVICE::register_block();
let interrupts = usb.int_st().read();
let tx = interrupts.serial_in_empty().bit_is_set();
let rx = interrupts.serial_out_recv_pkt().bit_is_set();
if tx {
usb.int_ena().modify(|_, w| w.serial_in_empty().clear_bit());
}
if rx {
usb.int_ena()
.modify(|_, w| w.serial_out_recv_pkt().clear_bit());
}
usb.int_clr().write(|w| {
w.serial_in_empty()
.clear_bit_by_one()
.serial_out_recv_pkt()
.clear_bit_by_one()
});
if rx {
WAKER_RX.wake();
}
if tx {
WAKER_TX.wake();
}
}

View File

@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) {
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let i2c0 = I2c::new_async(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz()); let i2c0 = I2c::new(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz()).into_async();
let mut lis3dh = Lis3dh::new_i2c(i2c0, SlaveAddr::Alternate).await.unwrap(); let mut lis3dh = Lis3dh::new_i2c(i2c0, SlaveAddr::Alternate).await.unwrap();
lis3dh.set_range(Range::G8).await.unwrap(); lis3dh.set_range(Range::G8).await.unwrap();

View File

@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) {
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let mut i2c = I2c::new_async(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz()); let mut i2c = I2c::new(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz()).into_async();
loop { loop {
let mut data = [0u8; 22]; let mut data = [0u8; 22];

View File

@ -60,7 +60,9 @@ async fn main(_spawner: Spawner) {
let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE); let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE);
let mut parallel = I2sParallel::new( let mut parallel = I2sParallel::new(
i2s, i2s,
dma_channel.configure_for_async(false, DmaPriority::Priority0), dma_channel
.configure(false, DmaPriority::Priority0)
.into_async(),
1.MHz(), 1.MHz(),
pins, pins,
clock, clock,

View File

@ -52,10 +52,11 @@ async fn main(_spawner: Spawner) {
Standard::Philips, Standard::Philips,
DataFormat::Data16Channel16, DataFormat::Data16Channel16,
44100u32.Hz(), 44100u32.Hz(),
dma_channel.configure_for_async(false, DmaPriority::Priority0), dma_channel.configure(false, DmaPriority::Priority0),
rx_descriptors, rx_descriptors,
tx_descriptors, tx_descriptors,
); )
.into_async();
#[cfg(not(feature = "esp32"))] #[cfg(not(feature = "esp32"))]
let i2s = i2s.with_mclk(io.pins.gpio0); let i2s = i2s.with_mclk(io.pins.gpio0);

View File

@ -74,10 +74,11 @@ async fn main(_spawner: Spawner) {
Standard::Philips, Standard::Philips,
DataFormat::Data16Channel16, DataFormat::Data16Channel16,
44100u32.Hz(), 44100u32.Hz(),
dma_channel.configure_for_async(false, DmaPriority::Priority0), dma_channel.configure(false, DmaPriority::Priority0),
rx_descriptors, rx_descriptors,
tx_descriptors, tx_descriptors,
); )
.into_async();
let i2s_tx = i2s let i2s_tx = i2s
.i2s_tx .i2s_tx

View File

@ -42,7 +42,9 @@ async fn main(_spawner: Spawner) {
let parl_io = ParlIoRxOnly::new( let parl_io = ParlIoRxOnly::new(
peripherals.PARL_IO, peripherals.PARL_IO,
dma_channel.configure_for_async(false, DmaPriority::Priority0), dma_channel
.configure(false, DmaPriority::Priority0)
.into_async(),
rx_descriptors, rx_descriptors,
1.MHz(), 1.MHz(),
) )

View File

@ -55,7 +55,9 @@ async fn main(_spawner: Spawner) {
let parl_io = ParlIoTxOnly::new( let parl_io = ParlIoTxOnly::new(
peripherals.PARL_IO, peripherals.PARL_IO,
dma_channel.configure_for_async(false, DmaPriority::Priority0), dma_channel
.configure(false, DmaPriority::Priority0)
.into_async(),
tx_descriptors, tx_descriptors,
1.MHz(), 1.MHz(),
) )

View File

@ -15,7 +15,7 @@ use esp_backtrace as _;
use esp_hal::{ use esp_hal::{
gpio::{Io, Level, Output}, gpio::{Io, Level, Output},
prelude::*, prelude::*,
rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreatorAsync}, rmt::{PulseCode, Rmt, RxChannelAsync, RxChannelConfig, RxChannelCreatorAsync},
timer::timg::TimerGroup, timer::timg::TimerGroup,
}; };
use esp_println::{print, println}; use esp_println::{print, println};
@ -54,7 +54,7 @@ async fn main(spawner: Spawner) {
} }
}; };
let rmt = Rmt::new_async(peripherals.RMT, freq).unwrap(); let rmt = Rmt::new(peripherals.RMT, freq).unwrap().into_async();
let rx_config = RxChannelConfig { let rx_config = RxChannelConfig {
clk_divider: 255, clk_divider: 255,
idle_threshold: 10000, idle_threshold: 10000,

View File

@ -17,7 +17,7 @@ use esp_backtrace as _;
use esp_hal::{ use esp_hal::{
gpio::Io, gpio::Io,
prelude::*, prelude::*,
rmt::{asynch::TxChannelAsync, PulseCode, Rmt, TxChannelConfig, TxChannelCreatorAsync}, rmt::{PulseCode, Rmt, TxChannelAsync, TxChannelConfig, TxChannelCreatorAsync},
timer::timg::TimerGroup, timer::timg::TimerGroup,
}; };
use esp_println::println; use esp_println::println;
@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) {
} }
}; };
let rmt = Rmt::new_async(peripherals.RMT, freq).unwrap(); let rmt = Rmt::new(peripherals.RMT, freq).unwrap().into_async();
let mut channel = rmt let mut channel = rmt
.channel0 .channel0

View File

@ -97,7 +97,9 @@ async fn main(spawner: Spawner) {
let config = Config::default().rx_fifo_full_threshold(READ_BUF_SIZE as u16); let config = Config::default().rx_fifo_full_threshold(READ_BUF_SIZE as u16);
let mut uart0 = Uart::new_async_with_config(peripherals.UART0, config, rx_pin, tx_pin).unwrap(); let mut uart0 = Uart::new_with_config(peripherals.UART0, config, rx_pin, tx_pin)
.unwrap()
.into_async();
uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None)); uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None));
let (rx, tx) = uart0.split(); let (rx, tx) = uart0.split();

View File

@ -63,8 +63,9 @@ async fn main(_spawner: Spawner) {
.with_mosi(mosi) .with_mosi(mosi)
.with_miso(miso) .with_miso(miso)
.with_cs(cs) .with_cs(cs)
.with_dma(dma_channel.configure_for_async(false, DmaPriority::Priority0)) .with_dma(dma_channel.configure(false, DmaPriority::Priority0))
.with_buffers(dma_rx_buf, dma_tx_buf); .with_buffers(dma_rx_buf, dma_tx_buf)
.into_async();
let send_buffer = [0, 1, 2, 3, 4, 5, 6, 7]; let send_buffer = [0, 1, 2, 3, 4, 5, 6, 7];
loop { loop {

View File

@ -103,17 +103,18 @@ async fn main(spawner: Spawner) {
// The speed of the bus. // The speed of the bus.
const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K; const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K;
// !!! Use `new_async` when using a transceiver. `new_async_no_transceiver` sets TX to open-drain // !!! Use `new` when using a transceiver. `new_no_transceiver` sets TX to open-drain
// Begin configuring the TWAI peripheral. The peripheral is in a reset like // Begin configuring the TWAI peripheral. The peripheral is in a reset like
// state that prevents transmission but allows configuration. // state that prevents transmission but allows configuration.
let mut twai_config = twai::TwaiConfiguration::new_async_no_transceiver( let mut twai_config = twai::TwaiConfiguration::new_no_transceiver(
peripherals.TWAI0, peripherals.TWAI0,
rx_pin, rx_pin,
tx_pin, tx_pin,
TWAI_BAUDRATE, TWAI_BAUDRATE,
TwaiMode::Normal, TwaiMode::Normal,
); )
.into_async();
// Partially filter the incoming messages to reduce overhead of receiving // Partially filter the incoming messages to reduce overhead of receiving
// undesired messages. Note that due to how the hardware filters messages, // undesired messages. Note that due to how the hardware filters messages,

View File

@ -68,7 +68,9 @@ async fn main(spawner: Spawner) {
let timg0 = TimerGroup::new(peripherals.TIMG0); let timg0 = TimerGroup::new(peripherals.TIMG0);
esp_hal_embassy::init(timg0.timer0); esp_hal_embassy::init(timg0.timer0);
let (rx, tx) = UsbSerialJtag::new_async(peripherals.USB_DEVICE).split(); let (rx, tx) = UsbSerialJtag::new(peripherals.USB_DEVICE)
.into_async()
.split();
static SIGNAL: StaticCell<Signal<NoopRawMutex, heapless::String<MAX_BUFFER_SIZE>>> = static SIGNAL: StaticCell<Signal<NoopRawMutex, heapless::String<MAX_BUFFER_SIZE>>> =
StaticCell::new(); StaticCell::new();

View File

@ -81,11 +81,13 @@ mod test {
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0)
.with_dma(dma_channel1.configure_for_async(false, DmaPriority::Priority0)) .with_dma(dma_channel1.configure(false, DmaPriority::Priority0))
.with_buffers(dma_rx_buf, dma_tx_buf); .with_buffers(dma_rx_buf, dma_tx_buf)
.into_async();
let spi2 = Spi::new(peripherals.SPI3, 100.kHz(), SpiMode::Mode0) let spi2 = Spi::new(peripherals.SPI3, 100.kHz(), SpiMode::Mode0)
.with_dma(dma_channel2.configure_for_async(false, DmaPriority::Priority0)); .with_dma(dma_channel2.configure(false, DmaPriority::Priority0))
.into_async();
let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
@ -144,9 +146,10 @@ mod test {
.with_dma( .with_dma(
peripherals peripherals
.dma_channel .dma_channel
.configure_for_async(false, DmaPriority::Priority0), .configure(false, DmaPriority::Priority0),
) )
.with_buffers(dma_rx_buf, dma_tx_buf); .with_buffers(dma_rx_buf, dma_tx_buf)
.into_async();
let send_buffer = mk_static!([u8; BUFFER_SIZE], [0u8; BUFFER_SIZE]); let send_buffer = mk_static!([u8; BUFFER_SIZE], [0u8; BUFFER_SIZE]);
loop { loop {

View File

@ -143,11 +143,11 @@ mod tests {
Standard::Philips, Standard::Philips,
DataFormat::Data16Channel16, DataFormat::Data16Channel16,
16000.Hz(), 16000.Hz(),
ctx.dma_channel ctx.dma_channel.configure(false, DmaPriority::Priority0),
.configure_for_async(false, DmaPriority::Priority0),
rx_descriptors, rx_descriptors,
tx_descriptors, tx_descriptors,
); )
.into_async();
let (_, dout) = hil_test::common_test_pins!(ctx.io); let (_, dout) = hil_test::common_test_pins!(ctx.io);

View File

@ -19,13 +19,14 @@ use esp_hal::{
Pcnt, Pcnt,
}, },
prelude::*, prelude::*,
Blocking,
}; };
use hil_test as _; use hil_test as _;
const DATA_SIZE: usize = 1024 * 10; const DATA_SIZE: usize = 1024 * 10;
struct Context<'d> { struct Context<'d> {
lcd_cam: LcdCam<'d, esp_hal::Blocking>, lcd_cam: LcdCam<'d, Blocking>,
pcnt: Pcnt<'d>, pcnt: Pcnt<'d>,
io: Io, io: Io,
dma: Dma<'d>, dma: Dma<'d>,
@ -79,7 +80,8 @@ mod tests {
let channel = ctx let channel = ctx
.dma .dma
.channel0 .channel0
.configure_for_async(false, DmaPriority::Priority0); .configure(false, DmaPriority::Priority0)
.into_async();
let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin); let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin);
let i8080 = I8080::new( let i8080 = I8080::new(

View File

@ -15,13 +15,14 @@ use esp_hal::{
LcdCam, LcdCam,
}, },
prelude::*, prelude::*,
Async,
}; };
use hil_test as _; use hil_test as _;
const DATA_SIZE: usize = 1024 * 10; const DATA_SIZE: usize = 1024 * 10;
struct Context<'d> { struct Context<'d> {
lcd_cam: LcdCam<'d, esp_hal::Async>, lcd_cam: LcdCam<'d, Async>,
dma: Dma<'d>, dma: Dma<'d>,
dma_buf: DmaTxBuf, dma_buf: DmaTxBuf,
} }
@ -36,7 +37,7 @@ mod tests {
let peripherals = esp_hal::init(esp_hal::Config::default()); let peripherals = esp_hal::init(esp_hal::Config::default());
let dma = Dma::new(peripherals.DMA); let dma = Dma::new(peripherals.DMA);
let lcd_cam = LcdCam::new_async(peripherals.LCD_CAM); let lcd_cam = LcdCam::new(peripherals.LCD_CAM).into_async();
let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, DATA_SIZE); let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, DATA_SIZE);
let dma_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let dma_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
@ -75,7 +76,8 @@ mod tests {
let channel = ctx let channel = ctx
.dma .dma
.channel0 .channel0
.configure_for_async(false, DmaPriority::Priority0); .configure(false, DmaPriority::Priority0)
.into_async();
let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin); let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin);
let i8080 = I8080::new( let i8080 = I8080::new(

View File

@ -92,7 +92,8 @@ mod tests {
let pio = ParlIoTxOnly::new( let pio = ParlIoTxOnly::new(
ctx.parl_io, ctx.parl_io,
ctx.dma_channel ctx.dma_channel
.configure_for_async(false, DmaPriority::Priority0), .configure(false, DmaPriority::Priority0)
.into_async(),
tx_descriptors, tx_descriptors,
10.MHz(), 10.MHz(),
) )
@ -159,7 +160,8 @@ mod tests {
let pio = ParlIoTxOnly::new( let pio = ParlIoTxOnly::new(
ctx.parl_io, ctx.parl_io,
ctx.dma_channel ctx.dma_channel
.configure_for_async(false, DmaPriority::Priority0), .configure(false, DmaPriority::Priority0)
.into_async(),
tx_descriptors, tx_descriptors,
10.MHz(), 10.MHz(),
) )

View File

@ -56,7 +56,7 @@ mod tests {
#[init] #[init]
fn init() -> Context<'static> { fn init() -> Context<'static> {
let peripherals = esp_hal::init(esp_hal::Config::default()); let peripherals = esp_hal::init(esp_hal::Config::default());
let mut rsa = Rsa::new_async(peripherals.RSA); let mut rsa = Rsa::new(peripherals.RSA).into_async();
nb::block!(rsa.ready()).unwrap(); nb::block!(rsa.ready()).unwrap();
Context { rsa } Context { rsa }

View File

@ -18,6 +18,7 @@ use esp_hal::{
peripheral::Peripheral, peripheral::Peripheral,
prelude::*, prelude::*,
spi::{master::Spi, SpiMode}, spi::{master::Spi, SpiMode},
Blocking,
}; };
#[cfg(pcnt)] #[cfg(pcnt)]
use esp_hal::{ use esp_hal::{
@ -35,7 +36,7 @@ cfg_if::cfg_if! {
} }
struct Context { struct Context {
spi: Spi<'static>, spi: Spi<'static, Blocking>,
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],
@ -392,11 +393,9 @@ mod tests {
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
let mut spi = ctx let mut spi = ctx
.spi .spi
.with_dma( .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0))
ctx.dma_channel .with_buffers(dma_rx_buf, dma_tx_buf)
.configure_for_async(false, DmaPriority::Priority0), .into_async();
)
.with_buffers(dma_rx_buf, dma_tx_buf);
ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source); ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source);
ctx.pcnt_unit ctx.pcnt_unit
@ -428,11 +427,9 @@ mod tests {
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
let mut spi = ctx let mut spi = ctx
.spi .spi
.with_dma( .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0))
ctx.dma_channel .with_buffers(dma_rx_buf, dma_tx_buf)
.configure_for_async(false, DmaPriority::Priority0), .into_async();
)
.with_buffers(dma_rx_buf, dma_tx_buf);
ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source); ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source);
ctx.pcnt_unit ctx.pcnt_unit
@ -557,10 +554,10 @@ mod tests {
let dma_rx_buf = DmaRxBuf::new(ctx.rx_descriptors, ctx.rx_buffer).unwrap(); let dma_rx_buf = DmaRxBuf::new(ctx.rx_descriptors, ctx.rx_buffer).unwrap();
let dma_tx_buf = DmaTxBuf::new(ctx.tx_descriptors, ctx.tx_buffer).unwrap(); let dma_tx_buf = DmaTxBuf::new(ctx.tx_descriptors, ctx.tx_buffer).unwrap();
let spi = ctx.spi.with_dma( let spi = ctx
ctx.dma_channel .spi
.configure_for_async(false, DmaPriority::Priority0), .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0))
); .into_async();
let mut transfer = spi let mut transfer = spi
.transfer(dma_rx_buf, dma_tx_buf) .transfer(dma_rx_buf, dma_tx_buf)

View File

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

View File

@ -26,7 +26,7 @@ mod tests {
let (rx, tx) = hil_test::common_test_pins!(io); let (rx, tx) = hil_test::common_test_pins!(io);
let uart = Uart::new_async(peripherals.UART0, rx, tx).unwrap(); let uart = Uart::new(peripherals.UART0, rx, tx).unwrap().into_async();
Context { uart } Context { uart }
} }

View File

@ -31,8 +31,8 @@ mod tests {
let (rx, tx) = hil_test::common_test_pins!(io); let (rx, tx) = hil_test::common_test_pins!(io);
let tx = UartTx::new_async(peripherals.UART0, tx).unwrap(); let tx = UartTx::new(peripherals.UART0, tx).unwrap().into_async();
let rx = UartRx::new_async(peripherals.UART1, rx).unwrap(); let rx = UartRx::new(peripherals.UART1, rx).unwrap().into_async();
Context { rx, tx } Context { rx, tx }
} }

View File

@ -18,6 +18,8 @@ mod tests {
let timg0 = TimerGroup::new(peripherals.TIMG0); let timg0 = TimerGroup::new(peripherals.TIMG0);
esp_hal_embassy::init(timg0.timer0); esp_hal_embassy::init(timg0.timer0);
_ = UsbSerialJtag::new_async(peripherals.USB_DEVICE).split(); _ = UsbSerialJtag::new(peripherals.USB_DEVICE)
.into_async()
.split();
} }
} }