into_async (#2430)

* Remove configure_for_async

* Add into_async and into_blocking to I2c

* Add into_async and into_blocking to UsbSerialJtag

* Rework LCD_CAM

* Rmt

* RSA

* TWAI

* Uart

* Documentation

* Disable interrupts set on other core

* Move configure into RegisterAccess

* Disable interrupts on the other core

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

View File

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

View File

@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- I2S Parallel output driver for ESP32. (#2348, #2436)
- 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]

View File

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

View File

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

View File

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

View File

@ -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<Self>;
type Tx = ChannelTxImpl<Self>;
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler {
match ch.tx.tx_impl.0.number() {
0 => DmaChannel0::handler(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::handler(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::handler(),
#[cfg(esp32s3)]
3 => DmaChannel3::handler(),
#[cfg(esp32s3)]
4 => DmaChannel4::handler(),
_ => unreachable!(),
}
}
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
match ch.tx.tx_impl.0.number() {
0 => DmaChannel0::isrs(),
#[cfg(not(esp32c2))]
1 => DmaChannel1::isrs(),
#[cfg(not(esp32c2))]
2 => DmaChannel2::isrs(),
#[cfg(esp32s3)]
3 => DmaChannel3::isrs(),
#[cfg(esp32s3)]
4 => DmaChannel4::isrs(),
_ => unreachable!(),
}
}
}
#[non_exhaustive]
@ -460,9 +492,27 @@ macro_rules! impl_channel {
impl crate::private::Sealed for [<DmaChannel $num>] {}
impl [<DmaChannel $num>] {
fn handler() -> InterruptHandler {
$async_handler
}
fn isrs() -> &'static [Interrupt] {
&[$(Interrupt::$interrupt),*]
}
}
impl DmaChannel for [<DmaChannel $num>] {
type Rx = ChannelRxImpl<SpecificGdmaChannel<$num>>;
type Tx = ChannelTxImpl<SpecificGdmaChannel<$num>>;
fn async_handler<M: Mode>(_ch: &Channel<'_, Self, M>) -> InterruptHandler {
Self::handler()
}
fn interrupts<M: Mode>(_ch: &Channel<'_, Self, M>,) -> &'static [Interrupt] {
Self::isrs()
}
}
impl DmaChannelConvert<AnyGdmaChannel> for [<DmaChannel $num>] {
@ -482,64 +532,22 @@ macro_rules! impl_channel {
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
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, [<DmaChannel $num>], M> {
let tx_impl = ChannelTxImpl(SpecificGdmaChannel::<$num> {});
tx_impl.set_burst_mode(burst_mode);
tx_impl.set_priority(priority);
let rx_impl = ChannelRxImpl(SpecificGdmaChannel::<$num> {});
rx_impl.set_burst_mode(burst_mode);
rx_impl.set_priority(priority);
// clear the mem2mem mode to avoid failed DMA if this
// channel was previously used for a mem2mem transfer.
rx_impl.set_mem2mem_mode(false);
crate::dma::Channel {
tx: ChannelTx::new(tx_impl, burst_mode),
rx: ChannelRx::new(rx_impl, burst_mode),
phantom: PhantomData,
}
}
/// Configure the channel for use with blocking APIs
///
/// 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, [<DmaChannel $num>], crate::Blocking> {
self.do_configure(burst_mode, priority)
}
) -> Channel<'a, [<DmaChannel $num>], 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, [<DmaChannel $num>], $crate::Async> {
let this = self.do_configure(burst_mode, priority);
[<DmaChannel $num>]::set_isr($async_handler);
this.configure(burst_mode, priority);
this
}

View File

@ -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<CH>(
channel: Channel<'d, CH, M>,
pub fn new<CH, DM>(
channel: Channel<'d, CH, DM>,
peripheral: impl DmaEligible,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
) -> Result<Self, DmaError>
where
CH: DmaChannelConvert<AnyGdmaChannel>,
DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
{
unsafe {
Self::new_unsafe(
@ -62,8 +63,8 @@ where
}
/// Create a new Mem2Mem instance with specific chunk size.
pub fn new_with_chunk_size<CH>(
channel: Channel<'d, CH, M>,
pub fn new_with_chunk_size<CH, DM>(
channel: Channel<'d, CH, DM>,
peripheral: impl DmaEligible,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
@ -71,6 +72,8 @@ where
) -> Result<Self, DmaError>
where
CH: DmaChannelConvert<AnyGdmaChannel>,
DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
{
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<CH>(
channel: Channel<'d, CH, M>,
pub unsafe fn new_unsafe<CH, DM>(
channel: Channel<'d, CH, DM>,
peripheral: DmaPeripheral,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
@ -98,6 +101,8 @@ where
) -> Result<Self, DmaError>
where
CH: DmaChannelConvert<AnyGdmaChannel>,
DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
{
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,

View File

@ -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<DmaRxInterrupt>;
/// A description of the TX half of a DMA Channel.
type Tx: TxRegisterAccess + InterruptAccess<DmaTxInterrupt>;
/// Returns the async interrupt handler.
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler;
/// Returns the interrupt.
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt];
}
#[doc(hidden)]
pub trait DmaChannelExt: DmaChannel {
fn get_rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt>;
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt>;
#[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<CH> 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<CH> 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<T: EnumSetType>: 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<MODE>,
pub(crate) phantom: PhantomData<M>,
}
impl<C> 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<Channel<'d, C, Blocking>> for Channel<'d, C, Async> {
fn from(channel: Channel<'d, C, Blocking>) -> Self {
channel.into_async()
}
}
impl<'d, C: DmaChannel> From<Channel<'d, C, Async>> for Channel<'d, C, Blocking> {
fn from(channel: Channel<'d, C, Async>) -> Self {
channel.into_blocking()
}
}
impl<'d, CH, M: Mode> Channel<'d, CH, M>
@ -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::<I2s0DmaChannel>();
}
#[cfg(i2s1)]
#[handler(priority = crate::interrupt::Priority::max())]
pub(crate) fn interrupt_handler_i2s1() {
pub(crate) fn interrupt_handler_i2s1_dma() {
handle_interrupt::<I2s1DmaChannel>();
}
}

View File

@ -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 [<Spi $num DmaChannel>] {}
impl [<Spi $num DmaChannel>] {
fn handler() -> InterruptHandler {
super::asynch::interrupt::[< interrupt_handler_spi $num _dma >]
}
fn isrs() -> &'static [Interrupt] {
&[Interrupt::[< SPI $num _DMA >]]
}
}
impl DmaChannel for [<Spi $num DmaChannel>] {
type Rx = SpiDmaRxChannelImpl<Self>;
type Tx = SpiDmaTxChannelImpl<Self>;
fn async_handler<M: Mode>(_ch: &Channel<'_, Self, M>) -> InterruptHandler {
Self::handler()
}
fn interrupts<M: Mode>(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
Self::isrs()
}
}
impl DmaChannelExt for [<Spi $num DmaChannel>] {
@ -353,14 +373,6 @@ macro_rules! ImplSpiChannel {
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
SpiDmaTxChannelImpl(Self {})
}
fn set_isr(handler: InterruptHandler) {
let interrupt = $crate::peripherals::Interrupt::[< SPI $num _DMA >];
unsafe {
crate::interrupt::bind_interrupt(interrupt, handler.handler());
}
crate::interrupt::enable(interrupt, handler.priority()).unwrap();
}
}
impl PdmaChannel for [<Spi $num DmaChannel>] {
@ -399,59 +411,19 @@ macro_rules! ImplSpiChannel {
pub struct [<Spi $num DmaChannelCreator>] {}
impl [<Spi $num DmaChannelCreator>] {
fn do_configure<'a, M: $crate::Mode>(
self,
burst_mode: bool,
priority: DmaPriority,
) -> Channel<'a, [<Spi $num DmaChannel>], M> {
#[cfg(esp32)]
{
// (only) on ESP32 we need to configure DPORT for the SPI DMA channels
let dport = unsafe { &*crate::peripherals::DPORT::PTR };
dport
.spi_dma_chan_sel()
.modify(|_, w| unsafe { w.[< spi $num _dma_chan_sel>]().bits($num - 1) });
}
let tx_impl = SpiDmaTxChannelImpl([<Spi $num DmaChannel>] {});
tx_impl.set_burst_mode(burst_mode);
tx_impl.set_priority(priority);
let rx_impl = SpiDmaRxChannelImpl([<Spi $num DmaChannel>] {});
rx_impl.set_burst_mode(burst_mode);
rx_impl.set_priority(priority);
Channel {
tx: ChannelTx::new(tx_impl, burst_mode),
rx: ChannelRx::new(rx_impl, burst_mode),
phantom: PhantomData,
}
}
/// Configure the channel for use with blocking APIs
///
/// 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, [<Spi $num DmaChannel>], $crate::Blocking> {
Self::do_configure(self, burst_mode, priority)
}
) -> Channel<'a, [<Spi $num DmaChannel>], Blocking> {
let mut this = Channel {
tx: ChannelTx::new(SpiDmaTxChannelImpl([<Spi $num DmaChannel>] {})),
rx: ChannelRx::new(SpiDmaRxChannelImpl([<Spi $num DmaChannel>] {})),
phantom: PhantomData,
};
/// Configure the channel for use with async APIs
///
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
pub fn configure_for_async<'a>(
self,
burst_mode: bool,
priority: DmaPriority,
) -> Channel<'a, [<Spi $num DmaChannel>], $crate::Async> {
let this = Self::do_configure(self, burst_mode, priority);
[<Spi $num DmaChannel>]::set_isr(super::asynch::interrupt::[< interrupt_handler_spi $num _dma >]);
this.configure(burst_mode, priority);
this
}
@ -784,9 +756,27 @@ macro_rules! ImplI2sChannel {
impl $crate::private::Sealed for [<I2s $num DmaChannel>] {}
impl [<I2s $num DmaChannel>] {
fn handler() -> InterruptHandler {
super::asynch::interrupt::[< interrupt_handler_i2s $num _dma >]
}
fn isrs() -> &'static [Interrupt] {
&[Interrupt::[< I2S $num >]]
}
}
impl DmaChannel for [<I2s $num DmaChannel>] {
type Rx = I2sDmaRxChannelImpl<Self>;
type Tx = I2sDmaTxChannelImpl<Self>;
fn async_handler<M: Mode>(_ch: &Channel<'_, Self, M>) -> InterruptHandler {
Self::handler()
}
fn interrupts<M: Mode>(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
Self::isrs()
}
}
impl DmaChannelExt for [<I2s $num DmaChannel>] {
@ -796,14 +786,6 @@ macro_rules! ImplI2sChannel {
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
I2sDmaTxChannelImpl(Self {})
}
fn set_isr(handler: InterruptHandler) {
let interrupt = $crate::peripherals::Interrupt::[< I2S $num >];
unsafe {
crate::interrupt::bind_interrupt(interrupt, handler.handler());
}
crate::interrupt::enable(interrupt, handler.priority()).unwrap();
}
}
impl PdmaChannel for [<I2s $num DmaChannel>] {
@ -838,50 +820,19 @@ macro_rules! ImplI2sChannel {
pub struct [<I2s $num DmaChannelCreator>] {}
impl [<I2s $num DmaChannelCreator>] {
fn do_configure<'a, M: $crate::Mode>(
self,
burst_mode: bool,
priority: DmaPriority,
) -> Channel<'a, [<I2s $num DmaChannel>], M> {
let tx_impl = I2sDmaTxChannelImpl([<I2s $num DmaChannel>] {});
tx_impl.set_burst_mode(burst_mode);
tx_impl.set_priority(priority);
let rx_impl = I2sDmaRxChannelImpl([<I2s $num DmaChannel>] {});
rx_impl.set_burst_mode(burst_mode);
rx_impl.set_priority(priority);
Channel {
tx: ChannelTx::new(tx_impl, burst_mode),
rx: ChannelRx::new(rx_impl, burst_mode),
phantom: PhantomData,
}
}
/// Configure the channel for use with blocking APIs
///
/// 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, [<I2s $num DmaChannel>], $crate::Blocking> {
Self::do_configure(self, burst_mode, priority)
}
) -> Channel<'a, [<I2s $num DmaChannel>], Blocking> {
let mut this = Channel {
tx: ChannelTx::new(I2sDmaTxChannelImpl([<I2s $num DmaChannel>] {})),
rx: ChannelRx::new(I2sDmaRxChannelImpl([<I2s $num DmaChannel>] {})),
phantom: PhantomData,
};
/// Configure the channel for use with async APIs
///
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
pub fn configure_for_async<'a>(
self,
burst_mode: bool,
priority: DmaPriority,
) -> Channel<'a, [<I2s $num DmaChannel>], $crate::Async> {
let this = Self::do_configure(self, burst_mode, priority);
[<I2s $num DmaChannel>]::set_isr(super::asynch::interrupt::[< interrupt_handler_i2s $num >]);
this.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<AnySpiDmaChannelInner>;
type Tx = SpiDmaTxChannelImpl<AnySpiDmaChannelInner>;
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler {
match &ch.tx.tx_impl.0 {
AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::handler(),
AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::handler(),
}
}
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
match &ch.tx.tx_impl.0 {
AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::isrs(),
AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::isrs(),
}
}
}
crate::any_enum! {
@ -998,6 +976,22 @@ impl crate::private::Sealed for AnyI2sDmaChannel {}
impl DmaChannel for AnyI2sDmaChannel {
type Rx = I2sDmaRxChannelImpl<AnyI2sDmaChannelInner>;
type Tx = I2sDmaTxChannelImpl<AnyI2sDmaChannelInner>;
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler {
match &ch.tx.tx_impl.0 {
AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::handler(),
#[cfg(i2s1)]
AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::handler(),
}
}
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
match &ch.tx.tx_impl.0 {
AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::isrs(),
#[cfg(i2s1)]
AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::isrs(),
}
}
}
crate::any_enum! {

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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<DmaMode>,
pub i2s_tx: TxCreator<'d, M, T>,
phantom: PhantomData<M>,
}
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<CH>(
pub fn new<CH, DM>(
i2s: impl Peripheral<P = impl RegisterAccess> + 'd,
standard: Standard,
data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<'d, CH, DmaMode>,
channel: Channel<'d, CH, DM>,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
) -> Self
where
CH: DmaChannelConvert<<AnyI2s as DmaEligible>::Dma>,
DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
{
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<CH>(
pub fn new_typed<CH, DM>(
i2s: impl Peripheral<P = T> + 'd,
standard: Standard,
data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<'d, CH, DmaMode>,
channel: Channel<'d, CH, DM>,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
) -> Self
where
CH: DmaChannelConvert<T::Dma>,
DM: Mode,
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
{
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::<Blocking>,
};
let channel = channel.into_async();
I2s {
i2s_rx: RxCreator {
i2s: self.i2s_rx.i2s,
rx_channel: channel.rx,
descriptors: self.i2s_rx.descriptors,
phantom: PhantomData,
},
i2s_tx: TxCreator {
i2s: self.i2s_tx.i2s,
tx_channel: channel.tx,
descriptors: self.i2s_tx.descriptors,
phantom: PhantomData,
},
phantom: PhantomData,
}
}
}
impl<'d, M, T> I2s<'d, M, T>
where
T: RegisterAccess,
M: Mode,
{
/// Configures the I2S peripheral to use a master clock (MCLK) output pin.
pub fn with_mclk<P: PeripheralOutput>(self, pin: impl Peripheral<P = P> + '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<DmaMode>,
pub(crate) phantom: PhantomData<M>,
}
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<DmaMode>,
pub(crate) phantom: PhantomData<M>,
}
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()
));
}
}

