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:
parent
c717f04d4d
commit
40c0a6944e
@ -1,2 +1,3 @@
|
||||
[alias]
|
||||
xtask = "run --package xtask --"
|
||||
xfmt = "xtask fmt-packages"
|
||||
|
||||
@ -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]
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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! {
|
||||
|
||||
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -53,8 +53,16 @@
|
||||
//! [`embedded-hal`]: https://crates.io/crates/embedded-hal
|
||||
|
||||
use core::marker::PhantomData;
|
||||
#[cfg(not(esp32))]
|
||||
use core::{
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embedded_hal::i2c::Operation as EhalOperation;
|
||||
use fugit::HertzU32;
|
||||
use procmacros::handler;
|
||||
|
||||
use crate::{
|
||||
clock::Clocks,
|
||||
@ -66,6 +74,7 @@ use crate::{
|
||||
system::PeripheralClockControl,
|
||||
Async,
|
||||
Blocking,
|
||||
Cpu,
|
||||
InterruptConfigurable,
|
||||
Mode,
|
||||
};
|
||||
@ -240,11 +249,123 @@ pub struct I2c<'d, DM: Mode, T = AnyI2c> {
|
||||
timeout: Option<u32>,
|
||||
}
|
||||
|
||||
impl<DM, T> I2c<'_, DM, T>
|
||||
impl<T> embedded_hal_02::blocking::i2c::Read for I2c<'_, Blocking, T>
|
||||
where
|
||||
T: Instance,
|
||||
DM: Mode,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.read(address, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> embedded_hal_02::blocking::i2c::Write for I2c<'_, Blocking, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
|
||||
self.write(addr, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> embedded_hal_02::blocking::i2c::WriteRead for I2c<'_, Blocking, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn write_read(
|
||||
&mut self,
|
||||
address: u8,
|
||||
bytes: &[u8],
|
||||
buffer: &mut [u8],
|
||||
) -> Result<(), Self::Error> {
|
||||
self.write_read(address, bytes, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, DM: Mode> embedded_hal::i2c::ErrorType for I2c<'_, DM, T> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<T, DM: Mode> embedded_hal::i2c::I2c for I2c<'_, DM, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
fn transaction(
|
||||
&mut self,
|
||||
address: u8,
|
||||
operations: &mut [embedded_hal::i2c::Operation<'_>],
|
||||
) -> Result<(), Self::Error> {
|
||||
self.transaction_impl(address, operations.iter_mut().map(Operation::from))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T, DM: Mode> I2c<'d, DM, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
fn new_internal<SDA: PeripheralOutput, SCL: PeripheralOutput>(
|
||||
i2c: impl Peripheral<P = T> + 'd,
|
||||
sda: impl Peripheral<P = SDA> + 'd,
|
||||
scl: impl Peripheral<P = SCL> + 'd,
|
||||
frequency: HertzU32,
|
||||
) -> Self {
|
||||
crate::into_ref!(i2c);
|
||||
crate::into_mapped_ref!(sda, scl);
|
||||
|
||||
let i2c = I2c {
|
||||
i2c,
|
||||
phantom: PhantomData,
|
||||
frequency,
|
||||
timeout: None,
|
||||
};
|
||||
|
||||
PeripheralClockControl::reset(i2c.i2c.peripheral());
|
||||
PeripheralClockControl::enable(i2c.i2c.peripheral());
|
||||
|
||||
// TODO: implement with_pins et. al.
|
||||
// avoid SCL/SDA going low during configuration
|
||||
scl.set_output_high(true, crate::private::Internal);
|
||||
sda.set_output_high(true, crate::private::Internal);
|
||||
|
||||
scl.set_to_open_drain_output(crate::private::Internal);
|
||||
scl.enable_input(true, crate::private::Internal);
|
||||
scl.pull_direction(Pull::Up, crate::private::Internal);
|
||||
|
||||
scl.connect_input_to_peripheral(i2c.i2c.scl_input_signal(), crate::private::Internal);
|
||||
scl.connect_peripheral_to_output(i2c.i2c.scl_output_signal(), crate::private::Internal);
|
||||
|
||||
sda.set_to_open_drain_output(crate::private::Internal);
|
||||
sda.enable_input(true, crate::private::Internal);
|
||||
sda.pull_direction(Pull::Up, crate::private::Internal);
|
||||
|
||||
sda.connect_input_to_peripheral(i2c.i2c.sda_input_signal(), crate::private::Internal);
|
||||
sda.connect_peripheral_to_output(i2c.i2c.sda_output_signal(), crate::private::Internal);
|
||||
|
||||
i2c.i2c.setup(frequency, None);
|
||||
i2c
|
||||
}
|
||||
|
||||
fn internal_recover(&self) {
|
||||
PeripheralClockControl::reset(self.i2c.peripheral());
|
||||
PeripheralClockControl::enable(self.i2c.peripheral());
|
||||
|
||||
self.i2c.setup(self.frequency, self.timeout);
|
||||
}
|
||||
|
||||
/// Set the I2C timeout.
|
||||
// TODO: explain this function better - what's the unit, what happens on
|
||||
// timeout, and just what exactly is a timeout in this context?
|
||||
pub fn with_timeout(mut self, timeout: Option<u32>) -> Self {
|
||||
self.timeout = timeout;
|
||||
self.i2c.setup(self.frequency, self.timeout);
|
||||
self
|
||||
}
|
||||
|
||||
fn transaction_impl<'a>(
|
||||
&mut self,
|
||||
address: u8,
|
||||
@ -303,10 +424,50 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> I2c<'_, Blocking, T>
|
||||
impl<'d> I2c<'d, Blocking> {
|
||||
/// Create a new I2C instance
|
||||
/// This will enable the peripheral but the peripheral won't get
|
||||
/// automatically disabled when this gets dropped.
|
||||
pub fn new<SDA: PeripheralOutput, SCL: PeripheralOutput>(
|
||||
i2c: impl Peripheral<P = impl Instance> + 'd,
|
||||
sda: impl Peripheral<P = SDA> + 'd,
|
||||
scl: impl Peripheral<P = SCL> + 'd,
|
||||
frequency: HertzU32,
|
||||
) -> Self {
|
||||
Self::new_typed(i2c.map_into(), sda, scl, frequency)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T> I2c<'d, Blocking, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
/// Create a new I2C instance
|
||||
/// This will enable the peripheral but the peripheral won't get
|
||||
/// automatically disabled when this gets dropped.
|
||||
pub fn new_typed<SDA: PeripheralOutput, SCL: PeripheralOutput>(
|
||||
i2c: impl Peripheral<P = T> + 'd,
|
||||
sda: impl Peripheral<P = SDA> + 'd,
|
||||
scl: impl Peripheral<P = SCL> + 'd,
|
||||
frequency: HertzU32,
|
||||
) -> Self {
|
||||
Self::new_internal(i2c, sda, scl, frequency)
|
||||
}
|
||||
|
||||
// TODO: missing interrupt APIs
|
||||
|
||||
/// Configures the I2C peripheral to operate in asynchronous mode.
|
||||
pub fn into_async(mut self) -> I2c<'d, Async, T> {
|
||||
self.set_interrupt_handler(self.i2c.async_handler());
|
||||
|
||||
I2c {
|
||||
i2c: self.i2c,
|
||||
phantom: PhantomData,
|
||||
frequency: self.frequency,
|
||||
timeout: self.timeout,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads enough bytes from slave with `address` to fill `buffer`
|
||||
pub fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
let chunk_count = buffer.len().div_ceil(I2C_CHUNK_SIZE);
|
||||
@ -430,163 +591,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> embedded_hal_02::blocking::i2c::Read for I2c<'_, Blocking, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.read(address, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> embedded_hal_02::blocking::i2c::Write for I2c<'_, Blocking, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
|
||||
self.write(addr, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> embedded_hal_02::blocking::i2c::WriteRead for I2c<'_, Blocking, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn write_read(
|
||||
&mut self,
|
||||
address: u8,
|
||||
bytes: &[u8],
|
||||
buffer: &mut [u8],
|
||||
) -> Result<(), Self::Error> {
|
||||
self.write_read(address, bytes, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, DM: Mode> embedded_hal::i2c::ErrorType for I2c<'_, DM, T> {
|
||||
type Error = Error;
|
||||
}
|
||||
|
||||
impl<T, DM: Mode> embedded_hal::i2c::I2c for I2c<'_, DM, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
fn transaction(
|
||||
&mut self,
|
||||
address: u8,
|
||||
operations: &mut [embedded_hal::i2c::Operation<'_>],
|
||||
) -> Result<(), Self::Error> {
|
||||
self.transaction_impl(address, operations.iter_mut().map(Operation::from))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T, DM: Mode> I2c<'d, DM, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
fn new_internal<SDA: PeripheralOutput, SCL: PeripheralOutput>(
|
||||
i2c: impl Peripheral<P = T> + 'd,
|
||||
sda: impl Peripheral<P = SDA> + 'd,
|
||||
scl: impl Peripheral<P = SCL> + 'd,
|
||||
frequency: HertzU32,
|
||||
) -> Self {
|
||||
crate::into_ref!(i2c);
|
||||
crate::into_mapped_ref!(sda, scl);
|
||||
|
||||
let i2c = I2c {
|
||||
i2c,
|
||||
phantom: PhantomData,
|
||||
frequency,
|
||||
timeout: None,
|
||||
};
|
||||
|
||||
PeripheralClockControl::reset(i2c.i2c.peripheral());
|
||||
PeripheralClockControl::enable(i2c.i2c.peripheral());
|
||||
|
||||
// TODO: implement with_pins et. al.
|
||||
// avoid SCL/SDA going low during configuration
|
||||
scl.set_output_high(true, crate::private::Internal);
|
||||
sda.set_output_high(true, crate::private::Internal);
|
||||
|
||||
scl.set_to_open_drain_output(crate::private::Internal);
|
||||
scl.enable_input(true, crate::private::Internal);
|
||||
scl.pull_direction(Pull::Up, crate::private::Internal);
|
||||
|
||||
scl.connect_input_to_peripheral(i2c.i2c.scl_input_signal(), crate::private::Internal);
|
||||
scl.connect_peripheral_to_output(i2c.i2c.scl_output_signal(), crate::private::Internal);
|
||||
|
||||
sda.set_to_open_drain_output(crate::private::Internal);
|
||||
sda.enable_input(true, crate::private::Internal);
|
||||
sda.pull_direction(Pull::Up, crate::private::Internal);
|
||||
|
||||
sda.connect_input_to_peripheral(i2c.i2c.sda_input_signal(), crate::private::Internal);
|
||||
sda.connect_peripheral_to_output(i2c.i2c.sda_output_signal(), crate::private::Internal);
|
||||
|
||||
i2c.i2c.setup(frequency, None);
|
||||
i2c
|
||||
}
|
||||
|
||||
fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
unsafe { crate::interrupt::bind_interrupt(self.i2c.interrupt(), handler.handler()) };
|
||||
unwrap!(crate::interrupt::enable(
|
||||
self.i2c.interrupt(),
|
||||
handler.priority()
|
||||
));
|
||||
}
|
||||
|
||||
fn internal_recover(&self) {
|
||||
PeripheralClockControl::reset(self.i2c.peripheral());
|
||||
PeripheralClockControl::enable(self.i2c.peripheral());
|
||||
|
||||
self.i2c.setup(self.frequency, self.timeout);
|
||||
}
|
||||
|
||||
/// Set the I2C timeout.
|
||||
// TODO: explain this function better - what's the unit, what happens on
|
||||
// timeout, and just what exactly is a timeout in this context?
|
||||
pub fn with_timeout(mut self, timeout: Option<u32>) -> Self {
|
||||
self.timeout = timeout;
|
||||
self.i2c.setup(self.frequency, self.timeout);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> I2c<'d, Blocking> {
|
||||
/// Create a new I2C instance
|
||||
/// This will enable the peripheral but the peripheral won't get
|
||||
/// automatically disabled when this gets dropped.
|
||||
pub fn new<SDA: PeripheralOutput, SCL: PeripheralOutput>(
|
||||
i2c: impl Peripheral<P = impl Instance> + 'd,
|
||||
sda: impl Peripheral<P = SDA> + 'd,
|
||||
scl: impl Peripheral<P = SCL> + 'd,
|
||||
frequency: HertzU32,
|
||||
) -> Self {
|
||||
Self::new_typed(i2c.map_into(), sda, scl, frequency)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T> I2c<'d, Blocking, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
/// Create a new I2C instance
|
||||
/// This will enable the peripheral but the peripheral won't get
|
||||
/// automatically disabled when this gets dropped.
|
||||
pub fn new_typed<SDA: PeripheralOutput, SCL: PeripheralOutput>(
|
||||
i2c: impl Peripheral<P = T> + 'd,
|
||||
sda: impl Peripheral<P = SDA> + 'd,
|
||||
scl: impl Peripheral<P = SCL> + 'd,
|
||||
frequency: HertzU32,
|
||||
) -> Self {
|
||||
Self::new_internal(i2c, sda, scl, frequency)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> crate::private::Sealed for I2c<'_, Blocking, T> where T: Instance {}
|
||||
|
||||
impl<T> InterruptConfigurable for I2c<'_, Blocking, T>
|
||||
@ -594,84 +598,43 @@ where
|
||||
T: Instance,
|
||||
{
|
||||
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
|
||||
self.internal_set_interrupt_handler(handler);
|
||||
for core in Cpu::other() {
|
||||
crate::interrupt::disable(core, self.i2c.interrupt());
|
||||
}
|
||||
unsafe { crate::interrupt::bind_interrupt(self.i2c.interrupt(), handler.handler()) };
|
||||
unwrap!(crate::interrupt::enable(
|
||||
self.i2c.interrupt(),
|
||||
handler.priority()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> I2c<'d, Async> {
|
||||
/// Create a new I2C instance
|
||||
/// This will enable the peripheral but the peripheral won't get
|
||||
/// automatically disabled when this gets dropped.
|
||||
pub fn new_async<SDA: PeripheralOutput, SCL: PeripheralOutput>(
|
||||
i2c: impl Peripheral<P = impl Instance> + 'd,
|
||||
sda: impl Peripheral<P = SDA> + 'd,
|
||||
scl: impl Peripheral<P = SCL> + 'd,
|
||||
frequency: HertzU32,
|
||||
) -> Self {
|
||||
Self::new_async_typed(i2c.map_into(), sda, scl, frequency)
|
||||
}
|
||||
}
|
||||
const NUM_I2C: usize = 1 + cfg!(i2c1) as usize;
|
||||
static WAKERS: [AtomicWaker; NUM_I2C] = [const { AtomicWaker::new() }; NUM_I2C];
|
||||
|
||||
impl<'d, T> I2c<'d, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
/// Create a new I2C instance
|
||||
/// This will enable the peripheral but the peripheral won't get
|
||||
/// automatically disabled when this gets dropped.
|
||||
pub fn new_async_typed<SDA: PeripheralOutput, SCL: PeripheralOutput>(
|
||||
i2c: impl Peripheral<P = T> + 'd,
|
||||
sda: impl Peripheral<P = SDA> + 'd,
|
||||
scl: impl Peripheral<P = SCL> + 'd,
|
||||
frequency: HertzU32,
|
||||
) -> Self {
|
||||
let mut this = Self::new_internal(i2c, sda, scl, frequency);
|
||||
|
||||
this.internal_set_interrupt_handler(this.i2c.async_handler());
|
||||
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
mod asynch {
|
||||
#[cfg(not(esp32))]
|
||||
use core::{
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embedded_hal::i2c::Operation as EhalOperation;
|
||||
use procmacros::handler;
|
||||
|
||||
use super::*;
|
||||
|
||||
const NUM_I2C: usize = 1 + cfg!(i2c1) as usize;
|
||||
static WAKERS: [AtomicWaker; NUM_I2C] = [const { AtomicWaker::new() }; NUM_I2C];
|
||||
|
||||
#[cfg_attr(esp32, allow(dead_code))]
|
||||
pub(crate) enum Event {
|
||||
#[cfg_attr(esp32, allow(dead_code))]
|
||||
pub(crate) enum Event {
|
||||
EndDetect,
|
||||
TxComplete,
|
||||
#[cfg(not(any(esp32, esp32s2)))]
|
||||
TxFifoWatermark,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(esp32))]
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
struct I2cFuture<'a, T>
|
||||
where
|
||||
#[cfg(not(esp32))]
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
struct I2cFuture<'a, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
{
|
||||
event: Event,
|
||||
instance: &'a T,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(esp32))]
|
||||
impl<'a, T> I2cFuture<'a, T>
|
||||
where
|
||||
#[cfg(not(esp32))]
|
||||
impl<'a, T> I2cFuture<'a, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
{
|
||||
pub fn new(event: Event, instance: &'a T) -> Self {
|
||||
instance.register_block().int_ena().modify(|_, w| {
|
||||
let w = match event {
|
||||
@ -742,13 +705,13 @@ mod asynch {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(esp32))]
|
||||
impl<T> core::future::Future for I2cFuture<'_, T>
|
||||
where
|
||||
#[cfg(not(esp32))]
|
||||
impl<'a, T> core::future::Future for I2cFuture<'a, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
{
|
||||
type Output = Result<(), Error>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
@ -766,12 +729,24 @@ mod asynch {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T> I2c<'d, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
/// Configure the I2C peripheral to operate in blocking mode.
|
||||
pub fn into_blocking(self) -> I2c<'d, Blocking, T> {
|
||||
crate::interrupt::disable(Cpu::current(), self.i2c.interrupt());
|
||||
|
||||
I2c {
|
||||
i2c: self.i2c,
|
||||
phantom: PhantomData,
|
||||
frequency: self.frequency,
|
||||
timeout: self.timeout,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> I2c<'_, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
#[cfg(any(esp32, esp32s2))]
|
||||
async fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
if buffer.len() > 32 {
|
||||
@ -793,11 +768,7 @@ mod asynch {
|
||||
}
|
||||
|
||||
#[cfg(any(esp32, esp32s2))]
|
||||
async fn write_remaining_tx_fifo(
|
||||
&self,
|
||||
start_index: usize,
|
||||
bytes: &[u8],
|
||||
) -> Result<(), Error> {
|
||||
async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> {
|
||||
if start_index >= bytes.len() {
|
||||
return Ok(());
|
||||
}
|
||||
@ -811,11 +782,7 @@ mod asynch {
|
||||
}
|
||||
|
||||
#[cfg(not(any(esp32, esp32s2)))]
|
||||
async fn write_remaining_tx_fifo(
|
||||
&self,
|
||||
start_index: usize,
|
||||
bytes: &[u8],
|
||||
) -> Result<(), Error> {
|
||||
async fn write_remaining_tx_fifo(&self, start_index: usize, bytes: &[u8]) -> Result<(), Error> {
|
||||
let mut index = start_index;
|
||||
loop {
|
||||
self.i2c.check_errors()?;
|
||||
@ -1078,19 +1045,19 @@ mod asynch {
|
||||
/// transaction.
|
||||
///
|
||||
/// Transaction contract:
|
||||
/// - Before executing the first operation an ST is sent automatically.
|
||||
/// This is followed by SAD+R/W as appropriate.
|
||||
/// - Before executing the first operation an ST is sent automatically. This
|
||||
/// is followed by SAD+R/W as appropriate.
|
||||
/// - Data from adjacent operations of the same type are sent after each
|
||||
/// other without an SP or SR.
|
||||
/// - Between adjacent operations of a different type an SR and SAD+R/W
|
||||
/// is sent.
|
||||
/// - Between adjacent operations of a different type an SR and SAD+R/W is
|
||||
/// sent.
|
||||
/// - After executing the last operation an SP is sent automatically.
|
||||
/// - If the last operation is a `Read` the master does not send an
|
||||
/// acknowledge for the last byte.
|
||||
///
|
||||
/// - `ST` = start condition
|
||||
/// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or
|
||||
/// 0 to indicate writing
|
||||
/// - `SAD+R/W` = slave address followed by bit 1 to indicate reading or 0
|
||||
/// to indicate writing
|
||||
/// - `SR` = repeated start condition
|
||||
/// - `SP` = stop condition
|
||||
pub async fn transaction<'a>(
|
||||
@ -1156,12 +1123,12 @@ mod asynch {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> embedded_hal_async::i2c::I2c for I2c<'_, Async, T>
|
||||
where
|
||||
impl<'d, T> embedded_hal_async::i2c::I2c for I2c<'d, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
{
|
||||
async fn transaction(
|
||||
&mut self,
|
||||
address: u8,
|
||||
@ -1170,9 +1137,9 @@ mod asynch {
|
||||
self.transaction_impl_async(address, operations.iter_mut().map(Operation::from))
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handler(regs: &RegisterBlock) {
|
||||
fn handler(regs: &RegisterBlock) {
|
||||
regs.int_ena().modify(|_, w| {
|
||||
w.end_detect().clear_bit();
|
||||
w.trans_complete().clear_bit();
|
||||
@ -1188,24 +1155,23 @@ mod asynch {
|
||||
|
||||
#[cfg(esp32)]
|
||||
regs.int_ena().modify(|_, w| w.ack_err().clear_bit());
|
||||
}
|
||||
}
|
||||
|
||||
#[handler]
|
||||
pub(super) fn i2c0_handler() {
|
||||
let regs = unsafe { &*crate::peripherals::I2C0::PTR };
|
||||
handler(regs);
|
||||
#[handler]
|
||||
pub(super) fn i2c0_handler() {
|
||||
let regs = unsafe { crate::peripherals::I2C0::steal() };
|
||||
handler(regs.register_block());
|
||||
|
||||
WAKERS[0].wake();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(i2c1)]
|
||||
#[handler]
|
||||
pub(super) fn i2c1_handler() {
|
||||
let regs = unsafe { &*crate::peripherals::I2C1::PTR };
|
||||
handler(regs);
|
||||
#[cfg(i2c1)]
|
||||
#[handler]
|
||||
pub(super) fn i2c1_handler() {
|
||||
let regs = unsafe { crate::peripherals::I2C1::steal() };
|
||||
handler(regs.register_block());
|
||||
|
||||
WAKERS[1].wake();
|
||||
}
|
||||
}
|
||||
|
||||
/// I2C Peripheral Instance
|
||||
@ -2248,7 +2214,7 @@ impl PeripheralMarker for crate::peripherals::I2C0 {
|
||||
impl Instance for crate::peripherals::I2C0 {
|
||||
#[inline(always)]
|
||||
fn async_handler(&self) -> InterruptHandler {
|
||||
asynch::i2c0_handler
|
||||
i2c0_handler
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@ -2299,7 +2265,7 @@ impl PeripheralMarker for crate::peripherals::I2C1 {
|
||||
impl Instance for crate::peripherals::I2C1 {
|
||||
#[inline(always)]
|
||||
fn async_handler(&self) -> InterruptHandler {
|
||||
asynch::i2c1_handler
|
||||
i2c1_handler
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
||||
@ -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()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
#[doc(hidden)]
|
||||
pub trait RxPins {
|
||||
const BUS_WIDTH: usize;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
#[doc(hidden)]
|
||||
pub trait TxPins {
|
||||
fn configure(&mut self);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,34 +115,23 @@ 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() {
|
||||
#[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 {
|
||||
// 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
|
||||
@ -166,8 +154,8 @@ mod private {
|
||||
.lcd_trans_done_int_raw()
|
||||
.bit()
|
||||
}
|
||||
}
|
||||
pub struct ClockDivider {
|
||||
}
|
||||
pub(crate) struct ClockDivider {
|
||||
// Integral LCD clock divider value. (8 bits)
|
||||
// Value 0 is treated as 256
|
||||
// Value 1 is treated as 2
|
||||
@ -179,12 +167,12 @@ mod private {
|
||||
|
||||
// Fractional clock divider denominator value. (6 bits)
|
||||
pub div_a: usize,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate_clkm(
|
||||
pub(crate) fn calculate_clkm(
|
||||
desired_frequency: usize,
|
||||
source_frequencies: &[usize],
|
||||
) -> (usize, ClockDivider) {
|
||||
) -> (usize, ClockDivider) {
|
||||
let mut result_freq = 0;
|
||||
let mut result = None;
|
||||
|
||||
@ -200,9 +188,9 @@ mod private {
|
||||
}
|
||||
|
||||
result.expect("Desired frequency was too low for the dividers to divide to")
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize {
|
||||
fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize {
|
||||
let n = match divider.div_num {
|
||||
0 => 256,
|
||||
1 => 2,
|
||||
@ -225,12 +213,12 @@ mod private {
|
||||
} else {
|
||||
source_frequency / n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_closest_divider(
|
||||
fn calculate_closest_divider(
|
||||
source_frequency: usize,
|
||||
desired_frequency: usize,
|
||||
) -> Option<ClockDivider> {
|
||||
) -> Option<ClockDivider> {
|
||||
let div_num = source_frequency / desired_frequency;
|
||||
if div_num < 2 {
|
||||
// Source clock isn't fast enough to reach the desired frequency.
|
||||
@ -282,24 +270,24 @@ mod private {
|
||||
}
|
||||
};
|
||||
Some(divider)
|
||||
}
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Euclidean_algorithm
|
||||
const fn hcf(a: usize, b: usize) -> usize {
|
||||
// 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 {
|
||||
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> {
|
||||
// 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;
|
||||
@ -316,5 +304,4 @@ mod private {
|
||||
(a, b, c, d) = (c, d, k * c - a, k * d - b);
|
||||
Some(next)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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() };
|
||||
parl_io.int_ena().write(|w| {
|
||||
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)),
|
||||
}
|
||||
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() };
|
||||
parl_io.int_clr().write(|w| {
|
||||
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()),
|
||||
}
|
||||
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
|
||||
|
||||
@ -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
@ -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();
|
||||
|
||||
@ -434,24 +434,19 @@ 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()));
|
||||
}
|
||||
}
|
||||
|
||||
/// RTC Watchdog Timer.
|
||||
|
||||
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
{
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// Create a new instance of [TwaiConfiguration] meant to connect two ESP32s
|
||||
/// directly
|
||||
///
|
||||
/// You don't need a transceiver by following the description in the
|
||||
/// `twai.rs` example
|
||||
pub fn new_async_no_transceiver<RX: PeripheralInput, TX: PeripheralOutput>(
|
||||
peripheral: impl Peripheral<P = impl Instance> + 'd,
|
||||
rx_pin: impl Peripheral<P = RX> + 'd,
|
||||
tx_pin: impl Peripheral<P = TX> + 'd,
|
||||
baud_rate: BaudRate,
|
||||
mode: TwaiMode,
|
||||
) -> Self {
|
||||
Self::new_async_no_transceiver_typed(peripheral.map_into(), rx_pin, tx_pin, baud_rate, mode)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1137,33 +1111,18 @@ impl<'d, T> TwaiConfiguration<'d, Async, T>
|
||||
where
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -126,10 +126,11 @@
|
||||
//! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/
|
||||
//! [embedded-io-async]: https://docs.rs/embedded-io-async/latest/embedded_io_async/
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use core::{marker::PhantomData, sync::atomic::Ordering, task::Poll};
|
||||
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use enumset::{EnumSet, EnumSetType};
|
||||
use portable_atomic::AtomicBool;
|
||||
|
||||
use self::config::Config;
|
||||
use crate::{
|
||||
@ -146,6 +147,7 @@ use crate::{
|
||||
peripherals::{uart0::RegisterBlock, Interrupt},
|
||||
private::Internal,
|
||||
system::PeripheralClockControl,
|
||||
Async,
|
||||
Blocking,
|
||||
InterruptConfigurable,
|
||||
Mode,
|
||||
@ -662,6 +664,42 @@ where
|
||||
|
||||
Ok(uart_tx)
|
||||
}
|
||||
|
||||
/// Reconfigures the driver to operate in [`Async`] mode.
|
||||
pub fn into_async(self) -> UartTx<'d, Async, T> {
|
||||
if !self.uart.state().is_rx_async.load(Ordering::Acquire) {
|
||||
self.uart
|
||||
.info()
|
||||
.set_interrupt_handler(self.uart.info().async_handler);
|
||||
}
|
||||
self.uart.state().is_tx_async.store(true, Ordering::Release);
|
||||
|
||||
UartTx {
|
||||
uart: self.uart,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T> UartTx<'d, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
/// Reconfigures the driver to operate in [`Blocking`] mode.
|
||||
pub fn into_blocking(self) -> UartTx<'d, Blocking, T> {
|
||||
self.uart
|
||||
.state()
|
||||
.is_tx_async
|
||||
.store(false, Ordering::Release);
|
||||
if !self.uart.state().is_rx_async.load(Ordering::Acquire) {
|
||||
self.uart.info().disable_interrupts();
|
||||
}
|
||||
|
||||
UartTx {
|
||||
uart: self.uart,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@ -963,6 +1001,50 @@ where
|
||||
|
||||
Ok(uart_rx)
|
||||
}
|
||||
|
||||
/// Reconfigures the driver to operate in [`Async`] mode.
|
||||
pub fn into_async(self) -> UartRx<'d, Async, T> {
|
||||
if !self.uart.state().is_tx_async.load(Ordering::Acquire) {
|
||||
self.uart
|
||||
.info()
|
||||
.set_interrupt_handler(self.uart.info().async_handler);
|
||||
}
|
||||
self.uart.state().is_rx_async.store(true, Ordering::Release);
|
||||
|
||||
UartRx {
|
||||
uart: self.uart,
|
||||
phantom: PhantomData,
|
||||
at_cmd_config: self.at_cmd_config,
|
||||
rx_timeout_config: self.rx_timeout_config,
|
||||
#[cfg(not(esp32))]
|
||||
symbol_len: self.symbol_len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T> UartRx<'d, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
/// Reconfigures the driver to operate in [`Blocking`] mode.
|
||||
pub fn into_blocking(self) -> UartRx<'d, Blocking, T> {
|
||||
self.uart
|
||||
.state()
|
||||
.is_rx_async
|
||||
.store(false, Ordering::Release);
|
||||
if !self.uart.state().is_tx_async.load(Ordering::Acquire) {
|
||||
self.uart.info().disable_interrupts();
|
||||
}
|
||||
|
||||
UartRx {
|
||||
uart: self.uart,
|
||||
phantom: PhantomData,
|
||||
at_cmd_config: self.at_cmd_config,
|
||||
rx_timeout_config: self.rx_timeout_config,
|
||||
#[cfg(not(esp32))]
|
||||
symbol_len: self.symbol_len,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Uart<'d, Blocking> {
|
||||
@ -1010,6 +1092,27 @@ where
|
||||
) -> Result<Self, Error> {
|
||||
UartBuilder::new(uart).with_tx(tx).with_rx(rx).init(config)
|
||||
}
|
||||
|
||||
/// Reconfigures the driver to operate in [`Async`] mode.
|
||||
pub fn into_async(self) -> Uart<'d, Async, T> {
|
||||
Uart {
|
||||
rx: self.rx.into_async(),
|
||||
tx: self.tx.into_async(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T> Uart<'d, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
/// Reconfigures the driver to operate in [`Blocking`] mode.
|
||||
pub fn into_blocking(self) -> Uart<'d, Blocking, T> {
|
||||
Uart {
|
||||
rx: self.rx.into_blocking(),
|
||||
tx: self.tx.into_blocking(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// List of exposed UART events.
|
||||
@ -1033,15 +1136,6 @@ where
|
||||
T: Instance,
|
||||
M: Mode,
|
||||
{
|
||||
fn inner_set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
// `self.tx.uart` and `self.rx.uart` are the same
|
||||
let interrupt = self.tx.uart.info().interrupt;
|
||||
unsafe {
|
||||
crate::interrupt::bind_interrupt(interrupt, handler.handler());
|
||||
unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure CTS pin
|
||||
pub fn with_cts(mut self, cts: impl Peripheral<P = impl PeripheralInput> + 'd) -> Self {
|
||||
self.rx = self.rx.with_cts(cts);
|
||||
@ -1123,66 +1217,24 @@ where
|
||||
self.rx.at_cmd_config = Some(config);
|
||||
}
|
||||
|
||||
/// Listen for the given interrupts
|
||||
fn enable_listen(&mut self, interrupts: EnumSet<UartInterrupt>, enable: bool) {
|
||||
let reg_block = self.register_block();
|
||||
|
||||
reg_block.int_ena().modify(|_, w| {
|
||||
for interrupt in interrupts {
|
||||
match interrupt {
|
||||
UartInterrupt::AtCmd => w.at_cmd_char_det().bit(enable),
|
||||
UartInterrupt::TxDone => w.tx_done().bit(enable),
|
||||
UartInterrupt::RxFifoFull => w.rxfifo_full().bit(enable),
|
||||
};
|
||||
}
|
||||
w
|
||||
});
|
||||
}
|
||||
|
||||
/// Listen for the given interrupts
|
||||
pub fn listen(&mut self, interrupts: impl Into<EnumSet<UartInterrupt>>) {
|
||||
self.enable_listen(interrupts.into(), true);
|
||||
self.tx.uart.info().enable_listen(interrupts.into(), true)
|
||||
}
|
||||
|
||||
/// Unlisten the given interrupts
|
||||
pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<UartInterrupt>>) {
|
||||
self.enable_listen(interrupts.into(), false);
|
||||
self.tx.uart.info().enable_listen(interrupts.into(), false)
|
||||
}
|
||||
|
||||
/// Gets asserted interrupts
|
||||
pub fn interrupts(&mut self) -> EnumSet<UartInterrupt> {
|
||||
let mut res = EnumSet::new();
|
||||
let reg_block = self.register_block();
|
||||
|
||||
let ints = reg_block.int_raw().read();
|
||||
|
||||
if ints.at_cmd_char_det().bit_is_set() {
|
||||
res.insert(UartInterrupt::AtCmd);
|
||||
}
|
||||
if ints.tx_done().bit_is_set() {
|
||||
res.insert(UartInterrupt::TxDone);
|
||||
}
|
||||
if ints.rxfifo_full().bit_is_set() {
|
||||
res.insert(UartInterrupt::RxFifoFull);
|
||||
}
|
||||
|
||||
res
|
||||
self.tx.uart.info().interrupts()
|
||||
}
|
||||
|
||||
/// Resets asserted interrupts
|
||||
pub fn clear_interrupts(&mut self, interrupts: EnumSet<UartInterrupt>) {
|
||||
let reg_block = self.register_block();
|
||||
|
||||
reg_block.int_clr().write(|w| {
|
||||
for interrupt in interrupts {
|
||||
match interrupt {
|
||||
UartInterrupt::AtCmd => w.at_cmd_char_det().clear_bit_by_one(),
|
||||
UartInterrupt::TxDone => w.tx_done().clear_bit_by_one(),
|
||||
UartInterrupt::RxFifoFull => w.rxfifo_full().clear_bit_by_one(),
|
||||
};
|
||||
}
|
||||
w
|
||||
});
|
||||
self.tx.uart.info().clear_interrupts(interrupts)
|
||||
}
|
||||
|
||||
/// Write a byte out over the UART
|
||||
@ -1479,7 +1531,8 @@ where
|
||||
T: Instance,
|
||||
{
|
||||
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
|
||||
self.inner_set_interrupt_handler(handler);
|
||||
// `self.tx.uart` and `self.rx.uart` are the same
|
||||
self.tx.uart.info().set_interrupt_handler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1751,21 +1804,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
mod asynch {
|
||||
use core::task::Poll;
|
||||
|
||||
use enumset::{EnumSet, EnumSetType};
|
||||
|
||||
use super::*;
|
||||
use crate::Async;
|
||||
|
||||
#[derive(EnumSetType, Debug)]
|
||||
pub(crate) enum TxEvent {
|
||||
#[derive(EnumSetType, Debug)]
|
||||
pub(crate) enum TxEvent {
|
||||
TxDone,
|
||||
TxFiFoEmpty,
|
||||
}
|
||||
#[derive(EnumSetType, Debug)]
|
||||
pub(crate) enum RxEvent {
|
||||
}
|
||||
#[derive(EnumSetType, Debug)]
|
||||
pub(crate) enum RxEvent {
|
||||
FifoFull,
|
||||
CmdCharDetected,
|
||||
FifoOvf,
|
||||
@ -1773,22 +1818,22 @@ mod asynch {
|
||||
GlitchDetected,
|
||||
FrameError,
|
||||
ParityError,
|
||||
}
|
||||
}
|
||||
|
||||
/// A future that resolves when the passed interrupt is triggered,
|
||||
/// or has been triggered in the meantime (flag set in INT_RAW).
|
||||
/// Upon construction the future enables the passed interrupt and when it
|
||||
/// is dropped it disables the interrupt again. The future returns the event
|
||||
/// that was initially passed, when it resolves.
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
struct UartRxFuture<'d> {
|
||||
/// A future that resolves when the passed interrupt is triggered,
|
||||
/// or has been triggered in the meantime (flag set in INT_RAW).
|
||||
/// Upon construction the future enables the passed interrupt and when it
|
||||
/// is dropped it disables the interrupt again. The future returns the event
|
||||
/// that was initially passed, when it resolves.
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
struct UartRxFuture<'d> {
|
||||
events: EnumSet<RxEvent>,
|
||||
uart: &'d Info,
|
||||
state: &'d State,
|
||||
registered: bool,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> UartRxFuture<'d> {
|
||||
impl<'d> UartRxFuture<'d> {
|
||||
pub fn new(uart: &'d Info, state: &'d State, events: impl Into<EnumSet<RxEvent>>) -> Self {
|
||||
Self {
|
||||
events: events.into(),
|
||||
@ -1835,9 +1880,9 @@ mod asynch {
|
||||
w
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::future::Future for UartRxFuture<'_> {
|
||||
impl core::future::Future for UartRxFuture<'_> {
|
||||
type Output = EnumSet<RxEvent>;
|
||||
|
||||
fn poll(
|
||||
@ -1856,25 +1901,25 @@ mod asynch {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for UartRxFuture<'_> {
|
||||
impl Drop for UartRxFuture<'_> {
|
||||
fn drop(&mut self) {
|
||||
// Although the isr disables the interrupt that occurred directly, we need to
|
||||
// disable the other interrupts (= the ones that did not occur), as
|
||||
// soon as this future goes out of scope.
|
||||
self.enable_listen(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
struct UartTxFuture<'d> {
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
struct UartTxFuture<'d> {
|
||||
events: EnumSet<TxEvent>,
|
||||
uart: &'d Info,
|
||||
state: &'d State,
|
||||
registered: bool,
|
||||
}
|
||||
impl<'d> UartTxFuture<'d> {
|
||||
}
|
||||
impl<'d> UartTxFuture<'d> {
|
||||
pub fn new(uart: &'d Info, state: &'d State, events: impl Into<EnumSet<TxEvent>>) -> Self {
|
||||
Self {
|
||||
events: events.into(),
|
||||
@ -1907,9 +1952,9 @@ mod asynch {
|
||||
w
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::future::Future for UartTxFuture<'_> {
|
||||
impl core::future::Future for UartTxFuture<'_> {
|
||||
type Output = ();
|
||||
|
||||
fn poll(
|
||||
@ -1928,78 +1973,21 @@ mod asynch {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for UartTxFuture<'_> {
|
||||
impl Drop for UartTxFuture<'_> {
|
||||
fn drop(&mut self) {
|
||||
// Although the isr disables the interrupt that occurred directly, we need to
|
||||
// disable the other interrupts (= the ones that did not occur), as
|
||||
// soon as this future goes out of scope.
|
||||
self.enable_listen(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Uart<'d, Async> {
|
||||
/// Create a new UART instance with defaults in [`Async`] mode.
|
||||
pub fn new_async<RX: PeripheralInput, TX: PeripheralOutput>(
|
||||
uart: impl Peripheral<P = impl Instance> + 'd,
|
||||
rx: impl Peripheral<P = RX> + 'd,
|
||||
tx: impl Peripheral<P = TX> + 'd,
|
||||
) -> Result<Self, Error> {
|
||||
Uart::new_async_typed(uart.map_into(), rx, tx)
|
||||
}
|
||||
|
||||
/// Create a new UART instance with configuration options in [`Async`]
|
||||
/// mode.
|
||||
pub fn new_async_with_config<RX: PeripheralInput, TX: PeripheralOutput>(
|
||||
uart: impl Peripheral<P = impl Instance> + 'd,
|
||||
config: Config,
|
||||
rx: impl Peripheral<P = RX> + 'd,
|
||||
tx: impl Peripheral<P = TX> + 'd,
|
||||
) -> Result<Self, Error> {
|
||||
Uart::new_async_with_config_typed(uart.map_into(), config, rx, tx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T> Uart<'d, Async, T>
|
||||
where
|
||||
impl<T> Uart<'_, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
/// Create a new UART instance with defaults in [`Async`] mode.
|
||||
pub fn new_async_typed<RX: PeripheralInput, TX: PeripheralOutput>(
|
||||
uart: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = RX> + 'd,
|
||||
tx: impl Peripheral<P = TX> + 'd,
|
||||
) -> Result<Self, Error> {
|
||||
Self::new_async_with_config_typed(uart, Config::default(), rx, tx)
|
||||
}
|
||||
|
||||
/// Create a new UART instance with configuration options in [`Async`]
|
||||
/// mode.
|
||||
pub fn new_async_with_config_typed<RX: PeripheralInput, TX: PeripheralOutput>(
|
||||
uart: impl Peripheral<P = T> + 'd,
|
||||
config: Config,
|
||||
rx: impl Peripheral<P = RX> + 'd,
|
||||
tx: impl Peripheral<P = TX> + 'd,
|
||||
) -> Result<Self, Error> {
|
||||
// FIXME: at the time of writing, the order of the pin assignments matters:
|
||||
// first binding RX, then TX makes tests fail. This is bad and needs to be
|
||||
// figured out.
|
||||
let mut this = UartBuilder::new(uart)
|
||||
.with_tx(tx)
|
||||
.with_rx(rx)
|
||||
.init(config)?;
|
||||
|
||||
this.inner_set_interrupt_handler(this.tx.uart.info().async_handler);
|
||||
|
||||
Ok(this)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Uart<'_, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
{
|
||||
/// Asynchronously reads data from the UART receive buffer into the
|
||||
/// provided buffer.
|
||||
pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
@ -2015,55 +2003,12 @@ mod asynch {
|
||||
pub async fn flush_async(&mut self) -> Result<(), Error> {
|
||||
self.tx.flush_async().await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> UartTx<'d, Async> {
|
||||
/// Create a new UART TX instance in [`Async`] mode.
|
||||
pub fn new_async<TX: PeripheralOutput>(
|
||||
uart: impl Peripheral<P = impl Instance> + 'd,
|
||||
tx: impl Peripheral<P = TX> + 'd,
|
||||
) -> Result<Self, Error> {
|
||||
UartTx::new_async_typed(uart.map_into(), tx)
|
||||
}
|
||||
|
||||
/// Create a new UART TX instance with configuration options in
|
||||
/// [`Async`] mode.
|
||||
pub fn new_async_with_config<TX: PeripheralOutput>(
|
||||
uart: impl Peripheral<P = impl Instance> + 'd,
|
||||
config: Config,
|
||||
tx: impl Peripheral<P = TX> + 'd,
|
||||
) -> Result<Self, Error> {
|
||||
UartTx::new_async_with_config_typed(uart.map_into(), config, tx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T> UartTx<'d, Async, T>
|
||||
where
|
||||
impl<'d, T> UartTx<'d, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
/// Create a new UART TX instance in [`Async`] mode.
|
||||
pub fn new_async_typed<TX: PeripheralOutput>(
|
||||
uart: impl Peripheral<P = T> + 'd,
|
||||
tx: impl Peripheral<P = TX> + 'd,
|
||||
) -> Result<Self, Error> {
|
||||
UartTx::new_async_with_config_typed(uart, Config::default(), tx)
|
||||
}
|
||||
|
||||
/// Create a new UART TX instance with configuration options in
|
||||
/// [`Async`] mode.
|
||||
pub fn new_async_with_config_typed<TX: PeripheralOutput>(
|
||||
uart: impl Peripheral<P = T> + 'd,
|
||||
config: Config,
|
||||
tx: impl Peripheral<P = TX> + 'd,
|
||||
) -> Result<Self, Error> {
|
||||
let mut this = UartBuilder::new(uart).with_tx(tx).init(config)?;
|
||||
|
||||
this.inner_set_interrupt_handler(this.tx.uart.info().async_handler);
|
||||
|
||||
let (_, uart_tx) = this.split();
|
||||
Ok(uart_tx)
|
||||
}
|
||||
|
||||
{
|
||||
/// Asynchronously writes data to the UART transmit buffer in chunks.
|
||||
///
|
||||
/// This function sends the contents of the provided buffer `words` over
|
||||
@ -2108,55 +2053,12 @@ mod asynch {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> UartRx<'d, Async> {
|
||||
/// Create a new UART RX instance in [`Async`] mode.
|
||||
pub fn new_async<RX: PeripheralInput>(
|
||||
uart: impl Peripheral<P = impl Instance> + 'd,
|
||||
rx: impl Peripheral<P = RX> + 'd,
|
||||
) -> Result<Self, Error> {
|
||||
Self::new_async_typed(uart.map_into(), rx)
|
||||
}
|
||||
|
||||
/// Create a new UART RX instance with configuration options in
|
||||
/// [`Async`] mode.
|
||||
pub fn new_async_with_config<RX: PeripheralInput>(
|
||||
uart: impl Peripheral<P = impl Instance> + 'd,
|
||||
config: Config,
|
||||
rx: impl Peripheral<P = RX> + 'd,
|
||||
) -> Result<Self, Error> {
|
||||
Self::new_async_with_config_typed(uart.map_into(), config, rx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T> UartRx<'d, Async, T>
|
||||
where
|
||||
impl<'d, T> UartRx<'d, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
/// Create a new UART RX instance in [`Async`] mode.
|
||||
pub fn new_async_typed(
|
||||
uart: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl PeripheralInput> + 'd,
|
||||
) -> Result<Self, Error> {
|
||||
Self::new_async_with_config_typed(uart, Config::default(), rx)
|
||||
}
|
||||
|
||||
/// Create a new UART RX instance with configuration options in
|
||||
/// [`Async`] mode.
|
||||
pub fn new_async_with_config_typed(
|
||||
uart: impl Peripheral<P = T> + 'd,
|
||||
config: Config,
|
||||
rx: impl Peripheral<P = impl PeripheralInput> + 'd,
|
||||
) -> Result<Self, Error> {
|
||||
let mut this = UartBuilder::new(uart).with_rx(rx).init(config)?;
|
||||
|
||||
this.inner_set_interrupt_handler(this.tx.uart.info().async_handler);
|
||||
|
||||
let (uart_rx, _) = this.split();
|
||||
Ok(uart_rx)
|
||||
}
|
||||
|
||||
{
|
||||
/// Read async to buffer slice `buf`.
|
||||
/// Waits until at least one byte is in the Rx FiFo
|
||||
/// and one of the following interrupts occurs:
|
||||
@ -2207,9 +2109,7 @@ mod asynch {
|
||||
RxEvent::GlitchDetected => return Err(Error::RxGlitchDetected),
|
||||
RxEvent::FrameError => return Err(Error::RxFrameError),
|
||||
RxEvent::ParityError => return Err(Error::RxParityError),
|
||||
RxEvent::FifoFull | RxEvent::CmdCharDetected | RxEvent::FifoTout => {
|
||||
continue
|
||||
}
|
||||
RxEvent::FifoFull | RxEvent::CmdCharDetected | RxEvent::FifoTout => continue,
|
||||
}
|
||||
}
|
||||
// Unfortunately, the uart's rx-timeout counter counts up whenever there is
|
||||
@ -2225,36 +2125,36 @@ mod asynch {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> embedded_io_async::Read for Uart<'_, Async, T>
|
||||
where
|
||||
impl<T> embedded_io_async::Read for Uart<'_, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
{
|
||||
/// In contrast to the documentation of embedded_io_async::Read, this
|
||||
/// method blocks until an uart interrupt occurs.
|
||||
/// See UartRx::read_async for more details.
|
||||
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||
self.read_async(buf).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> embedded_io_async::Read for UartRx<'_, Async, T>
|
||||
where
|
||||
impl<T> embedded_io_async::Read for UartRx<'_, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
{
|
||||
/// In contrast to the documentation of embedded_io_async::Read, this
|
||||
/// method blocks until an uart interrupt occurs.
|
||||
/// See UartRx::read_async for more details.
|
||||
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||
self.read_async(buf).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> embedded_io_async::Write for Uart<'_, Async, T>
|
||||
where
|
||||
impl<T> embedded_io_async::Write for Uart<'_, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
{
|
||||
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||
self.write_async(buf).await
|
||||
}
|
||||
@ -2262,12 +2162,12 @@ mod asynch {
|
||||
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
self.flush_async().await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> embedded_io_async::Write for UartTx<'_, Async, T>
|
||||
where
|
||||
impl<T> embedded_io_async::Write for UartTx<'_, Async, T>
|
||||
where
|
||||
T: Instance,
|
||||
{
|
||||
{
|
||||
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||
self.write_async(buf).await
|
||||
}
|
||||
@ -2275,13 +2175,13 @@ mod asynch {
|
||||
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
self.flush_async().await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupt handler for all UART instances
|
||||
/// Clears and disables interrupts that have occurred and have their enable
|
||||
/// bit set. The fact that an interrupt has been disabled is used by the
|
||||
/// futures to detect that they should indeed resolve after being woken up
|
||||
pub(super) fn intr_handler(uart: &Info, state: &State) {
|
||||
/// Interrupt handler for all UART instances
|
||||
/// Clears and disables interrupts that have occurred and have their enable
|
||||
/// bit set. The fact that an interrupt has been disabled is used by the
|
||||
/// futures to detect that they should indeed resolve after being woken up
|
||||
pub(super) fn intr_handler(uart: &Info, state: &State) {
|
||||
let interrupts = uart.register_block().int_st().read();
|
||||
let interrupt_bits = interrupts.bits(); // = int_raw & int_ena
|
||||
let rx_wake = interrupts.rxfifo_full().bit_is_set()
|
||||
@ -2305,7 +2205,6 @@ mod asynch {
|
||||
if rx_wake {
|
||||
state.rx_waker.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Low-power UART
|
||||
@ -2502,6 +2401,22 @@ pub mod lp_uart {
|
||||
}
|
||||
}
|
||||
|
||||
impl Info {
|
||||
fn set_interrupt_handler(&self, handler: InterruptHandler) {
|
||||
for core in crate::Cpu::other() {
|
||||
crate::interrupt::disable(core, self.interrupt);
|
||||
}
|
||||
self.enable_listen(EnumSet::all(), false);
|
||||
self.clear_interrupts(EnumSet::all());
|
||||
unsafe { crate::interrupt::bind_interrupt(self.interrupt, handler.handler()) };
|
||||
unwrap!(crate::interrupt::enable(self.interrupt, handler.priority()));
|
||||
}
|
||||
|
||||
fn disable_interrupts(&self) {
|
||||
crate::interrupt::disable(crate::Cpu::current(), self.interrupt);
|
||||
}
|
||||
}
|
||||
|
||||
/// UART Peripheral Instance
|
||||
pub trait Instance: Peripheral<P = Self> + PeripheralMarker + Into<AnyUart> + 'static {
|
||||
/// Returns the peripheral data and state describing this UART instance.
|
||||
@ -2553,6 +2468,12 @@ pub struct State {
|
||||
|
||||
/// Waker for the asynchronous TX operations.
|
||||
pub tx_waker: AtomicWaker,
|
||||
|
||||
/// Stores whether the TX half is configured for async operation.
|
||||
pub is_rx_async: AtomicBool,
|
||||
|
||||
/// Stores whether the RX half is configured for async operation.
|
||||
pub is_tx_async: AtomicBool,
|
||||
}
|
||||
|
||||
impl Info {
|
||||
@ -2560,6 +2481,56 @@ impl Info {
|
||||
pub fn register_block(&self) -> &RegisterBlock {
|
||||
unsafe { &*self.register_block }
|
||||
}
|
||||
|
||||
/// Listen for the given interrupts
|
||||
fn enable_listen(&self, interrupts: EnumSet<UartInterrupt>, enable: bool) {
|
||||
let reg_block = self.register_block();
|
||||
|
||||
reg_block.int_ena().modify(|_, w| {
|
||||
for interrupt in interrupts {
|
||||
match interrupt {
|
||||
UartInterrupt::AtCmd => w.at_cmd_char_det().bit(enable),
|
||||
UartInterrupt::TxDone => w.tx_done().bit(enable),
|
||||
UartInterrupt::RxFifoFull => w.rxfifo_full().bit(enable),
|
||||
};
|
||||
}
|
||||
w
|
||||
});
|
||||
}
|
||||
|
||||
fn interrupts(&self) -> EnumSet<UartInterrupt> {
|
||||
let mut res = EnumSet::new();
|
||||
let reg_block = self.register_block();
|
||||
|
||||
let ints = reg_block.int_raw().read();
|
||||
|
||||
if ints.at_cmd_char_det().bit_is_set() {
|
||||
res.insert(UartInterrupt::AtCmd);
|
||||
}
|
||||
if ints.tx_done().bit_is_set() {
|
||||
res.insert(UartInterrupt::TxDone);
|
||||
}
|
||||
if ints.rxfifo_full().bit_is_set() {
|
||||
res.insert(UartInterrupt::RxFifoFull);
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn clear_interrupts(&self, interrupts: EnumSet<UartInterrupt>) {
|
||||
let reg_block = self.register_block();
|
||||
|
||||
reg_block.int_clr().write(|w| {
|
||||
for interrupt in interrupts {
|
||||
match interrupt {
|
||||
UartInterrupt::AtCmd => w.at_cmd_char_det().clear_bit_by_one(),
|
||||
UartInterrupt::TxDone => w.tx_done().clear_bit_by_one(),
|
||||
UartInterrupt::RxFifoFull => w.rxfifo_full().clear_bit_by_one(),
|
||||
};
|
||||
}
|
||||
w
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Info {
|
||||
@ -2576,12 +2547,14 @@ macro_rules! impl_instance {
|
||||
fn parts(&self) -> (&Info, &State) {
|
||||
#[crate::macros::handler]
|
||||
pub(super) fn irq_handler() {
|
||||
asynch::intr_handler(&PERIPHERAL, &STATE);
|
||||
intr_handler(&PERIPHERAL, &STATE);
|
||||
}
|
||||
|
||||
static STATE: State = State {
|
||||
tx_waker: AtomicWaker::new(),
|
||||
rx_waker: AtomicWaker::new(),
|
||||
is_rx_async: AtomicBool::new(false),
|
||||
is_tx_async: AtomicBool::new(false),
|
||||
};
|
||||
|
||||
static PERIPHERAL: Info = Info {
|
||||
|
||||
@ -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,35 +677,25 @@ 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};
|
||||
|
||||
// Static instance of the waker for each component of the peripheral:
|
||||
static WAKER_TX: AtomicWaker = AtomicWaker::new();
|
||||
static WAKER_RX: AtomicWaker = AtomicWaker::new();
|
||||
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
pub(crate) struct UsbSerialJtagWriteFuture<'d> {
|
||||
phantom: PhantomData<&'d mut USB_DEVICE>,
|
||||
}
|
||||
|
||||
impl UsbSerialJtagWriteFuture<'_> {
|
||||
pub fn new() -> Self {
|
||||
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());
|
||||
|
||||
Self {
|
||||
phantom: PhantomData,
|
||||
}
|
||||
Self { _peripheral }
|
||||
}
|
||||
|
||||
fn event_bit_is_clear(&self) -> bool {
|
||||
@ -690,9 +705,9 @@ mod asynch {
|
||||
.serial_in_empty()
|
||||
.bit_is_clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::future::Future for UsbSerialJtagWriteFuture<'_> {
|
||||
impl core::future::Future for UsbSerialJtagWriteFuture<'_> {
|
||||
type Output = ();
|
||||
|
||||
fn poll(
|
||||
@ -706,24 +721,23 @@ mod asynch {
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
pub(crate) struct UsbSerialJtagReadFuture<'d> {
|
||||
phantom: PhantomData<&'d mut USB_DEVICE>,
|
||||
}
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
struct UsbSerialJtagReadFuture<'d> {
|
||||
_peripheral: PeripheralRef<'d, USB_DEVICE>,
|
||||
}
|
||||
|
||||
impl UsbSerialJtagReadFuture<'_> {
|
||||
pub fn new() -> Self {
|
||||
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 {
|
||||
phantom: PhantomData,
|
||||
}
|
||||
Self { _peripheral }
|
||||
}
|
||||
|
||||
fn event_bit_is_clear(&self) -> bool {
|
||||
@ -733,9 +747,9 @@ mod asynch {
|
||||
.serial_out_recv_pkt()
|
||||
.bit_is_clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::future::Future for UsbSerialJtagReadFuture<'_> {
|
||||
impl core::future::Future for UsbSerialJtagReadFuture<'_> {
|
||||
type Output = ();
|
||||
|
||||
fn poll(
|
||||
@ -749,18 +763,27 @@ mod asynch {
|
||||
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<'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> {
|
||||
impl UsbSerialJtagTx<'_, Async> {
|
||||
async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> {
|
||||
let reg_block = USB_DEVICE::register_block();
|
||||
|
||||
@ -772,7 +795,7 @@ mod asynch {
|
||||
}
|
||||
reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit());
|
||||
|
||||
UsbSerialJtagWriteFuture::new().await;
|
||||
UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -785,14 +808,14 @@ mod asynch {
|
||||
.out_fifo_empty()
|
||||
.bit_is_clear()
|
||||
{
|
||||
UsbSerialJtagWriteFuture::new().await;
|
||||
UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UsbSerialJtagRx<'_, Async> {
|
||||
impl UsbSerialJtagRx<'_, Async> {
|
||||
async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
if buf.is_empty() {
|
||||
return Ok(0);
|
||||
@ -803,12 +826,12 @@ mod asynch {
|
||||
if read_bytes > 0 {
|
||||
return Ok(read_bytes);
|
||||
}
|
||||
UsbSerialJtagReadFuture::new().await;
|
||||
}
|
||||
UsbSerialJtagReadFuture::new(self.peripheral.reborrow()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_io_async::Write for UsbSerialJtag<'_, Async> {
|
||||
impl embedded_io_async::Write for UsbSerialJtag<'_, Async> {
|
||||
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||
embedded_io_async::Write::write(&mut self.tx, buf).await
|
||||
}
|
||||
@ -816,9 +839,9 @@ mod asynch {
|
||||
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> {
|
||||
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?;
|
||||
|
||||
@ -828,22 +851,22 @@ mod asynch {
|
||||
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||
self.flush_tx_async().await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_io_async::Read for UsbSerialJtag<'_, Async> {
|
||||
impl embedded_io_async::Read for UsbSerialJtag<'_, Async> {
|
||||
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||
embedded_io_async::Read::read(&mut self.rx, buf).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> {
|
||||
impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> {
|
||||
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||
self.read_bytes_async(buf).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[handler]
|
||||
fn async_interrupt_handler() {
|
||||
#[handler]
|
||||
fn async_interrupt_handler() {
|
||||
let usb = USB_DEVICE::register_block();
|
||||
let interrupts = usb.int_st().read();
|
||||
|
||||
@ -871,5 +894,4 @@ mod asynch {
|
||||
if tx {
|
||||
WAKER_TX.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(),
|
||||
)
|
||||
|
||||
@ -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(),
|
||||
)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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(),
|
||||
)
|
||||
|
||||
@ -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 }
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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 }
|
||||
}
|
||||
|
||||
@ -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 }
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user