diff --git a/.cargo/config.toml b/.cargo/config.toml index 35049cbcb..9f81e3044 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,3 @@ [alias] xtask = "run --package xtask --" +xfmt = "xtask fmt-packages" diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index d24d3bb07..e01115be0 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -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) - Add an option to configure `WDT` action (#2330) - `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 @@ -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) - 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) +- The `rmt::asynch::RxChannelAsync` and `rmt::asynch::TxChannelAsync` traits have been moved to `rmt` (#2430) ### 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 `lcd_cam::lcd::i8080::{TxEightBits, TxSixteenBits}` (#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] diff --git a/esp-hal/MIGRATING-0.21.md b/esp-hal/MIGRATING-0.21.md index 7898ecabc..70bc8386e 100644 --- a/esp-hal/MIGRATING-0.21.md +++ b/esp-hal/MIGRATING-0.21.md @@ -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 You no longer have to specify the peripheral instance in the driver's type for the following diff --git a/esp-hal/src/aes/mod.rs b/esp-hal/src/aes/mod.rs index f8c4f970c..eac8f9506 100644 --- a/esp-hal/src/aes/mod.rs +++ b/esp-hal/src/aes/mod.rs @@ -250,6 +250,7 @@ pub mod dma { WriteBuffer, }, peripherals::AES, + Blocking, }; const ALIGN_SIZE: usize = core::mem::size_of::(); @@ -275,7 +276,7 @@ pub mod dma { /// The underlying [`Aes`](super::Aes) driver pub aes: super::Aes<'d>, - channel: Channel<'d, ::Dma, crate::Blocking>, + channel: Channel<'d, ::Dma, Blocking>, rx_chain: DescriptorChain, tx_chain: DescriptorChain, } @@ -284,12 +285,11 @@ pub mod dma { /// Enable DMA for the current instance of the AES driver pub fn with_dma( self, - channel: Channel<'d, C, crate::Blocking>, + channel: Channel<'d, C, Blocking>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> AesDma<'d> where - Self: Sized, C: DmaChannelConvert<::Dma>, { AesDma { diff --git a/esp-hal/src/assist_debug.rs b/esp-hal/src/assist_debug.rs index 1426ff2fa..945d1e87c 100644 --- a/esp-hal/src/assist_debug.rs +++ b/esp-hal/src/assist_debug.rs @@ -26,7 +26,7 @@ use crate::{ interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, - peripherals::ASSIST_DEBUG, + peripherals::{Interrupt, ASSIST_DEBUG}, InterruptConfigurable, }; @@ -51,17 +51,14 @@ impl crate::private::Sealed for DebugAssist<'_> {} impl InterruptConfigurable for DebugAssist<'_> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt( - crate::peripherals::Interrupt::ASSIST_DEBUG, - handler.handler(), - ); - crate::interrupt::enable( - crate::peripherals::Interrupt::ASSIST_DEBUG, - handler.priority(), - ) - .unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::ASSIST_DEBUG); } + unsafe { crate::interrupt::bind_interrupt(Interrupt::ASSIST_DEBUG, handler.handler()) }; + unwrap!(crate::interrupt::enable( + Interrupt::ASSIST_DEBUG, + handler.priority() + )); } } diff --git a/esp-hal/src/dma/gdma.rs b/esp-hal/src/dma/gdma.rs index 0eac232c8..769b570e2 100644 --- a/esp-hal/src/dma/gdma.rs +++ b/esp-hal/src/dma/gdma.rs @@ -17,7 +17,9 @@ use crate::{ dma::*, peripheral::PeripheralRef, + peripherals::Interrupt, system::{Peripheral, PeripheralClockControl}, + Blocking, }; #[doc(hidden)] @@ -33,6 +35,36 @@ impl crate::private::Sealed for AnyGdmaChannel {} impl DmaChannel for AnyGdmaChannel { type Rx = ChannelRxImpl; type Tx = ChannelTxImpl; + + fn async_handler(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(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] @@ -460,9 +492,27 @@ macro_rules! impl_channel { impl crate::private::Sealed for [] {} + impl [] { + fn handler() -> InterruptHandler { + $async_handler + } + + fn isrs() -> &'static [Interrupt] { + &[$(Interrupt::$interrupt),*] + } + } + impl DmaChannel for [] { type Rx = ChannelRxImpl>; type Tx = ChannelTxImpl>; + + fn async_handler(_ch: &Channel<'_, Self, M>) -> InterruptHandler { + Self::handler() + } + + fn interrupts(_ch: &Channel<'_, Self, M>,) -> &'static [Interrupt] { + Self::isrs() + } } impl DmaChannelConvert for [] { @@ -482,64 +532,22 @@ macro_rules! impl_channel { fn get_tx_interrupts() -> impl InterruptAccess { 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> { - fn do_configure<'a, M: crate::Mode>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> crate::dma::Channel<'a, [], 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 - /// - /// 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>( self, burst_mode: bool, priority: DmaPriority, - ) -> crate::dma::Channel<'a, [], crate::Blocking> { - self.do_configure(burst_mode, priority) - } + ) -> Channel<'a, [], Blocking> { + 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 - /// - /// 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, [], $crate::Async> { - let this = self.do_configure(burst_mode, priority); - - []::set_isr($async_handler); + this.configure(burst_mode, priority); this } diff --git a/esp-hal/src/dma/m2m.rs b/esp-hal/src/dma/m2m.rs index c6e69984f..2fce9e40c 100644 --- a/esp-hal/src/dma/m2m.rs +++ b/esp-hal/src/dma/m2m.rs @@ -18,6 +18,8 @@ use crate::{ Tx, WriteBuffer, }, + Async, + Blocking, Mode, }; @@ -36,19 +38,18 @@ where peripheral: DmaPeripheral, } -impl<'d, M> Mem2Mem<'d, M> -where - M: Mode, -{ +impl<'d> Mem2Mem<'d, Blocking> { /// Create a new Mem2Mem instance. - pub fn new( - channel: Channel<'d, CH, M>, + pub fn new( + channel: Channel<'d, CH, DM>, peripheral: impl DmaEligible, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Result where CH: DmaChannelConvert, + DM: Mode, + Channel<'d, CH, Blocking>: From>, { unsafe { Self::new_unsafe( @@ -62,8 +63,8 @@ where } /// Create a new Mem2Mem instance with specific chunk size. - pub fn new_with_chunk_size( - channel: Channel<'d, CH, M>, + pub fn new_with_chunk_size( + channel: Channel<'d, CH, DM>, peripheral: impl DmaEligible, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], @@ -71,6 +72,8 @@ where ) -> Result where CH: DmaChannelConvert, + DM: Mode, + Channel<'d, CH, Blocking>: From>, { unsafe { Self::new_unsafe( @@ -89,8 +92,8 @@ where /// /// You must ensure that your not using DMA for the same peripheral and /// that your the only one using the DmaPeripheral. - pub unsafe fn new_unsafe( - channel: Channel<'d, CH, M>, + pub unsafe fn new_unsafe( + channel: Channel<'d, CH, DM>, peripheral: DmaPeripheral, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], @@ -98,6 +101,8 @@ where ) -> Result where CH: DmaChannelConvert, + DM: Mode, + Channel<'d, CH, Blocking>: From>, { if !(1..=4092).contains(&chunk_size) { return Err(DmaError::InvalidChunkSize); @@ -106,13 +111,28 @@ where return Err(DmaError::OutOfDescriptors); } Ok(Mem2Mem { - channel: channel.degrade(), + channel: Channel::<_, Blocking>::from(channel).degrade(), peripheral, rx_chain: DescriptorChain::new_with_chunk_size(rx_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. pub fn start_transfer<'t, TXBUF, RXBUF>( &mut self, diff --git a/esp-hal/src/dma/mod.rs b/esp-hal/src/dma/mod.rs index 389b1acea..df652f9ff 100644 --- a/esp-hal/src/dma/mod.rs +++ b/esp-hal/src/dma/mod.rs @@ -58,6 +58,25 @@ 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 {} macro_rules! impl_word { @@ -356,17 +375,6 @@ impl DmaDescriptor { // Send (where the compiler sees fit). 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; #[cfg(gdma)] mod gdma; @@ -1562,21 +1570,24 @@ impl RxCircularState { } /// 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. type Rx: RxRegisterAccess + InterruptAccess; /// A description of the TX half of a DMA Channel. type Tx: TxRegisterAccess + InterruptAccess; + + /// Returns the async interrupt handler. + fn async_handler(ch: &Channel<'_, Self, M>) -> InterruptHandler; + + /// Returns the interrupt. + fn interrupts(ch: &Channel<'_, Self, M>) -> &'static [Interrupt]; } #[doc(hidden)] pub trait DmaChannelExt: DmaChannel { fn get_rx_interrupts() -> impl InterruptAccess; fn get_tx_interrupts() -> impl InterruptAccess; - - #[doc(hidden)] - fn set_isr(handler: InterruptHandler); } #[doc(hidden)] @@ -1668,9 +1679,14 @@ impl<'a, CH> ChannelRx<'a, CH> where 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 { - burst_mode, + burst_mode: false, rx_impl, _phantom: PhantomData, } @@ -1688,6 +1704,12 @@ where _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 crate::private::Sealed for ChannelRx<'_, CH> where CH: DmaChannel {} @@ -1886,9 +1908,9 @@ impl<'a, CH> ChannelTx<'a, CH> where CH: DmaChannel, { - fn new(tx_impl: CH::Tx, burst_mode: bool) -> Self { + fn new(tx_impl: CH::Tx) -> Self { Self { - burst_mode, + burst_mode: false, tx_impl, _phantom: PhantomData, } @@ -1906,6 +1928,12 @@ where _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 crate::private::Sealed for ChannelTx<'_, CH> where CH: DmaChannel {} @@ -2076,6 +2104,12 @@ pub trait RegisterAccess: crate::private::Sealed { #[cfg(pdma)] 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)] @@ -2114,31 +2148,38 @@ pub trait InterruptAccess: crate::private::Sealed { } /// DMA Channel -pub struct Channel<'d, CH, MODE> +pub struct Channel<'d, CH, M> where CH: DmaChannel, - MODE: Mode, + M: Mode, { /// RX half of the channel pub rx: ChannelRx<'d, CH>, /// TX half of the channel pub tx: ChannelTx<'d, CH>, - phantom: PhantomData, + pub(crate) phantom: PhantomData, } -impl Channel<'_, C, crate::Blocking> +impl<'d, C> Channel<'d, C, Blocking> where C: DmaChannel, { - /// Sets the interrupt handler for RX and TX interrupts, enables them - /// with [crate::interrupt::Priority::max()] + /// Sets the interrupt handler for RX and TX interrupts. /// /// Interrupts are not enabled at the peripheral level here. pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) 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 @@ -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> for Channel<'d, C, Async> { + fn from(channel: Channel<'d, C, Blocking>) -> Self { + channel.into_async() + } +} + +impl<'d, C: DmaChannel> From> 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> @@ -2906,13 +2994,13 @@ pub(crate) mod asynch { #[cfg(i2s0)] #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_i2s0() { + pub(crate) fn interrupt_handler_i2s0_dma() { handle_interrupt::(); } #[cfg(i2s1)] #[handler(priority = crate::interrupt::Priority::max())] - pub(crate) fn interrupt_handler_i2s1() { + pub(crate) fn interrupt_handler_i2s1_dma() { handle_interrupt::(); } } diff --git a/esp-hal/src/dma/pdma.rs b/esp-hal/src/dma/pdma.rs index 56941dd13..ab18f2387 100644 --- a/esp-hal/src/dma/pdma.rs +++ b/esp-hal/src/dma/pdma.rs @@ -16,7 +16,9 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::{ dma::*, peripheral::PeripheralRef, + peripherals::Interrupt, system::{Peripheral, PeripheralClockControl}, + Blocking, }; type SpiRegisterBlock = crate::peripherals::spi2::RegisterBlock; @@ -341,9 +343,27 @@ macro_rules! ImplSpiChannel { #[non_exhaustive] pub struct [] {} + impl [] { + fn handler() -> InterruptHandler { + super::asynch::interrupt::[< interrupt_handler_spi $num _dma >] + } + + fn isrs() -> &'static [Interrupt] { + &[Interrupt::[< SPI $num _DMA >]] + } + } + impl DmaChannel for [] { type Rx = SpiDmaRxChannelImpl; type Tx = SpiDmaTxChannelImpl; + + fn async_handler(_ch: &Channel<'_, Self, M>) -> InterruptHandler { + Self::handler() + } + + fn interrupts(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { + Self::isrs() + } } impl DmaChannelExt for [] { @@ -353,14 +373,6 @@ macro_rules! ImplSpiChannel { fn get_tx_interrupts() -> impl InterruptAccess { 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 [] { @@ -399,59 +411,19 @@ macro_rules! ImplSpiChannel { pub struct [] {} impl [] { - fn do_configure<'a, M: $crate::Mode>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> Channel<'a, [], 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([] {}); - tx_impl.set_burst_mode(burst_mode); - tx_impl.set_priority(priority); - - let rx_impl = SpiDmaRxChannelImpl([] {}); - 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 - /// - /// 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>( self, burst_mode: bool, priority: DmaPriority, - ) -> Channel<'a, [], $crate::Blocking> { - Self::do_configure(self, burst_mode, priority) - } + ) -> Channel<'a, [], Blocking> { + let mut this = Channel { + tx: ChannelTx::new(SpiDmaTxChannelImpl([] {})), + rx: ChannelRx::new(SpiDmaRxChannelImpl([] {})), + phantom: PhantomData, + }; - /// Configure the channel for use with async 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_for_async<'a>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> Channel<'a, [], $crate::Async> { - let this = Self::do_configure(self, burst_mode, priority); - - []::set_isr(super::asynch::interrupt::[< interrupt_handler_spi $num _dma >]); + this.configure(burst_mode, priority); this } @@ -784,9 +756,27 @@ macro_rules! ImplI2sChannel { impl $crate::private::Sealed for [] {} + impl [] { + fn handler() -> InterruptHandler { + super::asynch::interrupt::[< interrupt_handler_i2s $num _dma >] + } + + fn isrs() -> &'static [Interrupt] { + &[Interrupt::[< I2S $num >]] + } + } + impl DmaChannel for [] { type Rx = I2sDmaRxChannelImpl; type Tx = I2sDmaTxChannelImpl; + + fn async_handler(_ch: &Channel<'_, Self, M>) -> InterruptHandler { + Self::handler() + } + + fn interrupts(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { + Self::isrs() + } } impl DmaChannelExt for [] { @@ -796,14 +786,6 @@ macro_rules! ImplI2sChannel { fn get_tx_interrupts() -> impl InterruptAccess { 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 [] { @@ -838,50 +820,19 @@ macro_rules! ImplI2sChannel { pub struct [] {} impl [] { - fn do_configure<'a, M: $crate::Mode>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> Channel<'a, [], M> { - let tx_impl = I2sDmaTxChannelImpl([] {}); - tx_impl.set_burst_mode(burst_mode); - tx_impl.set_priority(priority); - - let rx_impl = I2sDmaRxChannelImpl([] {}); - 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 - /// - /// 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>( self, burst_mode: bool, priority: DmaPriority, - ) -> Channel<'a, [], $crate::Blocking> { - Self::do_configure(self, burst_mode, priority) - } + ) -> Channel<'a, [], Blocking> { + let mut this = Channel { + tx: ChannelTx::new(I2sDmaTxChannelImpl([] {})), + rx: ChannelRx::new(I2sDmaRxChannelImpl([] {})), + phantom: PhantomData, + }; - /// Configure the channel for use with async 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_for_async<'a>( - self, - burst_mode: bool, - priority: DmaPriority, - ) -> Channel<'a, [], $crate::Async> { - let this = Self::do_configure(self, burst_mode, priority); - - []::set_isr(super::asynch::interrupt::[< interrupt_handler_i2s $num >]); + this.configure(burst_mode, priority); this } @@ -929,6 +880,19 @@ impl<'d> Dma<'d> { ) -> Dma<'d> { 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 { _inner: dma.into_ref(), spi2channel: Spi2DmaChannelCreator {}, @@ -962,6 +926,20 @@ impl crate::private::Sealed for AnySpiDmaChannel {} impl DmaChannel for AnySpiDmaChannel { type Rx = SpiDmaRxChannelImpl; type Tx = SpiDmaTxChannelImpl; + + fn async_handler(ch: &Channel<'_, Self, M>) -> InterruptHandler { + match &ch.tx.tx_impl.0 { + AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::handler(), + AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::handler(), + } + } + + fn interrupts(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] { + match &ch.tx.tx_impl.0 { + AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::isrs(), + AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::isrs(), + } + } } crate::any_enum! { @@ -998,6 +976,22 @@ impl crate::private::Sealed for AnyI2sDmaChannel {} impl DmaChannel for AnyI2sDmaChannel { type Rx = I2sDmaRxChannelImpl; type Tx = I2sDmaTxChannelImpl; + + fn async_handler(ch: &Channel<'_, Self, M>) -> InterruptHandler { + match &ch.tx.tx_impl.0 { + AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::handler(), + #[cfg(i2s1)] + AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::handler(), + } + } + + fn interrupts(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! { diff --git a/esp-hal/src/ecc.rs b/esp-hal/src/ecc.rs index 59ee1f891..7c6ccfcc2 100644 --- a/esp-hal/src/ecc.rs +++ b/esp-hal/src/ecc.rs @@ -30,7 +30,7 @@ use core::marker::PhantomData; use crate::{ interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, - peripherals::ECC, + peripherals::{Interrupt, ECC}, reg_access::{AlignmentHelper, SocDependentEndianess}, system::{Peripheral as PeripheralEnable, PeripheralClockControl}, InterruptConfigurable, @@ -117,11 +117,11 @@ impl crate::private::Sealed for Ecc<'_, crate::Blocking> {} impl InterruptConfigurable for Ecc<'_, crate::Blocking> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::ECC, handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::ECC, handler.priority()) - .unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::ECC); } + unsafe { crate::interrupt::bind_interrupt(Interrupt::ECC, handler.handler()) }; + unwrap!(crate::interrupt::enable(Interrupt::ECC, handler.priority())); } } diff --git a/esp-hal/src/i2c.rs b/esp-hal/src/i2c.rs index 8b919fd6c..452369252 100644 --- a/esp-hal/src/i2c.rs +++ b/esp-hal/src/i2c.rs @@ -53,8 +53,16 @@ //! [`embedded-hal`]: https://crates.io/crates/embedded-hal 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 procmacros::handler; use crate::{ clock::Clocks, @@ -66,6 +74,7 @@ use crate::{ system::PeripheralClockControl, Async, Blocking, + Cpu, InterruptConfigurable, Mode, }; @@ -240,11 +249,123 @@ pub struct I2c<'d, DM: Mode, T = AnyI2c> { timeout: Option, } -impl I2c<'_, DM, T> +impl embedded_hal_02::blocking::i2c::Read for I2c<'_, Blocking, T> where T: Instance, - DM: Mode, { + type Error = Error; + + fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.read(address, buffer) + } +} + +impl 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 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 embedded_hal::i2c::ErrorType for I2c<'_, DM, T> { + type Error = Error; +} + +impl 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( + i2c: impl Peripheral

+ 'd, + sda: impl Peripheral

+ 'd, + scl: impl Peripheral

+ '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) -> Self { + self.timeout = timeout; + self.i2c.setup(self.frequency, self.timeout); + self + } + fn transaction_impl<'a>( &mut self, address: u8, @@ -303,10 +424,50 @@ where } } -impl 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( + i2c: impl Peripheral

+ 'd, + sda: impl Peripheral

+ 'd, + scl: impl Peripheral

+ '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( + i2c: impl Peripheral

+ 'd, + sda: impl Peripheral

+ 'd, + scl: impl Peripheral

+ '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` pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); @@ -430,163 +591,6 @@ where } } -impl 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 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 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 embedded_hal::i2c::ErrorType for I2c<'_, DM, T> { - type Error = Error; -} - -impl 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( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ '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) -> 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( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ '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( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Self { - Self::new_internal(i2c, sda, scl, frequency) - } -} - impl crate::private::Sealed for I2c<'_, Blocking, T> where T: Instance {} impl InterruptConfigurable for I2c<'_, Blocking, T> @@ -594,21 +598,136 @@ where T: Instance, { 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> { - /// 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( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Self { - Self::new_async_typed(i2c.map_into(), sda, scl, frequency) +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, + TxComplete, + #[cfg(not(any(esp32, esp32s2)))] + TxFifoWatermark, +} + +#[cfg(not(esp32))] +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct I2cFuture<'a, T> +where + T: Instance, +{ + event: Event, + instance: &'a T, +} + +#[cfg(not(esp32))] +impl<'a, T> I2cFuture<'a, T> +where + T: Instance, +{ + pub fn new(event: Event, instance: &'a T) -> Self { + instance.register_block().int_ena().modify(|_, w| { + let w = match event { + Event::EndDetect => w.end_detect().set_bit(), + Event::TxComplete => w.trans_complete().set_bit(), + #[cfg(not(any(esp32, esp32s2)))] + Event::TxFifoWatermark => w.txfifo_wm().set_bit(), + }; + + w.arbitration_lost().set_bit(); + w.time_out().set_bit(); + + #[cfg(esp32)] + w.ack_err().set_bit(); + #[cfg(not(esp32))] + w.nack().set_bit(); + + w + }); + + Self { event, instance } + } + + fn event_bit_is_clear(&self) -> bool { + let r = self.instance.register_block().int_ena().read(); + + match self.event { + Event::EndDetect => r.end_detect().bit_is_clear(), + Event::TxComplete => r.trans_complete().bit_is_clear(), + #[cfg(not(any(esp32, esp32s2)))] + Event::TxFifoWatermark => r.txfifo_wm().bit_is_clear(), + } + } + + fn check_error(&self) -> Result<(), Error> { + let r = self.instance.register_block().int_raw().read(); + + if r.arbitration_lost().bit_is_set() { + return Err(Error::ArbitrationLost); + } + + if r.time_out().bit_is_set() { + return Err(Error::TimeOut); + } + + #[cfg(not(esp32))] + if r.nack().bit_is_set() { + return Err(Error::AckCheckFailed); + } + + #[cfg(esp32)] + if r.ack_err().bit_is_set() { + return Err(Error::AckCheckFailed); + } + + #[cfg(not(esp32))] + if r.trans_complete().bit_is_set() + && self + .instance + .register_block() + .sr() + .read() + .resp_rec() + .bit_is_clear() + { + return Err(Error::AckCheckFailed); + } + + Ok(()) + } +} + +#[cfg(not(esp32))] +impl<'a, T> core::future::Future for I2cFuture<'a, T> +where + T: Instance, +{ + type Output = Result<(), Error>; + + fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { + WAKERS[self.instance.i2c_number()].register(ctx.waker()); + + let error = self.check_error(); + + if error.is_err() { + return Poll::Ready(error); + } + + if self.event_bit_is_clear() { + Poll::Ready(Ok(())) + } else { + Poll::Pending + } } } @@ -616,596 +735,443 @@ impl<'d, T> I2c<'d, Async, 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_async_typed( - i2c: impl Peripheral

+ 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Self { - let mut this = Self::new_internal(i2c, sda, scl, frequency); + /// 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()); - 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, - TxComplete, - #[cfg(not(any(esp32, esp32s2)))] - TxFifoWatermark, + I2c { + i2c: self.i2c, + phantom: PhantomData, + frequency: self.frequency, + timeout: self.timeout, + } } - #[cfg(not(esp32))] - #[must_use = "futures do nothing unless you `.await` or poll them"] - struct I2cFuture<'a, T> - where - T: Instance, - { - event: Event, - instance: &'a T, - } - - #[cfg(not(esp32))] - impl<'a, T> I2cFuture<'a, T> - where - T: Instance, - { - pub fn new(event: Event, instance: &'a T) -> Self { - instance.register_block().int_ena().modify(|_, w| { - let w = match event { - Event::EndDetect => w.end_detect().set_bit(), - Event::TxComplete => w.trans_complete().set_bit(), - #[cfg(not(any(esp32, esp32s2)))] - Event::TxFifoWatermark => w.txfifo_wm().set_bit(), - }; - - w.arbitration_lost().set_bit(); - w.time_out().set_bit(); - - #[cfg(esp32)] - w.ack_err().set_bit(); - #[cfg(not(esp32))] - w.nack().set_bit(); - - w - }); - - Self { event, instance } + #[cfg(any(esp32, esp32s2))] + async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { + if buffer.len() > 32 { + panic!("On ESP32 and ESP32-S2 the max I2C read is limited to 32 bytes"); } - fn event_bit_is_clear(&self) -> bool { - let r = self.instance.register_block().int_ena().read(); + self.wait_for_completion(false).await?; - match self.event { - Event::EndDetect => r.end_detect().bit_is_clear(), - Event::TxComplete => r.trans_complete().bit_is_clear(), - #[cfg(not(any(esp32, esp32s2)))] - Event::TxFifoWatermark => r.txfifo_wm().bit_is_clear(), - } + for byte in buffer.iter_mut() { + *byte = read_fifo(self.i2c.register_block()); } - fn check_error(&self) -> Result<(), Error> { - let r = self.instance.register_block().int_raw().read(); + Ok(()) + } - if r.arbitration_lost().bit_is_set() { - return Err(Error::ArbitrationLost); + #[cfg(not(any(esp32, esp32s2)))] + async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { + self.i2c.read_all_from_fifo(buffer) + } + + #[cfg(any(esp32, esp32s2))] + async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> { + if start_index >= bytes.len() { + return Ok(()); + } + + for b in bytes { + write_fifo(self.i2c.register_block(), *b); + self.i2c.check_errors()?; + } + + Ok(()) + } + + #[cfg(not(any(esp32, esp32s2)))] + async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> { + let mut index = start_index; + loop { + self.i2c.check_errors()?; + + I2cFuture::new(Event::TxFifoWatermark, &*self.i2c).await?; + + self.i2c + .register_block() + .int_clr() + .write(|w| w.txfifo_wm().clear_bit_by_one()); + + I2cFuture::new(Event::TxFifoWatermark, &*self.i2c).await?; + + if index >= bytes.len() { + break Ok(()); } - if r.time_out().bit_is_set() { + write_fifo(self.i2c.register_block(), bytes[index]); + index += 1; + } + } + + #[cfg(not(esp32))] + async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { + self.i2c.check_errors()?; + + if end_only { + I2cFuture::new(Event::EndDetect, &*self.i2c).await?; + } else { + let res = embassy_futures::select::select( + I2cFuture::new(Event::TxComplete, &*self.i2c), + I2cFuture::new(Event::EndDetect, &*self.i2c), + ) + .await; + + match res { + embassy_futures::select::Either::First(res) => res?, + embassy_futures::select::Either::Second(res) => res?, + } + } + self.i2c.check_all_commands_done()?; + + Ok(()) + } + + #[cfg(esp32)] + async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { + // for ESP32 we need a timeout here but wasting a timer seems unnecessary + // given the short time we spend here + + let mut tout = MAX_ITERATIONS / 10; // adjust the timeout because we are yielding in the loop + loop { + let interrupts = self.i2c.register_block().int_raw().read(); + + self.i2c.check_errors()?; + + // Handle completion cases + // A full transmission was completed (either a STOP condition or END was + // processed) + if (!end_only && interrupts.trans_complete().bit_is_set()) + || interrupts.end_detect().bit_is_set() + { + break; + } + + tout -= 1; + if tout == 0 { return Err(Error::TimeOut); } - #[cfg(not(esp32))] - if r.nack().bit_is_set() { - return Err(Error::AckCheckFailed); - } - - #[cfg(esp32)] - if r.ack_err().bit_is_set() { - return Err(Error::AckCheckFailed); - } - - #[cfg(not(esp32))] - if r.trans_complete().bit_is_set() - && self - .instance - .register_block() - .sr() - .read() - .resp_rec() - .bit_is_clear() - { - return Err(Error::AckCheckFailed); - } - - Ok(()) + embassy_futures::yield_now().await; } + self.i2c.check_all_commands_done()?; + Ok(()) } + /// Executes an async I2C write operation. + /// - `addr` is the address of the slave device. + /// - `bytes` is the data two be sent. + /// - `start` indicates whether the operation should start by a START + /// condition and sending the address. + /// - `stop` indicates whether the operation should end with a STOP + /// condition. + /// - `cmd_iterator` is an iterator over the command registers. + async fn write_operation<'a, I>( + &self, + address: u8, + bytes: &[u8], + start: bool, + stop: bool, + cmd_iterator: &mut I, + ) -> Result<(), Error> + where + I: Iterator, + { + // Short circuit for zero length writes without start or end as that would be an + // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255 + if bytes.is_empty() && !start && !stop { + return Ok(()); + } + + // Reset FIFO and command list + self.i2c.reset_fifo(); + self.i2c.reset_command_list(); + if start { + add_cmd(cmd_iterator, Command::Start)?; + } + self.i2c.setup_write(address, bytes, start, cmd_iterator)?; + add_cmd( + cmd_iterator, + if stop { Command::Stop } else { Command::End }, + )?; + let index = self.i2c.fill_tx_fifo(bytes); + self.i2c.start_transmission(); + + // Fill the FIFO with the remaining bytes: + self.write_remaining_tx_fifo(index, bytes).await?; + self.wait_for_completion(!stop).await?; + Ok(()) + } + + /// Executes an async I2C read operation. + /// - `addr` is the address of the slave device. + /// - `buffer` is the buffer to store the read data. + /// - `start` indicates whether the operation should start by a START + /// condition and sending the address. + /// - `stop` indicates whether the operation should end with a STOP + /// condition. + /// - `will_continue` indicates whether there is another read operation + /// following this one and we should not nack the last byte. + /// - `cmd_iterator` is an iterator over the command registers. + async fn read_operation<'a, I>( + &self, + address: u8, + buffer: &mut [u8], + start: bool, + stop: bool, + will_continue: bool, + cmd_iterator: &mut I, + ) -> Result<(), Error> + where + I: Iterator, + { + // Short circuit for zero length reads as that would be an invalid operation + // read lengths in the TRM (at least for ESP32-S3) are 1-255 + if buffer.is_empty() { + return Ok(()); + } + + // Reset FIFO and command list + self.i2c.reset_fifo(); + self.i2c.reset_command_list(); + if start { + add_cmd(cmd_iterator, Command::Start)?; + } + self.i2c + .setup_read(address, buffer, start, will_continue, cmd_iterator)?; + add_cmd( + cmd_iterator, + if stop { Command::Stop } else { Command::End }, + )?; + self.i2c.start_transmission(); + self.read_all_from_fifo(buffer).await?; + self.wait_for_completion(!stop).await?; + Ok(()) + } + + /// Writes bytes to slave with address `address` + pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { + let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); + for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { + // Clear all I2C interrupts + self.i2c.clear_all_interrupts(); + + let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + + self.write_operation( + address, + chunk, + idx == 0, + idx == chunk_count - 1, + cmd_iterator, + ) + .await?; + } + + Ok(()) + } + + /// Reads enough bytes from slave with `address` to fill `buffer` + pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { + let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); + for (idx, chunk) in buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { + // Clear all I2C interrupts + self.i2c.clear_all_interrupts(); + + let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + + self.read_operation( + address, + chunk, + idx == 0, + idx == chunk_count - 1, + idx < chunk_count - 1, + cmd_iterator, + ) + .await?; + } + + Ok(()) + } + + /// Writes bytes to slave with address `address` and then reads enough + /// bytes to fill `buffer` *in a single transaction* + pub async fn write_read( + &mut self, + address: u8, + write_buffer: &[u8], + read_buffer: &mut [u8], + ) -> Result<(), Error> { + let write_count = write_buffer.len().div_ceil(I2C_CHUNK_SIZE); + let read_count = read_buffer.len().div_ceil(I2C_CHUNK_SIZE); + for (idx, chunk) in write_buffer.chunks(I2C_CHUNK_SIZE).enumerate() { + // Clear all I2C interrupts + self.i2c.clear_all_interrupts(); + + let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + + self.write_operation( + address, + chunk, + idx == 0, + idx == write_count - 1 && read_count == 0, + cmd_iterator, + ) + .await?; + } + + for (idx, chunk) in read_buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { + // Clear all I2C interrupts + self.i2c.clear_all_interrupts(); + + let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + + self.read_operation( + address, + chunk, + idx == 0, + idx == read_count - 1, + idx < read_count - 1, + cmd_iterator, + ) + .await?; + } + + Ok(()) + } + + /// Execute the provided operations on the I2C bus as a single + /// transaction. + /// + /// Transaction contract: + /// - Before executing the first operation an ST is sent automatically. This + /// is followed by SAD+R/W as appropriate. + /// - Data from adjacent operations of the same type are sent after each + /// other without an SP or SR. + /// - Between adjacent operations of a different type an SR and SAD+R/W is + /// sent. + /// - After executing the last operation an SP is sent automatically. + /// - If the last operation is a `Read` the master does not send an + /// acknowledge for the last byte. + /// + /// - `ST` = start condition + /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0 + /// to indicate writing + /// - `SR` = repeated start condition + /// - `SP` = stop condition + pub async fn transaction<'a>( + &mut self, + address: u8, + operations: impl IntoIterator>, + ) -> Result<(), Error> { + self.transaction_impl_async(address, operations.into_iter().map(Operation::from)) + .await + } + + async fn transaction_impl_async<'a>( + &mut self, + address: u8, + operations: impl Iterator>, + ) -> Result<(), Error> { + let mut last_op: Option = None; + // filter out 0 length read operations + let mut op_iter = operations + .filter(|op| op.is_write() || !op.is_empty()) + .peekable(); + + while let Some(op) = op_iter.next() { + let next_op = op_iter.peek().map(|v| v.kind()); + let kind = op.kind(); + // Clear all I2C interrupts + self.i2c.clear_all_interrupts(); + + let cmd_iterator = &mut self.i2c.register_block().comd_iter(); + match op { + Operation::Write(buffer) => { + // execute a write operation: + // - issue START/RSTART if op is different from previous + // - issue STOP if op is the last one + self.write_operation( + address, + buffer, + !matches!(last_op, Some(OpKind::Write)), + next_op.is_none(), + cmd_iterator, + ) + .await?; + } + Operation::Read(buffer) => { + // execute a read operation: + // - issue START/RSTART if op is different from previous + // - issue STOP if op is the last one + // - will_continue is true if there is another read operation next + self.read_operation( + address, + buffer, + !matches!(last_op, Some(OpKind::Read)), + next_op.is_none(), + matches!(next_op, Some(OpKind::Read)), + cmd_iterator, + ) + .await?; + } + } + + last_op = Some(kind); + } + + Ok(()) + } +} + +impl<'d, T> embedded_hal_async::i2c::I2c for I2c<'d, Async, T> +where + T: Instance, +{ + async fn transaction( + &mut self, + address: u8, + operations: &mut [EhalOperation<'_>], + ) -> Result<(), Self::Error> { + self.transaction_impl_async(address, operations.iter_mut().map(Operation::from)) + .await + } +} + +fn handler(regs: &RegisterBlock) { + regs.int_ena().modify(|_, w| { + w.end_detect().clear_bit(); + w.trans_complete().clear_bit(); + w.arbitration_lost().clear_bit(); + w.time_out().clear_bit() + }); + + #[cfg(not(any(esp32, esp32s2)))] + regs.int_ena().modify(|_, w| w.txfifo_wm().clear_bit()); + #[cfg(not(esp32))] - impl core::future::Future for I2cFuture<'_, T> - where - T: Instance, - { - type Output = Result<(), Error>; + regs.int_ena().modify(|_, w| w.nack().clear_bit()); - fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { - WAKERS[self.instance.i2c_number()].register(ctx.waker()); + #[cfg(esp32)] + regs.int_ena().modify(|_, w| w.ack_err().clear_bit()); +} - let error = self.check_error(); +#[handler] +pub(super) fn i2c0_handler() { + let regs = unsafe { crate::peripherals::I2C0::steal() }; + handler(regs.register_block()); - if error.is_err() { - return Poll::Ready(error); - } + WAKERS[0].wake(); +} - if self.event_bit_is_clear() { - Poll::Ready(Ok(())) - } else { - Poll::Pending - } - } - } +#[cfg(i2c1)] +#[handler] +pub(super) fn i2c1_handler() { + let regs = unsafe { crate::peripherals::I2C1::steal() }; + handler(regs.register_block()); - impl I2c<'_, Async, T> - where - T: Instance, - { - #[cfg(any(esp32, esp32s2))] - async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { - if buffer.len() > 32 { - panic!("On ESP32 and ESP32-S2 the max I2C read is limited to 32 bytes"); - } - - self.wait_for_completion(false).await?; - - for byte in buffer.iter_mut() { - *byte = read_fifo(self.i2c.register_block()); - } - - Ok(()) - } - - #[cfg(not(any(esp32, esp32s2)))] - async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> { - self.i2c.read_all_from_fifo(buffer) - } - - #[cfg(any(esp32, esp32s2))] - async fn write_remaining_tx_fifo( - &self, - start_index: usize, - bytes: &[u8], - ) -> Result<(), Error> { - if start_index >= bytes.len() { - return Ok(()); - } - - for b in bytes { - write_fifo(self.i2c.register_block(), *b); - self.i2c.check_errors()?; - } - - Ok(()) - } - - #[cfg(not(any(esp32, esp32s2)))] - async fn write_remaining_tx_fifo( - &self, - start_index: usize, - bytes: &[u8], - ) -> Result<(), Error> { - let mut index = start_index; - loop { - self.i2c.check_errors()?; - - I2cFuture::new(Event::TxFifoWatermark, &*self.i2c).await?; - - self.i2c - .register_block() - .int_clr() - .write(|w| w.txfifo_wm().clear_bit_by_one()); - - I2cFuture::new(Event::TxFifoWatermark, &*self.i2c).await?; - - if index >= bytes.len() { - break Ok(()); - } - - write_fifo(self.i2c.register_block(), bytes[index]); - index += 1; - } - } - - #[cfg(not(esp32))] - async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { - self.i2c.check_errors()?; - - if end_only { - I2cFuture::new(Event::EndDetect, &*self.i2c).await?; - } else { - let res = embassy_futures::select::select( - I2cFuture::new(Event::TxComplete, &*self.i2c), - I2cFuture::new(Event::EndDetect, &*self.i2c), - ) - .await; - - match res { - embassy_futures::select::Either::First(res) => res?, - embassy_futures::select::Either::Second(res) => res?, - } - } - self.i2c.check_all_commands_done()?; - - Ok(()) - } - - #[cfg(esp32)] - async fn wait_for_completion(&self, end_only: bool) -> Result<(), Error> { - // for ESP32 we need a timeout here but wasting a timer seems unnecessary - // given the short time we spend here - - let mut tout = MAX_ITERATIONS / 10; // adjust the timeout because we are yielding in the loop - loop { - let interrupts = self.i2c.register_block().int_raw().read(); - - self.i2c.check_errors()?; - - // Handle completion cases - // A full transmission was completed (either a STOP condition or END was - // processed) - if (!end_only && interrupts.trans_complete().bit_is_set()) - || interrupts.end_detect().bit_is_set() - { - break; - } - - tout -= 1; - if tout == 0 { - return Err(Error::TimeOut); - } - - embassy_futures::yield_now().await; - } - self.i2c.check_all_commands_done()?; - Ok(()) - } - - /// Executes an async I2C write operation. - /// - `addr` is the address of the slave device. - /// - `bytes` is the data two be sent. - /// - `start` indicates whether the operation should start by a START - /// condition and sending the address. - /// - `stop` indicates whether the operation should end with a STOP - /// condition. - /// - `cmd_iterator` is an iterator over the command registers. - async fn write_operation<'a, I>( - &self, - address: u8, - bytes: &[u8], - start: bool, - stop: bool, - cmd_iterator: &mut I, - ) -> Result<(), Error> - where - I: Iterator, - { - // Short circuit for zero length writes without start or end as that would be an - // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255 - if bytes.is_empty() && !start && !stop { - return Ok(()); - } - - // Reset FIFO and command list - self.i2c.reset_fifo(); - self.i2c.reset_command_list(); - if start { - add_cmd(cmd_iterator, Command::Start)?; - } - self.i2c.setup_write(address, bytes, start, cmd_iterator)?; - add_cmd( - cmd_iterator, - if stop { Command::Stop } else { Command::End }, - )?; - let index = self.i2c.fill_tx_fifo(bytes); - self.i2c.start_transmission(); - - // Fill the FIFO with the remaining bytes: - self.write_remaining_tx_fifo(index, bytes).await?; - self.wait_for_completion(!stop).await?; - Ok(()) - } - - /// Executes an async I2C read operation. - /// - `addr` is the address of the slave device. - /// - `buffer` is the buffer to store the read data. - /// - `start` indicates whether the operation should start by a START - /// condition and sending the address. - /// - `stop` indicates whether the operation should end with a STOP - /// condition. - /// - `will_continue` indicates whether there is another read operation - /// following this one and we should not nack the last byte. - /// - `cmd_iterator` is an iterator over the command registers. - async fn read_operation<'a, I>( - &self, - address: u8, - buffer: &mut [u8], - start: bool, - stop: bool, - will_continue: bool, - cmd_iterator: &mut I, - ) -> Result<(), Error> - where - I: Iterator, - { - // Short circuit for zero length reads as that would be an invalid operation - // read lengths in the TRM (at least for ESP32-S3) are 1-255 - if buffer.is_empty() { - return Ok(()); - } - - // Reset FIFO and command list - self.i2c.reset_fifo(); - self.i2c.reset_command_list(); - if start { - add_cmd(cmd_iterator, Command::Start)?; - } - self.i2c - .setup_read(address, buffer, start, will_continue, cmd_iterator)?; - add_cmd( - cmd_iterator, - if stop { Command::Stop } else { Command::End }, - )?; - self.i2c.start_transmission(); - self.read_all_from_fifo(buffer).await?; - self.wait_for_completion(!stop).await?; - Ok(()) - } - - /// Writes bytes to slave with address `address` - pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); - for (idx, chunk) in buffer.chunks(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); - - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - - self.write_operation( - address, - chunk, - idx == 0, - idx == chunk_count - 1, - cmd_iterator, - ) - .await?; - } - - Ok(()) - } - - /// Reads enough bytes from slave with `address` to fill `buffer` - pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { - let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE); - for (idx, chunk) in buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); - - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - - self.read_operation( - address, - chunk, - idx == 0, - idx == chunk_count - 1, - idx < chunk_count - 1, - cmd_iterator, - ) - .await?; - } - - Ok(()) - } - - /// Writes bytes to slave with address `address` and then reads enough - /// bytes to fill `buffer` *in a single transaction* - pub async fn write_read( - &mut self, - address: u8, - write_buffer: &[u8], - read_buffer: &mut [u8], - ) -> Result<(), Error> { - let write_count = write_buffer.len().div_ceil(I2C_CHUNK_SIZE); - let read_count = read_buffer.len().div_ceil(I2C_CHUNK_SIZE); - for (idx, chunk) in write_buffer.chunks(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); - - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - - self.write_operation( - address, - chunk, - idx == 0, - idx == write_count - 1 && read_count == 0, - cmd_iterator, - ) - .await?; - } - - for (idx, chunk) in read_buffer.chunks_mut(I2C_CHUNK_SIZE).enumerate() { - // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); - - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - - self.read_operation( - address, - chunk, - idx == 0, - idx == read_count - 1, - idx < read_count - 1, - cmd_iterator, - ) - .await?; - } - - Ok(()) - } - - /// Execute the provided operations on the I2C bus as a single - /// transaction. - /// - /// Transaction contract: - /// - Before executing the first operation an ST is sent automatically. - /// This is followed by SAD+R/W as appropriate. - /// - Data from adjacent operations of the same type are sent after each - /// other without an SP or SR. - /// - Between adjacent operations of a different type an SR and SAD+R/W - /// is sent. - /// - After executing the last operation an SP is sent automatically. - /// - If the last operation is a `Read` the master does not send an - /// acknowledge for the last byte. - /// - /// - `ST` = start condition - /// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or - /// 0 to indicate writing - /// - `SR` = repeated start condition - /// - `SP` = stop condition - pub async fn transaction<'a>( - &mut self, - address: u8, - operations: impl IntoIterator>, - ) -> Result<(), Error> { - self.transaction_impl_async(address, operations.into_iter().map(Operation::from)) - .await - } - - async fn transaction_impl_async<'a>( - &mut self, - address: u8, - operations: impl Iterator>, - ) -> Result<(), Error> { - let mut last_op: Option = None; - // filter out 0 length read operations - let mut op_iter = operations - .filter(|op| op.is_write() || !op.is_empty()) - .peekable(); - - while let Some(op) = op_iter.next() { - let next_op = op_iter.peek().map(|v| v.kind()); - let kind = op.kind(); - // Clear all I2C interrupts - self.i2c.clear_all_interrupts(); - - let cmd_iterator = &mut self.i2c.register_block().comd_iter(); - match op { - Operation::Write(buffer) => { - // execute a write operation: - // - issue START/RSTART if op is different from previous - // - issue STOP if op is the last one - self.write_operation( - address, - buffer, - !matches!(last_op, Some(OpKind::Write)), - next_op.is_none(), - cmd_iterator, - ) - .await?; - } - Operation::Read(buffer) => { - // execute a read operation: - // - issue START/RSTART if op is different from previous - // - issue STOP if op is the last one - // - will_continue is true if there is another read operation next - self.read_operation( - address, - buffer, - !matches!(last_op, Some(OpKind::Read)), - next_op.is_none(), - matches!(next_op, Some(OpKind::Read)), - cmd_iterator, - ) - .await?; - } - } - - last_op = Some(kind); - } - - Ok(()) - } - } - - impl embedded_hal_async::i2c::I2c for I2c<'_, Async, T> - where - T: Instance, - { - async fn transaction( - &mut self, - address: u8, - operations: &mut [EhalOperation<'_>], - ) -> Result<(), Self::Error> { - self.transaction_impl_async(address, operations.iter_mut().map(Operation::from)) - .await - } - } - - fn handler(regs: &RegisterBlock) { - regs.int_ena().modify(|_, w| { - w.end_detect().clear_bit(); - w.trans_complete().clear_bit(); - w.arbitration_lost().clear_bit(); - w.time_out().clear_bit() - }); - - #[cfg(not(any(esp32, esp32s2)))] - regs.int_ena().modify(|_, w| w.txfifo_wm().clear_bit()); - - #[cfg(not(esp32))] - regs.int_ena().modify(|_, w| w.nack().clear_bit()); - - #[cfg(esp32)] - regs.int_ena().modify(|_, w| w.ack_err().clear_bit()); - } - - #[handler] - pub(super) fn i2c0_handler() { - let regs = unsafe { &*crate::peripherals::I2C0::PTR }; - handler(regs); - - WAKERS[0].wake(); - } - - #[cfg(i2c1)] - #[handler] - pub(super) fn i2c1_handler() { - let regs = unsafe { &*crate::peripherals::I2C1::PTR }; - handler(regs); - - WAKERS[1].wake(); - } + WAKERS[1].wake(); } /// I2C Peripheral Instance @@ -2248,7 +2214,7 @@ impl PeripheralMarker for crate::peripherals::I2C0 { impl Instance for crate::peripherals::I2C0 { #[inline(always)] fn async_handler(&self) -> InterruptHandler { - asynch::i2c0_handler + i2c0_handler } #[inline(always)] @@ -2299,7 +2265,7 @@ impl PeripheralMarker for crate::peripherals::I2C1 { impl Instance for crate::peripherals::I2C1 { #[inline(always)] fn async_handler(&self) -> InterruptHandler { - asynch::i2c1_handler + i2c1_handler } #[inline(always)] diff --git a/esp-hal/src/i2s.rs b/esp-hal/src/i2s.rs index d17e87a88..c5b2c1bbc 100644 --- a/esp-hal/src/i2s.rs +++ b/esp-hal/src/i2s.rs @@ -107,6 +107,8 @@ use crate::{ interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, system::PeripheralClockControl, + Async, + Blocking, InterruptConfigurable, Mode, }; @@ -253,16 +255,16 @@ impl DataFormat { } /// Instance of the I2S peripheral driver -pub struct I2s<'d, DmaMode, T = AnyI2s> +pub struct I2s<'d, M, T = AnyI2s> where T: RegisterAccess, - DmaMode: Mode, + M: Mode, { /// 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. - pub i2s_tx: TxCreator<'d, DmaMode, T>, - phantom: PhantomData, + pub i2s_tx: TxCreator<'d, M, T>, + phantom: PhantomData, } impl<'d, DmaMode, T> I2s<'d, DmaMode, T> @@ -369,24 +371,23 @@ where } } -impl<'d, DmaMode> I2s<'d, DmaMode> -where - DmaMode: Mode, -{ +impl<'d> I2s<'d, Blocking> { /// Construct a new I2S peripheral driver instance for the first I2S /// peripheral #[allow(clippy::too_many_arguments)] - pub fn new( + pub fn new( i2s: impl Peripheral

+ 'd, standard: Standard, data_format: DataFormat, sample_rate: impl Into, - channel: Channel<'d, CH, DmaMode>, + channel: Channel<'d, CH, DM>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Self where CH: DmaChannelConvert<::Dma>, + DM: Mode, + Channel<'d, CH, Blocking>: From>, { Self::new_typed( i2s.map_into(), @@ -400,25 +401,26 @@ where } } -impl<'d, DmaMode, T> I2s<'d, DmaMode, T> +impl<'d, T> I2s<'d, Blocking, T> where T: RegisterAccess, - DmaMode: Mode, { /// Construct a new I2S peripheral driver instance for the first I2S /// peripheral #[allow(clippy::too_many_arguments)] - pub fn new_typed( + pub fn new_typed( i2s: impl Peripheral

+ 'd, standard: Standard, data_format: DataFormat, sample_rate: impl Into, - channel: Channel<'d, CH, DmaMode>, + channel: Channel<'d, CH, DM>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], ) -> Self where CH: DmaChannelConvert, + DM: Mode, + Channel<'d, CH, Blocking>: From>, { crate::into_ref!(i2s); Self::new_internal( @@ -426,12 +428,43 @@ where standard, data_format, sample_rate, - channel, + channel.into(), rx_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::, + }; + 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. pub fn with_mclk(self, pin: impl Peripheral

+ 'd) -> Self { crate::into_mapped_ref!(pin); @@ -757,20 +790,20 @@ mod private { }, interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, - peripherals::I2S0, + peripherals::{Interrupt, I2S0}, private, Mode, }; - pub struct TxCreator<'d, DmaMode, T> + pub struct TxCreator<'d, M, T> where T: RegisterAccess, - DmaMode: Mode, + M: Mode, { pub i2s: PeripheralRef<'d, T>, pub tx_channel: ChannelTx<'d, T::Dma>, pub descriptors: &'static mut [DmaDescriptor], - pub(crate) phantom: PhantomData, + pub(crate) phantom: PhantomData, } 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 T: RegisterAccess, - DmaMode: Mode, + M: Mode, { pub i2s: PeripheralRef<'d, T>, pub rx_channel: ChannelRx<'d, T::Dma>, pub descriptors: &'static mut [DmaDescriptor], - pub(crate) phantom: PhantomData, + pub(crate) phantom: PhantomData, } - impl<'d, DmaMode, T> RxCreator<'d, DmaMode, T> + impl<'d, M, T> RxCreator<'d, M, T> where T: RegisterAccess, - DmaMode: Mode, + M: Mode, { - pub fn build(self) -> I2sRx<'d, DmaMode, T> { + pub fn build(self) -> I2sRx<'d, M, T> { I2sRx { i2s: self.i2s, rx_channel: self.rx_channel, @@ -1582,9 +1615,14 @@ mod private { impl RegisterAccessPrivate for I2S0 { 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()); - crate::interrupt::enable(crate::peripherals::Interrupt::I2S0, handler.priority()) - .unwrap(); + unwrap!(crate::interrupt::enable( + Interrupt::I2S0, + handler.priority() + )); } } @@ -1682,9 +1720,14 @@ mod private { #[cfg(i2s1)] impl RegisterAccessPrivate for I2S1 { 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()); - crate::interrupt::enable(crate::peripherals::Interrupt::I2S1, handler.priority()) - .unwrap(); + unwrap!(crate::interrupt::enable( + Interrupt::I2S1, + handler.priority() + )); } } diff --git a/esp-hal/src/interrupt/software.rs b/esp-hal/src/interrupt/software.rs index 64156a68d..8b4284f7b 100644 --- a/esp-hal/src/interrupt/software.rs +++ b/esp-hal/src/interrupt/software.rs @@ -62,10 +62,11 @@ impl SoftwareInterrupt { _ => unreachable!(), }; - unsafe { - crate::interrupt::bind_interrupt(interrupt, handler.handler()); - crate::interrupt::enable(interrupt, handler.priority()).unwrap(); + 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())); } /// Trigger this software-interrupt diff --git a/esp-hal/src/lcd_cam/cam.rs b/esp-hal/src/lcd_cam/cam.rs index abf7b5d39..dee3a3759 100644 --- a/esp-hal/src/lcd_cam/cam.rs +++ b/esp-hal/src/lcd_cam/cam.rs @@ -81,7 +81,7 @@ use crate::{ OutputSignal, Pull, }, - lcd_cam::{cam::private::RxPins, private::calculate_clkm, BitOrder, ByteOrder}, + lcd_cam::{calculate_clkm, BitOrder, ByteOrder}, peripheral::{Peripheral, PeripheralRef}, peripherals::LCD_CAM, }; @@ -604,8 +604,7 @@ impl RxPins for RxSixteenBits { const BUS_WIDTH: usize = 2; } -mod private { - pub trait RxPins { - const BUS_WIDTH: usize; - } +#[doc(hidden)] +pub trait RxPins { + const BUS_WIDTH: usize; } diff --git a/esp-hal/src/lcd_cam/lcd/i8080.rs b/esp-hal/src/lcd_cam/lcd/i8080.rs index 72ab45dea..2017f4d07 100644 --- a/esp-hal/src/lcd_cam/lcd/i8080.rs +++ b/esp-hal/src/lcd_cam/lcd/i8080.rs @@ -75,12 +75,13 @@ use crate::{ OutputSignal, }, lcd_cam::{ - asynch::LCD_DONE_WAKER, - lcd::{i8080::private::TxPins, ClockMode, DelayMode, Phase, Polarity}, - private::{calculate_clkm, Instance}, + calculate_clkm, + lcd::{ClockMode, DelayMode, Phase, Polarity}, BitOrder, ByteOrder, + Instance, Lcd, + LCD_DONE_WAKER, }, peripheral::{Peripheral, PeripheralRef}, peripherals::LCD_CAM, @@ -703,8 +704,7 @@ impl<'d> TxPins for TxSixteenBits<'d> { } } -mod private { - pub trait TxPins { - fn configure(&mut self); - } +#[doc(hidden)] +pub trait TxPins { + fn configure(&mut self); } diff --git a/esp-hal/src/lcd_cam/mod.rs b/esp-hal/src/lcd_cam/mod.rs index 38a29f83b..b7172260d 100644 --- a/esp-hal/src/lcd_cam/mod.rs +++ b/esp-hal/src/lcd_cam/mod.rs @@ -10,12 +10,18 @@ pub mod lcd; use core::marker::PhantomData; +use embassy_sync::waitqueue::AtomicWaker; + use crate::{ interrupt::InterruptHandler, lcd_cam::{cam::Cam, lcd::Lcd}, + macros::handler, peripheral::Peripheral, - peripherals::LCD_CAM, + peripherals::{Interrupt, LCD_CAM}, system::{self, PeripheralClockControl}, + Async, + Blocking, + Cpu, InterruptConfigurable, }; @@ -27,7 +33,7 @@ pub struct LcdCam<'d, DM: crate::Mode> { pub cam: Cam<'d>, } -impl<'d> LcdCam<'d, crate::Blocking> { +impl<'d> LcdCam<'d, Blocking> { /// Creates a new `LcdCam` instance. pub fn new(lcd_cam: impl Peripheral

+ 'd) -> Self { crate::into_ref!(lcd_cam); @@ -40,56 +46,49 @@ impl<'d> LcdCam<'d, crate::Blocking> { lcd_cam: unsafe { lcd_cam.clone_unchecked() }, _mode: PhantomData, }, - cam: Cam { - lcd_cam: unsafe { lcd_cam.clone_unchecked() }, - }, + cam: Cam { lcd_cam }, } } -} -impl<'d> crate::private::Sealed for LcdCam<'d, crate::Blocking> {} -// TODO: This interrupt is shared with the Camera module, we should handle this -// in a similar way to the gpio::IO -impl<'d> InterruptConfigurable for LcdCam<'d, crate::Blocking> { - 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

+ '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 { + /// Reconfigures the peripheral for asynchronous operation. + pub fn into_async(mut self) -> LcdCam<'d, Async> { + self.set_interrupt_handler(interrupt_handler); + LcdCam { lcd: Lcd { - lcd_cam: unsafe { lcd_cam.clone_unchecked() }, + lcd_cam: self.lcd.lcd_cam, _mode: PhantomData, }, - cam: Cam { - lcd_cam: unsafe { lcd_cam.clone_unchecked() }, + cam: self.cam, + } + } +} + +impl crate::private::Sealed for LcdCam<'_, Blocking> {} +// TODO: This interrupt is shared with the Camera module, we should handle this +// in a similar way to the gpio::IO +impl InterruptConfigurable for LcdCam<'_, Blocking> { + fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::LCD_CAM); + } + unsafe { crate::interrupt::bind_interrupt(Interrupt::LCD_CAM, handler.handler()) }; + unwrap!(crate::interrupt::enable( + Interrupt::LCD_CAM, + handler.priority() + )); + } +} + +impl<'d> LcdCam<'d, Async> { + /// Reconfigures the peripheral for blocking operation. + pub fn into_blocking(self) -> LcdCam<'d, Blocking> { + crate::interrupt::disable(Cpu::current(), Interrupt::LCD_CAM); + LcdCam { + lcd: Lcd { + lcd_cam: self.lcd.lcd_cam, + _mode: PhantomData, }, + cam: self.cam, } } } @@ -116,205 +115,193 @@ pub enum ByteOrder { Inverted = 1, } -#[doc(hidden)] -pub mod asynch { - use embassy_sync::waitqueue::AtomicWaker; - use procmacros::handler; +pub(crate) static LCD_DONE_WAKER: AtomicWaker = AtomicWaker::new(); - use super::private::Instance; - - 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! - if Instance::is_lcd_done_set() { - Instance::unlisten_lcd_done(); - LCD_DONE_WAKER.wake() - } +#[handler] +fn interrupt_handler() { + // TODO: this is a shared interrupt with Camera and here we ignore that! + if Instance::is_lcd_done_set() { + Instance::unlisten_lcd_done(); + LCD_DONE_WAKER.wake() } } -mod private { - use crate::peripherals::LCD_CAM; +pub(crate) struct Instance; - 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 - // CriticalSection will be needed to protect these shared registers. - impl Instance { - pub(crate) fn listen_lcd_done() { - let lcd_cam = unsafe { LCD_CAM::steal() }; - lcd_cam - .lc_dma_int_ena() - .modify(|_, w| w.lcd_trans_done_int_ena().set_bit()); - } - - pub(crate) fn unlisten_lcd_done() { - let lcd_cam = unsafe { LCD_CAM::steal() }; - lcd_cam - .lc_dma_int_ena() - .modify(|_, w| w.lcd_trans_done_int_ena().clear_bit()); - } - - pub(crate) fn is_lcd_done_set() -> bool { - let lcd_cam = unsafe { LCD_CAM::steal() }; - lcd_cam - .lc_dma_int_raw() - .read() - .lcd_trans_done_int_raw() - .bit() - } - } - pub struct ClockDivider { - // Integral LCD clock divider value. (8 bits) - // Value 0 is treated as 256 - // Value 1 is treated as 2 - // Value N is treated as N - pub div_num: usize, - - // Fractional clock divider numerator value. (6 bits) - pub div_b: usize, - - // Fractional clock divider denominator value. (6 bits) - pub div_a: usize, +// 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 +// CriticalSection will be needed to protect these shared registers. +impl Instance { + pub(crate) fn listen_lcd_done() { + let lcd_cam = unsafe { LCD_CAM::steal() }; + lcd_cam + .lc_dma_int_ena() + .modify(|_, w| w.lcd_trans_done_int_ena().set_bit()); } - pub fn calculate_clkm( - desired_frequency: usize, - source_frequencies: &[usize], - ) -> (usize, ClockDivider) { - let mut result_freq = 0; - let mut result = None; + pub(crate) fn unlisten_lcd_done() { + let lcd_cam = unsafe { LCD_CAM::steal() }; + lcd_cam + .lc_dma_int_ena() + .modify(|_, w| w.lcd_trans_done_int_ena().clear_bit()); + } - for (i, &source_frequency) in source_frequencies.iter().enumerate() { - let div = calculate_closest_divider(source_frequency, desired_frequency); - if let Some(div) = div { - let freq = calculate_output_frequency(source_frequency, &div); - if result.is_none() || freq > result_freq { - result = Some((i, div)); - result_freq = freq; - } + pub(crate) fn is_lcd_done_set() -> bool { + let lcd_cam = unsafe { LCD_CAM::steal() }; + lcd_cam + .lc_dma_int_raw() + .read() + .lcd_trans_done_int_raw() + .bit() + } +} +pub(crate) struct ClockDivider { + // Integral LCD clock divider value. (8 bits) + // Value 0 is treated as 256 + // Value 1 is treated as 2 + // Value N is treated as N + pub div_num: usize, + + // Fractional clock divider numerator value. (6 bits) + pub div_b: usize, + + // Fractional clock divider denominator value. (6 bits) + pub div_a: usize, +} + +pub(crate) fn calculate_clkm( + desired_frequency: usize, + source_frequencies: &[usize], +) -> (usize, ClockDivider) { + let mut result_freq = 0; + let mut result = None; + + for (i, &source_frequency) in source_frequencies.iter().enumerate() { + let div = calculate_closest_divider(source_frequency, desired_frequency); + if let Some(div) = div { + let freq = calculate_output_frequency(source_frequency, &div); + if result.is_none() || freq > result_freq { + result = Some((i, div)); + result_freq = freq; } } - - result.expect("Desired frequency was too low for the dividers to divide to") } - fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize { - let n = match divider.div_num { - 0 => 256, - 1 => 2, - _ => divider.div_num.min(256), - }; + result.expect("Desired frequency was too low for the dividers to divide to") +} - if divider.div_b != 0 && divider.div_a != 0 { - // OUTPUT = SOURCE / (N + B/A) - // OUTPUT = SOURCE / ((NA + B)/A) - // OUTPUT = (SOURCE * A) / (NA + B) +fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize { + let n = match divider.div_num { + 0 => 256, + 1 => 2, + _ => divider.div_num.min(256), + }; - // u64 is required to fit the numbers from this arithmetic. + if divider.div_b != 0 && divider.div_a != 0 { + // OUTPUT = SOURCE / (N + B/A) + // OUTPUT = SOURCE / ((NA + B)/A) + // OUTPUT = (SOURCE * A) / (NA + B) - let source = source_frequency as u64; - let n = n as u64; - let a = divider.div_b as u64; - let b = divider.div_a as u64; + // u64 is required to fit the numbers from this arithmetic. - ((source * a) / (n * a + b)) as _ - } else { - source_frequency / n - } + let source = source_frequency as u64; + let n = n as u64; + let a = divider.div_b as u64; + let b = divider.div_a as u64; + + ((source * a) / (n * a + b)) as _ + } else { + source_frequency / n + } +} + +fn calculate_closest_divider( + source_frequency: usize, + desired_frequency: usize, +) -> Option { + let div_num = source_frequency / desired_frequency; + if div_num < 2 { + // Source clock isn't fast enough to reach the desired frequency. + // Return max output. + return Some(ClockDivider { + div_num: 1, + div_b: 0, + div_a: 0, + }); + } + if div_num > 256 { + // Source is too fast to divide to the desired frequency. Return None. + return None; } - fn calculate_closest_divider( - source_frequency: usize, - desired_frequency: usize, - ) -> Option { - let div_num = source_frequency / desired_frequency; - if div_num < 2 { - // Source clock isn't fast enough to reach the desired frequency. - // Return max output. - return Some(ClockDivider { - div_num: 1, - div_b: 0, - div_a: 0, - }); + let div_num = if div_num == 256 { 0 } else { div_num }; + + let div_fraction = { + let div_remainder = source_frequency % desired_frequency; + let gcd = hcf(div_remainder, desired_frequency); + Fraction { + numerator: div_remainder / gcd, + denominator: desired_frequency / gcd, } - if div_num > 256 { - // Source is too fast to divide to the desired frequency. Return None. + }; + + let divider = if div_fraction.numerator == 0 { + ClockDivider { + div_num, + div_b: 0, + div_a: 0, + } + } else { + let target = div_fraction; + let closest = farey_sequence(63) + .find(|curr| { + // https://en.wikipedia.org/wiki/Fraction#Adding_unlike_quantities + + let new_curr_num = curr.numerator * target.denominator; + let new_target_num = target.numerator * curr.denominator; + new_curr_num >= new_target_num + }) + .expect("The fraction must be between 0 and 1"); + + ClockDivider { + div_num, + div_b: closest.numerator, + div_a: closest.denominator, + } + }; + Some(divider) +} + +// https://en.wikipedia.org/wiki/Euclidean_algorithm +const fn hcf(a: usize, b: usize) -> usize { + if b != 0 { + hcf(b, a % b) + } else { + a + } +} + +struct Fraction { + pub numerator: usize, + pub denominator: usize, +} + +// https://en.wikipedia.org/wiki/Farey_sequence#Next_term +fn farey_sequence(denominator: usize) -> impl Iterator { + let mut a = 0; + let mut b = 1; + let mut c = 1; + let mut d = denominator; + core::iter::from_fn(move || { + if a > denominator { return None; } - - let div_num = if div_num == 256 { 0 } else { div_num }; - - let div_fraction = { - let div_remainder = source_frequency % desired_frequency; - let gcd = hcf(div_remainder, desired_frequency); - Fraction { - numerator: div_remainder / gcd, - denominator: desired_frequency / gcd, - } + let next = Fraction { + numerator: a, + denominator: b, }; - - let divider = if div_fraction.numerator == 0 { - ClockDivider { - div_num, - div_b: 0, - div_a: 0, - } - } else { - let target = div_fraction; - let closest = farey_sequence(63) - .find(|curr| { - // https://en.wikipedia.org/wiki/Fraction#Adding_unlike_quantities - - let new_curr_num = curr.numerator * target.denominator; - let new_target_num = target.numerator * curr.denominator; - new_curr_num >= new_target_num - }) - .expect("The fraction must be between 0 and 1"); - - ClockDivider { - div_num, - div_b: closest.numerator, - div_a: closest.denominator, - } - }; - Some(divider) - } - - // https://en.wikipedia.org/wiki/Euclidean_algorithm - const fn hcf(a: usize, b: usize) -> usize { - if b != 0 { - hcf(b, a % b) - } else { - a - } - } - - struct Fraction { - pub numerator: usize, - pub denominator: usize, - } - - // https://en.wikipedia.org/wiki/Farey_sequence#Next_term - fn farey_sequence(denominator: usize) -> impl Iterator { - let mut a = 0; - let mut b = 1; - let mut c = 1; - let mut d = denominator; - core::iter::from_fn(move || { - if a > denominator { - return None; - } - let next = Fraction { - numerator: a, - denominator: b, - }; - let k = (denominator + b) / d; - (a, b, c, d) = (c, d, k * c - a, k * d - b); - Some(next) - }) - } + let k = (denominator + b) / d; + (a, b, c, d) = (c, d, k * c - a, k * d - b); + Some(next) + }) } diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index de8b0c6c8..8ff2815bc 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -374,6 +374,21 @@ impl Cpu { pub fn current() -> Self { get_core() } + + /// Returns an iterator over the "other" cores. + #[inline(always)] + pub fn other() -> impl Iterator { + 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 diff --git a/esp-hal/src/parl_io.rs b/esp-hal/src/parl_io.rs index 0c4229d72..89043b088 100644 --- a/esp-hal/src/parl_io.rs +++ b/esp-hal/src/parl_io.rs @@ -52,7 +52,7 @@ use crate::{ gpio::interconnect::{InputConnection, OutputConnection, PeripheralInput, PeripheralOutput}, interrupt::InterruptHandler, peripheral::{self, Peripheral}, - peripherals::{self, PARL_IO}, + peripherals::{self, Interrupt, PARL_IO}, system::PeripheralClockControl, Blocking, InterruptConfigurable, @@ -923,42 +923,52 @@ where fn internal_set_interrupt_handler(handler: InterruptHandler) { #[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()); - crate::interrupt::enable(crate::peripherals::Interrupt::PARL_IO, handler.priority()) - .unwrap(); + unwrap!(crate::interrupt::enable( + Interrupt::PARL_IO, + handler.priority() + )); } #[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_rx_interrupt(handler.handler()); - crate::interrupt::enable( - crate::peripherals::Interrupt::PARL_IO_TX, + unwrap!(crate::interrupt::enable( + Interrupt::PARL_IO_TX, handler.priority(), - ) - .unwrap(); - crate::interrupt::enable( - crate::peripherals::Interrupt::PARL_IO_RX, + )); + unwrap!(crate::interrupt::enable( + Interrupt::PARL_IO_RX, handler.priority(), - ) - .unwrap(); + )); } } fn internal_listen(interrupts: EnumSet, enable: bool) { let parl_io = unsafe { PARL_IO::steal() }; - for interrupt in interrupts { - match interrupt { - ParlIoInterrupt::TxFifoReEmpty => parl_io - .int_ena() - .modify(|_, w| w.tx_fifo_rempty().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)), + parl_io.int_ena().write(|w| { + for interrupt in interrupts { + match interrupt { + ParlIoInterrupt::TxFifoReEmpty => w.tx_fifo_rempty().bit(enable), + ParlIoInterrupt::RxFifoWOvf => w.rx_fifo_wovf().bit(enable), + ParlIoInterrupt::TxEof => w.tx_eof().bit(enable), + }; } - } + w + }); } fn internal_interrupts() -> EnumSet { @@ -980,17 +990,16 @@ fn internal_interrupts() -> EnumSet { fn internal_clear_interrupts(interrupts: EnumSet) { let parl_io = unsafe { PARL_IO::steal() }; - for interrupt in interrupts { - match interrupt { - ParlIoInterrupt::TxFifoReEmpty => parl_io - .int_clr() - .write(|w| w.tx_fifo_rempty().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()), + parl_io.int_clr().write(|w| { + for interrupt in interrupts { + match interrupt { + ParlIoInterrupt::TxFifoReEmpty => w.tx_fifo_rempty().clear_bit_by_one(), + ParlIoInterrupt::RxFifoWOvf => w.rx_fifo_wovf().clear_bit_by_one(), + ParlIoInterrupt::TxEof => w.tx_eof().clear_bit_by_one(), + }; } - } + w + }); } /// Parallel IO in full duplex mode diff --git a/esp-hal/src/pcnt/mod.rs b/esp-hal/src/pcnt/mod.rs index d7598a5e7..742404b3f 100644 --- a/esp-hal/src/pcnt/mod.rs +++ b/esp-hal/src/pcnt/mod.rs @@ -113,9 +113,10 @@ impl crate::private::Sealed for Pcnt<'_> {} impl InterruptConfigurable for Pcnt<'_> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()); - interrupt::enable(Interrupt::PCNT, handler.priority()).unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::PCNT); } + unsafe { interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()) }; + unwrap!(interrupt::enable(Interrupt::PCNT, handler.priority())); } } diff --git a/esp-hal/src/rmt.rs b/esp-hal/src/rmt.rs index 80f0d99fe..1ba39b342 100644 --- a/esp-hal/src/rmt.rs +++ b/esp-hal/src/rmt.rs @@ -80,17 +80,25 @@ //! //! > Note: on ESP32 and ESP32-S2 you cannot specify a base frequency other than 80 MHz -use core::marker::PhantomData; +use core::{ + marker::PhantomData, + pin::Pin, + task::{Context, Poll}, +}; +use embassy_sync::waitqueue::AtomicWaker; +use enumset::{EnumSet, EnumSetType}; use fugit::HertzU32; use crate::{ gpio::interconnect::{PeripheralInput, PeripheralOutput}, - interrupt::InterruptHandler, + macros::handler, peripheral::Peripheral, - rmt::private::CreateInstance, + peripherals::Interrupt, soc::constants, system::PeripheralClockControl, + Async, + Blocking, InterruptConfigurable, }; @@ -206,8 +214,6 @@ pub struct RxChannelConfig { pub use impl_for_chip::{ChannelCreator, Rmt}; -use self::asynch::{RxChannelAsync, TxChannelAsync}; - impl<'d, M> Rmt<'d, M> where M: crate::Mode, @@ -237,14 +243,6 @@ where Ok(me) } - pub(crate) fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::RMT, handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::RMT, handler.priority()) - .unwrap(); - } - } - #[cfg(not(any(esp32, esp32s2)))] fn configure_clock(&self, frequency: HertzU32) -> Result<(), Error> { let src_clock = crate::soc::constants::RMT_CLOCK_SRC_FREQ; @@ -265,7 +263,7 @@ where } } -impl<'d> Rmt<'d, crate::Blocking> { +impl<'d> Rmt<'d, Blocking> { /// Create a new RMT instance pub fn new( peripheral: impl Peripheral

+ 'd, @@ -273,34 +271,27 @@ impl<'d> Rmt<'d, crate::Blocking> { ) -> Result { Self::new_internal(peripheral, frequency) } + + /// Reconfigures the driver for asynchronous operation. + pub fn into_async(mut self) -> Rmt<'d, Async> { + self.set_interrupt_handler(async_interrupt_handler); + Rmt::create(self.peripheral) + } } -impl crate::private::Sealed for Rmt<'_, crate::Blocking> {} +impl crate::private::Sealed for Rmt<'_, Blocking> {} -impl InterruptConfigurable for Rmt<'_, crate::Blocking> { +impl InterruptConfigurable for Rmt<'_, Blocking> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { - self.internal_set_interrupt_handler(handler); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::RMT); + } + unsafe { crate::interrupt::bind_interrupt(Interrupt::RMT, handler.handler()) }; + unwrap!(crate::interrupt::enable(Interrupt::RMT, handler.priority())); } } -impl<'d> Rmt<'d, crate::Async> { - /// Create a new RMT instance - pub fn new_async( - peripheral: impl Peripheral

+ 'd, - frequency: HertzU32, - ) -> Result { - let mut this = Self::new_internal(peripheral, frequency)?; - this.internal_set_interrupt_handler(asynch::async_interrupt_handler); - Ok(this) - } -} - -fn configure_rx_channel< - 'd, - P: PeripheralInput, - T: private::RxChannelInternal, - M: crate::Mode, ->( +fn configure_rx_channel<'d, P: PeripheralInput, T: RxChannelInternal, M: crate::Mode>( pin: impl Peripheral

+ 'd, config: RxChannelConfig, ) -> Result { @@ -321,8 +312,8 @@ fn configure_rx_channel< } crate::into_mapped_ref!(pin); - pin.init_input(crate::gpio::Pull::None, crate::private::Internal); - pin.connect_input_to_peripheral(T::input_signal(), crate::private::Internal); + pin.init_input(crate::gpio::Pull::None, crate::Internal); + pin.connect_input_to_peripheral(T::input_signal(), crate::Internal); T::set_divider(config.clk_divider); T::set_carrier( @@ -337,18 +328,13 @@ fn configure_rx_channel< Ok(T::new()) } -fn configure_tx_channel< - 'd, - P: PeripheralOutput, - T: private::TxChannelInternal, - M: crate::Mode, ->( +fn configure_tx_channel<'d, P: PeripheralOutput, T: TxChannelInternal, M: crate::Mode>( pin: impl Peripheral

+ 'd, config: TxChannelConfig, ) -> Result { crate::into_mapped_ref!(pin); - pin.set_to_push_pull_output(crate::private::Internal); - pin.connect_peripheral_to_output(T::output_signal(), crate::private::Internal); + pin.set_to_push_pull_output(crate::Internal); + pin.connect_peripheral_to_output(T::output_signal(), crate::Internal); T::set_divider(config.clk_divider); T::set_carrier( @@ -455,7 +441,7 @@ where /// Wait for the transaction to complete pub fn wait(mut self) -> Result { loop { - if >::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } @@ -464,8 +450,8 @@ where } // wait for TX-THR - while !>::is_threshold_set() {} - >::reset_threshold_set(); + while !>::is_threshold_set() {} + >::reset_threshold_set(); // re-fill TX RAM let ram_index = (((self.index - constants::RMT_CHANNEL_RAM_SIZE) @@ -490,11 +476,11 @@ where } loop { - if >::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if >::is_done() { + if >::is_done() { break; } } @@ -517,15 +503,15 @@ where { /// Stop transaction when the current iteration ends. pub fn stop_next(self) -> Result { - >::set_continuous(false); - >::update(); + >::set_continuous(false); + >::update(); loop { - if >::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if >::is_done() { + if >::is_done() { break; } } @@ -535,8 +521,8 @@ where /// Stop transaction as soon as possible. pub fn stop(self) -> Result { - >::set_continuous(false); - >::update(); + >::set_continuous(false); + >::update(); let ptr = (constants::RMT_RAM_START + C::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) @@ -548,11 +534,11 @@ where } loop { - if >::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if >::is_done() { + if >::is_done() { break; } } @@ -562,13 +548,14 @@ where /// Check if the `loopcount` interrupt bit is set pub fn is_loopcount_interrupt_set(&self) -> bool { - >::is_loopcount_interrupt_set() + >::is_loopcount_interrupt_set() } } macro_rules! impl_tx_channel_creator { ($channel:literal) => { - impl<'d, P> $crate::rmt::TxChannelCreator<'d, $crate::rmt::Channel<$crate::Blocking, $channel>, P> + impl<'d, P> + $crate::rmt::TxChannelCreator<'d, $crate::rmt::Channel<$crate::Blocking, $channel>, P> for ChannelCreator<$crate::Blocking, $channel> where P: $crate::gpio::interconnect::PeripheralOutput, @@ -577,20 +564,22 @@ macro_rules! impl_tx_channel_creator { impl $crate::rmt::TxChannel for $crate::rmt::Channel<$crate::Blocking, $channel> {} - impl<'d, P> $crate::rmt::TxChannelCreatorAsync<'d, $crate::rmt::Channel<$crate::Async, $channel>, P> + impl<'d, P> + $crate::rmt::TxChannelCreatorAsync<'d, $crate::rmt::Channel<$crate::Async, $channel>, P> for ChannelCreator<$crate::Async, $channel> where P: $crate::gpio::interconnect::PeripheralOutput, { } - impl $crate::rmt::asynch::TxChannelAsync for $crate::rmt::Channel<$crate::Async, $channel> {} + impl $crate::rmt::TxChannelAsync for $crate::rmt::Channel<$crate::Async, $channel> {} }; } macro_rules! impl_rx_channel_creator { ($channel:literal) => { - impl<'d, P> $crate::rmt::RxChannelCreator<'d, $crate::rmt::Channel<$crate::Blocking, $channel>, P> + impl<'d, P> + $crate::rmt::RxChannelCreator<'d, $crate::rmt::Channel<$crate::Blocking, $channel>, P> for ChannelCreator<$crate::Blocking, $channel> where P: $crate::gpio::interconnect::PeripheralInput, @@ -599,14 +588,15 @@ macro_rules! impl_rx_channel_creator { impl $crate::rmt::RxChannel for $crate::rmt::Channel<$crate::Blocking, $channel> {} - impl<'d, P> $crate::rmt::RxChannelCreatorAsync<'d, $crate::rmt::Channel<$crate::Async, $channel>, P> - for ChannelCreator<$crate::Async, $channel> + impl<'d, P> + $crate::rmt::RxChannelCreatorAsync<'d, $crate::rmt::Channel<$crate::Async, $channel>, P> + for ChannelCreator<$crate::Async, $channel> where P: $crate::gpio::interconnect::PeripheralInput, { } - impl $crate::rmt::asynch::RxChannelAsync for $crate::rmt::Channel<$crate::Async, $channel> {} + impl $crate::rmt::RxChannelAsync for $crate::rmt::Channel<$crate::Async, $channel> {} }; } @@ -614,7 +604,6 @@ macro_rules! impl_rx_channel_creator { mod impl_for_chip { use core::marker::PhantomData; - use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance @@ -622,7 +611,7 @@ mod impl_for_chip { where M: crate::Mode, { - _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, + pub(super) peripheral: PeripheralRef<'d, crate::peripherals::RMT>, /// RMT Channel 0. pub channel0: ChannelCreator, /// RMT Channel 1. @@ -634,15 +623,17 @@ mod impl_for_chip { phantom: PhantomData, } - impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + impl<'d, M> Rmt<'d, M> where M: crate::Mode, { - fn create(peripheral: impl Peripheral

+ 'd) -> Self { + pub(super) fn create( + peripheral: impl Peripheral

+ 'd, + ) -> Self { crate::into_ref!(peripheral); Self { - _peripheral: peripheral, + peripheral, channel0: ChannelCreator { phantom: PhantomData, }, @@ -674,18 +665,17 @@ mod impl_for_chip { impl_rx_channel_creator!(2); impl_rx_channel_creator!(3); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_0, 0); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_1, 1); + super::chip_specific::impl_tx_channel!(RMT_SIG_0, 0); + super::chip_specific::impl_tx_channel!(RMT_SIG_1, 1); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_0, 2, 0); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_1, 3, 1); + super::chip_specific::impl_rx_channel!(RMT_SIG_0, 2, 0); + super::chip_specific::impl_rx_channel!(RMT_SIG_1, 3, 1); } #[cfg(esp32)] mod impl_for_chip { use core::marker::PhantomData; - use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance @@ -693,7 +683,7 @@ mod impl_for_chip { where M: crate::Mode, { - _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, + pub(super) peripheral: PeripheralRef<'d, crate::peripherals::RMT>, /// RMT Channel 0. pub channel0: ChannelCreator, /// RMT Channel 1. @@ -713,15 +703,17 @@ mod impl_for_chip { phantom: PhantomData, } - impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + impl<'d, M> Rmt<'d, M> where M: crate::Mode, { - fn create(peripheral: impl Peripheral

+ 'd) -> Self { + pub(super) fn create( + peripheral: impl Peripheral

+ 'd, + ) -> Self { crate::into_ref!(peripheral); Self { - _peripheral: peripheral, + peripheral, channel0: ChannelCreator { phantom: PhantomData, }, @@ -777,30 +769,29 @@ mod impl_for_chip { impl_rx_channel_creator!(6); impl_rx_channel_creator!(7); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_0, 0); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_1, 1); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_2, 2); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_3, 3); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_4, 4); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_5, 5); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_6, 6); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_7, 7); + super::chip_specific::impl_tx_channel!(RMT_SIG_0, 0); + super::chip_specific::impl_tx_channel!(RMT_SIG_1, 1); + super::chip_specific::impl_tx_channel!(RMT_SIG_2, 2); + super::chip_specific::impl_tx_channel!(RMT_SIG_3, 3); + super::chip_specific::impl_tx_channel!(RMT_SIG_4, 4); + super::chip_specific::impl_tx_channel!(RMT_SIG_5, 5); + super::chip_specific::impl_tx_channel!(RMT_SIG_6, 6); + super::chip_specific::impl_tx_channel!(RMT_SIG_7, 7); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_0, 0); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_1, 1); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_2, 2); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_3, 3); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_4, 4); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_5, 5); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_6, 6); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_7, 7); + super::chip_specific::impl_rx_channel!(RMT_SIG_0, 0); + super::chip_specific::impl_rx_channel!(RMT_SIG_1, 1); + super::chip_specific::impl_rx_channel!(RMT_SIG_2, 2); + super::chip_specific::impl_rx_channel!(RMT_SIG_3, 3); + super::chip_specific::impl_rx_channel!(RMT_SIG_4, 4); + super::chip_specific::impl_rx_channel!(RMT_SIG_5, 5); + super::chip_specific::impl_rx_channel!(RMT_SIG_6, 6); + super::chip_specific::impl_rx_channel!(RMT_SIG_7, 7); } #[cfg(esp32s2)] mod impl_for_chip { use core::marker::PhantomData; - use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance @@ -808,7 +799,7 @@ mod impl_for_chip { where M: crate::Mode, { - _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, + pub(super) peripheral: PeripheralRef<'d, crate::peripherals::RMT>, /// RMT Channel 0. pub channel0: ChannelCreator, /// RMT Channel 1. @@ -820,15 +811,17 @@ mod impl_for_chip { phantom: PhantomData, } - impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + impl<'d, M> Rmt<'d, M> where M: crate::Mode, { - fn create(peripheral: impl Peripheral

+ 'd) -> Self { + pub(super) fn create( + peripheral: impl Peripheral

+ 'd, + ) -> Self { crate::into_ref!(peripheral); Self { - _peripheral: peripheral, + peripheral, channel0: ChannelCreator { phantom: PhantomData, }, @@ -864,22 +857,21 @@ mod impl_for_chip { impl_rx_channel_creator!(2); impl_rx_channel_creator!(3); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_0, 0); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_1, 1); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_2, 2); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_3, 3); + super::chip_specific::impl_tx_channel!(RMT_SIG_0, 0); + super::chip_specific::impl_tx_channel!(RMT_SIG_1, 1); + super::chip_specific::impl_tx_channel!(RMT_SIG_2, 2); + super::chip_specific::impl_tx_channel!(RMT_SIG_3, 3); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_0, 0); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_1, 1); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_2, 2); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_3, 3); + super::chip_specific::impl_rx_channel!(RMT_SIG_0, 0); + super::chip_specific::impl_rx_channel!(RMT_SIG_1, 1); + super::chip_specific::impl_rx_channel!(RMT_SIG_2, 2); + super::chip_specific::impl_rx_channel!(RMT_SIG_3, 3); } #[cfg(esp32s3)] mod impl_for_chip { use core::marker::PhantomData; - use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance @@ -887,7 +879,7 @@ mod impl_for_chip { where M: crate::Mode, { - _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, + pub(super) peripheral: PeripheralRef<'d, crate::peripherals::RMT>, /// RMT Channel 0. pub channel0: ChannelCreator, /// RMT Channel 1. @@ -907,15 +899,17 @@ mod impl_for_chip { phantom: PhantomData, } - impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + impl<'d, M> Rmt<'d, M> where M: crate::Mode, { - fn create(peripheral: impl Peripheral

+ 'd) -> Self { + pub(super) fn create( + peripheral: impl Peripheral

+ 'd, + ) -> Self { crate::into_ref!(peripheral); Self { - _peripheral: peripheral, + peripheral, channel0: ChannelCreator { phantom: PhantomData, }, @@ -963,15 +957,15 @@ mod impl_for_chip { impl_rx_channel_creator!(6); impl_rx_channel_creator!(7); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_0, 0); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_1, 1); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_2, 2); - super::chip_specific::impl_tx_channel!(Channel, RMT_SIG_3, 3); + super::chip_specific::impl_tx_channel!(RMT_SIG_0, 0); + super::chip_specific::impl_tx_channel!(RMT_SIG_1, 1); + super::chip_specific::impl_tx_channel!(RMT_SIG_2, 2); + super::chip_specific::impl_tx_channel!(RMT_SIG_3, 3); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_0, 4, 0); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_1, 5, 1); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_2, 6, 2); - super::chip_specific::impl_rx_channel!(Channel, RMT_SIG_3, 7, 3); + super::chip_specific::impl_rx_channel!(RMT_SIG_0, 4, 0); + super::chip_specific::impl_rx_channel!(RMT_SIG_1, 5, 1); + super::chip_specific::impl_rx_channel!(RMT_SIG_2, 6, 2); + super::chip_specific::impl_rx_channel!(RMT_SIG_3, 7, 3); } /// RMT Channel @@ -985,7 +979,7 @@ where } /// Channel in TX mode -pub trait TxChannel: private::TxChannelInternal { +pub trait TxChannel: TxChannelInternal { /// Start transmitting the given pulse code sequence. /// This returns a [`SingleShotTxTransaction`] which can be used to wait for /// the transaction to complete and get back the channel for further @@ -1052,18 +1046,18 @@ where /// Wait for the transaction to complete pub fn wait(self) -> Result { loop { - if >::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if >::is_done() { + if >::is_done() { break; } } - >::stop(); - >::clear_interrupts(); - >::update(); + >::stop(); + >::clear_interrupts(); + >::update(); let ptr = (constants::RMT_RAM_START + C::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) @@ -1078,7 +1072,7 @@ where } /// Channel is RX mode -pub trait RxChannel: private::RxChannelInternal { +pub trait RxChannel: RxChannelInternal { /// Start receiving pulse codes into the given buffer. /// This returns a [RxTransaction] which can be used to wait for receive to /// complete and get back the channel for further use. @@ -1103,497 +1097,409 @@ pub trait RxChannel: private::RxChannelInternal { } } -/// Async functionality -pub mod asynch { - use core::{ - pin::Pin, - task::{Context, Poll}, - }; +#[cfg(any(esp32, esp32s3))] +const NUM_CHANNELS: usize = 8; +#[cfg(not(any(esp32, esp32s3)))] +const NUM_CHANNELS: usize = 4; - use embassy_sync::waitqueue::AtomicWaker; - use procmacros::handler; +static WAKER: [AtomicWaker; NUM_CHANNELS] = [const { AtomicWaker::new() }; NUM_CHANNELS]; - use super::{private::Event, *}; +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub(crate) struct RmtTxFuture +where + T: TxChannelAsync, +{ + _phantom: PhantomData, +} - #[cfg(any(esp32, esp32s3))] - const NUM_CHANNELS: usize = 8; - #[cfg(not(any(esp32, esp32s3)))] - const NUM_CHANNELS: usize = 4; - - static WAKER: [AtomicWaker; NUM_CHANNELS] = [const { AtomicWaker::new() }; NUM_CHANNELS]; - - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub(crate) struct RmtTxFuture - where - T: TxChannelAsync, - { - _phantom: PhantomData, - } - - impl RmtTxFuture - where - T: TxChannelAsync, - { - pub fn new(_instance: &T) -> Self { - Self { - _phantom: PhantomData, - } - } - } - - impl core::future::Future for RmtTxFuture - where - T: TxChannelAsync, - { - type Output = (); - - fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { - WAKER[T::CHANNEL as usize].register(ctx.waker()); - - if T::is_error() || T::is_done() { - Poll::Ready(()) - } else { - Poll::Pending - } - } - } - - /// TX channel in async mode - pub trait TxChannelAsync: private::TxChannelInternal { - /// Start transmitting the given pulse code sequence. - /// The length of sequence cannot exceed the size of the allocated RMT - /// RAM. - async fn transmit + Copy>(&mut self, data: &[T]) -> Result<(), Error> - where - Self: Sized, - { - if data.len() > constants::RMT_CHANNEL_RAM_SIZE { - return Err(Error::InvalidArgument); - } - - Self::clear_interrupts(); - Self::listen_interrupt(super::private::Event::End); - Self::listen_interrupt(super::private::Event::Error); - Self::send_raw(data, false, 0); - - RmtTxFuture::new(self).await; - - if Self::is_error() { - Err(Error::TransmissionError) - } else { - Ok(()) - } - } - } - - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub(crate) struct RmtRxFuture - where - T: RxChannelAsync, - { - _phantom: PhantomData, - } - - impl RmtRxFuture - where - T: RxChannelAsync, - { - pub fn new(_instance: &T) -> Self { - Self { - _phantom: PhantomData, - } - } - } - - impl core::future::Future for RmtRxFuture - where - T: RxChannelAsync, - { - type Output = (); - - fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { - WAKER[T::CHANNEL as usize].register(ctx.waker()); - if T::is_error() || T::is_done() { - Poll::Ready(()) - } else { - Poll::Pending - } - } - } - - /// RX channel in async mode - pub trait RxChannelAsync: private::RxChannelInternal { - /// Start receiving a pulse code sequence. - /// The length of sequence cannot exceed the size of the allocated RMT - /// RAM. - async fn receive + Copy>(&mut self, data: &mut [T]) -> Result<(), Error> - where - Self: Sized, - { - if data.len() > constants::RMT_CHANNEL_RAM_SIZE { - return Err(Error::InvalidArgument); - } - - Self::clear_interrupts(); - Self::listen_interrupt(super::private::Event::End); - Self::listen_interrupt(super::private::Event::Error); - Self::start_receive_raw(); - - RmtRxFuture::new(self).await; - - if Self::is_error() { - Err(Error::TransmissionError) - } else { - Self::stop(); - Self::clear_interrupts(); - Self::update(); - - let ptr = (constants::RMT_RAM_START - + Self::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) - as *mut u32; - let len = data.len(); - for (idx, entry) in data.iter_mut().take(len).enumerate() { - *entry = unsafe { ptr.add(idx).read_volatile().into() }; - } - - Ok(()) - } - } - } - - #[cfg(not(any(esp32, esp32s2)))] - #[handler] - pub(super) fn async_interrupt_handler() { - if let Some(channel) = super::chip_specific::pending_interrupt_for_channel() { - use crate::rmt::private::{RxChannelInternal, TxChannelInternal}; - - match channel { - 0 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - 1 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - 2 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - 3 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - - #[cfg(any(esp32, esp32s3))] - 4 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - #[cfg(any(esp32, esp32s3))] - 5 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - #[cfg(any(esp32, esp32s3))] - 6 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - #[cfg(any(esp32, esp32s3))] - 7 => { - super::Channel::::unlisten_interrupt(Event::End); - super::Channel::::unlisten_interrupt(Event::Error); - } - - _ => unreachable!(), - } - - WAKER[channel].wake(); - } - } - - #[cfg(any(esp32, esp32s2))] - #[handler] - pub(super) fn async_interrupt_handler() { - if let Some(channel) = super::chip_specific::pending_interrupt_for_channel() { - match channel { - 0 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - 1 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - 2 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - 3 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - #[cfg(esp32)] - 4 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - #[cfg(any(esp32, esp32s3))] - 5 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - #[cfg(any(esp32, esp32s3))] - 6 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - #[cfg(any(esp32, esp32s3))] - 7 => { - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::TxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::End, - ); - as super::private::RxChannelInternal>::unlisten_interrupt( - Event::Error, - ); - } - - _ => unreachable!(), - } - - WAKER[channel].wake(); +impl RmtTxFuture +where + T: TxChannelAsync, +{ + pub fn new(_instance: &T) -> Self { + Self { + _phantom: PhantomData, } } } -mod private { - use crate::{peripheral::Peripheral, soc::constants}; +impl core::future::Future for RmtTxFuture +where + T: TxChannelAsync, +{ + type Output = (); - pub enum Event { - Error, - Threshold, - End, + fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { + WAKER[T::CHANNEL as usize].register(ctx.waker()); + + if T::is_error() || T::is_done() { + Poll::Ready(()) + } else { + Poll::Pending + } } +} - pub trait CreateInstance<'d> { - fn create(peripheral: impl Peripheral

+ 'd) -> Self; - } - - pub trait TxChannelInternal +/// TX channel in async mode +pub trait TxChannelAsync: TxChannelInternal { + /// Start transmitting the given pulse code sequence. + /// The length of sequence cannot exceed the size of the allocated RMT + /// RAM. + async fn transmit<'a, T: Into + Copy>(&mut self, data: &'a [T]) -> Result<(), Error> where - M: crate::Mode, + Self: Sized, { - const CHANNEL: u8; + if data.len() > constants::RMT_CHANNEL_RAM_SIZE { + return Err(Error::InvalidArgument); + } - fn new() -> Self; + Self::clear_interrupts(); + Self::listen_interrupt(Event::End); + Self::listen_interrupt(Event::Error); + Self::send_raw(data, false, 0); - fn output_signal() -> crate::gpio::OutputSignal; + RmtTxFuture::new(self).await; - fn set_divider(divider: u8); + if Self::is_error() { + Err(Error::TransmissionError) + } else { + Ok(()) + } + } +} - fn update(); +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub(crate) struct RmtRxFuture +where + T: RxChannelAsync, +{ + _phantom: PhantomData, +} - fn set_generate_repeat_interrupt(repeats: u16); +impl RmtRxFuture +where + T: RxChannelAsync, +{ + pub fn new(_instance: &T) -> Self { + Self { + _phantom: PhantomData, + } + } +} - fn clear_interrupts(); +impl core::future::Future for RmtRxFuture +where + T: RxChannelAsync, +{ + type Output = (); - fn set_continuous(continuous: bool); + fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { + WAKER[T::CHANNEL as usize].register(ctx.waker()); + if T::is_error() || T::is_done() { + Poll::Ready(()) + } else { + Poll::Pending + } + } +} - fn set_wrap_mode(wrap: bool); +/// RX channel in async mode +pub trait RxChannelAsync: RxChannelInternal { + /// Start receiving a pulse code sequence. + /// The length of sequence cannot exceed the size of the allocated RMT + /// RAM. + async fn receive<'a, T: From + Copy>(&mut self, data: &'a mut [T]) -> Result<(), Error> + where + Self: Sized, + { + if data.len() > constants::RMT_CHANNEL_RAM_SIZE { + return Err(Error::InvalidArgument); + } - fn set_carrier(carrier: bool, high: u16, low: u16, level: bool); + Self::clear_interrupts(); + Self::listen_interrupt(Event::End); + Self::listen_interrupt(Event::Error); + Self::start_receive_raw(); - fn set_idle_output(enable: bool, level: bool); + RmtRxFuture::new(self).await; - fn set_memsize(memsize: u8); - - fn start_tx(); - - fn is_done() -> bool; - - fn is_error() -> bool; - - fn is_threshold_set() -> bool; - - fn reset_threshold_set(); - - fn set_threshold(threshold: u8); - - fn is_loopcount_interrupt_set() -> bool; - - fn send_raw + Copy>(data: &[T], continuous: bool, repeat: u16) -> usize { + if Self::is_error() { + Err(Error::TransmissionError) + } else { + Self::stop(); Self::clear_interrupts(); + Self::update(); let ptr = (constants::RMT_RAM_START + Self::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) as *mut u32; - for (idx, entry) in data - .iter() - .take(constants::RMT_CHANNEL_RAM_SIZE) - .enumerate() - { - unsafe { - ptr.add(idx).write_volatile((*entry).into()); - } + let len = data.len(); + for (idx, entry) in data.iter_mut().take(len).enumerate() { + *entry = unsafe { ptr.add(idx).read_volatile().into() }; } - Self::set_threshold((constants::RMT_CHANNEL_RAM_SIZE / 2) as u8); - Self::set_continuous(continuous); - Self::set_generate_repeat_interrupt(repeat); - Self::set_wrap_mode(true); - Self::set_memsize(1); - Self::update(); - Self::start_tx(); - Self::update(); + Ok(()) + } + } +} - if data.len() >= constants::RMT_CHANNEL_RAM_SIZE { - constants::RMT_CHANNEL_RAM_SIZE - } else { - data.len() +#[cfg(not(any(esp32, esp32s2)))] +#[handler] +fn async_interrupt_handler() { + let Some(channel) = chip_specific::pending_interrupt_for_channel() else { + return; + }; + match channel { + 0 => Channel::::unlisten_interrupt(Event::End | Event::Error), + 1 => Channel::::unlisten_interrupt(Event::End | Event::Error), + 2 => Channel::::unlisten_interrupt(Event::End | Event::Error), + 3 => Channel::::unlisten_interrupt(Event::End | Event::Error), + + #[cfg(any(esp32, esp32s3))] + 4 => Channel::::unlisten_interrupt(Event::End | Event::Error), + #[cfg(any(esp32, esp32s3))] + 5 => Channel::::unlisten_interrupt(Event::End | Event::Error), + #[cfg(any(esp32, esp32s3))] + 6 => Channel::::unlisten_interrupt(Event::End | Event::Error), + #[cfg(any(esp32, esp32s3))] + 7 => Channel::::unlisten_interrupt(Event::End | Event::Error), + + _ => unreachable!(), + } + + WAKER[channel].wake(); +} + +#[cfg(any(esp32, esp32s2))] +#[handler] +fn async_interrupt_handler() { + let Some(channel) = chip_specific::pending_interrupt_for_channel() else { + return; + }; + match channel { + 0 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + 1 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + 2 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + 3 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + #[cfg(esp32)] + 4 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + #[cfg(any(esp32, esp32s3))] + 5 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + #[cfg(any(esp32, esp32s3))] + 6 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + #[cfg(any(esp32, esp32s3))] + 7 => { + as TxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + as RxChannelInternal>::unlisten_interrupt( + Event::End | Event::Error, + ); + } + + _ => unreachable!(), + } + + WAKER[channel].wake(); +} + +#[derive(Debug, EnumSetType)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[doc(hidden)] +pub enum Event { + Error, + Threshold, + End, +} + +#[doc(hidden)] +pub trait TxChannelInternal +where + M: crate::Mode, +{ + const CHANNEL: u8; + + fn new() -> Self; + + fn output_signal() -> crate::gpio::OutputSignal; + + fn set_divider(divider: u8); + + fn update(); + + fn set_generate_repeat_interrupt(repeats: u16); + + fn clear_interrupts(); + + fn set_continuous(continuous: bool); + + fn set_wrap_mode(wrap: bool); + + fn set_carrier(carrier: bool, high: u16, low: u16, level: bool); + + fn set_idle_output(enable: bool, level: bool); + + fn set_memsize(memsize: u8); + + fn start_tx(); + + fn is_done() -> bool; + + fn is_error() -> bool; + + fn is_threshold_set() -> bool; + + fn reset_threshold_set(); + + fn set_threshold(threshold: u8); + + fn is_loopcount_interrupt_set() -> bool; + + fn send_raw + Copy>(data: &[T], continuous: bool, repeat: u16) -> usize { + Self::clear_interrupts(); + + let ptr = (constants::RMT_RAM_START + + Self::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) + as *mut u32; + for (idx, entry) in data + .iter() + .take(constants::RMT_CHANNEL_RAM_SIZE) + .enumerate() + { + unsafe { + ptr.add(idx).write_volatile((*entry).into()); } } - fn stop(); + Self::set_threshold((constants::RMT_CHANNEL_RAM_SIZE / 2) as u8); + Self::set_continuous(continuous); + Self::set_generate_repeat_interrupt(repeat); + Self::set_wrap_mode(true); + Self::set_memsize(1); + Self::update(); + Self::start_tx(); + Self::update(); - fn enable_listen_interrupt(event: Event, enable: bool); - - fn listen_interrupt(event: Event) { - Self::enable_listen_interrupt(event, true); - } - - fn unlisten_interrupt(event: Event) { - Self::enable_listen_interrupt(event, false); + if data.len() >= constants::RMT_CHANNEL_RAM_SIZE { + constants::RMT_CHANNEL_RAM_SIZE + } else { + data.len() } } - pub trait RxChannelInternal - where - M: crate::Mode, - { - const CHANNEL: u8; + fn stop(); - fn new() -> Self; + fn enable_listen_interrupt(event: EnumSet, enable: bool); - fn input_signal() -> crate::gpio::InputSignal; + fn listen_interrupt(event: impl Into>) { + Self::enable_listen_interrupt(event.into(), true); + } - fn set_divider(divider: u8); + fn unlisten_interrupt(event: impl Into>) { + Self::enable_listen_interrupt(event.into(), false); + } +} - fn update(); +#[doc(hidden)] +pub trait RxChannelInternal +where + M: crate::Mode, +{ + const CHANNEL: u8; - fn clear_interrupts(); + fn new() -> Self; - fn set_wrap_mode(wrap: bool); + fn input_signal() -> crate::gpio::InputSignal; - fn set_carrier(carrier: bool, high: u16, low: u16, level: bool); + fn set_divider(divider: u8); - fn set_memsize(memsize: u8); + fn update(); - fn start_rx(); + fn clear_interrupts(); - fn is_done() -> bool; + fn set_wrap_mode(wrap: bool); - fn is_error() -> bool; + fn set_carrier(carrier: bool, high: u16, low: u16, level: bool); - fn start_receive_raw() { - Self::clear_interrupts(); - Self::set_wrap_mode(false); - Self::set_memsize(1); - Self::start_rx(); - Self::update(); - } + fn set_memsize(memsize: u8); - fn stop(); + fn start_rx(); - fn set_filter_threshold(value: u8); + fn is_done() -> bool; - fn set_idle_threshold(value: u16); + fn is_error() -> bool; - fn enable_listen_interrupt(event: Event, enable: bool); + fn start_receive_raw() { + Self::clear_interrupts(); + Self::set_wrap_mode(false); + Self::set_memsize(1); + Self::start_rx(); + Self::update(); + } - fn listen_interrupt(event: Event) { - Self::enable_listen_interrupt(event, true); - } + fn stop(); - fn unlisten_interrupt(event: Event) { - Self::enable_listen_interrupt(event, false); - } + fn set_filter_threshold(value: u8); + + fn set_idle_threshold(value: u16); + + fn enable_listen_interrupt(event: EnumSet, enable: bool); + + fn listen_interrupt(event: impl Into>) { + Self::enable_listen_interrupt(event.into(), true); + } + + fn unlisten_interrupt(event: impl Into>) { + Self::enable_listen_interrupt(event.into(), false); } } @@ -1681,9 +1587,9 @@ mod chip_specific { } macro_rules! impl_tx_channel { - ($channel:ident, $signal:ident, $ch_num:literal) => { + ($signal:ident, $ch_num:literal) => { paste::paste! { - impl $crate::rmt::private::TxChannelInternal for $crate::rmt::$channel where M: $crate::Mode { + impl $crate::rmt::TxChannelInternal for $crate::rmt::Channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { @@ -1823,19 +1729,15 @@ mod chip_specific { Self::update(); } - fn enable_listen_interrupt(event: $crate::rmt::private::Event, enable: bool) { + fn enable_listen_interrupt(events: enumset::EnumSet<$crate::rmt::Event>, enable: bool) { let rmt = unsafe { &*crate::peripherals::RMT::PTR }; rmt.int_ena().modify(|_, w| { - match event { - $crate::rmt::private::Event::Error => { - w.[< ch $ch_num _tx_err >]().bit(enable); - } - $crate::rmt::private::Event::End => { - w.[< ch $ch_num _tx_end >]().bit(enable); - } - $crate::rmt::private::Event::Threshold => { - w.[< ch $ch_num _tx_thr_event >]().bit(enable); - } + for event in events { + match event { + $crate::rmt::Event::Error => w.[< ch $ch_num _tx_err >]().bit(enable), + $crate::rmt::Event::End => w.[< ch $ch_num _tx_end >]().bit(enable), + $crate::rmt::Event::Threshold => w.[< ch $ch_num _tx_thr_event >]().bit(enable), + }; } w }); @@ -1846,9 +1748,9 @@ mod chip_specific { } macro_rules! impl_rx_channel { - ($channel:ident, $signal:ident, $ch_num:literal, $ch_index:literal) => { + ($signal:ident, $ch_num:literal, $ch_index:literal) => { paste::paste! { - impl $crate::rmt::private::RxChannelInternal for $crate::rmt::$channel where M: $crate::Mode { + impl $crate::rmt::RxChannelInternal for $crate::rmt::Channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { @@ -1943,19 +1845,15 @@ mod chip_specific { rmt.[< ch $ch_num _rx_conf0 >]().modify(|_, w| unsafe { w.idle_thres().bits(value) }); } - fn enable_listen_interrupt(event: $crate::rmt::private::Event, enable: bool) { + fn enable_listen_interrupt(events: enumset::EnumSet<$crate::rmt::Event>, enable: bool) { let rmt = unsafe { &*crate::peripherals::RMT::PTR }; rmt.int_ena().modify(|_, w| { - match event { - $crate::rmt::private::Event::Error => { - w.[< ch $ch_num _rx_err >]().bit(enable); - } - $crate::rmt::private::Event::End => { - w.[< ch $ch_num _rx_end >]().bit(enable); - } - $crate::rmt::private::Event::Threshold => { - w.[< ch $ch_num _rx_thr_event >]().bit(enable); - } + for event in events { + match event { + $crate::rmt::Event::Error => w.[< ch $ch_num _rx_err >]().bit(enable), + $crate::rmt::Event::End => w.[< ch $ch_num _rx_end >]().bit(enable), + $crate::rmt::Event::Threshold => w.[< ch $ch_num _rx_thr_event >]().bit(enable), + }; } w }); @@ -2039,9 +1937,9 @@ mod chip_specific { } macro_rules! impl_tx_channel { - ($channel:ident, $signal:ident, $ch_num:literal) => { + ($signal:ident, $ch_num:literal) => { paste::paste! { - impl super::private::TxChannelInternal for super::$channel where M: $crate::Mode { + impl super::TxChannelInternal for $crate::rmt::Channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { @@ -2171,40 +2069,28 @@ mod chip_specific { } } - fn enable_listen_interrupt(event: $crate::rmt::private::Event, enable: bool) { + fn enable_listen_interrupt(events: enumset::EnumSet<$crate::rmt::Event>, enable: bool) { let rmt = unsafe { &*crate::peripherals::RMT::PTR }; rmt.int_ena().modify(|_,w| { - match event { - $crate::rmt::private::Event::Error => { - w.[< ch $ch_num _err >]().bit(enable) - } - $crate::rmt::private::Event::End => { - w.[< ch $ch_num _tx_end >]().bit(enable) - } - $crate::rmt::private::Event::Threshold => { - w.[< ch $ch_num _tx_thr_event >]().bit(enable) - } - }; + for event in events { + match event { + $crate::rmt::Event::Error => w.[< ch $ch_num _err >]().bit(enable), + $crate::rmt::Event::End => w.[< ch $ch_num _tx_end >]().bit(enable), + $crate::rmt::Event::Threshold => w.[< ch $ch_num _tx_thr_event >]().bit(enable), + }; + } w }); } - - fn listen_interrupt(event: $crate::rmt::private::Event) { - Self::enable_listen_interrupt(event, true) - } - - fn unlisten_interrupt(event: $crate::rmt::private::Event) { - Self::enable_listen_interrupt(event, false) - } } } } } macro_rules! impl_rx_channel { - ($channel:ident, $signal:ident, $ch_num:literal) => { + ($signal:ident, $ch_num:literal) => { paste::paste! { - impl super::private::RxChannelInternal for super::$channel where M: $crate::Mode { + impl super::RxChannelInternal for $crate::rmt::Channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { @@ -2304,31 +2190,19 @@ mod chip_specific { rmt.[< ch $ch_num conf0 >]().modify(|_, w| unsafe { w.idle_thres().bits(value) }); } - fn enable_listen_interrupt(event: $crate::rmt::private::Event, enable: bool) { + fn enable_listen_interrupt(events: enumset::EnumSet<$crate::rmt::Event>, enable: bool) { let rmt = unsafe { &*crate::peripherals::RMT::PTR }; rmt.int_ena().modify(|_, w| { - match event { - $crate::rmt::private::Event::Error => { - w.[< ch $ch_num _err >]().bit(enable) - } - $crate::rmt::private::Event::End => { - w.[< ch $ch_num _rx_end >]().bit(enable) - } - $crate::rmt::private::Event::Threshold => { - w.[< ch $ch_num _tx_thr_event >]().bit(enable) - } - }; + for event in events { + match event { + $crate::rmt::Event::Error => w.[< ch $ch_num _err >]().bit(enable), + $crate::rmt::Event::End => w.[< ch $ch_num _rx_end >]().bit(enable), + $crate::rmt::Event::Threshold => w.[< ch $ch_num _tx_thr_event >]().bit(enable), + }; + } w }); } - - fn listen_interrupt(event: $crate::rmt::private::Event) { - Self::enable_listen_interrupt(event, true) - } - - fn unlisten_interrupt(event: $crate::rmt::private::Event) { - Self::enable_listen_interrupt(event, false) - } } } } diff --git a/esp-hal/src/rsa/mod.rs b/esp-hal/src/rsa/mod.rs index a92c6bb51..cde24f4e8 100644 --- a/esp-hal/src/rsa/mod.rs +++ b/esp-hal/src/rsa/mod.rs @@ -26,8 +26,11 @@ use core::{marker::PhantomData, ptr::copy_nonoverlapping}; use crate::{ interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, - peripherals::RSA, + peripherals::{Interrupt, RSA}, system::{Peripheral as PeripheralEnable, PeripheralClockControl}, + Async, + Blocking, + Cpu, InterruptConfigurable, }; @@ -47,29 +50,44 @@ pub struct Rsa<'d, DM: crate::Mode> { phantom: PhantomData, } -impl<'d> Rsa<'d, crate::Blocking> { +impl<'d> Rsa<'d, Blocking> { /// Create a new instance in [crate::Blocking] mode. /// /// Optionally an interrupt handler can be bound. pub fn new(rsa: impl Peripheral

+ 'd) -> Self { Self::new_internal(rsa) } -} -impl crate::private::Sealed for Rsa<'_, crate::Blocking> {} - -impl InterruptConfigurable for Rsa<'_, crate::Blocking> { - fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - self.internal_set_interrupt_handler(handler); + /// Reconfigures the RSA driver to operate in asynchronous mode. + pub fn into_async(mut self) -> Rsa<'d, Async> { + self.set_interrupt_handler(asynch::rsa_interrupt_handler); + Rsa { + 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. - pub fn new_async(rsa: impl Peripheral

+ 'd) -> Self { - let mut this = Self::new_internal(rsa); - this.internal_set_interrupt_handler(asynch::rsa_interrupt_handler); - this + pub fn into_blocking(self) -> Rsa<'d, Blocking> { + crate::interrupt::disable(Cpu::current(), Interrupt::RSA); + Rsa { + 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) { while !self.is_idle() {} self.clear_interrupt(); diff --git a/esp-hal/src/rtc_cntl/mod.rs b/esp-hal/src/rtc_cntl/mod.rs index 140e9c42c..987f687cb 100644 --- a/esp-hal/src/rtc_cntl/mod.rs +++ b/esp-hal/src/rtc_cntl/mod.rs @@ -434,23 +434,18 @@ impl crate::private::Sealed for Rtc<'_> {} impl InterruptConfigurable for Rtc<'_> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - interrupt::bind_interrupt( - #[cfg(any(esp32c6, esp32h2))] - Interrupt::LP_WDT, - #[cfg(not(any(esp32c6, esp32h2)))] - 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(); + cfg_if::cfg_if! { + if #[cfg(any(esp32c6, esp32h2))] { + let interrupt = Interrupt::LP_WDT; + } else { + let interrupt = Interrupt::RTC_CORE; + } } + for core in crate::Cpu::other() { + crate::interrupt::disable(core, interrupt); + } + unsafe { interrupt::bind_interrupt(interrupt, handler.handler()) }; + unwrap!(interrupt::enable(interrupt, handler.priority())); } } diff --git a/esp-hal/src/sha.rs b/esp-hal/src/sha.rs index b230f3b17..48e852276 100644 --- a/esp-hal/src/sha.rs +++ b/esp-hal/src/sha.rs @@ -62,6 +62,8 @@ use core::{borrow::BorrowMut, convert::Infallible, marker::PhantomData, mem::siz #[cfg(feature = "digest")] pub use digest::Digest; +#[cfg(not(esp32))] +use crate::peripherals::Interrupt; use crate::{ peripheral::{Peripheral, PeripheralRef}, peripherals::SHA, @@ -103,11 +105,11 @@ impl crate::private::Sealed for Sha<'_> {} #[cfg(not(esp32))] impl crate::InterruptConfigurable for Sha<'_> { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::SHA, handler.handler()); - crate::interrupt::enable(crate::peripherals::Interrupt::SHA, handler.priority()) - .unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, Interrupt::SHA); } + unsafe { crate::interrupt::bind_interrupt(Interrupt::SHA, handler.handler()) }; + unwrap!(crate::interrupt::enable(Interrupt::SHA, handler.priority())); } } diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 3e54ad3dd..cd906e3fa 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -61,6 +61,8 @@ //! [`embedded-hal-bus`]: https://docs.rs/embedded-hal-bus/latest/embedded_hal_bus/spi/index.html //! [`embassy-embedded-hal`]: https://docs.embassy.dev/embassy-embedded-hal/git/default/shared_bus/index.html +use core::marker::PhantomData; + pub use dma::*; #[cfg(gdma)] use enumset::EnumSet; @@ -73,7 +75,16 @@ use procmacros::ram; use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode}; use crate::{ clock::Clocks, - dma::{DmaChannelConvert, DmaEligible, DmaRxBuffer, DmaTxBuffer, PeripheralMarker, Rx, Tx}, + dma::{ + Channel, + DmaChannelConvert, + DmaEligible, + DmaRxBuffer, + DmaTxBuffer, + PeripheralMarker, + Rx, + Tx, + }, gpio::{ interconnect::{OutputConnection, PeripheralOutput}, InputSignal, @@ -86,6 +97,8 @@ use crate::{ private, spi::AnySpi, system::PeripheralClockControl, + Async, + Blocking, Mode, }; @@ -423,12 +436,14 @@ impl Address { } /// SPI peripheral driver -pub struct Spi<'d, T = AnySpi> { +pub struct Spi<'d, M, T = AnySpi> { spi: PeripheralRef<'d, T>, + _mode: PhantomData, } -impl<'d, T> Spi<'d, T> +impl<'d, M, T> Spi<'d, M, T> where + M: Mode, T: InstanceDma, { /// 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 /// and returns an instance of `SpiDma` that supports DMA /// operations. - pub fn with_dma( - self, - channel: crate::dma::Channel<'d, CH, DmaMode>, - ) -> SpiDma<'d, DmaMode, T> + pub fn with_dma(self, channel: Channel<'d, CH, DM>) -> SpiDma<'d, M, T> where CH: DmaChannelConvert, - DmaMode: Mode, + DM: Mode, + Channel<'d, CH, M>: From>, { - SpiDma::new(self.spi, channel) + SpiDma::new(self.spi, channel.into()) } } -impl Spi<'_, T> +impl Spi<'_, M, T> where T: Instance, { @@ -484,18 +497,36 @@ where } } -impl<'d> Spi<'d> { +impl<'d> Spi<'d, Blocking> { /// Constructs an SPI instance in 8bit dataframe mode. pub fn new( spi: impl Peripheral

+ 'd, frequency: HertzU32, mode: SpiMode, - ) -> Spi<'d> { + ) -> Spi<'d, Blocking> { 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 T: Instance, { @@ -504,10 +535,13 @@ where spi: impl Peripheral

+ 'd, frequency: HertzU32, mode: SpiMode, - ) -> Spi<'d, T> { + ) -> Spi<'d, M, T> { crate::into_ref!(spi); - let mut spi = Spi { spi }; + let mut spi = Spi { + spi, + _mode: PhantomData, + }; spi.spi.reset_peripheral(); spi.spi.enable_peripheral(); spi.spi.setup(frequency); @@ -616,7 +650,7 @@ where } } -impl<'d, T> Spi<'d, T> +impl<'d, M, T> Spi<'d, M, T> where T: QspiInstance, { @@ -663,7 +697,7 @@ where } } -impl Spi<'_, T> +impl Spi<'_, M, T> where T: Instance, { @@ -754,7 +788,7 @@ where } } -impl embedded_hal_02::spi::FullDuplex for Spi<'_, T> +impl embedded_hal_02::spi::FullDuplex for Spi<'_, M, T> where T: Instance, { @@ -769,7 +803,7 @@ where } } -impl embedded_hal_02::blocking::spi::Transfer for Spi<'_, T> +impl embedded_hal_02::blocking::spi::Transfer for Spi<'_, M, T> where T: Instance, { @@ -780,7 +814,7 @@ where } } -impl embedded_hal_02::blocking::spi::Write for Spi<'_, T> +impl embedded_hal_02::blocking::spi::Write for Spi<'_, M, T> where T: Instance, { @@ -812,9 +846,7 @@ mod dma { Rx, Tx, }, - Blocking, InterruptConfigurable, - Mode, }; /// A DMA capable SPI instance. @@ -837,6 +869,40 @@ mod dma { 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))] unsafe impl<'d, M, T> Send for SpiDma<'d, M, T> where @@ -868,6 +934,9 @@ mod dma { /// Interrupts are not enabled at the peripheral level here. fn set_interrupt_handler(&mut self, handler: InterruptHandler) { let interrupt = self.spi.interrupt(); + 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())); } @@ -1180,7 +1249,7 @@ mod dma { } } - impl SpiDmaTransfer<'_, crate::Async, Buf, T> + impl SpiDmaTransfer<'_, Async, Buf, T> where T: InstanceDma, { @@ -1460,6 +1529,34 @@ mod dma { 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> where T: InstanceDma, @@ -1699,7 +1796,7 @@ mod dma { } } - impl embedded_hal_02::blocking::spi::Transfer for SpiDmaBus<'_, crate::Blocking, T> + impl embedded_hal_02::blocking::spi::Transfer for SpiDmaBus<'_, Blocking, T> where T: InstanceDma, { @@ -1711,7 +1808,7 @@ mod dma { } } - impl embedded_hal_02::blocking::spi::Write for SpiDmaBus<'_, crate::Blocking, T> + impl embedded_hal_02::blocking::spi::Write for SpiDmaBus<'_, Blocking, T> where T: InstanceDma, { @@ -1731,6 +1828,7 @@ mod dma { }; use super::*; + use crate::Async; struct DropGuard { inner: ManuallyDrop, @@ -1770,7 +1868,7 @@ mod dma { } } - impl SpiDmaBus<'_, crate::Async, T> + impl SpiDmaBus<'_, Async, T> where T: InstanceDma, { @@ -1884,7 +1982,7 @@ mod dma { } } - impl embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, crate::Async, T> + impl embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, Async, T> where T: InstanceDma, { @@ -1959,11 +2057,11 @@ mod ehal1 { use super::*; - impl embedded_hal::spi::ErrorType for Spi<'_, T> { + impl embedded_hal::spi::ErrorType for Spi<'_, M, T> { type Error = Error; } - impl FullDuplex for Spi<'_, T> + impl FullDuplex for Spi<'_, M, T> where T: Instance, { @@ -1976,7 +2074,7 @@ mod ehal1 { } } - impl SpiBus for Spi<'_, T> + impl SpiBus for Spi<'_, M, T> where T: Instance, { diff --git a/esp-hal/src/spi/slave.rs b/esp-hal/src/spi/slave.rs index 0447c1870..8bea967bd 100644 --- a/esp-hal/src/spi/slave.rs +++ b/esp-hal/src/spi/slave.rs @@ -70,6 +70,8 @@ //! //! See [tracking issue](https://github.com/esp-rs/esp-hal/issues/469) for more information. +use core::marker::PhantomData; + use super::{Error, SpiMode}; use crate::{ dma::{DescriptorChain, DmaChannelConvert, DmaEligible, PeripheralMarker, Rx, Tx}, @@ -83,6 +85,7 @@ use crate::{ private, spi::AnySpi, system::PeripheralClockControl, + Blocking, }; const MAX_DMA_SIZE: usize = 32768 - 32; @@ -90,13 +93,14 @@ const MAX_DMA_SIZE: usize = 32768 - 32; /// SPI peripheral driver. /// /// See the [module-level documentation][self] for more details. -pub struct Spi<'d, T = AnySpi> { +pub struct Spi<'d, M, T = AnySpi> { spi: PeripheralRef<'d, T>, #[allow(dead_code)] data_mode: SpiMode, + _mode: PhantomData, } -impl<'d> Spi<'d> { +impl<'d> Spi<'d, Blocking> { /// Constructs an SPI instance in 8bit dataframe mode. pub fn new< SCK: PeripheralInput, @@ -110,12 +114,12 @@ impl<'d> Spi<'d> { miso: impl Peripheral

+ 'd, cs: impl Peripheral

+ 'd, mode: SpiMode, - ) -> Spi<'d> { + ) -> Spi<'d, Blocking> { 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 T: Instance, { @@ -132,7 +136,7 @@ where miso: impl Peripheral

+ 'd, cs: impl Peripheral

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

+ 'd, mode: SpiMode) -> Spi<'d, T> { + pub(crate) fn new_internal(spi: impl Peripheral

+ 'd, mode: SpiMode) -> Spi<'d, M, T> { crate::into_ref!(spi); let mut spi = Spi { spi, data_mode: mode, + _mode: PhantomData, }; PeripheralClockControl::reset(spi.spi.peripheral()); @@ -193,36 +198,38 @@ pub mod dma { Mode, }; - impl<'d, T> Spi<'d, T> + impl<'d, M, T> Spi<'d, M, T> where T: InstanceDma, + M: Mode, { /// Configures the SPI3 peripheral with the provided DMA channel and /// descriptors. #[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")] - pub fn with_dma( + pub fn with_dma( mut self, - channel: Channel<'d, CH, DmaMode>, + channel: Channel<'d, CH, DM>, rx_descriptors: &'static mut [DmaDescriptor], tx_descriptors: &'static mut [DmaDescriptor], - ) -> SpiDma<'d, DmaMode, T> + ) -> SpiDma<'d, M, T> where CH: DmaChannelConvert, - DmaMode: Mode, + DM: Mode, + Channel<'d, CH, M>: From>, { 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. - pub struct SpiDma<'d, DmaMode, T = AnySpi> + pub struct SpiDma<'d, M, T = AnySpi> where T: InstanceDma, - DmaMode: Mode, + M: Mode, { 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, tx_chain: DescriptorChain, } diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index de70e909e..2a666c652 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -549,6 +549,10 @@ pub trait Comparator { _ => unreachable!(), }; + for core in crate::Cpu::other() { + crate::interrupt::disable(core, interrupt); + } + #[cfg(not(esp32s2))] unsafe { interrupt::bind_interrupt(interrupt, handler.handler()); diff --git a/esp-hal/src/timer/timg.rs b/esp-hal/src/timer/timg.rs index 1409e1620..60f4a4bc1 100644 --- a/esp-hal/src/timer/timg.rs +++ b/esp-hal/src/timer/timg.rs @@ -553,10 +553,11 @@ where _ => unreachable!(), }; - unsafe { - interrupt::bind_interrupt(interrupt, handler.handler()); + for core in crate::Cpu::other() { + 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 { diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index 12f3ffd4e..b1db036b1 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -840,10 +840,15 @@ where } fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) { - unsafe { - crate::interrupt::bind_interrupt(self.twai.interrupt(), handler.handler()); - crate::interrupt::enable(self.twai.interrupt(), handler.priority()).unwrap(); + for core in crate::Cpu::other() { + crate::interrupt::disable(core, self.twai.interrupt()); } + 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. @@ -1027,17 +1032,6 @@ where 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> { @@ -1101,35 +1095,15 @@ where ) -> Self { Self::new_internal(peripheral, rx_pin, tx_pin, baud_rate, true, mode) } -} -impl<'d> TwaiConfiguration<'d, Async> { - /// Create a new instance of [TwaiConfiguration] - /// - /// You will need to use a transceiver to connect to the TWAI bus - pub fn new_async( - peripheral: impl Peripheral

+ 'd, - rx_pin: impl Peripheral

+ 'd, - tx_pin: impl Peripheral

+ '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( - peripheral: impl Peripheral

+ 'd, - rx_pin: impl Peripheral

+ 'd, - tx_pin: impl Peripheral

+ 'd, - baud_rate: BaudRate, - mode: TwaiMode, - ) -> Self { - Self::new_async_no_transceiver_typed(peripheral.map_into(), rx_pin, tx_pin, baud_rate, mode) + /// Convert the configuration into an async configuration. + pub fn into_async(mut self) -> TwaiConfiguration<'d, Async, T> { + self.set_interrupt_handler(self.twai.async_handler()); + TwaiConfiguration { + twai: self.twai, + phantom: PhantomData, + mode: self.mode, + } } } @@ -1137,33 +1111,18 @@ impl<'d, T> TwaiConfiguration<'d, Async, T> where T: Instance, { - /// Create a new instance of [TwaiConfiguration] in async mode - /// - /// You will need to use a transceiver to connect to the TWAI bus - pub fn new_async_typed( - peripheral: impl Peripheral

+ 'd, - rx_pin: impl Peripheral

+ 'd, - tx_pin: impl Peripheral

+ 'd, - baud_rate: BaudRate, - mode: TwaiMode, - ) -> Self { - TwaiConfiguration::new_typed(peripheral, rx_pin, tx_pin, baud_rate, mode).into_async() - } + /// Convert the configuration into a blocking configuration. + pub fn into_blocking(self) -> TwaiConfiguration<'d, Blocking, T> { + use crate::{interrupt, Cpu}; - /// Create a new instance of [TwaiConfiguration] meant to connect two ESP32s - /// directly in async mode - /// - /// You don't need a transceiver by following the description in the - /// `twai.rs` example - pub fn new_async_no_transceiver_typed( - peripheral: impl Peripheral

+ 'd, - rx_pin: impl Peripheral

+ 'd, - tx_pin: impl Peripheral

+ 'd, - baud_rate: BaudRate, - mode: TwaiMode, - ) -> Self { - TwaiConfiguration::new_no_transceiver_typed(peripheral, rx_pin, tx_pin, baud_rate, mode) - .into_async() + interrupt::disable(Cpu::current(), self.twai.interrupt()); + + // Re-create in blocking mode + TwaiConfiguration { + twai: self.twai, + phantom: PhantomData, + mode: self.mode, + } } } diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index f7418dc72..6a371e95b 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -126,10 +126,11 @@ //! [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/ -use core::marker::PhantomData; +use core::{marker::PhantomData, sync::atomic::Ordering, task::Poll}; use embassy_sync::waitqueue::AtomicWaker; use enumset::{EnumSet, EnumSetType}; +use portable_atomic::AtomicBool; use self::config::Config; use crate::{ @@ -146,6 +147,7 @@ use crate::{ peripherals::{uart0::RegisterBlock, Interrupt}, private::Internal, system::PeripheralClockControl, + Async, Blocking, InterruptConfigurable, Mode, @@ -662,6 +664,42 @@ where 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)] @@ -963,6 +1001,50 @@ where 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> { @@ -1010,6 +1092,27 @@ where ) -> Result { 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. @@ -1033,15 +1136,6 @@ where T: Instance, 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 pub fn with_cts(mut self, cts: impl Peripheral

+ 'd) -> Self { self.rx = self.rx.with_cts(cts); @@ -1123,66 +1217,24 @@ where self.rx.at_cmd_config = Some(config); } - /// Listen for the given interrupts - fn enable_listen(&mut self, interrupts: EnumSet, 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 pub fn listen(&mut self, interrupts: impl Into>) { - self.enable_listen(interrupts.into(), true); + self.tx.uart.info().enable_listen(interrupts.into(), true) } /// Unlisten the given interrupts pub fn unlisten(&mut self, interrupts: impl Into>) { - self.enable_listen(interrupts.into(), false); + self.tx.uart.info().enable_listen(interrupts.into(), false) } /// Gets asserted interrupts pub fn interrupts(&mut self) -> EnumSet { - 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 + self.tx.uart.info().interrupts() } /// Resets asserted interrupts pub fn clear_interrupts(&mut self, interrupts: EnumSet) { - 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 - }); + self.tx.uart.info().clear_interrupts(interrupts) } /// Write a byte out over the UART @@ -1479,7 +1531,8 @@ where T: Instance, { 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,560 +1804,406 @@ where } } -mod asynch { - use core::task::Poll; +#[derive(EnumSetType, Debug)] +pub(crate) enum TxEvent { + TxDone, + TxFiFoEmpty, +} +#[derive(EnumSetType, Debug)] +pub(crate) enum RxEvent { + FifoFull, + CmdCharDetected, + FifoOvf, + FifoTout, + GlitchDetected, + FrameError, + ParityError, +} - use enumset::{EnumSet, EnumSetType}; +/// A future that resolves when the passed interrupt is triggered, +/// or has been triggered in the meantime (flag set in INT_RAW). +/// Upon construction the future enables the passed interrupt and when it +/// is dropped it disables the interrupt again. The future returns the event +/// that was initially passed, when it resolves. +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct UartRxFuture<'d> { + events: EnumSet, + uart: &'d Info, + state: &'d State, + registered: bool, +} - use super::*; - use crate::Async; - - #[derive(EnumSetType, Debug)] - pub(crate) enum TxEvent { - TxDone, - TxFiFoEmpty, - } - #[derive(EnumSetType, Debug)] - pub(crate) enum RxEvent { - FifoFull, - CmdCharDetected, - FifoOvf, - FifoTout, - GlitchDetected, - FrameError, - ParityError, +impl<'d> UartRxFuture<'d> { + pub fn new(uart: &'d Info, state: &'d State, events: impl Into>) -> Self { + Self { + events: events.into(), + uart, + state, + registered: false, + } } - /// A future that resolves when the passed interrupt is triggered, - /// or has been triggered in the meantime (flag set in INT_RAW). - /// Upon construction the future enables the passed interrupt and when it - /// is dropped it disables the interrupt again. The future returns the event - /// that was initially passed, when it resolves. - #[must_use = "futures do nothing unless you `.await` or poll them"] - struct UartRxFuture<'d> { - events: EnumSet, - uart: &'d Info, - state: &'d State, - registered: bool, - } + fn triggered_events(&self) -> EnumSet { + let interrupts_enabled = self.uart.register_block().int_ena().read(); + let mut events_triggered = EnumSet::new(); + for event in self.events { + let event_triggered = match event { + RxEvent::FifoFull => interrupts_enabled.rxfifo_full().bit_is_clear(), + RxEvent::CmdCharDetected => interrupts_enabled.at_cmd_char_det().bit_is_clear(), - impl<'d> UartRxFuture<'d> { - pub fn new(uart: &'d Info, state: &'d State, events: impl Into>) -> Self { - Self { - events: events.into(), - uart, - state, - registered: false, + RxEvent::FifoOvf => interrupts_enabled.rxfifo_ovf().bit_is_clear(), + RxEvent::FifoTout => interrupts_enabled.rxfifo_tout().bit_is_clear(), + RxEvent::GlitchDetected => interrupts_enabled.glitch_det().bit_is_clear(), + RxEvent::FrameError => interrupts_enabled.frm_err().bit_is_clear(), + RxEvent::ParityError => interrupts_enabled.parity_err().bit_is_clear(), + }; + if event_triggered { + events_triggered |= event; } } + events_triggered + } - fn triggered_events(&self) -> EnumSet { - let interrupts_enabled = self.uart.register_block().int_ena().read(); - let mut events_triggered = EnumSet::new(); + fn enable_listen(&self, enable: bool) { + self.uart.register_block().int_ena().modify(|_, w| { for event in self.events { - let event_triggered = match event { - RxEvent::FifoFull => interrupts_enabled.rxfifo_full().bit_is_clear(), - RxEvent::CmdCharDetected => interrupts_enabled.at_cmd_char_det().bit_is_clear(), - - RxEvent::FifoOvf => interrupts_enabled.rxfifo_ovf().bit_is_clear(), - RxEvent::FifoTout => interrupts_enabled.rxfifo_tout().bit_is_clear(), - RxEvent::GlitchDetected => interrupts_enabled.glitch_det().bit_is_clear(), - RxEvent::FrameError => interrupts_enabled.frm_err().bit_is_clear(), - RxEvent::ParityError => interrupts_enabled.parity_err().bit_is_clear(), + match event { + RxEvent::FifoFull => w.rxfifo_full().bit(enable), + RxEvent::CmdCharDetected => w.at_cmd_char_det().bit(enable), + RxEvent::FifoOvf => w.rxfifo_ovf().bit(enable), + RxEvent::FifoTout => w.rxfifo_tout().bit(enable), + RxEvent::GlitchDetected => w.glitch_det().bit(enable), + RxEvent::FrameError => w.frm_err().bit(enable), + RxEvent::ParityError => w.parity_err().bit(enable), }; - if event_triggered { - events_triggered |= event; - } } - events_triggered - } + w + }); + } +} - fn enable_listen(&self, enable: bool) { - self.uart.register_block().int_ena().modify(|_, w| { - for event in self.events { - match event { - RxEvent::FifoFull => w.rxfifo_full().bit(enable), - RxEvent::CmdCharDetected => w.at_cmd_char_det().bit(enable), - RxEvent::FifoOvf => w.rxfifo_ovf().bit(enable), - RxEvent::FifoTout => w.rxfifo_tout().bit(enable), - RxEvent::GlitchDetected => w.glitch_det().bit(enable), - RxEvent::FrameError => w.frm_err().bit(enable), - RxEvent::ParityError => w.parity_err().bit(enable), - }; - } - w - }); +impl core::future::Future for UartRxFuture<'_> { + type Output = EnumSet; + + fn poll( + mut self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + if !self.registered { + self.state.rx_waker.register(cx.waker()); + self.enable_listen(true); + self.registered = true; + } + let events = self.triggered_events(); + if !events.is_empty() { + Poll::Ready(events) + } else { + Poll::Pending + } + } +} + +impl Drop for UartRxFuture<'_> { + fn drop(&mut self) { + // Although the isr disables the interrupt that occurred directly, we need to + // disable the other interrupts (= the ones that did not occur), as + // soon as this future goes out of scope. + self.enable_listen(false); + } +} + +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct UartTxFuture<'d> { + events: EnumSet, + uart: &'d Info, + state: &'d State, + registered: bool, +} +impl<'d> UartTxFuture<'d> { + pub fn new(uart: &'d Info, state: &'d State, events: impl Into>) -> Self { + Self { + events: events.into(), + uart, + state, + registered: false, } } - impl core::future::Future for UartRxFuture<'_> { - type Output = EnumSet; - - fn poll( - mut self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll { - if !self.registered { - self.state.rx_waker.register(cx.waker()); - self.enable_listen(true); - self.registered = true; - } - let events = self.triggered_events(); - if !events.is_empty() { - Poll::Ready(events) - } else { - Poll::Pending + fn triggered_events(&self) -> bool { + let interrupts_enabled = self.uart.register_block().int_ena().read(); + let mut event_triggered = false; + for event in self.events { + event_triggered |= match event { + TxEvent::TxDone => interrupts_enabled.tx_done().bit_is_clear(), + TxEvent::TxFiFoEmpty => interrupts_enabled.txfifo_empty().bit_is_clear(), } } + event_triggered } - impl Drop for UartRxFuture<'_> { - fn drop(&mut self) { - // Although the isr disables the interrupt that occurred directly, we need to - // disable the other interrupts (= the ones that did not occur), as - // soon as this future goes out of scope. - self.enable_listen(false); - } - } - - #[must_use = "futures do nothing unless you `.await` or poll them"] - struct UartTxFuture<'d> { - events: EnumSet, - uart: &'d Info, - state: &'d State, - registered: bool, - } - impl<'d> UartTxFuture<'d> { - pub fn new(uart: &'d Info, state: &'d State, events: impl Into>) -> Self { - Self { - events: events.into(), - uart, - state, - registered: false, - } - } - - fn triggered_events(&self) -> bool { - let interrupts_enabled = self.uart.register_block().int_ena().read(); - let mut event_triggered = false; + fn enable_listen(&self, enable: bool) { + self.uart.register_block().int_ena().modify(|_, w| { for event in self.events { - event_triggered |= match event { - TxEvent::TxDone => interrupts_enabled.tx_done().bit_is_clear(), - TxEvent::TxFiFoEmpty => interrupts_enabled.txfifo_empty().bit_is_clear(), - } + match event { + TxEvent::TxDone => w.tx_done().bit(enable), + TxEvent::TxFiFoEmpty => w.txfifo_empty().bit(enable), + }; } - event_triggered + w + }); + } +} + +impl core::future::Future for UartTxFuture<'_> { + type Output = (); + + fn poll( + mut self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + if !self.registered { + self.state.tx_waker.register(cx.waker()); + self.enable_listen(true); + self.registered = true; } - fn enable_listen(&self, enable: bool) { - self.uart.register_block().int_ena().modify(|_, w| { - for event in self.events { - match event { - TxEvent::TxDone => w.tx_done().bit(enable), - TxEvent::TxFiFoEmpty => w.txfifo_empty().bit(enable), - }; - } - w - }); + if self.triggered_events() { + Poll::Ready(()) + } else { + Poll::Pending } } +} - impl core::future::Future for UartTxFuture<'_> { - type Output = (); +impl Drop for UartTxFuture<'_> { + fn drop(&mut self) { + // Although the isr disables the interrupt that occurred directly, we need to + // disable the other interrupts (= the ones that did not occur), as + // soon as this future goes out of scope. + self.enable_listen(false); + } +} - fn poll( - mut self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll { - if !self.registered { - self.state.tx_waker.register(cx.waker()); - self.enable_listen(true); - self.registered = true; +impl Uart<'_, Async, T> +where + T: Instance, +{ + /// Asynchronously reads data from the UART receive buffer into the + /// provided buffer. + pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { + self.rx.read_async(buf).await + } + + /// Asynchronously writes data to the UART transmit buffer. + pub async fn write_async(&mut self, words: &[u8]) -> Result { + self.tx.write_async(words).await + } + + /// Asynchronously flushes the UART transmit buffer. + pub async fn flush_async(&mut self) -> Result<(), Error> { + self.tx.flush_async().await + } +} + +impl<'d, T> UartTx<'d, Async, T> +where + T: Instance, +{ + /// Asynchronously writes data to the UART transmit buffer in chunks. + /// + /// This function sends the contents of the provided buffer `words` over + /// the UART. Data is written in chunks to avoid overflowing the + /// transmit FIFO, and the function waits asynchronously when + /// necessary for space in the buffer to become available. + pub async fn write_async(&mut self, words: &[u8]) -> Result { + let mut count = 0; + let mut offset: usize = 0; + loop { + let mut next_offset = offset + (UART_FIFO_SIZE - self.tx_fifo_count()) as usize; + if next_offset > words.len() { + next_offset = words.len(); } - if self.triggered_events() { - Poll::Ready(()) - } else { - Poll::Pending + for byte in &words[offset..next_offset] { + self.write_byte(*byte).unwrap(); // should never fail + count += 1; + } + + if next_offset >= words.len() { + break; + } + + offset = next_offset; + UartTxFuture::new(self.uart.info(), self.uart.state(), TxEvent::TxFiFoEmpty).await; + } + + Ok(count) + } + + /// Asynchronously flushes the UART transmit buffer. + /// + /// This function ensures that all pending data in the transmit FIFO has + /// been sent over the UART. If the FIFO contains data, it waits + /// for the transmission to complete before returning. + pub async fn flush_async(&mut self) -> Result<(), Error> { + let count = self.tx_fifo_count(); + if count > 0 { + UartTxFuture::new(self.uart.info(), self.uart.state(), TxEvent::TxDone).await; + } + + Ok(()) + } +} + +impl<'d, T> UartRx<'d, Async, T> +where + T: Instance, +{ + /// Read async to buffer slice `buf`. + /// Waits until at least one byte is in the Rx FiFo + /// and one of the following interrupts occurs: + /// - `RXFIFO_FULL` + /// - `RXFIFO_OVF` + /// - `AT_CMD_CHAR_DET` (only if `set_at_cmd` was called) + /// - `RXFIFO_TOUT` (only if `set_rx_timeout was called) + /// + /// The interrupts in question are enabled during the body of this + /// function. The method immediately returns when the interrupt + /// has already occurred before calling this method (e.g. status + /// bit set, but interrupt not enabled) + /// + /// # Params + /// - `buf` buffer slice to write the bytes into + /// + /// + /// # Ok + /// When successful, returns the number of bytes written to buf. + /// This method will never return Ok(0) + pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Err(Error::InvalidArgument); + } + + loop { + let mut events = RxEvent::FifoFull + | RxEvent::FifoOvf + | RxEvent::FrameError + | RxEvent::GlitchDetected + | RxEvent::ParityError; + + if self.at_cmd_config.is_some() { + events |= RxEvent::CmdCharDetected; + } + if self.rx_timeout_config.is_some() { + events |= RxEvent::FifoTout; + } + + let events_happened = + UartRxFuture::new(self.uart.info(), self.uart.state(), events).await; + // always drain the fifo, if an error has occurred the data is lost + let read_bytes = self.drain_fifo(buf); + // check error events + for event_happened in events_happened { + match event_happened { + RxEvent::FifoOvf => return Err(Error::RxFifoOvf), + RxEvent::GlitchDetected => return Err(Error::RxGlitchDetected), + RxEvent::FrameError => return Err(Error::RxFrameError), + RxEvent::ParityError => return Err(Error::RxParityError), + RxEvent::FifoFull | RxEvent::CmdCharDetected | RxEvent::FifoTout => continue, + } + } + // Unfortunately, the uart's rx-timeout counter counts up whenever there is + // data in the fifo, even if the interrupt is disabled and the status bit + // cleared. Since we do not drain the fifo in the interrupt handler, we need to + // reset the counter here, after draining the fifo. + self.register_block() + .int_clr() + .write(|w| w.rxfifo_tout().clear_bit_by_one()); + + if read_bytes > 0 { + return Ok(read_bytes); } } } +} - impl Drop for UartTxFuture<'_> { - fn drop(&mut self) { - // Although the isr disables the interrupt that occurred directly, we need to - // disable the other interrupts (= the ones that did not occur), as - // soon as this future goes out of scope. - self.enable_listen(false); - } +impl embedded_io_async::Read for Uart<'_, Async, T> +where + T: Instance, +{ + /// In contrast to the documentation of embedded_io_async::Read, this + /// method blocks until an uart interrupt occurs. + /// See UartRx::read_async for more details. + async fn read(&mut self, buf: &mut [u8]) -> Result { + self.read_async(buf).await + } +} + +impl embedded_io_async::Read for UartRx<'_, Async, T> +where + T: Instance, +{ + /// In contrast to the documentation of embedded_io_async::Read, this + /// method blocks until an uart interrupt occurs. + /// See UartRx::read_async for more details. + async fn read(&mut self, buf: &mut [u8]) -> Result { + self.read_async(buf).await + } +} + +impl embedded_io_async::Write for Uart<'_, Async, T> +where + T: Instance, +{ + async fn write(&mut self, buf: &[u8]) -> Result { + self.write_async(buf).await } - impl<'d> Uart<'d, Async> { - /// Create a new UART instance with defaults in [`Async`] mode. - pub fn new_async( - uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, - ) -> Result { - Uart::new_async_typed(uart.map_into(), rx, tx) - } + async fn flush(&mut self) -> Result<(), Self::Error> { + self.flush_async().await + } +} - /// Create a new UART instance with configuration options in [`Async`] - /// mode. - pub fn new_async_with_config( - uart: impl Peripheral

+ 'd, - config: Config, - rx: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, - ) -> Result { - Uart::new_async_with_config_typed(uart.map_into(), config, rx, tx) - } +impl embedded_io_async::Write for UartTx<'_, Async, T> +where + T: Instance, +{ + async fn write(&mut self, buf: &[u8]) -> Result { + self.write_async(buf).await } - impl<'d, T> Uart<'d, Async, T> - where - T: Instance, - { - /// Create a new UART instance with defaults in [`Async`] mode. - pub fn new_async_typed( - uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, - ) -> Result { - 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( - uart: impl Peripheral

+ 'd, - config: Config, - rx: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, - ) -> Result { - // 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) - } + async fn flush(&mut self) -> Result<(), Self::Error> { + self.flush_async().await } +} - impl Uart<'_, Async, T> - where - T: Instance, - { - /// Asynchronously reads data from the UART receive buffer into the - /// provided buffer. - pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { - self.rx.read_async(buf).await - } +/// Interrupt handler for all UART instances +/// 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 +/// futures to detect that they should indeed resolve after being woken up +pub(super) fn intr_handler(uart: &Info, state: &State) { + let interrupts = uart.register_block().int_st().read(); + let interrupt_bits = interrupts.bits(); // = int_raw & int_ena + let rx_wake = interrupts.rxfifo_full().bit_is_set() + || interrupts.rxfifo_ovf().bit_is_set() + || interrupts.rxfifo_tout().bit_is_set() + || interrupts.at_cmd_char_det().bit_is_set() + || interrupts.glitch_det().bit_is_set() + || interrupts.frm_err().bit_is_set() + || interrupts.parity_err().bit_is_set(); + let tx_wake = interrupts.tx_done().bit_is_set() || interrupts.txfifo_empty().bit_is_set(); + uart.register_block() + .int_clr() + .write(|w| unsafe { w.bits(interrupt_bits) }); + uart.register_block() + .int_ena() + .modify(|r, w| unsafe { w.bits(r.bits() & !interrupt_bits) }); - /// Asynchronously writes data to the UART transmit buffer. - pub async fn write_async(&mut self, words: &[u8]) -> Result { - self.tx.write_async(words).await - } - - /// Asynchronously flushes the UART transmit buffer. - pub async fn flush_async(&mut self) -> Result<(), Error> { - self.tx.flush_async().await - } + if tx_wake { + state.tx_waker.wake(); } - - impl<'d> UartTx<'d, Async> { - /// Create a new UART TX instance in [`Async`] mode. - pub fn new_async( - uart: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, - ) -> Result { - 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( - uart: impl Peripheral

+ 'd, - config: Config, - tx: impl Peripheral

+ 'd, - ) -> Result { - UartTx::new_async_with_config_typed(uart.map_into(), config, tx) - } - } - - impl<'d, T> UartTx<'d, Async, T> - where - T: Instance, - { - /// Create a new UART TX instance in [`Async`] mode. - pub fn new_async_typed( - uart: impl Peripheral

+ 'd, - tx: impl Peripheral

+ 'd, - ) -> Result { - 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( - uart: impl Peripheral

+ 'd, - config: Config, - tx: impl Peripheral

+ 'd, - ) -> Result { - 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. - /// - /// This function sends the contents of the provided buffer `words` over - /// the UART. Data is written in chunks to avoid overflowing the - /// transmit FIFO, and the function waits asynchronously when - /// necessary for space in the buffer to become available. - pub async fn write_async(&mut self, words: &[u8]) -> Result { - let mut count = 0; - let mut offset: usize = 0; - loop { - let mut next_offset = offset + (UART_FIFO_SIZE - self.tx_fifo_count()) as usize; - if next_offset > words.len() { - next_offset = words.len(); - } - - for byte in &words[offset..next_offset] { - self.write_byte(*byte).unwrap(); // should never fail - count += 1; - } - - if next_offset >= words.len() { - break; - } - - offset = next_offset; - UartTxFuture::new(self.uart.info(), self.uart.state(), TxEvent::TxFiFoEmpty).await; - } - - Ok(count) - } - - /// Asynchronously flushes the UART transmit buffer. - /// - /// This function ensures that all pending data in the transmit FIFO has - /// been sent over the UART. If the FIFO contains data, it waits - /// for the transmission to complete before returning. - pub async fn flush_async(&mut self) -> Result<(), Error> { - let count = self.tx_fifo_count(); - if count > 0 { - UartTxFuture::new(self.uart.info(), self.uart.state(), TxEvent::TxDone).await; - } - - Ok(()) - } - } - - impl<'d> UartRx<'d, Async> { - /// Create a new UART RX instance in [`Async`] mode. - pub fn new_async( - uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, - ) -> Result { - 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( - uart: impl Peripheral

+ 'd, - config: Config, - rx: impl Peripheral

+ 'd, - ) -> Result { - Self::new_async_with_config_typed(uart.map_into(), config, rx) - } - } - - impl<'d, T> UartRx<'d, Async, T> - where - T: Instance, - { - /// Create a new UART RX instance in [`Async`] mode. - pub fn new_async_typed( - uart: impl Peripheral

+ 'd, - rx: impl Peripheral

+ 'd, - ) -> Result { - 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

+ 'd, - config: Config, - rx: impl Peripheral

+ 'd, - ) -> Result { - 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`. - /// Waits until at least one byte is in the Rx FiFo - /// and one of the following interrupts occurs: - /// - `RXFIFO_FULL` - /// - `RXFIFO_OVF` - /// - `AT_CMD_CHAR_DET` (only if `set_at_cmd` was called) - /// - `RXFIFO_TOUT` (only if `set_rx_timeout was called) - /// - /// The interrupts in question are enabled during the body of this - /// function. The method immediately returns when the interrupt - /// has already occurred before calling this method (e.g. status - /// bit set, but interrupt not enabled) - /// - /// # Params - /// - `buf` buffer slice to write the bytes into - /// - /// - /// # Ok - /// When successful, returns the number of bytes written to buf. - /// This method will never return Ok(0) - pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { - if buf.is_empty() { - return Err(Error::InvalidArgument); - } - - loop { - let mut events = RxEvent::FifoFull - | RxEvent::FifoOvf - | RxEvent::FrameError - | RxEvent::GlitchDetected - | RxEvent::ParityError; - - if self.at_cmd_config.is_some() { - events |= RxEvent::CmdCharDetected; - } - if self.rx_timeout_config.is_some() { - events |= RxEvent::FifoTout; - } - - let events_happened = - UartRxFuture::new(self.uart.info(), self.uart.state(), events).await; - // always drain the fifo, if an error has occurred the data is lost - let read_bytes = self.drain_fifo(buf); - // check error events - for event_happened in events_happened { - match event_happened { - RxEvent::FifoOvf => return Err(Error::RxFifoOvf), - RxEvent::GlitchDetected => return Err(Error::RxGlitchDetected), - RxEvent::FrameError => return Err(Error::RxFrameError), - RxEvent::ParityError => return Err(Error::RxParityError), - RxEvent::FifoFull | RxEvent::CmdCharDetected | RxEvent::FifoTout => { - continue - } - } - } - // Unfortunately, the uart's rx-timeout counter counts up whenever there is - // data in the fifo, even if the interrupt is disabled and the status bit - // cleared. Since we do not drain the fifo in the interrupt handler, we need to - // reset the counter here, after draining the fifo. - self.register_block() - .int_clr() - .write(|w| w.rxfifo_tout().clear_bit_by_one()); - - if read_bytes > 0 { - return Ok(read_bytes); - } - } - } - } - - impl embedded_io_async::Read for Uart<'_, Async, T> - where - T: Instance, - { - /// In contrast to the documentation of embedded_io_async::Read, this - /// method blocks until an uart interrupt occurs. - /// See UartRx::read_async for more details. - async fn read(&mut self, buf: &mut [u8]) -> Result { - self.read_async(buf).await - } - } - - impl embedded_io_async::Read for UartRx<'_, Async, T> - where - T: Instance, - { - /// In contrast to the documentation of embedded_io_async::Read, this - /// method blocks until an uart interrupt occurs. - /// See UartRx::read_async for more details. - async fn read(&mut self, buf: &mut [u8]) -> Result { - self.read_async(buf).await - } - } - - impl embedded_io_async::Write for Uart<'_, Async, T> - where - T: Instance, - { - async fn write(&mut self, buf: &[u8]) -> Result { - self.write_async(buf).await - } - - async fn flush(&mut self) -> Result<(), Self::Error> { - self.flush_async().await - } - } - - impl embedded_io_async::Write for UartTx<'_, Async, T> - where - T: Instance, - { - async fn write(&mut self, buf: &[u8]) -> Result { - self.write_async(buf).await - } - - async fn flush(&mut self) -> Result<(), Self::Error> { - self.flush_async().await - } - } - - /// Interrupt handler for all UART instances - /// 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 - /// futures to detect that they should indeed resolve after being woken up - pub(super) fn intr_handler(uart: &Info, state: &State) { - let interrupts = uart.register_block().int_st().read(); - let interrupt_bits = interrupts.bits(); // = int_raw & int_ena - let rx_wake = interrupts.rxfifo_full().bit_is_set() - || interrupts.rxfifo_ovf().bit_is_set() - || interrupts.rxfifo_tout().bit_is_set() - || interrupts.at_cmd_char_det().bit_is_set() - || interrupts.glitch_det().bit_is_set() - || interrupts.frm_err().bit_is_set() - || interrupts.parity_err().bit_is_set(); - let tx_wake = interrupts.tx_done().bit_is_set() || interrupts.txfifo_empty().bit_is_set(); - uart.register_block() - .int_clr() - .write(|w| unsafe { w.bits(interrupt_bits) }); - uart.register_block() - .int_ena() - .modify(|r, w| unsafe { w.bits(r.bits() & !interrupt_bits) }); - - if tx_wake { - state.tx_waker.wake(); - } - if rx_wake { - state.rx_waker.wake(); - } + if rx_wake { + state.rx_waker.wake(); } } @@ -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 pub trait Instance: Peripheral

+ PeripheralMarker + Into + 'static { /// Returns the peripheral data and state describing this UART instance. @@ -2553,6 +2468,12 @@ pub struct State { /// Waker for the asynchronous TX operations. 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 { @@ -2560,6 +2481,56 @@ impl Info { pub fn register_block(&self) -> &RegisterBlock { unsafe { &*self.register_block } } + + /// Listen for the given interrupts + fn enable_listen(&self, interrupts: EnumSet, 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 { + 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) { + 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 { @@ -2576,12 +2547,14 @@ macro_rules! impl_instance { fn parts(&self) -> (&Info, &State) { #[crate::macros::handler] pub(super) fn irq_handler() { - asynch::intr_handler(&PERIPHERAL, &STATE); + intr_handler(&PERIPHERAL, &STATE); } static STATE: State = State { tx_waker: AtomicWaker::new(), rx_waker: AtomicWaker::new(), + is_rx_async: AtomicBool::new(false), + is_tx_async: AtomicBool::new(false), }; static PERIPHERAL: Info = Info { diff --git a/esp-hal/src/usb_serial_jtag.rs b/esp-hal/src/usb_serial_jtag.rs index a2247baca..42c82f8aa 100644 --- a/esp-hal/src/usb_serial_jtag.rs +++ b/esp-hal/src/usb_serial_jtag.rs @@ -75,14 +75,18 @@ //! [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/ -use core::{convert::Infallible, marker::PhantomData}; +use core::{convert::Infallible, marker::PhantomData, task::Poll}; + +use embassy_sync::waitqueue::AtomicWaker; +use procmacros::handler; use crate::{ - interrupt::InterruptHandler, - peripheral::Peripheral, + peripheral::{Peripheral, PeripheralRef}, peripherals::{usb_device::RegisterBlock, Interrupt, USB_DEVICE}, system::PeripheralClockControl, + Async, Blocking, + Cpu, InterruptConfigurable, Mode, }; @@ -98,20 +102,24 @@ pub struct UsbSerialJtag<'d, M> { /// USB Serial/JTAG (Transmit) pub struct UsbSerialJtagTx<'d, M> { - phantom: PhantomData<(&'d mut USB_DEVICE, M)>, + peripheral: PeripheralRef<'d, USB_DEVICE>, + phantom: PhantomData, } /// USB Serial/JTAG (Receive) pub struct UsbSerialJtagRx<'d, M> { - phantom: PhantomData<(&'d mut USB_DEVICE, M)>, + peripheral: PeripheralRef<'d, USB_DEVICE>, + phantom: PhantomData, } -impl UsbSerialJtagTx<'_, M> +impl<'d, M> UsbSerialJtagTx<'d, M> where M: Mode, { - fn new_inner() -> Self { + fn new_inner(peripheral: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(peripheral); Self { + peripheral, phantom: PhantomData, } } @@ -183,12 +191,14 @@ where } } -impl UsbSerialJtagRx<'_, M> +impl<'d, M> UsbSerialJtagRx<'d, M> where M: Mode, { - fn new_inner() -> Self { + fn new_inner(peripheral: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(peripheral); Self { + peripheral, phantom: PhantomData, } } @@ -263,13 +273,37 @@ impl<'d> UsbSerialJtag<'d, Blocking> { pub fn new(usb_device: impl Peripheral

+ 'd) -> Self { 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 InterruptConfigurable for UsbSerialJtag<'_, Blocking> { 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 M: Mode, { - fn new_inner(_usb_device: impl Peripheral

+ 'd) -> Self { + fn new_inner(usb_device: impl Peripheral

+ 'd) -> Self { // Do NOT reset the peripheral. Doing so will result in a broken USB JTAG // connection. PeripheralClockControl::enable(crate::system::Peripheral::UsbDevice); @@ -293,29 +327,20 @@ where // doesn't swap the pullups too, this works around that. if Efuse::read_bit(USB_EXCHG_PINS) { USB_DEVICE::register_block().conf0().modify(|_, w| { - w.pad_pull_override() - .set_bit() - .dm_pullup() - .clear_bit() - .dp_pullup() - .set_bit() + w.pad_pull_override().set_bit(); + w.dm_pullup().clear_bit(); + w.dp_pullup().set_bit() }); } } + crate::into_ref!(usb_device); + Self { - rx: UsbSerialJtagRx::new_inner(), - tx: UsbSerialJtagTx::new_inner(), + rx: UsbSerialJtagRx::new_inner(unsafe { usb_device.clone_unchecked() }), + 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, /// which is particularly useful when having two tasks correlating to /// transmitting and receiving. @@ -652,224 +677,221 @@ where } } -mod asynch { - use core::{marker::PhantomData, task::Poll}; +// Static instance of the waker for each component of the peripheral: +static WAKER_TX: AtomicWaker = AtomicWaker::new(); +static WAKER_RX: AtomicWaker = AtomicWaker::new(); - use embassy_sync::waitqueue::AtomicWaker; - use procmacros::handler; +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct UsbSerialJtagWriteFuture<'d> { + _peripheral: PeripheralRef<'d, USB_DEVICE>, +} - use super::{Error, Instance, UsbSerialJtag, UsbSerialJtagRx, UsbSerialJtagTx}; - use crate::{peripheral::Peripheral, peripherals::USB_DEVICE, Async}; +impl<'d> UsbSerialJtagWriteFuture<'d> { + fn new(_peripheral: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(_peripheral); + // Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT + // interrupt + USB_DEVICE::register_block() + .int_ena() + .modify(|_, w| w.serial_in_empty().set_bit()); - // Static instance of the waker for each component of the peripheral: - 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>, + Self { _peripheral } } - impl UsbSerialJtagWriteFuture<'_> { - pub fn new() -> Self { - // Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT - // interrupt - USB_DEVICE::register_block() - .int_ena() - .modify(|_, w| w.serial_in_empty().set_bit()); - - Self { - phantom: PhantomData, - } - } - - fn event_bit_is_clear(&self) -> bool { - USB_DEVICE::register_block() - .int_ena() - .read() - .serial_in_empty() - .bit_is_clear() - } + fn event_bit_is_clear(&self) -> bool { + USB_DEVICE::register_block() + .int_ena() + .read() + .serial_in_empty() + .bit_is_clear() } +} - impl core::future::Future for UsbSerialJtagWriteFuture<'_> { - type Output = (); +impl core::future::Future for UsbSerialJtagWriteFuture<'_> { + type Output = (); - fn poll( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll { - WAKER_TX.register(cx.waker()); - if self.event_bit_is_clear() { - Poll::Ready(()) - } else { - Poll::Pending - } - } - } - - #[must_use = "futures do nothing unless you `.await` or poll them"] - pub(crate) struct UsbSerialJtagReadFuture<'d> { - phantom: PhantomData<&'d mut USB_DEVICE>, - } - - impl UsbSerialJtagReadFuture<'_> { - pub fn new() -> Self { - // Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT - // interrupt - USB_DEVICE::register_block() - .int_ena() - .modify(|_, w| w.serial_out_recv_pkt().set_bit()); - - Self { - phantom: PhantomData, - } - } - - fn event_bit_is_clear(&self) -> bool { - USB_DEVICE::register_block() - .int_ena() - .read() - .serial_out_recv_pkt() - .bit_is_clear() - } - } - - impl core::future::Future for UsbSerialJtagReadFuture<'_> { - type Output = (); - - fn poll( - self: core::pin::Pin<&mut Self>, - cx: &mut core::task::Context<'_>, - ) -> core::task::Poll { - WAKER_RX.register(cx.waker()); - if self.event_bit_is_clear() { - Poll::Ready(()) - } else { - Poll::Pending - } - } - } - - impl<'d> UsbSerialJtag<'d, Async> { - /// Create a new USB serial/JTAG instance in asynchronous mode - pub fn new_async(usb_device: impl Peripheral

+ 'd) -> Self { - let mut this = Self::new_inner(usb_device); - this.inner_set_interrupt_handler(async_interrupt_handler); - this - } - } - - impl UsbSerialJtagTx<'_, Async> { - async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> { - let reg_block = USB_DEVICE::register_block(); - - for chunk in words.chunks(64) { - for byte in chunk { - reg_block - .ep1() - .write(|w| unsafe { w.rdwr_byte().bits(*byte) }); - } - reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit()); - - UsbSerialJtagWriteFuture::new().await; - } - - Ok(()) - } - - async fn flush_tx_async(&mut self) -> Result<(), Error> { - if USB_DEVICE::register_block() - .jfifo_st() - .read() - .out_fifo_empty() - .bit_is_clear() - { - UsbSerialJtagWriteFuture::new().await; - } - - Ok(()) - } - } - - impl UsbSerialJtagRx<'_, Async> { - async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result { - if buf.is_empty() { - return Ok(0); - } - - loop { - let read_bytes = self.drain_rx_fifo(buf); - if read_bytes > 0 { - return Ok(read_bytes); - } - UsbSerialJtagReadFuture::new().await; - } - } - } - - impl embedded_io_async::Write for UsbSerialJtag<'_, Async> { - async fn write(&mut self, buf: &[u8]) -> Result { - embedded_io_async::Write::write(&mut self.tx, buf).await - } - - async fn flush(&mut self) -> Result<(), Self::Error> { - embedded_io_async::Write::flush(&mut self.tx).await - } - } - - impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> { - async fn write(&mut self, buf: &[u8]) -> Result { - self.write_bytes_async(buf).await?; - - Ok(buf.len()) - } - - async fn flush(&mut self) -> Result<(), Self::Error> { - self.flush_tx_async().await - } - } - - impl embedded_io_async::Read for UsbSerialJtag<'_, Async> { - async fn read(&mut self, buf: &mut [u8]) -> Result { - embedded_io_async::Read::read(&mut self.rx, buf).await - } - } - - impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> { - async fn read(&mut self, buf: &mut [u8]) -> Result { - self.read_bytes_async(buf).await - } - } - - #[handler] - fn async_interrupt_handler() { - let usb = USB_DEVICE::register_block(); - let interrupts = usb.int_st().read(); - - let tx = interrupts.serial_in_empty().bit_is_set(); - let rx = interrupts.serial_out_recv_pkt().bit_is_set(); - - if tx { - usb.int_ena().modify(|_, w| w.serial_in_empty().clear_bit()); - } - if rx { - usb.int_ena() - .modify(|_, w| w.serial_out_recv_pkt().clear_bit()); - } - - usb.int_clr().write(|w| { - w.serial_in_empty() - .clear_bit_by_one() - .serial_out_recv_pkt() - .clear_bit_by_one() - }); - - if rx { - WAKER_RX.wake(); - } - if tx { - WAKER_TX.wake(); + fn poll( + self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + WAKER_TX.register(cx.waker()); + if self.event_bit_is_clear() { + Poll::Ready(()) + } else { + Poll::Pending } } } + +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct UsbSerialJtagReadFuture<'d> { + _peripheral: PeripheralRef<'d, USB_DEVICE>, +} + +impl<'d> UsbSerialJtagReadFuture<'d> { + fn new(_peripheral: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(_peripheral); + // Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT + // interrupt + USB_DEVICE::register_block() + .int_ena() + .modify(|_, w| w.serial_out_recv_pkt().set_bit()); + + Self { _peripheral } + } + + fn event_bit_is_clear(&self) -> bool { + USB_DEVICE::register_block() + .int_ena() + .read() + .serial_out_recv_pkt() + .bit_is_clear() + } +} + +impl core::future::Future for UsbSerialJtagReadFuture<'_> { + type Output = (); + + fn poll( + self: core::pin::Pin<&mut Self>, + cx: &mut core::task::Context<'_>, + ) -> core::task::Poll { + WAKER_RX.register(cx.waker()); + if self.event_bit_is_clear() { + Poll::Ready(()) + } else { + Poll::Pending + } + } +} + +impl<'d> UsbSerialJtag<'d, Async> { + /// Reconfigure the USB Serial JTAG peripheral to operate in blocking + /// mode. + pub fn into_blocking(self) -> UsbSerialJtag<'d, Blocking> { + crate::interrupt::disable(Cpu::current(), Interrupt::USB_DEVICE); + UsbSerialJtag { + rx: UsbSerialJtagRx { + peripheral: self.rx.peripheral, + phantom: PhantomData, + }, + tx: UsbSerialJtagTx { + peripheral: self.tx.peripheral, + phantom: PhantomData, + }, + } + } +} + +impl UsbSerialJtagTx<'_, Async> { + async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> { + let reg_block = USB_DEVICE::register_block(); + + for chunk in words.chunks(64) { + for byte in chunk { + reg_block + .ep1() + .write(|w| unsafe { w.rdwr_byte().bits(*byte) }); + } + reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit()); + + UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await; + } + + Ok(()) + } + + async fn flush_tx_async(&mut self) -> Result<(), Error> { + if USB_DEVICE::register_block() + .jfifo_st() + .read() + .out_fifo_empty() + .bit_is_clear() + { + UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await; + } + + Ok(()) + } +} + +impl UsbSerialJtagRx<'_, Async> { + async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Ok(0); + } + + loop { + let read_bytes = self.drain_rx_fifo(buf); + if read_bytes > 0 { + return Ok(read_bytes); + } + UsbSerialJtagReadFuture::new(self.peripheral.reborrow()).await; + } + } +} + +impl embedded_io_async::Write for UsbSerialJtag<'_, Async> { + async fn write(&mut self, buf: &[u8]) -> Result { + embedded_io_async::Write::write(&mut self.tx, buf).await + } + + async fn flush(&mut self) -> Result<(), Self::Error> { + embedded_io_async::Write::flush(&mut self.tx).await + } +} + +impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> { + async fn write(&mut self, buf: &[u8]) -> Result { + self.write_bytes_async(buf).await?; + + Ok(buf.len()) + } + + async fn flush(&mut self) -> Result<(), Self::Error> { + self.flush_tx_async().await + } +} + +impl embedded_io_async::Read for UsbSerialJtag<'_, Async> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + embedded_io_async::Read::read(&mut self.rx, buf).await + } +} + +impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + self.read_bytes_async(buf).await + } +} + +#[handler] +fn async_interrupt_handler() { + let usb = USB_DEVICE::register_block(); + let interrupts = usb.int_st().read(); + + let tx = interrupts.serial_in_empty().bit_is_set(); + let rx = interrupts.serial_out_recv_pkt().bit_is_set(); + + if tx { + usb.int_ena().modify(|_, w| w.serial_in_empty().clear_bit()); + } + if rx { + usb.int_ena() + .modify(|_, w| w.serial_out_recv_pkt().clear_bit()); + } + + usb.int_clr().write(|w| { + w.serial_in_empty() + .clear_bit_by_one() + .serial_out_recv_pkt() + .clear_bit_by_one() + }); + + if rx { + WAKER_RX.wake(); + } + if tx { + WAKER_TX.wake(); + } +} diff --git a/examples/src/bin/embassy_i2c.rs b/examples/src/bin/embassy_i2c.rs index d6b10e04b..152369854 100644 --- a/examples/src/bin/embassy_i2c.rs +++ b/examples/src/bin/embassy_i2c.rs @@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) { 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(); lis3dh.set_range(Range::G8).await.unwrap(); diff --git a/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs b/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs index 737cc84ab..24fb3b779 100644 --- a/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs +++ b/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs @@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) { 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 { let mut data = [0u8; 22]; diff --git a/examples/src/bin/embassy_i2s_parallel.rs b/examples/src/bin/embassy_i2s_parallel.rs index dcf0167d8..509f71835 100644 --- a/examples/src/bin/embassy_i2s_parallel.rs +++ b/examples/src/bin/embassy_i2s_parallel.rs @@ -60,7 +60,9 @@ async fn main(_spawner: Spawner) { let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE); let mut parallel = I2sParallel::new( i2s, - dma_channel.configure_for_async(false, DmaPriority::Priority0), + dma_channel + .configure(false, DmaPriority::Priority0) + .into_async(), 1.MHz(), pins, clock, diff --git a/examples/src/bin/embassy_i2s_read.rs b/examples/src/bin/embassy_i2s_read.rs index 17c48383c..afb796c1c 100644 --- a/examples/src/bin/embassy_i2s_read.rs +++ b/examples/src/bin/embassy_i2s_read.rs @@ -52,10 +52,11 @@ async fn main(_spawner: Spawner) { Standard::Philips, DataFormat::Data16Channel16, 44100u32.Hz(), - dma_channel.configure_for_async(false, DmaPriority::Priority0), + dma_channel.configure(false, DmaPriority::Priority0), rx_descriptors, tx_descriptors, - ); + ) + .into_async(); #[cfg(not(feature = "esp32"))] let i2s = i2s.with_mclk(io.pins.gpio0); diff --git a/examples/src/bin/embassy_i2s_sound.rs b/examples/src/bin/embassy_i2s_sound.rs index 50660d818..2c807a475 100644 --- a/examples/src/bin/embassy_i2s_sound.rs +++ b/examples/src/bin/embassy_i2s_sound.rs @@ -74,10 +74,11 @@ async fn main(_spawner: Spawner) { Standard::Philips, DataFormat::Data16Channel16, 44100u32.Hz(), - dma_channel.configure_for_async(false, DmaPriority::Priority0), + dma_channel.configure(false, DmaPriority::Priority0), rx_descriptors, tx_descriptors, - ); + ) + .into_async(); let i2s_tx = i2s .i2s_tx diff --git a/examples/src/bin/embassy_parl_io_rx.rs b/examples/src/bin/embassy_parl_io_rx.rs index 83fccaec5..95e28f696 100644 --- a/examples/src/bin/embassy_parl_io_rx.rs +++ b/examples/src/bin/embassy_parl_io_rx.rs @@ -42,7 +42,9 @@ async fn main(_spawner: Spawner) { let parl_io = ParlIoRxOnly::new( peripherals.PARL_IO, - dma_channel.configure_for_async(false, DmaPriority::Priority0), + dma_channel + .configure(false, DmaPriority::Priority0) + .into_async(), rx_descriptors, 1.MHz(), ) diff --git a/examples/src/bin/embassy_parl_io_tx.rs b/examples/src/bin/embassy_parl_io_tx.rs index 9a1ca372f..e177ad506 100644 --- a/examples/src/bin/embassy_parl_io_tx.rs +++ b/examples/src/bin/embassy_parl_io_tx.rs @@ -55,7 +55,9 @@ async fn main(_spawner: Spawner) { let parl_io = ParlIoTxOnly::new( peripherals.PARL_IO, - dma_channel.configure_for_async(false, DmaPriority::Priority0), + dma_channel + .configure(false, DmaPriority::Priority0) + .into_async(), tx_descriptors, 1.MHz(), ) diff --git a/examples/src/bin/embassy_rmt_rx.rs b/examples/src/bin/embassy_rmt_rx.rs index 0befacef8..4ebfd23c5 100644 --- a/examples/src/bin/embassy_rmt_rx.rs +++ b/examples/src/bin/embassy_rmt_rx.rs @@ -15,7 +15,7 @@ use esp_backtrace as _; use esp_hal::{ gpio::{Io, Level, Output}, prelude::*, - rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreatorAsync}, + rmt::{PulseCode, Rmt, RxChannelAsync, RxChannelConfig, RxChannelCreatorAsync}, timer::timg::TimerGroup, }; 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 { clk_divider: 255, idle_threshold: 10000, diff --git a/examples/src/bin/embassy_rmt_tx.rs b/examples/src/bin/embassy_rmt_tx.rs index 04ddc45d5..79413f3c8 100644 --- a/examples/src/bin/embassy_rmt_tx.rs +++ b/examples/src/bin/embassy_rmt_tx.rs @@ -17,7 +17,7 @@ use esp_backtrace as _; use esp_hal::{ gpio::Io, prelude::*, - rmt::{asynch::TxChannelAsync, PulseCode, Rmt, TxChannelConfig, TxChannelCreatorAsync}, + rmt::{PulseCode, Rmt, TxChannelAsync, TxChannelConfig, TxChannelCreatorAsync}, timer::timg::TimerGroup, }; 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 .channel0 diff --git a/examples/src/bin/embassy_serial.rs b/examples/src/bin/embassy_serial.rs index e03136d7f..70728701a 100644 --- a/examples/src/bin/embassy_serial.rs +++ b/examples/src/bin/embassy_serial.rs @@ -97,7 +97,9 @@ async fn main(spawner: Spawner) { 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)); let (rx, tx) = uart0.split(); diff --git a/examples/src/bin/embassy_spi.rs b/examples/src/bin/embassy_spi.rs index 334cd7137..2ae0afe97 100644 --- a/examples/src/bin/embassy_spi.rs +++ b/examples/src/bin/embassy_spi.rs @@ -63,8 +63,9 @@ async fn main(_spawner: Spawner) { .with_mosi(mosi) .with_miso(miso) .with_cs(cs) - .with_dma(dma_channel.configure_for_async(false, DmaPriority::Priority0)) - .with_buffers(dma_rx_buf, dma_tx_buf); + .with_dma(dma_channel.configure(false, DmaPriority::Priority0)) + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); let send_buffer = [0, 1, 2, 3, 4, 5, 6, 7]; loop { diff --git a/examples/src/bin/embassy_twai.rs b/examples/src/bin/embassy_twai.rs index 40128f04a..b6140cd7c 100644 --- a/examples/src/bin/embassy_twai.rs +++ b/examples/src/bin/embassy_twai.rs @@ -103,17 +103,18 @@ async fn main(spawner: Spawner) { // The speed of the bus. 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 // 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, rx_pin, tx_pin, TWAI_BAUDRATE, TwaiMode::Normal, - ); + ) + .into_async(); // Partially filter the incoming messages to reduce overhead of receiving // undesired messages. Note that due to how the hardware filters messages, diff --git a/examples/src/bin/embassy_usb_serial_jtag.rs b/examples/src/bin/embassy_usb_serial_jtag.rs index 8944ed2dc..f1855834d 100644 --- a/examples/src/bin/embassy_usb_serial_jtag.rs +++ b/examples/src/bin/embassy_usb_serial_jtag.rs @@ -68,7 +68,9 @@ async fn main(spawner: Spawner) { let timg0 = TimerGroup::new(peripherals.TIMG0); 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>> = StaticCell::new(); diff --git a/hil-test/tests/embassy_interrupt_spi_dma.rs b/hil-test/tests/embassy_interrupt_spi_dma.rs index 65499ab4a..9ff60bfdd 100644 --- a/hil-test/tests/embassy_interrupt_spi_dma.rs +++ b/hil-test/tests/embassy_interrupt_spi_dma.rs @@ -81,11 +81,13 @@ mod test { let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0) - .with_dma(dma_channel1.configure_for_async(false, DmaPriority::Priority0)) - .with_buffers(dma_rx_buf, dma_tx_buf); + .with_dma(dma_channel1.configure(false, DmaPriority::Priority0)) + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); 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); @@ -144,9 +146,10 @@ mod test { .with_dma( peripherals .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]); loop { diff --git a/hil-test/tests/i2s.rs b/hil-test/tests/i2s.rs index b6d785879..b3d3a733a 100644 --- a/hil-test/tests/i2s.rs +++ b/hil-test/tests/i2s.rs @@ -143,11 +143,11 @@ mod tests { Standard::Philips, DataFormat::Data16Channel16, 16000.Hz(), - ctx.dma_channel - .configure_for_async(false, DmaPriority::Priority0), + ctx.dma_channel.configure(false, DmaPriority::Priority0), rx_descriptors, tx_descriptors, - ); + ) + .into_async(); let (_, dout) = hil_test::common_test_pins!(ctx.io); diff --git a/hil-test/tests/lcd_cam_i8080.rs b/hil-test/tests/lcd_cam_i8080.rs index 85d5c8493..2ac4b856b 100644 --- a/hil-test/tests/lcd_cam_i8080.rs +++ b/hil-test/tests/lcd_cam_i8080.rs @@ -19,13 +19,14 @@ use esp_hal::{ Pcnt, }, prelude::*, + Blocking, }; use hil_test as _; const DATA_SIZE: usize = 1024 * 10; struct Context<'d> { - lcd_cam: LcdCam<'d, esp_hal::Blocking>, + lcd_cam: LcdCam<'d, Blocking>, pcnt: Pcnt<'d>, io: Io, dma: Dma<'d>, @@ -79,7 +80,8 @@ mod tests { let channel = ctx .dma .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 i8080 = I8080::new( diff --git a/hil-test/tests/lcd_cam_i8080_async.rs b/hil-test/tests/lcd_cam_i8080_async.rs index c5c36d209..df44d0022 100644 --- a/hil-test/tests/lcd_cam_i8080_async.rs +++ b/hil-test/tests/lcd_cam_i8080_async.rs @@ -15,13 +15,14 @@ use esp_hal::{ LcdCam, }, prelude::*, + Async, }; use hil_test as _; const DATA_SIZE: usize = 1024 * 10; struct Context<'d> { - lcd_cam: LcdCam<'d, esp_hal::Async>, + lcd_cam: LcdCam<'d, Async>, dma: Dma<'d>, dma_buf: DmaTxBuf, } @@ -36,7 +37,7 @@ mod tests { let peripherals = esp_hal::init(esp_hal::Config::default()); 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 dma_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); @@ -75,7 +76,8 @@ mod tests { let channel = ctx .dma .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 i8080 = I8080::new( diff --git a/hil-test/tests/parl_io_tx_async.rs b/hil-test/tests/parl_io_tx_async.rs index cdb177a48..2557672c4 100644 --- a/hil-test/tests/parl_io_tx_async.rs +++ b/hil-test/tests/parl_io_tx_async.rs @@ -92,7 +92,8 @@ mod tests { let pio = ParlIoTxOnly::new( ctx.parl_io, ctx.dma_channel - .configure_for_async(false, DmaPriority::Priority0), + .configure(false, DmaPriority::Priority0) + .into_async(), tx_descriptors, 10.MHz(), ) @@ -159,7 +160,8 @@ mod tests { let pio = ParlIoTxOnly::new( ctx.parl_io, ctx.dma_channel - .configure_for_async(false, DmaPriority::Priority0), + .configure(false, DmaPriority::Priority0) + .into_async(), tx_descriptors, 10.MHz(), ) diff --git a/hil-test/tests/rsa_async.rs b/hil-test/tests/rsa_async.rs index 105f424e2..671c853a8 100644 --- a/hil-test/tests/rsa_async.rs +++ b/hil-test/tests/rsa_async.rs @@ -56,7 +56,7 @@ mod tests { #[init] fn init() -> Context<'static> { 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(); Context { rsa } diff --git a/hil-test/tests/spi_full_duplex.rs b/hil-test/tests/spi_full_duplex.rs index 1af4146ff..326501e23 100644 --- a/hil-test/tests/spi_full_duplex.rs +++ b/hil-test/tests/spi_full_duplex.rs @@ -18,6 +18,7 @@ use esp_hal::{ peripheral::Peripheral, prelude::*, spi::{master::Spi, SpiMode}, + Blocking, }; #[cfg(pcnt)] use esp_hal::{ @@ -35,7 +36,7 @@ cfg_if::cfg_if! { } struct Context { - spi: Spi<'static>, + spi: Spi<'static, Blocking>, dma_channel: DmaChannelCreator, // Reuse the really large buffer so we don't run out of DRAM with many tests rx_buffer: &'static mut [u8], @@ -392,11 +393,9 @@ mod tests { let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let mut spi = ctx .spi - .with_dma( - ctx.dma_channel - .configure_for_async(false, DmaPriority::Priority0), - ) - .with_buffers(dma_rx_buf, dma_tx_buf); + .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)) + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source); ctx.pcnt_unit @@ -428,11 +427,9 @@ mod tests { let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap(); let mut spi = ctx .spi - .with_dma( - ctx.dma_channel - .configure_for_async(false, DmaPriority::Priority0), - ) - .with_buffers(dma_rx_buf, dma_tx_buf); + .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)) + .with_buffers(dma_rx_buf, dma_tx_buf) + .into_async(); ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source); ctx.pcnt_unit @@ -557,10 +554,10 @@ mod tests { 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 spi = ctx.spi.with_dma( - ctx.dma_channel - .configure_for_async(false, DmaPriority::Priority0), - ); + let spi = ctx + .spi + .with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0)) + .into_async(); let mut transfer = spi .transfer(dma_rx_buf, dma_tx_buf) diff --git a/hil-test/tests/spi_slave.rs b/hil-test/tests/spi_slave.rs index f39791b68..76aac7818 100644 --- a/hil-test/tests/spi_slave.rs +++ b/hil-test/tests/spi_slave.rs @@ -13,6 +13,7 @@ use esp_hal::{ dma_buffers, gpio::{interconnect::InputSignal, Io, Level, Output}, spi::{slave::Spi, SpiMode}, + Blocking, }; use hil_test as _; @@ -25,7 +26,7 @@ cfg_if::cfg_if! { } struct Context { - spi: Spi<'static>, + spi: Spi<'static, Blocking>, dma_channel: DmaChannelCreator, bitbang_spi: BitbangSpi, } diff --git a/hil-test/tests/uart_async.rs b/hil-test/tests/uart_async.rs index 5ebc7f006..5adcd854a 100644 --- a/hil-test/tests/uart_async.rs +++ b/hil-test/tests/uart_async.rs @@ -26,7 +26,7 @@ mod tests { 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 } } diff --git a/hil-test/tests/uart_tx_rx_async.rs b/hil-test/tests/uart_tx_rx_async.rs index d02f0a387..4122d0963 100644 --- a/hil-test/tests/uart_tx_rx_async.rs +++ b/hil-test/tests/uart_tx_rx_async.rs @@ -31,8 +31,8 @@ mod tests { let (rx, tx) = hil_test::common_test_pins!(io); - let tx = UartTx::new_async(peripherals.UART0, tx).unwrap(); - let rx = UartRx::new_async(peripherals.UART1, rx).unwrap(); + let tx = UartTx::new(peripherals.UART0, tx).unwrap().into_async(); + let rx = UartRx::new(peripherals.UART1, rx).unwrap().into_async(); Context { rx, tx } } diff --git a/hil-test/tests/usb_serial_jtag.rs b/hil-test/tests/usb_serial_jtag.rs index c5e5bf445..4f7cdb328 100644 --- a/hil-test/tests/usb_serial_jtag.rs +++ b/hil-test/tests/usb_serial_jtag.rs @@ -18,6 +18,8 @@ mod tests { let timg0 = TimerGroup::new(peripherals.TIMG0); esp_hal_embassy::init(timg0.timer0); - _ = UsbSerialJtag::new_async(peripherals.USB_DEVICE).split(); + _ = UsbSerialJtag::new(peripherals.USB_DEVICE) + .into_async() + .split(); } }