View File

@ -62,10 +62,11 @@ impl<const NUM: u8> SoftwareInterrupt<NUM> {
_ => 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

View File

@ -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;
}

View File

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

View File

@ -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<P = LCD_CAM> + '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<P = LCD_CAM> + 'd) -> Self {
crate::into_ref!(lcd_cam);
PeripheralClockControl::enable(system::Peripheral::LcdCam);
unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::LCD_CAM,
asynch::interrupt_handler.handler(),
);
}
crate::interrupt::enable(
crate::peripherals::Interrupt::LCD_CAM,
asynch::interrupt_handler.priority(),
)
.unwrap();
Self {
/// 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<ClockDivider> {
let div_num = source_frequency / desired_frequency;
if div_num < 2 {
// Source clock isn't fast enough to reach the desired frequency.
// Return max output.
return Some(ClockDivider {
div_num: 1,
div_b: 0,
div_a: 0,
});
}
if div_num > 256 {
// Source is too fast to divide to the desired frequency. Return None.
return None;
}
fn calculate_closest_divider(
source_frequency: usize,
desired_frequency: usize,
) -> Option<ClockDivider> {
let div_num = source_frequency / desired_frequency;
if div_num < 2 {
// Source clock isn't fast enough to reach the desired frequency.
// Return max output.
return Some(ClockDivider {
div_num: 1,
div_b: 0,
div_a: 0,
});
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<Item = Fraction> {
let mut a = 0;
let mut b = 1;
let mut c = 1;
let mut d = denominator;
core::iter::from_fn(move || {
if a > denominator {
return None;
}
let 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<Item = Fraction> {
let mut a = 0;
let mut b = 1;
let mut c = 1;
let mut d = denominator;
core::iter::from_fn(move || {
if a > denominator {
return None;
}
let next = Fraction {
numerator: a,
denominator: b,
};
let k = (denominator + b) / d;
(a, b, c, d) = (c, d, k * c - a, k * d - b);
Some(next)
})
}
let k = (denominator + b) / d;
(a, b, c, d) = (c, d, k * c - a, k * d - b);
Some(next)
})
}

View File

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

View File

@ -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<ParlIoInterrupt>, 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<ParlIoInterrupt> {
@ -980,17 +990,16 @@ fn internal_interrupts() -> EnumSet<ParlIoInterrupt> {
fn internal_clear_interrupts(interrupts: EnumSet<ParlIoInterrupt>) {
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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -26,8 +26,11 @@ use core::{marker::PhantomData, ptr::copy_nonoverlapping};
use crate::{
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<DM>,
}
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<P = RSA> + '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<P = RSA> + '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();

View File

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

View File

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

View File

@ -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<M>,
}
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<CH, DmaMode>(
self,
channel: crate::dma::Channel<'d, CH, DmaMode>,
) -> SpiDma<'d, DmaMode, T>
pub fn with_dma<CH, DM>(self, channel: Channel<'d, CH, DM>) -> SpiDma<'d, M, T>
where
CH: DmaChannelConvert<T::Dma>,
DmaMode: Mode,
DM: Mode,
Channel<'d, CH, M>: From<Channel<'d, CH, DM>>,
{
SpiDma::new(self.spi, channel)
SpiDma::new(self.spi, channel.into())
}
}
impl<T> Spi<'_, T>
impl<M, T> Spi<'_, M, T>
where
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<P = impl Instance> + '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<P = T> + '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<T> Spi<'_, T>
impl<M, T> Spi<'_, M, T>
where
T: Instance,
{
@ -754,7 +788,7 @@ where
}
}
impl<T> embedded_hal_02::spi::FullDuplex<u8> for Spi<'_, T>
impl<M, T> embedded_hal_02::spi::FullDuplex<u8> for Spi<'_, M, T>
where
T: Instance,
{
@ -769,7 +803,7 @@ where
}
}
impl<T> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'_, T>
impl<M, T> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'_, M, T>
where
T: Instance,
{
@ -780,7 +814,7 @@ where
}
}
impl<T> embedded_hal_02::blocking::spi::Write<u8> for Spi<'_, T>
impl<M, T> embedded_hal_02::blocking::spi::Write<u8> for Spi<'_, M, T>
where
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<T, Buf> SpiDmaTransfer<'_, crate::Async, Buf, T>
impl<T, Buf> 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<T> embedded_hal_02::blocking::spi::Transfer<u8> for SpiDmaBus<'_, crate::Blocking, T>
impl<T> embedded_hal_02::blocking::spi::Transfer<u8> for SpiDmaBus<'_, Blocking, T>
where
T: InstanceDma,
{
@ -1711,7 +1808,7 @@ mod dma {
}
}
impl<T> embedded_hal_02::blocking::spi::Write<u8> for SpiDmaBus<'_, crate::Blocking, T>
impl<T> embedded_hal_02::blocking::spi::Write<u8> for SpiDmaBus<'_, Blocking, T>
where
T: InstanceDma,
{
@ -1731,6 +1828,7 @@ mod dma {
};
use super::*;
use crate::Async;
struct DropGuard<I, F: FnOnce(I)> {
inner: ManuallyDrop<I>,
@ -1770,7 +1868,7 @@ mod dma {
}
}
impl<T> SpiDmaBus<'_, crate::Async, T>
impl<T> SpiDmaBus<'_, Async, T>
where
T: InstanceDma,
{
@ -1884,7 +1982,7 @@ mod dma {
}
}
impl<T> embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, crate::Async, T>
impl<T> embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, Async, T>
where
T: InstanceDma,
{
@ -1959,11 +2057,11 @@ mod ehal1 {
use super::*;
impl<T> embedded_hal::spi::ErrorType for Spi<'_, T> {
impl<M, T> embedded_hal::spi::ErrorType for Spi<'_, M, T> {
type Error = Error;
}
impl<T> FullDuplex for Spi<'_, T>
impl<M, T> FullDuplex for Spi<'_, M, T>
where
T: Instance,
{
@ -1976,7 +2074,7 @@ mod ehal1 {
}
}
impl<T> SpiBus for Spi<'_, T>
impl<M, T> SpiBus for Spi<'_, M, T>
where
T: Instance,
{

View File

@ -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<M>,
}
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<P = MISO> + 'd,
cs: impl Peripheral<P = CS> + '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<P = MISO> + 'd,
cs: impl Peripheral<P = CS> + '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<P = T> + 'd, mode: SpiMode) -> Spi<'d, T> {
pub(crate) fn new_internal(spi: impl Peripheral<P = T> + 'd, mode: SpiMode) -> Spi<'d, M, T> {
crate::into_ref!(spi);
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<CH, DmaMode>(
pub fn with_dma<CH, DM>(
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<T::Dma>,
DmaMode: Mode,
DM: Mode,
Channel<'d, CH, M>: From<Channel<'d, CH, DM>>,
{
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,
}

View File

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

View File

@ -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 {

View File

@ -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<RX: PeripheralInput, TX: PeripheralOutput>(
peripheral: impl Peripheral<P = impl Instance> + 'd,
rx_pin: impl Peripheral<P = RX> + 'd,
tx_pin: impl Peripheral<P = TX> + 'd,
baud_rate: BaudRate,
mode: TwaiMode,
) -> Self {
Self::new_async_typed(peripheral.map_into(), rx_pin, tx_pin, baud_rate, mode)
}
/// Create a new instance of [TwaiConfiguration] meant to connect two ESP32s
/// directly
///
/// You don't need a transceiver by following the description in the
/// `twai.rs` example
pub fn new_async_no_transceiver<RX: PeripheralInput, TX: PeripheralOutput>(
peripheral: impl Peripheral<P = impl Instance> + 'd,
rx_pin: impl Peripheral<P = RX> + 'd,
tx_pin: impl Peripheral<P = TX> + 'd,
baud_rate: BaudRate,
mode: TwaiMode,
) -> Self {
Self::new_async_no_transceiver_typed(peripheral.map_into(), rx_pin, tx_pin, baud_rate, mode)
/// 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<RX: PeripheralInput, TX: PeripheralOutput>(
peripheral: impl Peripheral<P = T> + 'd,
rx_pin: impl Peripheral<P = RX> + 'd,
tx_pin: impl Peripheral<P = TX> + 'd,
baud_rate: BaudRate,
mode: TwaiMode,
) -> Self {
TwaiConfiguration::new_typed(peripheral, rx_pin, tx_pin, baud_rate, mode).into_async()
}
/// 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<RX: PeripheralInput, TX: PeripheralOutput>(
peripheral: impl Peripheral<P = T> + 'd,
rx_pin: impl Peripheral<P = RX> + 'd,
tx_pin: impl Peripheral<P = TX> + 'd,
baud_rate: BaudRate,
mode: TwaiMode,
) -> Self {
TwaiConfiguration::new_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,
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -75,14 +75,18 @@
//! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/
//! [embedded-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<M>,
}
/// USB Serial/JTAG (Receive)
pub struct UsbSerialJtagRx<'d, M> {
phantom: PhantomData<(&'d mut USB_DEVICE, M)>,
peripheral: PeripheralRef<'d, USB_DEVICE>,
phantom: PhantomData<M>,
}
impl<M> UsbSerialJtagTx<'_, M>
impl<'d, M> UsbSerialJtagTx<'d, M>
where
M: Mode,
{
fn new_inner() -> Self {
fn new_inner(peripheral: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
crate::into_ref!(peripheral);
Self {
peripheral,
phantom: PhantomData,
}
}
@ -183,12 +191,14 @@ where
}
}
impl<M> UsbSerialJtagRx<'_, M>
impl<'d, M> UsbSerialJtagRx<'d, M>
where
M: Mode,
{
fn new_inner() -> Self {
fn new_inner(peripheral: impl Peripheral<P = USB_DEVICE> + '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<P = USB_DEVICE> + '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<P = USB_DEVICE> + 'd) -> Self {
fn new_inner(usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
// Do NOT reset the peripheral. Doing so will result in a broken USB JTAG
// 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<P = USB_DEVICE> + 'd) -> Self {
crate::into_ref!(_peripheral);
// Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT
// interrupt
USB_DEVICE::register_block()
.int_ena()
.modify(|_, w| w.serial_in_empty().set_bit());
// Static instance of the waker for each component of the peripheral:
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<Self::Output> {
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<Self::Output> {
WAKER_RX.register(cx.waker());
if self.event_bit_is_clear() {
Poll::Ready(())
} else {
Poll::Pending
}
}
}
impl<'d> UsbSerialJtag<'d, Async> {
/// Create a new USB serial/JTAG instance in asynchronous mode
pub fn new_async(usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
let mut this = Self::new_inner(usb_device);
this.inner_set_interrupt_handler(async_interrupt_handler);
this
}
}
impl UsbSerialJtagTx<'_, Async> {
async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> {
let reg_block = USB_DEVICE::register_block();
for chunk in words.chunks(64) {
for byte in chunk {
reg_block
.ep1()
.write(|w| unsafe { w.rdwr_byte().bits(*byte) });
}
reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit());
UsbSerialJtagWriteFuture::new().await;
}
Ok(())
}
async fn flush_tx_async(&mut self) -> Result<(), Error> {
if USB_DEVICE::register_block()
.jfifo_st()
.read()
.out_fifo_empty()
.bit_is_clear()
{
UsbSerialJtagWriteFuture::new().await;
}
Ok(())
}
}
impl UsbSerialJtagRx<'_, Async> {
async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
if buf.is_empty() {
return Ok(0);
}
loop {
let read_bytes = self.drain_rx_fifo(buf);
if read_bytes > 0 {
return Ok(read_bytes);
}
UsbSerialJtagReadFuture::new().await;
}
}
}
impl embedded_io_async::Write for UsbSerialJtag<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
embedded_io_async::Write::write(&mut self.tx, buf).await
}
async fn flush(&mut self) -> Result<(), Self::Error> {
embedded_io_async::Write::flush(&mut self.tx).await
}
}
impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_bytes_async(buf).await?;
Ok(buf.len())
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush_tx_async().await
}
}
impl embedded_io_async::Read for UsbSerialJtag<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
embedded_io_async::Read::read(&mut self.rx, buf).await
}
}
impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_bytes_async(buf).await
}
}
#[handler]
fn async_interrupt_handler() {
let usb = USB_DEVICE::register_block();
let interrupts = usb.int_st().read();
let tx = interrupts.serial_in_empty().bit_is_set();
let rx = interrupts.serial_out_recv_pkt().bit_is_set();
if tx {
usb.int_ena().modify(|_, w| w.serial_in_empty().clear_bit());
}
if rx {
usb.int_ena()
.modify(|_, w| w.serial_out_recv_pkt().clear_bit());
}
usb.int_clr().write(|w| {
w.serial_in_empty()
.clear_bit_by_one()
.serial_out_recv_pkt()
.clear_bit_by_one()
});
if rx {
WAKER_RX.wake();
}
if tx {
WAKER_TX.wake();
fn poll(
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
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<P = USB_DEVICE> + 'd) -> Self {
crate::into_ref!(_peripheral);
// Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT
// interrupt
USB_DEVICE::register_block()
.int_ena()
.modify(|_, w| w.serial_out_recv_pkt().set_bit());
Self { _peripheral }
}
fn event_bit_is_clear(&self) -> bool {
USB_DEVICE::register_block()
.int_ena()
.read()
.serial_out_recv_pkt()
.bit_is_clear()
}
}
impl core::future::Future for UsbSerialJtagReadFuture<'_> {
type Output = ();
fn poll(
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
WAKER_RX.register(cx.waker());
if self.event_bit_is_clear() {
Poll::Ready(())
} else {
Poll::Pending
}
}
}
impl<'d> UsbSerialJtag<'d, Async> {
/// Reconfigure the USB Serial JTAG peripheral to operate in blocking
/// mode.
pub fn into_blocking(self) -> UsbSerialJtag<'d, Blocking> {
crate::interrupt::disable(Cpu::current(), Interrupt::USB_DEVICE);
UsbSerialJtag {
rx: UsbSerialJtagRx {
peripheral: self.rx.peripheral,
phantom: PhantomData,
},
tx: UsbSerialJtagTx {
peripheral: self.tx.peripheral,
phantom: PhantomData,
},
}
}
}
impl UsbSerialJtagTx<'_, Async> {
async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> {
let reg_block = USB_DEVICE::register_block();
for chunk in words.chunks(64) {
for byte in chunk {
reg_block
.ep1()
.write(|w| unsafe { w.rdwr_byte().bits(*byte) });
}
reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit());
UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await;
}
Ok(())
}
async fn flush_tx_async(&mut self) -> Result<(), Error> {
if USB_DEVICE::register_block()
.jfifo_st()
.read()
.out_fifo_empty()
.bit_is_clear()
{
UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await;
}
Ok(())
}
}
impl UsbSerialJtagRx<'_, Async> {
async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
if buf.is_empty() {
return Ok(0);
}
loop {
let read_bytes = self.drain_rx_fifo(buf);
if read_bytes > 0 {
return Ok(read_bytes);
}
UsbSerialJtagReadFuture::new(self.peripheral.reborrow()).await;
}
}
}
impl embedded_io_async::Write for UsbSerialJtag<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
embedded_io_async::Write::write(&mut self.tx, buf).await
}
async fn flush(&mut self) -> Result<(), Self::Error> {
embedded_io_async::Write::flush(&mut self.tx).await
}
}
impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_bytes_async(buf).await?;
Ok(buf.len())
}
async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush_tx_async().await
}
}
impl embedded_io_async::Read for UsbSerialJtag<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
embedded_io_async::Read::read(&mut self.rx, buf).await
}
}
impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_bytes_async(buf).await
}
}
#[handler]
fn async_interrupt_handler() {
let usb = USB_DEVICE::register_block();
let interrupts = usb.int_st().read();
let tx = interrupts.serial_in_empty().bit_is_set();
let rx = interrupts.serial_out_recv_pkt().bit_is_set();
if tx {
usb.int_ena().modify(|_, w| w.serial_in_empty().clear_bit());
}
if rx {
usb.int_ena()
.modify(|_, w| w.serial_out_recv_pkt().clear_bit());
}
usb.int_clr().write(|w| {
w.serial_in_empty()
.clear_bit_by_one()
.serial_out_recv_pkt()
.clear_bit_by_one()
});
if rx {
WAKER_RX.wake();
}
if tx {
WAKER_TX.wake();
}
}

View File

@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) {
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
let 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();

View File

@ -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];

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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(),
)

View File

@ -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(),
)

View File

@ -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,

View File

@ -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

View File

@ -97,7 +97,9 @@ async fn main(spawner: Spawner) {
let config = Config::default().rx_fifo_full_threshold(READ_BUF_SIZE as u16);
let 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();

View File

@ -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 {

View File

@ -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,

View File

@ -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<Signal<NoopRawMutex, heapless::String<MAX_BUFFER_SIZE>>> =
StaticCell::new();

View File

@ -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 {

View File

@ -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);

View File

@ -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(

View File

@ -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(

View File

@ -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(),
)

View File

@ -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 }

View File

@ -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)

View File

@ -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,
}

View File

@ -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 }
}

View File

@ -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 }
}

View File

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