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()));
} }
} }

View File

@ -53,8 +53,16 @@
//! [`embedded-hal`]: https://crates.io/crates/embedded-hal //! [`embedded-hal`]: https://crates.io/crates/embedded-hal
use core::marker::PhantomData; use core::marker::PhantomData;
#[cfg(not(esp32))]
use core::{
pin::Pin,
task::{Context, Poll},
};
use embassy_sync::waitqueue::AtomicWaker;
use embedded_hal::i2c::Operation as EhalOperation;
use fugit::HertzU32; use fugit::HertzU32;
use procmacros::handler;
use crate::{ use crate::{
clock::Clocks, clock::Clocks,
@ -66,6 +74,7 @@ use crate::{
system::PeripheralClockControl, system::PeripheralClockControl,
Async, Async,
Blocking, Blocking,
Cpu,
InterruptConfigurable, InterruptConfigurable,
Mode, Mode,
}; };
@ -240,11 +249,123 @@ pub struct I2c<'d, DM: Mode, T = AnyI2c> {
timeout: Option<u32>, timeout: Option<u32>,
} }
impl<DM, T> I2c<'_, DM, T> impl<T> embedded_hal_02::blocking::i2c::Read for I2c<'_, Blocking, T>
where where
T: Instance, T: Instance,
DM: Mode,
{ {
type Error = Error;
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.read(address, buffer)
}
}
impl<T> embedded_hal_02::blocking::i2c::Write for I2c<'_, Blocking, T>
where
T: Instance,
{
type Error = Error;
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
self.write(addr, bytes)
}
}
impl<T> embedded_hal_02::blocking::i2c::WriteRead for I2c<'_, Blocking, T>
where
T: Instance,
{
type Error = Error;
fn write_read(
&mut self,
address: u8,
bytes: &[u8],
buffer: &mut [u8],
) -> Result<(), Self::Error> {
self.write_read(address, bytes, buffer)
}
}
impl<T, DM: Mode> embedded_hal::i2c::ErrorType for I2c<'_, DM, T> {
type Error = Error;
}
impl<T, DM: Mode> embedded_hal::i2c::I2c for I2c<'_, DM, T>
where
T: Instance,
{
fn transaction(
&mut self,
address: u8,
operations: &mut [embedded_hal::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
self.transaction_impl(address, operations.iter_mut().map(Operation::from))
}
}
impl<'d, T, DM: Mode> I2c<'d, DM, T>
where
T: Instance,
{
fn new_internal<SDA: PeripheralOutput, SCL: PeripheralOutput>(
i2c: impl Peripheral<P = T> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
) -> Self {
crate::into_ref!(i2c);
crate::into_mapped_ref!(sda, scl);
let i2c = I2c {
i2c,
phantom: PhantomData,
frequency,
timeout: None,
};
PeripheralClockControl::reset(i2c.i2c.peripheral());
PeripheralClockControl::enable(i2c.i2c.peripheral());
// TODO: implement with_pins et. al.
// avoid SCL/SDA going low during configuration
scl.set_output_high(true, crate::private::Internal);
sda.set_output_high(true, crate::private::Internal);
scl.set_to_open_drain_output(crate::private::Internal);
scl.enable_input(true, crate::private::Internal);
scl.pull_direction(Pull::Up, crate::private::Internal);
scl.connect_input_to_peripheral(i2c.i2c.scl_input_signal(), crate::private::Internal);
scl.connect_peripheral_to_output(i2c.i2c.scl_output_signal(), crate::private::Internal);
sda.set_to_open_drain_output(crate::private::Internal);
sda.enable_input(true, crate::private::Internal);
sda.pull_direction(Pull::Up, crate::private::Internal);
sda.connect_input_to_peripheral(i2c.i2c.sda_input_signal(), crate::private::Internal);
sda.connect_peripheral_to_output(i2c.i2c.sda_output_signal(), crate::private::Internal);
i2c.i2c.setup(frequency, None);
i2c
}
fn internal_recover(&self) {
PeripheralClockControl::reset(self.i2c.peripheral());
PeripheralClockControl::enable(self.i2c.peripheral());
self.i2c.setup(self.frequency, self.timeout);
}
/// Set the I2C timeout.
// TODO: explain this function better - what's the unit, what happens on
// timeout, and just what exactly is a timeout in this context?
pub fn with_timeout(mut self, timeout: Option<u32>) -> Self {
self.timeout = timeout;
self.i2c.setup(self.frequency, self.timeout);
self
}
fn transaction_impl<'a>( fn transaction_impl<'a>(
&mut self, &mut self,
address: u8, address: u8,
@ -303,10 +424,50 @@ where
} }
} }
impl<T> I2c<'_, Blocking, T> impl<'d> I2c<'d, Blocking> {
/// Create a new I2C instance
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new<SDA: PeripheralOutput, SCL: PeripheralOutput>(
i2c: impl Peripheral<P = impl Instance> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
) -> Self {
Self::new_typed(i2c.map_into(), sda, scl, frequency)
}
}
impl<'d, T> I2c<'d, Blocking, T>
where where
T: Instance, T: Instance,
{ {
/// Create a new I2C instance
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new_typed<SDA: PeripheralOutput, SCL: PeripheralOutput>(
i2c: impl Peripheral<P = T> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
) -> Self {
Self::new_internal(i2c, sda, scl, frequency)
}
// TODO: missing interrupt APIs
/// Configures the I2C peripheral to operate in asynchronous mode.
pub fn into_async(mut self) -> I2c<'d, Async, T> {
self.set_interrupt_handler(self.i2c.async_handler());
I2c {
i2c: self.i2c,
phantom: PhantomData,
frequency: self.frequency,
timeout: self.timeout,
}
}
/// Reads enough bytes from slave with `address` to fill `buffer` /// Reads enough bytes from slave with `address` to fill `buffer`
pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE);
@ -430,163 +591,6 @@ where
} }
} }
impl<T> embedded_hal_02::blocking::i2c::Read for I2c<'_, Blocking, T>
where
T: Instance,
{
type Error = Error;
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.read(address, buffer)
}
}
impl<T> embedded_hal_02::blocking::i2c::Write for I2c<'_, Blocking, T>
where
T: Instance,
{
type Error = Error;
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
self.write(addr, bytes)
}
}
impl<T> embedded_hal_02::blocking::i2c::WriteRead for I2c<'_, Blocking, T>
where
T: Instance,
{
type Error = Error;
fn write_read(
&mut self,
address: u8,
bytes: &[u8],
buffer: &mut [u8],
) -> Result<(), Self::Error> {
self.write_read(address, bytes, buffer)
}
}
impl<T, DM: Mode> embedded_hal::i2c::ErrorType for I2c<'_, DM, T> {
type Error = Error;
}
impl<T, DM: Mode> embedded_hal::i2c::I2c for I2c<'_, DM, T>
where
T: Instance,
{
fn transaction(
&mut self,
address: u8,
operations: &mut [embedded_hal::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
self.transaction_impl(address, operations.iter_mut().map(Operation::from))
}
}
impl<'d, T, DM: Mode> I2c<'d, DM, T>
where
T: Instance,
{
fn new_internal<SDA: PeripheralOutput, SCL: PeripheralOutput>(
i2c: impl Peripheral<P = T> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
) -> Self {
crate::into_ref!(i2c);
crate::into_mapped_ref!(sda, scl);
let i2c = I2c {
i2c,
phantom: PhantomData,
frequency,
timeout: None,
};
PeripheralClockControl::reset(i2c.i2c.peripheral());
PeripheralClockControl::enable(i2c.i2c.peripheral());
// TODO: implement with_pins et. al.
// avoid SCL/SDA going low during configuration
scl.set_output_high(true, crate::private::Internal);
sda.set_output_high(true, crate::private::Internal);
scl.set_to_open_drain_output(crate::private::Internal);
scl.enable_input(true, crate::private::Internal);
scl.pull_direction(Pull::Up, crate::private::Internal);
scl.connect_input_to_peripheral(i2c.i2c.scl_input_signal(), crate::private::Internal);
scl.connect_peripheral_to_output(i2c.i2c.scl_output_signal(), crate::private::Internal);
sda.set_to_open_drain_output(crate::private::Internal);
sda.enable_input(true, crate::private::Internal);
sda.pull_direction(Pull::Up, crate::private::Internal);
sda.connect_input_to_peripheral(i2c.i2c.sda_input_signal(), crate::private::Internal);
sda.connect_peripheral_to_output(i2c.i2c.sda_output_signal(), crate::private::Internal);
i2c.i2c.setup(frequency, None);
i2c
}
fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) {
unsafe { crate::interrupt::bind_interrupt(self.i2c.interrupt(), handler.handler()) };
unwrap!(crate::interrupt::enable(
self.i2c.interrupt(),
handler.priority()
));
}
fn internal_recover(&self) {
PeripheralClockControl::reset(self.i2c.peripheral());
PeripheralClockControl::enable(self.i2c.peripheral());
self.i2c.setup(self.frequency, self.timeout);
}
/// Set the I2C timeout.
// TODO: explain this function better - what's the unit, what happens on
// timeout, and just what exactly is a timeout in this context?
pub fn with_timeout(mut self, timeout: Option<u32>) -> Self {
self.timeout = timeout;
self.i2c.setup(self.frequency, self.timeout);
self
}
}
impl<'d> I2c<'d, Blocking> {
/// Create a new I2C instance
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new<SDA: PeripheralOutput, SCL: PeripheralOutput>(
i2c: impl Peripheral<P = impl Instance> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
) -> Self {
Self::new_typed(i2c.map_into(), sda, scl, frequency)
}
}
impl<'d, T> I2c<'d, Blocking, T>
where
T: Instance,
{
/// Create a new I2C instance
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new_typed<SDA: PeripheralOutput, SCL: PeripheralOutput>(
i2c: impl Peripheral<P = T> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
) -> Self {
Self::new_internal(i2c, sda, scl, frequency)
}
}
impl<T> crate::private::Sealed for I2c<'_, Blocking, T> where T: Instance {} impl<T> crate::private::Sealed for I2c<'_, Blocking, T> where T: Instance {}
impl<T> InterruptConfigurable for I2c<'_, Blocking, T> impl<T> InterruptConfigurable for I2c<'_, Blocking, T>
@ -594,84 +598,43 @@ where
T: Instance, T: Instance,
{ {
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
self.internal_set_interrupt_handler(handler); for core in Cpu::other() {
crate::interrupt::disable(core, self.i2c.interrupt());
}
unsafe { crate::interrupt::bind_interrupt(self.i2c.interrupt(), handler.handler()) };
unwrap!(crate::interrupt::enable(
self.i2c.interrupt(),
handler.priority()
));
} }
} }
impl<'d> I2c<'d, Async> { const NUM_I2C: usize = 1 + cfg!(i2c1) as usize;
/// Create a new I2C instance static WAKERS: [AtomicWaker; NUM_I2C] = [const { AtomicWaker::new() }; NUM_I2C];
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new_async<SDA: PeripheralOutput, SCL: PeripheralOutput>(
i2c: impl Peripheral<P = impl Instance> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
) -> Self {
Self::new_async_typed(i2c.map_into(), sda, scl, frequency)
}
}
impl<'d, T> I2c<'d, Async, T> #[cfg_attr(esp32, allow(dead_code))]
where pub(crate) enum Event {
T: Instance,
{
/// Create a new I2C instance
/// This will enable the peripheral but the peripheral won't get
/// automatically disabled when this gets dropped.
pub fn new_async_typed<SDA: PeripheralOutput, SCL: PeripheralOutput>(
i2c: impl Peripheral<P = T> + 'd,
sda: impl Peripheral<P = SDA> + 'd,
scl: impl Peripheral<P = SCL> + 'd,
frequency: HertzU32,
) -> Self {
let mut this = Self::new_internal(i2c, sda, scl, frequency);
this.internal_set_interrupt_handler(this.i2c.async_handler());
this
}
}
mod asynch {
#[cfg(not(esp32))]
use core::{
pin::Pin,
task::{Context, Poll},
};
use embassy_sync::waitqueue::AtomicWaker;
use embedded_hal::i2c::Operation as EhalOperation;
use procmacros::handler;
use super::*;
const NUM_I2C: usize = 1 + cfg!(i2c1) as usize;
static WAKERS: [AtomicWaker; NUM_I2C] = [const { AtomicWaker::new() }; NUM_I2C];
#[cfg_attr(esp32, allow(dead_code))]
pub(crate) enum Event {
EndDetect, EndDetect,
TxComplete, TxComplete,
#[cfg(not(any(esp32, esp32s2)))] #[cfg(not(any(esp32, esp32s2)))]
TxFifoWatermark, TxFifoWatermark,
} }
#[cfg(not(esp32))] #[cfg(not(esp32))]
#[must_use = "futures do nothing unless you `.await` or poll them"] #[must_use = "futures do nothing unless you `.await` or poll them"]
struct I2cFuture<'a, T> struct I2cFuture<'a, T>
where where
T: Instance, T: Instance,
{ {
event: Event, event: Event,
instance: &'a T, instance: &'a T,
} }
#[cfg(not(esp32))] #[cfg(not(esp32))]
impl<'a, T> I2cFuture<'a, T> impl<'a, T> I2cFuture<'a, T>
where where
T: Instance, T: Instance,
{ {
pub fn new(event: Event, instance: &'a T) -> Self { pub fn new(event: Event, instance: &'a T) -> Self {
instance.register_block().int_ena().modify(|_, w| { instance.register_block().int_ena().modify(|_, w| {
let w = match event { let w = match event {
@ -742,13 +705,13 @@ mod asynch {
Ok(()) Ok(())
} }
} }
#[cfg(not(esp32))] #[cfg(not(esp32))]
impl<T> core::future::Future for I2cFuture<'_, T> impl<'a, T> core::future::Future for I2cFuture<'a, T>
where where
T: Instance, T: Instance,
{ {
type Output = Result<(), Error>; type Output = Result<(), Error>;
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
@ -766,12 +729,24 @@ mod asynch {
Poll::Pending Poll::Pending
} }
} }
}
impl<'d, T> I2c<'d, Async, T>
where
T: Instance,
{
/// Configure the I2C peripheral to operate in blocking mode.
pub fn into_blocking(self) -> I2c<'d, Blocking, T> {
crate::interrupt::disable(Cpu::current(), self.i2c.interrupt());
I2c {
i2c: self.i2c,
phantom: PhantomData,
frequency: self.frequency,
timeout: self.timeout,
}
} }
impl<T> I2c<'_, Async, T>
where
T: Instance,
{
#[cfg(any(esp32, esp32s2))] #[cfg(any(esp32, esp32s2))]
async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> {
if buffer.len() > 32 { if buffer.len() > 32 {
@ -793,11 +768,7 @@ mod asynch {
} }
#[cfg(any(esp32, esp32s2))] #[cfg(any(esp32, esp32s2))]
async fn write_remaining_tx_fifo( async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> {
&self,
start_index: usize,
bytes: &[u8],
) -> Result<(), Error> {
if start_index >= bytes.len() { if start_index >= bytes.len() {
return Ok(()); return Ok(());
} }
@ -811,11 +782,7 @@ mod asynch {
} }
#[cfg(not(any(esp32, esp32s2)))] #[cfg(not(any(esp32, esp32s2)))]
async fn write_remaining_tx_fifo( async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> {
&self,
start_index: usize,
bytes: &[u8],
) -> Result<(), Error> {
let mut index = start_index; let mut index = start_index;
loop { loop {
self.i2c.check_errors()?; self.i2c.check_errors()?;
@ -1078,19 +1045,19 @@ mod asynch {
/// transaction. /// transaction.
/// ///
/// Transaction contract: /// Transaction contract:
/// - Before executing the first operation an ST is sent automatically. /// - Before executing the first operation an ST is sent automatically. This
/// This is followed by SAD+R/W as appropriate. /// is followed by SAD+R/W as appropriate.
/// - Data from adjacent operations of the same type are sent after each /// - Data from adjacent operations of the same type are sent after each
/// other without an SP or SR. /// other without an SP or SR.
/// - Between adjacent operations of a different type an SR and SAD+R/W /// - Between adjacent operations of a different type an SR and SAD+R/W is
/// is sent. /// sent.
/// - After executing the last operation an SP is sent automatically. /// - After executing the last operation an SP is sent automatically.
/// - If the last operation is a `Read` the master does not send an /// - If the last operation is a `Read` the master does not send an
/// acknowledge for the last byte. /// acknowledge for the last byte.
/// ///
/// - `ST` = start condition /// - `ST` = start condition
/// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0
/// 0 to indicate writing /// to indicate writing
/// - `SR` = repeated start condition /// - `SR` = repeated start condition
/// - `SP` = stop condition /// - `SP` = stop condition
pub async fn transaction<'a>( pub async fn transaction<'a>(
@ -1156,12 +1123,12 @@ mod asynch {
Ok(()) Ok(())
} }
} }
impl<T> embedded_hal_async::i2c::I2c for I2c<'_, Async, T> impl<'d, T> embedded_hal_async::i2c::I2c for I2c<'d, Async, T>
where where
T: Instance, T: Instance,
{ {
async fn transaction( async fn transaction(
&mut self, &mut self,
address: u8, address: u8,
@ -1170,9 +1137,9 @@ mod asynch {
self.transaction_impl_async(address, operations.iter_mut().map(Operation::from)) self.transaction_impl_async(address, operations.iter_mut().map(Operation::from))
.await .await
} }
} }
fn handler(regs: &RegisterBlock) { fn handler(regs: &RegisterBlock) {
regs.int_ena().modify(|_, w| { regs.int_ena().modify(|_, w| {
w.end_detect().clear_bit(); w.end_detect().clear_bit();
w.trans_complete().clear_bit(); w.trans_complete().clear_bit();
@ -1188,24 +1155,23 @@ mod asynch {
#[cfg(esp32)] #[cfg(esp32)]
regs.int_ena().modify(|_, w| w.ack_err().clear_bit()); regs.int_ena().modify(|_, w| w.ack_err().clear_bit());
} }
#[handler] #[handler]
pub(super) fn i2c0_handler() { pub(super) fn i2c0_handler() {
let regs = unsafe { &*crate::peripherals::I2C0::PTR }; let regs = unsafe { crate::peripherals::I2C0::steal() };
handler(regs); handler(regs.register_block());
WAKERS[0].wake(); WAKERS[0].wake();
} }
#[cfg(i2c1)] #[cfg(i2c1)]
#[handler] #[handler]
pub(super) fn i2c1_handler() { pub(super) fn i2c1_handler() {
let regs = unsafe { &*crate::peripherals::I2C1::PTR }; let regs = unsafe { crate::peripherals::I2C1::steal() };
handler(regs); handler(regs.register_block());
WAKERS[1].wake(); WAKERS[1].wake();
}
} }
/// I2C Peripheral Instance /// I2C Peripheral Instance
@ -2248,7 +2214,7 @@ impl PeripheralMarker for crate::peripherals::I2C0 {
impl Instance for crate::peripherals::I2C0 { impl Instance for crate::peripherals::I2C0 {
#[inline(always)] #[inline(always)]
fn async_handler(&self) -> InterruptHandler { fn async_handler(&self) -> InterruptHandler {
asynch::i2c0_handler i2c0_handler
} }
#[inline(always)] #[inline(always)]
@ -2299,7 +2265,7 @@ impl PeripheralMarker for crate::peripherals::I2C1 {
impl Instance for crate::peripherals::I2C1 { impl Instance for crate::peripherals::I2C1 {
#[inline(always)] #[inline(always)]
fn async_handler(&self) -> InterruptHandler { fn async_handler(&self) -> InterruptHandler {
asynch::i2c1_handler i2c1_handler
} }
#[inline(always)] #[inline(always)]

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,34 +115,23 @@ 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();
#[handler]
pub(crate) fn interrupt_handler() {
// TODO: this is a shared interrupt with Camera and here we ignore that! // TODO: this is a shared interrupt with Camera and here we ignore that!
if Instance::is_lcd_done_set() { if Instance::is_lcd_done_set() {
Instance::unlisten_lcd_done(); Instance::unlisten_lcd_done();
LCD_DONE_WAKER.wake() 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.
impl Instance {
pub(crate) fn listen_lcd_done() { pub(crate) fn listen_lcd_done() {
let lcd_cam = unsafe { LCD_CAM::steal() }; let lcd_cam = unsafe { LCD_CAM::steal() };
lcd_cam lcd_cam
@ -166,8 +154,8 @@ mod private {
.lcd_trans_done_int_raw() .lcd_trans_done_int_raw()
.bit() .bit()
} }
} }
pub struct ClockDivider { pub(crate) struct ClockDivider {
// Integral LCD clock divider value. (8 bits) // Integral LCD clock divider value. (8 bits)
// Value 0 is treated as 256 // Value 0 is treated as 256
// Value 1 is treated as 2 // Value 1 is treated as 2
@ -179,12 +167,12 @@ mod private {
// Fractional clock divider denominator value. (6 bits) // Fractional clock divider denominator value. (6 bits)
pub div_a: usize, pub div_a: usize,
} }
pub fn calculate_clkm( pub(crate) fn calculate_clkm(
desired_frequency: usize, desired_frequency: usize,
source_frequencies: &[usize], source_frequencies: &[usize],
) -> (usize, ClockDivider) { ) -> (usize, ClockDivider) {
let mut result_freq = 0; let mut result_freq = 0;
let mut result = None; let mut result = None;
@ -200,9 +188,9 @@ mod private {
} }
result.expect("Desired frequency was too low for the dividers to divide to") result.expect("Desired frequency was too low for the dividers to divide to")
} }
fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize { fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize {
let n = match divider.div_num { let n = match divider.div_num {
0 => 256, 0 => 256,
1 => 2, 1 => 2,
@ -225,12 +213,12 @@ mod private {
} else { } else {
source_frequency / n source_frequency / n
} }
} }
fn calculate_closest_divider( fn calculate_closest_divider(
source_frequency: usize, source_frequency: usize,
desired_frequency: usize, desired_frequency: usize,
) -> Option<ClockDivider> { ) -> Option<ClockDivider> {
let div_num = source_frequency / desired_frequency; let div_num = source_frequency / desired_frequency;
if div_num < 2 { if div_num < 2 {
// Source clock isn't fast enough to reach the desired frequency. // Source clock isn't fast enough to reach the desired frequency.
@ -282,24 +270,24 @@ mod private {
} }
}; };
Some(divider) Some(divider)
} }
// https://en.wikipedia.org/wiki/Euclidean_algorithm // https://en.wikipedia.org/wiki/Euclidean_algorithm
const fn hcf(a: usize, b: usize) -> usize { const fn hcf(a: usize, b: usize) -> usize {
if b != 0 { if b != 0 {
hcf(b, a % b) hcf(b, a % b)
} else { } else {
a a
} }
} }
struct Fraction { struct Fraction {
pub numerator: usize, pub numerator: usize,
pub denominator: usize, pub denominator: usize,
} }
// https://en.wikipedia.org/wiki/Farey_sequence#Next_term // https://en.wikipedia.org/wiki/Farey_sequence#Next_term
fn farey_sequence(denominator: usize) -> impl Iterator<Item = Fraction> { fn farey_sequence(denominator: usize) -> impl Iterator<Item = Fraction> {
let mut a = 0; let mut a = 0;
let mut b = 1; let mut b = 1;
let mut c = 1; let mut c = 1;
@ -316,5 +304,4 @@ mod private {
(a, b, c, d) = (c, d, k * c - a, k * d - b); (a, b, c, d) = (c, d, k * c - a, k * d - b);
Some(next) 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() };
parl_io.int_ena().write(|w| {
for interrupt in interrupts { for interrupt in interrupts {
match interrupt { match interrupt {
ParlIoInterrupt::TxFifoReEmpty => parl_io ParlIoInterrupt::TxFifoReEmpty => w.tx_fifo_rempty().bit(enable),
.int_ena() ParlIoInterrupt::RxFifoWOvf => w.rx_fifo_wovf().bit(enable),
.modify(|_, w| w.tx_fifo_rempty().bit(enable)), ParlIoInterrupt::TxEof => w.tx_eof().bit(enable),
ParlIoInterrupt::RxFifoWOvf => parl_io };
.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() };
parl_io.int_clr().write(|w| {
for interrupt in interrupts { for interrupt in interrupts {
match interrupt { match interrupt {
ParlIoInterrupt::TxFifoReEmpty => parl_io ParlIoInterrupt::TxFifoReEmpty => w.tx_fifo_rempty().clear_bit_by_one(),
.int_clr() ParlIoInterrupt::RxFifoWOvf => w.rx_fifo_wovf().clear_bit_by_one(),
.write(|w| w.tx_fifo_rempty().clear_bit_by_one()), ParlIoInterrupt::TxEof => w.tx_eof().clear_bit_by_one(),
ParlIoInterrupt::RxFifoWOvf => parl_io };
.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,24 +434,19 @@ 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()));
}
} }
/// RTC Watchdog Timer. /// RTC Watchdog Timer.

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()
} }
} }

View File

@ -126,10 +126,11 @@
//! [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::marker::PhantomData; use core::{marker::PhantomData, sync::atomic::Ordering, task::Poll};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use enumset::{EnumSet, EnumSetType}; use enumset::{EnumSet, EnumSetType};
use portable_atomic::AtomicBool;
use self::config::Config; use self::config::Config;
use crate::{ use crate::{
@ -146,6 +147,7 @@ use crate::{
peripherals::{uart0::RegisterBlock, Interrupt}, peripherals::{uart0::RegisterBlock, Interrupt},
private::Internal, private::Internal,
system::PeripheralClockControl, system::PeripheralClockControl,
Async,
Blocking, Blocking,
InterruptConfigurable, InterruptConfigurable,
Mode, Mode,
@ -662,6 +664,42 @@ where
Ok(uart_tx) Ok(uart_tx)
} }
/// Reconfigures the driver to operate in [`Async`] mode.
pub fn into_async(self) -> UartTx<'d, Async, T> {
if !self.uart.state().is_rx_async.load(Ordering::Acquire) {
self.uart
.info()
.set_interrupt_handler(self.uart.info().async_handler);
}
self.uart.state().is_tx_async.store(true, Ordering::Release);
UartTx {
uart: self.uart,
phantom: PhantomData,
}
}
}
impl<'d, T> UartTx<'d, Async, T>
where
T: Instance,
{
/// Reconfigures the driver to operate in [`Blocking`] mode.
pub fn into_blocking(self) -> UartTx<'d, Blocking, T> {
self.uart
.state()
.is_tx_async
.store(false, Ordering::Release);
if !self.uart.state().is_rx_async.load(Ordering::Acquire) {
self.uart.info().disable_interrupts();
}
UartTx {
uart: self.uart,
phantom: PhantomData,
}
}
} }
#[inline(always)] #[inline(always)]
@ -963,6 +1001,50 @@ where
Ok(uart_rx) Ok(uart_rx)
} }
/// Reconfigures the driver to operate in [`Async`] mode.
pub fn into_async(self) -> UartRx<'d, Async, T> {
if !self.uart.state().is_tx_async.load(Ordering::Acquire) {
self.uart
.info()
.set_interrupt_handler(self.uart.info().async_handler);
}
self.uart.state().is_rx_async.store(true, Ordering::Release);
UartRx {
uart: self.uart,
phantom: PhantomData,
at_cmd_config: self.at_cmd_config,
rx_timeout_config: self.rx_timeout_config,
#[cfg(not(esp32))]
symbol_len: self.symbol_len,
}
}
}
impl<'d, T> UartRx<'d, Async, T>
where
T: Instance,
{
/// Reconfigures the driver to operate in [`Blocking`] mode.
pub fn into_blocking(self) -> UartRx<'d, Blocking, T> {
self.uart
.state()
.is_rx_async
.store(false, Ordering::Release);
if !self.uart.state().is_tx_async.load(Ordering::Acquire) {
self.uart.info().disable_interrupts();
}
UartRx {
uart: self.uart,
phantom: PhantomData,
at_cmd_config: self.at_cmd_config,
rx_timeout_config: self.rx_timeout_config,
#[cfg(not(esp32))]
symbol_len: self.symbol_len,
}
}
} }
impl<'d> Uart<'d, Blocking> { impl<'d> Uart<'d, Blocking> {
@ -1010,6 +1092,27 @@ where
) -> Result<Self, Error> { ) -> Result<Self, Error> {
UartBuilder::new(uart).with_tx(tx).with_rx(rx).init(config) UartBuilder::new(uart).with_tx(tx).with_rx(rx).init(config)
} }
/// Reconfigures the driver to operate in [`Async`] mode.
pub fn into_async(self) -> Uart<'d, Async, T> {
Uart {
rx: self.rx.into_async(),
tx: self.tx.into_async(),
}
}
}
impl<'d, T> Uart<'d, Async, T>
where
T: Instance,
{
/// Reconfigures the driver to operate in [`Blocking`] mode.
pub fn into_blocking(self) -> Uart<'d, Blocking, T> {
Uart {
rx: self.rx.into_blocking(),
tx: self.tx.into_blocking(),
}
}
} }
/// List of exposed UART events. /// List of exposed UART events.
@ -1033,15 +1136,6 @@ where
T: Instance, T: Instance,
M: Mode, M: Mode,
{ {
fn inner_set_interrupt_handler(&mut self, handler: InterruptHandler) {
// `self.tx.uart` and `self.rx.uart` are the same
let interrupt = self.tx.uart.info().interrupt;
unsafe {
crate::interrupt::bind_interrupt(interrupt, handler.handler());
unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
}
}
/// Configure CTS pin /// Configure CTS pin
pub fn with_cts(mut self, cts: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self { pub fn with_cts(mut self, cts: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self {
self.rx = self.rx.with_cts(cts); self.rx = self.rx.with_cts(cts);
@ -1123,66 +1217,24 @@ where
self.rx.at_cmd_config = Some(config); self.rx.at_cmd_config = Some(config);
} }
/// Listen for the given interrupts
fn enable_listen(&mut self, interrupts: EnumSet<UartInterrupt>, enable: bool) {
let reg_block = self.register_block();
reg_block.int_ena().modify(|_, w| {
for interrupt in interrupts {
match interrupt {
UartInterrupt::AtCmd => w.at_cmd_char_det().bit(enable),
UartInterrupt::TxDone => w.tx_done().bit(enable),
UartInterrupt::RxFifoFull => w.rxfifo_full().bit(enable),
};
}
w
});
}
/// Listen for the given interrupts /// Listen for the given interrupts
pub fn listen(&mut self, interrupts: impl Into<EnumSet<UartInterrupt>>) { pub fn listen(&mut self, interrupts: impl Into<EnumSet<UartInterrupt>>) {
self.enable_listen(interrupts.into(), true); self.tx.uart.info().enable_listen(interrupts.into(), true)
} }
/// Unlisten the given interrupts /// Unlisten the given interrupts
pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<UartInterrupt>>) { pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<UartInterrupt>>) {
self.enable_listen(interrupts.into(), false); self.tx.uart.info().enable_listen(interrupts.into(), false)
} }
/// Gets asserted interrupts /// Gets asserted interrupts
pub fn interrupts(&mut self) -> EnumSet<UartInterrupt> { pub fn interrupts(&mut self) -> EnumSet<UartInterrupt> {
let mut res = EnumSet::new(); self.tx.uart.info().interrupts()
let reg_block = self.register_block();
let ints = reg_block.int_raw().read();
if ints.at_cmd_char_det().bit_is_set() {
res.insert(UartInterrupt::AtCmd);
}
if ints.tx_done().bit_is_set() {
res.insert(UartInterrupt::TxDone);
}
if ints.rxfifo_full().bit_is_set() {
res.insert(UartInterrupt::RxFifoFull);
}
res
} }
/// Resets asserted interrupts /// Resets asserted interrupts
pub fn clear_interrupts(&mut self, interrupts: EnumSet<UartInterrupt>) { pub fn clear_interrupts(&mut self, interrupts: EnumSet<UartInterrupt>) {
let reg_block = self.register_block(); self.tx.uart.info().clear_interrupts(interrupts)
reg_block.int_clr().write(|w| {
for interrupt in interrupts {
match interrupt {
UartInterrupt::AtCmd => w.at_cmd_char_det().clear_bit_by_one(),
UartInterrupt::TxDone => w.tx_done().clear_bit_by_one(),
UartInterrupt::RxFifoFull => w.rxfifo_full().clear_bit_by_one(),
};
}
w
});
} }
/// Write a byte out over the UART /// Write a byte out over the UART
@ -1479,7 +1531,8 @@ where
T: Instance, T: Instance,
{ {
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); // `self.tx.uart` and `self.rx.uart` are the same
self.tx.uart.info().set_interrupt_handler(handler);
} }
} }
@ -1751,21 +1804,13 @@ where
} }
} }
mod asynch { #[derive(EnumSetType, Debug)]
use core::task::Poll; pub(crate) enum TxEvent {
use enumset::{EnumSet, EnumSetType};
use super::*;
use crate::Async;
#[derive(EnumSetType, Debug)]
pub(crate) enum TxEvent {
TxDone, TxDone,
TxFiFoEmpty, TxFiFoEmpty,
} }
#[derive(EnumSetType, Debug)] #[derive(EnumSetType, Debug)]
pub(crate) enum RxEvent { pub(crate) enum RxEvent {
FifoFull, FifoFull,
CmdCharDetected, CmdCharDetected,
FifoOvf, FifoOvf,
@ -1773,22 +1818,22 @@ mod asynch {
GlitchDetected, GlitchDetected,
FrameError, FrameError,
ParityError, ParityError,
} }
/// A future that resolves when the passed interrupt is triggered, /// A future that resolves when the passed interrupt is triggered,
/// or has been triggered in the meantime (flag set in INT_RAW). /// or has been triggered in the meantime (flag set in INT_RAW).
/// Upon construction the future enables the passed interrupt and when it /// Upon construction the future enables the passed interrupt and when it
/// is dropped it disables the interrupt again. The future returns the event /// is dropped it disables the interrupt again. The future returns the event
/// that was initially passed, when it resolves. /// that was initially passed, when it resolves.
#[must_use = "futures do nothing unless you `.await` or poll them"] #[must_use = "futures do nothing unless you `.await` or poll them"]
struct UartRxFuture<'d> { struct UartRxFuture<'d> {
events: EnumSet<RxEvent>, events: EnumSet<RxEvent>,
uart: &'d Info, uart: &'d Info,
state: &'d State, state: &'d State,
registered: bool, registered: bool,
} }
impl<'d> UartRxFuture<'d> { impl<'d> UartRxFuture<'d> {
pub fn new(uart: &'d Info, state: &'d State, events: impl Into<EnumSet<RxEvent>>) -> Self { pub fn new(uart: &'d Info, state: &'d State, events: impl Into<EnumSet<RxEvent>>) -> Self {
Self { Self {
events: events.into(), events: events.into(),
@ -1835,9 +1880,9 @@ mod asynch {
w w
}); });
} }
} }
impl core::future::Future for UartRxFuture<'_> { impl core::future::Future for UartRxFuture<'_> {
type Output = EnumSet<RxEvent>; type Output = EnumSet<RxEvent>;
fn poll( fn poll(
@ -1856,25 +1901,25 @@ mod asynch {
Poll::Pending Poll::Pending
} }
} }
} }
impl Drop for UartRxFuture<'_> { impl Drop for UartRxFuture<'_> {
fn drop(&mut self) { fn drop(&mut self) {
// Although the isr disables the interrupt that occurred directly, we need to // Although the isr disables the interrupt that occurred directly, we need to
// disable the other interrupts (= the ones that did not occur), as // disable the other interrupts (= the ones that did not occur), as
// soon as this future goes out of scope. // soon as this future goes out of scope.
self.enable_listen(false); self.enable_listen(false);
} }
} }
#[must_use = "futures do nothing unless you `.await` or poll them"] #[must_use = "futures do nothing unless you `.await` or poll them"]
struct UartTxFuture<'d> { struct UartTxFuture<'d> {
events: EnumSet<TxEvent>, events: EnumSet<TxEvent>,
uart: &'d Info, uart: &'d Info,
state: &'d State, state: &'d State,
registered: bool, registered: bool,
} }
impl<'d> UartTxFuture<'d> { impl<'d> UartTxFuture<'d> {
pub fn new(uart: &'d Info, state: &'d State, events: impl Into<EnumSet<TxEvent>>) -> Self { pub fn new(uart: &'d Info, state: &'d State, events: impl Into<EnumSet<TxEvent>>) -> Self {
Self { Self {
events: events.into(), events: events.into(),
@ -1907,9 +1952,9 @@ mod asynch {
w w
}); });
} }
} }
impl core::future::Future for UartTxFuture<'_> { impl core::future::Future for UartTxFuture<'_> {
type Output = (); type Output = ();
fn poll( fn poll(
@ -1928,78 +1973,21 @@ mod asynch {
Poll::Pending Poll::Pending
} }
} }
} }
impl Drop for UartTxFuture<'_> { impl Drop for UartTxFuture<'_> {
fn drop(&mut self) { fn drop(&mut self) {
// Although the isr disables the interrupt that occurred directly, we need to // Although the isr disables the interrupt that occurred directly, we need to
// disable the other interrupts (= the ones that did not occur), as // disable the other interrupts (= the ones that did not occur), as
// soon as this future goes out of scope. // soon as this future goes out of scope.
self.enable_listen(false); self.enable_listen(false);
} }
} }
impl<'d> Uart<'d, Async> { impl<T> Uart<'_, Async, T>
/// Create a new UART instance with defaults in [`Async`] mode. where
pub fn new_async<RX: PeripheralInput, TX: PeripheralOutput>(
uart: impl Peripheral<P = impl Instance> + 'd,
rx: impl Peripheral<P = RX> + 'd,
tx: impl Peripheral<P = TX> + 'd,
) -> Result<Self, Error> {
Uart::new_async_typed(uart.map_into(), rx, tx)
}
/// Create a new UART instance with configuration options in [`Async`]
/// mode.
pub fn new_async_with_config<RX: PeripheralInput, TX: PeripheralOutput>(
uart: impl Peripheral<P = impl Instance> + 'd,
config: Config,
rx: impl Peripheral<P = RX> + 'd,
tx: impl Peripheral<P = TX> + 'd,
) -> Result<Self, Error> {
Uart::new_async_with_config_typed(uart.map_into(), config, rx, tx)
}
}
impl<'d, T> Uart<'d, Async, T>
where
T: Instance, T: Instance,
{ {
/// Create a new UART instance with defaults in [`Async`] mode.
pub fn new_async_typed<RX: PeripheralInput, TX: PeripheralOutput>(
uart: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = RX> + 'd,
tx: impl Peripheral<P = TX> + 'd,
) -> Result<Self, Error> {
Self::new_async_with_config_typed(uart, Config::default(), rx, tx)
}
/// Create a new UART instance with configuration options in [`Async`]
/// mode.
pub fn new_async_with_config_typed<RX: PeripheralInput, TX: PeripheralOutput>(
uart: impl Peripheral<P = T> + 'd,
config: Config,
rx: impl Peripheral<P = RX> + 'd,
tx: impl Peripheral<P = TX> + 'd,
) -> Result<Self, Error> {
// FIXME: at the time of writing, the order of the pin assignments matters:
// first binding RX, then TX makes tests fail. This is bad and needs to be
// figured out.
let mut this = UartBuilder::new(uart)
.with_tx(tx)
.with_rx(rx)
.init(config)?;
this.inner_set_interrupt_handler(this.tx.uart.info().async_handler);
Ok(this)
}
}
impl<T> Uart<'_, Async, T>
where
T: Instance,
{
/// Asynchronously reads data from the UART receive buffer into the /// Asynchronously reads data from the UART receive buffer into the
/// provided buffer. /// provided buffer.
pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> { pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
@ -2015,55 +2003,12 @@ mod asynch {
pub async fn flush_async(&mut self) -> Result<(), Error> { pub async fn flush_async(&mut self) -> Result<(), Error> {
self.tx.flush_async().await self.tx.flush_async().await
} }
} }
impl<'d> UartTx<'d, Async> { impl<'d, T> UartTx<'d, Async, T>
/// Create a new UART TX instance in [`Async`] mode. where
pub fn new_async<TX: PeripheralOutput>(
uart: impl Peripheral<P = impl Instance> + 'd,
tx: impl Peripheral<P = TX> + 'd,
) -> Result<Self, Error> {
UartTx::new_async_typed(uart.map_into(), tx)
}
/// Create a new UART TX instance with configuration options in
/// [`Async`] mode.
pub fn new_async_with_config<TX: PeripheralOutput>(
uart: impl Peripheral<P = impl Instance> + 'd,
config: Config,
tx: impl Peripheral<P = TX> + 'd,
) -> Result<Self, Error> {
UartTx::new_async_with_config_typed(uart.map_into(), config, tx)
}
}
impl<'d, T> UartTx<'d, Async, T>
where
T: Instance, T: Instance,
{ {
/// Create a new UART TX instance in [`Async`] mode.
pub fn new_async_typed<TX: PeripheralOutput>(
uart: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = TX> + 'd,
) -> Result<Self, Error> {
UartTx::new_async_with_config_typed(uart, Config::default(), tx)
}
/// Create a new UART TX instance with configuration options in
/// [`Async`] mode.
pub fn new_async_with_config_typed<TX: PeripheralOutput>(
uart: impl Peripheral<P = T> + 'd,
config: Config,
tx: impl Peripheral<P = TX> + 'd,
) -> Result<Self, Error> {
let mut this = UartBuilder::new(uart).with_tx(tx).init(config)?;
this.inner_set_interrupt_handler(this.tx.uart.info().async_handler);
let (_, uart_tx) = this.split();
Ok(uart_tx)
}
/// Asynchronously writes data to the UART transmit buffer in chunks. /// Asynchronously writes data to the UART transmit buffer in chunks.
/// ///
/// This function sends the contents of the provided buffer `words` over /// This function sends the contents of the provided buffer `words` over
@ -2108,55 +2053,12 @@ mod asynch {
Ok(()) Ok(())
} }
} }
impl<'d> UartRx<'d, Async> { impl<'d, T> UartRx<'d, Async, T>
/// Create a new UART RX instance in [`Async`] mode. where
pub fn new_async<RX: PeripheralInput>(
uart: impl Peripheral<P = impl Instance> + 'd,
rx: impl Peripheral<P = RX> + 'd,
) -> Result<Self, Error> {
Self::new_async_typed(uart.map_into(), rx)
}
/// Create a new UART RX instance with configuration options in
/// [`Async`] mode.
pub fn new_async_with_config<RX: PeripheralInput>(
uart: impl Peripheral<P = impl Instance> + 'd,
config: Config,
rx: impl Peripheral<P = RX> + 'd,
) -> Result<Self, Error> {
Self::new_async_with_config_typed(uart.map_into(), config, rx)
}
}
impl<'d, T> UartRx<'d, Async, T>
where
T: Instance, T: Instance,
{ {
/// Create a new UART RX instance in [`Async`] mode.
pub fn new_async_typed(
uart: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl PeripheralInput> + 'd,
) -> Result<Self, Error> {
Self::new_async_with_config_typed(uart, Config::default(), rx)
}
/// Create a new UART RX instance with configuration options in
/// [`Async`] mode.
pub fn new_async_with_config_typed(
uart: impl Peripheral<P = T> + 'd,
config: Config,
rx: impl Peripheral<P = impl PeripheralInput> + 'd,
) -> Result<Self, Error> {
let mut this = UartBuilder::new(uart).with_rx(rx).init(config)?;
this.inner_set_interrupt_handler(this.tx.uart.info().async_handler);
let (uart_rx, _) = this.split();
Ok(uart_rx)
}
/// Read async to buffer slice `buf`. /// Read async to buffer slice `buf`.
/// Waits until at least one byte is in the Rx FiFo /// Waits until at least one byte is in the Rx FiFo
/// and one of the following interrupts occurs: /// and one of the following interrupts occurs:
@ -2207,9 +2109,7 @@ mod asynch {
RxEvent::GlitchDetected => return Err(Error::RxGlitchDetected), RxEvent::GlitchDetected => return Err(Error::RxGlitchDetected),
RxEvent::FrameError => return Err(Error::RxFrameError), RxEvent::FrameError => return Err(Error::RxFrameError),
RxEvent::ParityError => return Err(Error::RxParityError), RxEvent::ParityError => return Err(Error::RxParityError),
RxEvent::FifoFull | RxEvent::CmdCharDetected | RxEvent::FifoTout => { RxEvent::FifoFull | RxEvent::CmdCharDetected | RxEvent::FifoTout => continue,
continue
}
} }
} }
// Unfortunately, the uart's rx-timeout counter counts up whenever there is // Unfortunately, the uart's rx-timeout counter counts up whenever there is
@ -2225,36 +2125,36 @@ mod asynch {
} }
} }
} }
} }
impl<T> embedded_io_async::Read for Uart<'_, Async, T> impl<T> embedded_io_async::Read for Uart<'_, Async, T>
where where
T: Instance, T: Instance,
{ {
/// In contrast to the documentation of embedded_io_async::Read, this /// In contrast to the documentation of embedded_io_async::Read, this
/// method blocks until an uart interrupt occurs. /// method blocks until an uart interrupt occurs.
/// See UartRx::read_async for more details. /// See UartRx::read_async for more details.
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_async(buf).await self.read_async(buf).await
} }
} }
impl<T> embedded_io_async::Read for UartRx<'_, Async, T> impl<T> embedded_io_async::Read for UartRx<'_, Async, T>
where where
T: Instance, T: Instance,
{ {
/// In contrast to the documentation of embedded_io_async::Read, this /// In contrast to the documentation of embedded_io_async::Read, this
/// method blocks until an uart interrupt occurs. /// method blocks until an uart interrupt occurs.
/// See UartRx::read_async for more details. /// See UartRx::read_async for more details.
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_async(buf).await self.read_async(buf).await
} }
} }
impl<T> embedded_io_async::Write for Uart<'_, Async, T> impl<T> embedded_io_async::Write for Uart<'_, Async, T>
where where
T: Instance, T: Instance,
{ {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_async(buf).await self.write_async(buf).await
} }
@ -2262,12 +2162,12 @@ mod asynch {
async fn flush(&mut self) -> Result<(), Self::Error> { async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush_async().await self.flush_async().await
} }
} }
impl<T> embedded_io_async::Write for UartTx<'_, Async, T> impl<T> embedded_io_async::Write for UartTx<'_, Async, T>
where where
T: Instance, T: Instance,
{ {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_async(buf).await self.write_async(buf).await
} }
@ -2275,13 +2175,13 @@ mod asynch {
async fn flush(&mut self) -> Result<(), Self::Error> { async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush_async().await self.flush_async().await
} }
} }
/// Interrupt handler for all UART instances /// Interrupt handler for all UART instances
/// Clears and disables interrupts that have occurred and have their enable /// Clears and disables interrupts that have occurred and have their enable
/// bit set. The fact that an interrupt has been disabled is used by the /// bit set. The fact that an interrupt has been disabled is used by the
/// futures to detect that they should indeed resolve after being woken up /// futures to detect that they should indeed resolve after being woken up
pub(super) fn intr_handler(uart: &Info, state: &State) { pub(super) fn intr_handler(uart: &Info, state: &State) {
let interrupts = uart.register_block().int_st().read(); let interrupts = uart.register_block().int_st().read();
let interrupt_bits = interrupts.bits(); // = int_raw & int_ena let interrupt_bits = interrupts.bits(); // = int_raw & int_ena
let rx_wake = interrupts.rxfifo_full().bit_is_set() let rx_wake = interrupts.rxfifo_full().bit_is_set()
@ -2305,7 +2205,6 @@ mod asynch {
if rx_wake { if rx_wake {
state.rx_waker.wake(); state.rx_waker.wake();
} }
}
} }
/// Low-power UART /// Low-power UART
@ -2502,6 +2401,22 @@ pub mod lp_uart {
} }
} }
impl Info {
fn set_interrupt_handler(&self, handler: InterruptHandler) {
for core in crate::Cpu::other() {
crate::interrupt::disable(core, self.interrupt);
}
self.enable_listen(EnumSet::all(), false);
self.clear_interrupts(EnumSet::all());
unsafe { crate::interrupt::bind_interrupt(self.interrupt, handler.handler()) };
unwrap!(crate::interrupt::enable(self.interrupt, handler.priority()));
}
fn disable_interrupts(&self) {
crate::interrupt::disable(crate::Cpu::current(), self.interrupt);
}
}
/// UART Peripheral Instance /// UART Peripheral Instance
pub trait Instance: Peripheral<P = Self> + PeripheralMarker + Into<AnyUart> + 'static { pub trait Instance: Peripheral<P = Self> + PeripheralMarker + Into<AnyUart> + 'static {
/// Returns the peripheral data and state describing this UART instance. /// Returns the peripheral data and state describing this UART instance.
@ -2553,6 +2468,12 @@ pub struct State {
/// Waker for the asynchronous TX operations. /// Waker for the asynchronous TX operations.
pub tx_waker: AtomicWaker, pub tx_waker: AtomicWaker,
/// Stores whether the TX half is configured for async operation.
pub is_rx_async: AtomicBool,
/// Stores whether the RX half is configured for async operation.
pub is_tx_async: AtomicBool,
} }
impl Info { impl Info {
@ -2560,6 +2481,56 @@ impl Info {
pub fn register_block(&self) -> &RegisterBlock { pub fn register_block(&self) -> &RegisterBlock {
unsafe { &*self.register_block } unsafe { &*self.register_block }
} }
/// Listen for the given interrupts
fn enable_listen(&self, interrupts: EnumSet<UartInterrupt>, enable: bool) {
let reg_block = self.register_block();
reg_block.int_ena().modify(|_, w| {
for interrupt in interrupts {
match interrupt {
UartInterrupt::AtCmd => w.at_cmd_char_det().bit(enable),
UartInterrupt::TxDone => w.tx_done().bit(enable),
UartInterrupt::RxFifoFull => w.rxfifo_full().bit(enable),
};
}
w
});
}
fn interrupts(&self) -> EnumSet<UartInterrupt> {
let mut res = EnumSet::new();
let reg_block = self.register_block();
let ints = reg_block.int_raw().read();
if ints.at_cmd_char_det().bit_is_set() {
res.insert(UartInterrupt::AtCmd);
}
if ints.tx_done().bit_is_set() {
res.insert(UartInterrupt::TxDone);
}
if ints.rxfifo_full().bit_is_set() {
res.insert(UartInterrupt::RxFifoFull);
}
res
}
fn clear_interrupts(&self, interrupts: EnumSet<UartInterrupt>) {
let reg_block = self.register_block();
reg_block.int_clr().write(|w| {
for interrupt in interrupts {
match interrupt {
UartInterrupt::AtCmd => w.at_cmd_char_det().clear_bit_by_one(),
UartInterrupt::TxDone => w.tx_done().clear_bit_by_one(),
UartInterrupt::RxFifoFull => w.rxfifo_full().clear_bit_by_one(),
};
}
w
});
}
} }
impl PartialEq for Info { impl PartialEq for Info {
@ -2576,12 +2547,14 @@ macro_rules! impl_instance {
fn parts(&self) -> (&Info, &State) { fn parts(&self) -> (&Info, &State) {
#[crate::macros::handler] #[crate::macros::handler]
pub(super) fn irq_handler() { pub(super) fn irq_handler() {
asynch::intr_handler(&PERIPHERAL, &STATE); intr_handler(&PERIPHERAL, &STATE);
} }
static STATE: State = State { static STATE: State = State {
tx_waker: AtomicWaker::new(), tx_waker: AtomicWaker::new(),
rx_waker: AtomicWaker::new(), rx_waker: AtomicWaker::new(),
is_rx_async: AtomicBool::new(false),
is_tx_async: AtomicBool::new(false),
}; };
static PERIPHERAL: Info = Info { static PERIPHERAL: Info = Info {

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,35 +677,25 @@ 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);
// Static instance of the waker for each component of the 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<'_> {
pub fn new() -> Self {
// Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT // Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT
// interrupt // interrupt
USB_DEVICE::register_block() USB_DEVICE::register_block()
.int_ena() .int_ena()
.modify(|_, w| w.serial_in_empty().set_bit()); .modify(|_, w| w.serial_in_empty().set_bit());
Self { Self { _peripheral }
phantom: PhantomData,
}
} }
fn event_bit_is_clear(&self) -> bool { fn event_bit_is_clear(&self) -> bool {
@ -690,9 +705,9 @@ mod asynch {
.serial_in_empty() .serial_in_empty()
.bit_is_clear() .bit_is_clear()
} }
} }
impl core::future::Future for UsbSerialJtagWriteFuture<'_> { impl core::future::Future for UsbSerialJtagWriteFuture<'_> {
type Output = (); type Output = ();
fn poll( fn poll(
@ -706,24 +721,23 @@ mod asynch {
Poll::Pending Poll::Pending
} }
} }
} }
#[must_use = "futures do nothing unless you `.await` or poll them"] #[must_use = "futures do nothing unless you `.await` or poll them"]
pub(crate) struct UsbSerialJtagReadFuture<'d> { struct UsbSerialJtagReadFuture<'d> {
phantom: PhantomData<&'d mut USB_DEVICE>, _peripheral: PeripheralRef<'d, USB_DEVICE>,
} }
impl UsbSerialJtagReadFuture<'_> { impl<'d> UsbSerialJtagReadFuture<'d> {
pub fn new() -> Self { 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 // Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT
// interrupt // interrupt
USB_DEVICE::register_block() USB_DEVICE::register_block()
.int_ena() .int_ena()
.modify(|_, w| w.serial_out_recv_pkt().set_bit()); .modify(|_, w| w.serial_out_recv_pkt().set_bit());
Self { Self { _peripheral }
phantom: PhantomData,
}
} }
fn event_bit_is_clear(&self) -> bool { fn event_bit_is_clear(&self) -> bool {
@ -733,9 +747,9 @@ mod asynch {
.serial_out_recv_pkt() .serial_out_recv_pkt()
.bit_is_clear() .bit_is_clear()
} }
} }
impl core::future::Future for UsbSerialJtagReadFuture<'_> { impl core::future::Future for UsbSerialJtagReadFuture<'_> {
type Output = (); type Output = ();
fn poll( fn poll(
@ -749,18 +763,27 @@ mod asynch {
Poll::Pending Poll::Pending
} }
} }
} }
impl<'d> UsbSerialJtag<'d, Async> { impl<'d> UsbSerialJtag<'d, Async> {
/// Create a new USB serial/JTAG instance in asynchronous mode /// Reconfigure the USB Serial JTAG peripheral to operate in blocking
pub fn new_async(usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self { /// mode.
let mut this = Self::new_inner(usb_device); pub fn into_blocking(self) -> UsbSerialJtag<'d, Blocking> {
this.inner_set_interrupt_handler(async_interrupt_handler); crate::interrupt::disable(Cpu::current(), Interrupt::USB_DEVICE);
this UsbSerialJtag {
rx: UsbSerialJtagRx {
peripheral: self.rx.peripheral,
phantom: PhantomData,
},
tx: UsbSerialJtagTx {
peripheral: self.tx.peripheral,
phantom: PhantomData,
},
} }
} }
}
impl UsbSerialJtagTx<'_, Async> { impl UsbSerialJtagTx<'_, Async> {
async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> { async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> {
let reg_block = USB_DEVICE::register_block(); let reg_block = USB_DEVICE::register_block();
@ -772,7 +795,7 @@ mod asynch {
} }
reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit()); reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit());
UsbSerialJtagWriteFuture::new().await; UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await;
} }
Ok(()) Ok(())
@ -785,14 +808,14 @@ mod asynch {
.out_fifo_empty() .out_fifo_empty()
.bit_is_clear() .bit_is_clear()
{ {
UsbSerialJtagWriteFuture::new().await; UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await;
} }
Ok(()) Ok(())
} }
} }
impl UsbSerialJtagRx<'_, Async> { impl UsbSerialJtagRx<'_, Async> {
async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> { async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
if buf.is_empty() { if buf.is_empty() {
return Ok(0); return Ok(0);
@ -803,12 +826,12 @@ mod asynch {
if read_bytes > 0 { if read_bytes > 0 {
return Ok(read_bytes); return Ok(read_bytes);
} }
UsbSerialJtagReadFuture::new().await; UsbSerialJtagReadFuture::new(self.peripheral.reborrow()).await;
}
} }
} }
}
impl embedded_io_async::Write for UsbSerialJtag<'_, Async> { impl embedded_io_async::Write for UsbSerialJtag<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
embedded_io_async::Write::write(&mut self.tx, buf).await embedded_io_async::Write::write(&mut self.tx, buf).await
} }
@ -816,9 +839,9 @@ mod asynch {
async fn flush(&mut self) -> Result<(), Self::Error> { async fn flush(&mut self) -> Result<(), Self::Error> {
embedded_io_async::Write::flush(&mut self.tx).await embedded_io_async::Write::flush(&mut self.tx).await
} }
} }
impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> { impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_bytes_async(buf).await?; self.write_bytes_async(buf).await?;
@ -828,22 +851,22 @@ mod asynch {
async fn flush(&mut self) -> Result<(), Self::Error> { async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush_tx_async().await self.flush_tx_async().await
} }
} }
impl embedded_io_async::Read for UsbSerialJtag<'_, Async> { impl embedded_io_async::Read for UsbSerialJtag<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
embedded_io_async::Read::read(&mut self.rx, buf).await embedded_io_async::Read::read(&mut self.rx, buf).await
} }
} }
impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> { impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_bytes_async(buf).await self.read_bytes_async(buf).await
} }
} }
#[handler] #[handler]
fn async_interrupt_handler() { fn async_interrupt_handler() {
let usb = USB_DEVICE::register_block(); let usb = USB_DEVICE::register_block();
let interrupts = usb.int_st().read(); let interrupts = usb.int_st().read();
@ -871,5 +894,4 @@ mod asynch {
if tx { if tx {
WAKER_TX.wake(); 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();
} }
} }