mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-01 22:31:23 +00:00
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]
|
[alias]
|
||||||
xtask = "run --package xtask --"
|
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)
|
- I2S Parallel output driver for ESP32. (#2348, #2436)
|
||||||
- Add an option to configure `WDT` action (#2330)
|
- Add an option to configure `WDT` action (#2330)
|
||||||
- `DmaDescriptor` is now `Send` (#2456)
|
- `DmaDescriptor` is now `Send` (#2456)
|
||||||
|
- `into_async` and `into_blocking` functions for most peripherals (#2430)
|
||||||
|
- API mode type parameter (currently always `Blocking`) to `master::Spi` and `slave::Spi` (#2430)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
@ -39,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Interrupt listen/unlisten/clear functions now accept any type that converts into `EnumSet` (i.e. single interrupt flags). (#2442)
|
- Interrupt listen/unlisten/clear functions now accept any type that converts into `EnumSet` (i.e. single interrupt flags). (#2442)
|
||||||
- SPI interrupt listening is now only available in Blocking mode. The `set_interrupt_handler` is available via `InterruptConfigurable` (#2442)
|
- SPI interrupt listening is now only available in Blocking mode. The `set_interrupt_handler` is available via `InterruptConfigurable` (#2442)
|
||||||
- Allow users to create DMA `Preparation`s (#2455)
|
- Allow users to create DMA `Preparation`s (#2455)
|
||||||
|
- The `rmt::asynch::RxChannelAsync` and `rmt::asynch::TxChannelAsync` traits have been moved to `rmt` (#2430)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@ -64,6 +67,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Removed the pin type parameters from `parl_io::{RxOneBit, RxTwoBits, RxFourBits, RxEightBits, RxSixteenBits}` (#2388)
|
- Removed the pin type parameters from `parl_io::{RxOneBit, RxTwoBits, RxFourBits, RxEightBits, RxSixteenBits}` (#2388)
|
||||||
- Removed the pin type parameters from `lcd_cam::lcd::i8080::{TxEightBits, TxSixteenBits}` (#2388)
|
- Removed the pin type parameters from `lcd_cam::lcd::i8080::{TxEightBits, TxSixteenBits}` (#2388)
|
||||||
- Removed the pin type parameters from `lcd_cam::cam::{RxEightBits, RxSixteenBits}` (#2388)
|
- Removed the pin type parameters from `lcd_cam::cam::{RxEightBits, RxSixteenBits}` (#2388)
|
||||||
|
- Most of the async-specific constructors (`new_async`, `new_async_no_transceiver`) have been removed. (#2430)
|
||||||
|
- The `configure_for_async` DMA functions have been removed (#2430)
|
||||||
|
|
||||||
## [0.21.1]
|
## [0.21.1]
|
||||||
|
|
||||||
|
@ -23,6 +23,41 @@ For example:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Removed `async`-specific constructors
|
||||||
|
|
||||||
|
The following async-specific constuctors have been removed:
|
||||||
|
|
||||||
|
- `configure_for_async` DMA channel constructors
|
||||||
|
- `TwaiConfiguration::new_async` and `TwaiConfiguration::new_async_no_transceiver`
|
||||||
|
- `I2c::new_async`
|
||||||
|
- `LcdCam::new_async`
|
||||||
|
- `UsbSerialJtag::new_async`
|
||||||
|
- `Rsa::new_async`
|
||||||
|
- `Rmt::new_async`
|
||||||
|
- `Uart::new_async`, `Uart::new_async_with_config`
|
||||||
|
- `UartRx::new_async`, `UartRx::new_async_with_config`
|
||||||
|
- `UartTx::new_async`, `UartTx::new_async_with_config`
|
||||||
|
|
||||||
|
You can use the blocking counterparts, then call `into_async` on the returned peripheral instead.
|
||||||
|
|
||||||
|
```diff
|
||||||
|
-let mut config = twai::TwaiConfiguration::new_async(
|
||||||
|
+let mut config = twai::TwaiConfiguration::new(
|
||||||
|
peripherals.TWAI0,
|
||||||
|
loopback_pin.peripheral_input(),
|
||||||
|
loopback_pin,
|
||||||
|
twai::BaudRate::B1000K,
|
||||||
|
TwaiMode::SelfTest,
|
||||||
|
-);
|
||||||
|
+).into_async();
|
||||||
|
```
|
||||||
|
|
||||||
|
Some drivers were implicitly configured to the asyncness of the DMA channel used to construct them.
|
||||||
|
This is no longer the case, and the following drivers will always be created in blocking mode:
|
||||||
|
|
||||||
|
- `I2s`
|
||||||
|
- `master::SpiDma` and `master::SpiDmaBus`
|
||||||
|
|
||||||
## Peripheral types are now optional
|
## Peripheral types are now optional
|
||||||
|
|
||||||
You no longer have to specify the peripheral instance in the driver's type for the following
|
You no longer have to specify the peripheral instance in the driver's type for the following
|
||||||
|
@ -250,6 +250,7 @@ pub mod dma {
|
|||||||
WriteBuffer,
|
WriteBuffer,
|
||||||
},
|
},
|
||||||
peripherals::AES,
|
peripherals::AES,
|
||||||
|
Blocking,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ALIGN_SIZE: usize = core::mem::size_of::<u32>();
|
const ALIGN_SIZE: usize = core::mem::size_of::<u32>();
|
||||||
@ -275,7 +276,7 @@ pub mod dma {
|
|||||||
/// The underlying [`Aes`](super::Aes) driver
|
/// The underlying [`Aes`](super::Aes) driver
|
||||||
pub aes: super::Aes<'d>,
|
pub aes: super::Aes<'d>,
|
||||||
|
|
||||||
channel: Channel<'d, <AES as DmaEligible>::Dma, crate::Blocking>,
|
channel: Channel<'d, <AES as DmaEligible>::Dma, Blocking>,
|
||||||
rx_chain: DescriptorChain,
|
rx_chain: DescriptorChain,
|
||||||
tx_chain: DescriptorChain,
|
tx_chain: DescriptorChain,
|
||||||
}
|
}
|
||||||
@ -284,12 +285,11 @@ pub mod dma {
|
|||||||
/// Enable DMA for the current instance of the AES driver
|
/// Enable DMA for the current instance of the AES driver
|
||||||
pub fn with_dma<C>(
|
pub fn with_dma<C>(
|
||||||
self,
|
self,
|
||||||
channel: Channel<'d, C, crate::Blocking>,
|
channel: Channel<'d, C, Blocking>,
|
||||||
rx_descriptors: &'static mut [DmaDescriptor],
|
rx_descriptors: &'static mut [DmaDescriptor],
|
||||||
tx_descriptors: &'static mut [DmaDescriptor],
|
tx_descriptors: &'static mut [DmaDescriptor],
|
||||||
) -> AesDma<'d>
|
) -> AesDma<'d>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
|
||||||
C: DmaChannelConvert<<AES as DmaEligible>::Dma>,
|
C: DmaChannelConvert<<AES as DmaEligible>::Dma>,
|
||||||
{
|
{
|
||||||
AesDma {
|
AesDma {
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
interrupt::InterruptHandler,
|
interrupt::InterruptHandler,
|
||||||
peripheral::{Peripheral, PeripheralRef},
|
peripheral::{Peripheral, PeripheralRef},
|
||||||
peripherals::ASSIST_DEBUG,
|
peripherals::{Interrupt, ASSIST_DEBUG},
|
||||||
InterruptConfigurable,
|
InterruptConfigurable,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -51,17 +51,14 @@ impl crate::private::Sealed for DebugAssist<'_> {}
|
|||||||
|
|
||||||
impl InterruptConfigurable for DebugAssist<'_> {
|
impl InterruptConfigurable for DebugAssist<'_> {
|
||||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
unsafe {
|
for core in crate::Cpu::other() {
|
||||||
crate::interrupt::bind_interrupt(
|
crate::interrupt::disable(core, Interrupt::ASSIST_DEBUG);
|
||||||
crate::peripherals::Interrupt::ASSIST_DEBUG,
|
|
||||||
handler.handler(),
|
|
||||||
);
|
|
||||||
crate::interrupt::enable(
|
|
||||||
crate::peripherals::Interrupt::ASSIST_DEBUG,
|
|
||||||
handler.priority(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
unsafe { crate::interrupt::bind_interrupt(Interrupt::ASSIST_DEBUG, handler.handler()) };
|
||||||
|
unwrap!(crate::interrupt::enable(
|
||||||
|
Interrupt::ASSIST_DEBUG,
|
||||||
|
handler.priority()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
dma::*,
|
dma::*,
|
||||||
peripheral::PeripheralRef,
|
peripheral::PeripheralRef,
|
||||||
|
peripherals::Interrupt,
|
||||||
system::{Peripheral, PeripheralClockControl},
|
system::{Peripheral, PeripheralClockControl},
|
||||||
|
Blocking,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -33,6 +35,36 @@ impl crate::private::Sealed for AnyGdmaChannel {}
|
|||||||
impl DmaChannel for AnyGdmaChannel {
|
impl DmaChannel for AnyGdmaChannel {
|
||||||
type Rx = ChannelRxImpl<Self>;
|
type Rx = ChannelRxImpl<Self>;
|
||||||
type Tx = ChannelTxImpl<Self>;
|
type Tx = ChannelTxImpl<Self>;
|
||||||
|
|
||||||
|
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler {
|
||||||
|
match ch.tx.tx_impl.0.number() {
|
||||||
|
0 => DmaChannel0::handler(),
|
||||||
|
#[cfg(not(esp32c2))]
|
||||||
|
1 => DmaChannel1::handler(),
|
||||||
|
#[cfg(not(esp32c2))]
|
||||||
|
2 => DmaChannel2::handler(),
|
||||||
|
#[cfg(esp32s3)]
|
||||||
|
3 => DmaChannel3::handler(),
|
||||||
|
#[cfg(esp32s3)]
|
||||||
|
4 => DmaChannel4::handler(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
|
||||||
|
match ch.tx.tx_impl.0.number() {
|
||||||
|
0 => DmaChannel0::isrs(),
|
||||||
|
#[cfg(not(esp32c2))]
|
||||||
|
1 => DmaChannel1::isrs(),
|
||||||
|
#[cfg(not(esp32c2))]
|
||||||
|
2 => DmaChannel2::isrs(),
|
||||||
|
#[cfg(esp32s3)]
|
||||||
|
3 => DmaChannel3::isrs(),
|
||||||
|
#[cfg(esp32s3)]
|
||||||
|
4 => DmaChannel4::isrs(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
@ -460,9 +492,27 @@ macro_rules! impl_channel {
|
|||||||
|
|
||||||
impl crate::private::Sealed for [<DmaChannel $num>] {}
|
impl crate::private::Sealed for [<DmaChannel $num>] {}
|
||||||
|
|
||||||
|
impl [<DmaChannel $num>] {
|
||||||
|
fn handler() -> InterruptHandler {
|
||||||
|
$async_handler
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isrs() -> &'static [Interrupt] {
|
||||||
|
&[$(Interrupt::$interrupt),*]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl DmaChannel for [<DmaChannel $num>] {
|
impl DmaChannel for [<DmaChannel $num>] {
|
||||||
type Rx = ChannelRxImpl<SpecificGdmaChannel<$num>>;
|
type Rx = ChannelRxImpl<SpecificGdmaChannel<$num>>;
|
||||||
type Tx = ChannelTxImpl<SpecificGdmaChannel<$num>>;
|
type Tx = ChannelTxImpl<SpecificGdmaChannel<$num>>;
|
||||||
|
|
||||||
|
fn async_handler<M: Mode>(_ch: &Channel<'_, Self, M>) -> InterruptHandler {
|
||||||
|
Self::handler()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interrupts<M: Mode>(_ch: &Channel<'_, Self, M>,) -> &'static [Interrupt] {
|
||||||
|
Self::isrs()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DmaChannelConvert<AnyGdmaChannel> for [<DmaChannel $num>] {
|
impl DmaChannelConvert<AnyGdmaChannel> for [<DmaChannel $num>] {
|
||||||
@ -482,64 +532,22 @@ macro_rules! impl_channel {
|
|||||||
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
|
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
|
||||||
ChannelTxImpl(SpecificGdmaChannel::<$num> {})
|
ChannelTxImpl(SpecificGdmaChannel::<$num> {})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_isr(handler: $crate::interrupt::InterruptHandler) {
|
|
||||||
let mut dma = unsafe { crate::peripherals::DMA::steal() };
|
|
||||||
$(
|
|
||||||
dma.[< bind_ $interrupt:lower _interrupt >](handler.handler());
|
|
||||||
$crate::interrupt::enable($crate::peripherals::Interrupt::$interrupt, handler.priority()).unwrap();
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelCreator<$num> {
|
impl ChannelCreator<$num> {
|
||||||
fn do_configure<'a, M: crate::Mode>(
|
|
||||||
self,
|
|
||||||
burst_mode: bool,
|
|
||||||
priority: DmaPriority,
|
|
||||||
) -> crate::dma::Channel<'a, [<DmaChannel $num>], M> {
|
|
||||||
let tx_impl = ChannelTxImpl(SpecificGdmaChannel::<$num> {});
|
|
||||||
tx_impl.set_burst_mode(burst_mode);
|
|
||||||
tx_impl.set_priority(priority);
|
|
||||||
|
|
||||||
let rx_impl = ChannelRxImpl(SpecificGdmaChannel::<$num> {});
|
|
||||||
rx_impl.set_burst_mode(burst_mode);
|
|
||||||
rx_impl.set_priority(priority);
|
|
||||||
// clear the mem2mem mode to avoid failed DMA if this
|
|
||||||
// channel was previously used for a mem2mem transfer.
|
|
||||||
rx_impl.set_mem2mem_mode(false);
|
|
||||||
|
|
||||||
crate::dma::Channel {
|
|
||||||
tx: ChannelTx::new(tx_impl, burst_mode),
|
|
||||||
rx: ChannelRx::new(rx_impl, burst_mode),
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configure the channel for use with blocking APIs
|
/// Configure the channel for use with blocking APIs
|
||||||
///
|
|
||||||
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
|
||||||
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
|
||||||
pub fn configure<'a>(
|
pub fn configure<'a>(
|
||||||
self,
|
self,
|
||||||
burst_mode: bool,
|
burst_mode: bool,
|
||||||
priority: DmaPriority,
|
priority: DmaPriority,
|
||||||
) -> crate::dma::Channel<'a, [<DmaChannel $num>], crate::Blocking> {
|
) -> Channel<'a, [<DmaChannel $num>], Blocking> {
|
||||||
self.do_configure(burst_mode, priority)
|
let mut this = Channel {
|
||||||
}
|
tx: ChannelTx::new(ChannelTxImpl(SpecificGdmaChannel::<$num> {})),
|
||||||
|
rx: ChannelRx::new(ChannelRxImpl(SpecificGdmaChannel::<$num> {})),
|
||||||
|
phantom: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
/// Configure the channel for use with async APIs
|
this.configure(burst_mode, priority);
|
||||||
///
|
|
||||||
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
|
||||||
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
|
||||||
pub fn configure_for_async<'a>(
|
|
||||||
self,
|
|
||||||
burst_mode: bool,
|
|
||||||
priority: DmaPriority,
|
|
||||||
) -> crate::dma::Channel<'a, [<DmaChannel $num>], $crate::Async> {
|
|
||||||
let this = self.do_configure(burst_mode, priority);
|
|
||||||
|
|
||||||
[<DmaChannel $num>]::set_isr($async_handler);
|
|
||||||
|
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ use crate::{
|
|||||||
Tx,
|
Tx,
|
||||||
WriteBuffer,
|
WriteBuffer,
|
||||||
},
|
},
|
||||||
|
Async,
|
||||||
|
Blocking,
|
||||||
Mode,
|
Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -36,19 +38,18 @@ where
|
|||||||
peripheral: DmaPeripheral,
|
peripheral: DmaPeripheral,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, M> Mem2Mem<'d, M>
|
impl<'d> Mem2Mem<'d, Blocking> {
|
||||||
where
|
|
||||||
M: Mode,
|
|
||||||
{
|
|
||||||
/// Create a new Mem2Mem instance.
|
/// Create a new Mem2Mem instance.
|
||||||
pub fn new<CH>(
|
pub fn new<CH, DM>(
|
||||||
channel: Channel<'d, CH, M>,
|
channel: Channel<'d, CH, DM>,
|
||||||
peripheral: impl DmaEligible,
|
peripheral: impl DmaEligible,
|
||||||
rx_descriptors: &'static mut [DmaDescriptor],
|
rx_descriptors: &'static mut [DmaDescriptor],
|
||||||
tx_descriptors: &'static mut [DmaDescriptor],
|
tx_descriptors: &'static mut [DmaDescriptor],
|
||||||
) -> Result<Self, DmaError>
|
) -> Result<Self, DmaError>
|
||||||
where
|
where
|
||||||
CH: DmaChannelConvert<AnyGdmaChannel>,
|
CH: DmaChannelConvert<AnyGdmaChannel>,
|
||||||
|
DM: Mode,
|
||||||
|
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
Self::new_unsafe(
|
Self::new_unsafe(
|
||||||
@ -62,8 +63,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Mem2Mem instance with specific chunk size.
|
/// Create a new Mem2Mem instance with specific chunk size.
|
||||||
pub fn new_with_chunk_size<CH>(
|
pub fn new_with_chunk_size<CH, DM>(
|
||||||
channel: Channel<'d, CH, M>,
|
channel: Channel<'d, CH, DM>,
|
||||||
peripheral: impl DmaEligible,
|
peripheral: impl DmaEligible,
|
||||||
rx_descriptors: &'static mut [DmaDescriptor],
|
rx_descriptors: &'static mut [DmaDescriptor],
|
||||||
tx_descriptors: &'static mut [DmaDescriptor],
|
tx_descriptors: &'static mut [DmaDescriptor],
|
||||||
@ -71,6 +72,8 @@ where
|
|||||||
) -> Result<Self, DmaError>
|
) -> Result<Self, DmaError>
|
||||||
where
|
where
|
||||||
CH: DmaChannelConvert<AnyGdmaChannel>,
|
CH: DmaChannelConvert<AnyGdmaChannel>,
|
||||||
|
DM: Mode,
|
||||||
|
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
Self::new_unsafe(
|
Self::new_unsafe(
|
||||||
@ -89,8 +92,8 @@ where
|
|||||||
///
|
///
|
||||||
/// You must ensure that your not using DMA for the same peripheral and
|
/// You must ensure that your not using DMA for the same peripheral and
|
||||||
/// that your the only one using the DmaPeripheral.
|
/// that your the only one using the DmaPeripheral.
|
||||||
pub unsafe fn new_unsafe<CH>(
|
pub unsafe fn new_unsafe<CH, DM>(
|
||||||
channel: Channel<'d, CH, M>,
|
channel: Channel<'d, CH, DM>,
|
||||||
peripheral: DmaPeripheral,
|
peripheral: DmaPeripheral,
|
||||||
rx_descriptors: &'static mut [DmaDescriptor],
|
rx_descriptors: &'static mut [DmaDescriptor],
|
||||||
tx_descriptors: &'static mut [DmaDescriptor],
|
tx_descriptors: &'static mut [DmaDescriptor],
|
||||||
@ -98,6 +101,8 @@ where
|
|||||||
) -> Result<Self, DmaError>
|
) -> Result<Self, DmaError>
|
||||||
where
|
where
|
||||||
CH: DmaChannelConvert<AnyGdmaChannel>,
|
CH: DmaChannelConvert<AnyGdmaChannel>,
|
||||||
|
DM: Mode,
|
||||||
|
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
|
||||||
{
|
{
|
||||||
if !(1..=4092).contains(&chunk_size) {
|
if !(1..=4092).contains(&chunk_size) {
|
||||||
return Err(DmaError::InvalidChunkSize);
|
return Err(DmaError::InvalidChunkSize);
|
||||||
@ -106,13 +111,28 @@ where
|
|||||||
return Err(DmaError::OutOfDescriptors);
|
return Err(DmaError::OutOfDescriptors);
|
||||||
}
|
}
|
||||||
Ok(Mem2Mem {
|
Ok(Mem2Mem {
|
||||||
channel: channel.degrade(),
|
channel: Channel::<_, Blocking>::from(channel).degrade(),
|
||||||
peripheral,
|
peripheral,
|
||||||
rx_chain: DescriptorChain::new_with_chunk_size(rx_descriptors, chunk_size),
|
rx_chain: DescriptorChain::new_with_chunk_size(rx_descriptors, chunk_size),
|
||||||
tx_chain: DescriptorChain::new_with_chunk_size(tx_descriptors, chunk_size),
|
tx_chain: DescriptorChain::new_with_chunk_size(tx_descriptors, chunk_size),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert Mem2Mem to an async Mem2Mem.
|
||||||
|
pub fn into_async(self) -> Mem2Mem<'d, Async> {
|
||||||
|
Mem2Mem {
|
||||||
|
channel: self.channel.into_async(),
|
||||||
|
rx_chain: self.rx_chain,
|
||||||
|
tx_chain: self.tx_chain,
|
||||||
|
peripheral: self.peripheral,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, M> Mem2Mem<'d, M>
|
||||||
|
where
|
||||||
|
M: Mode,
|
||||||
|
{
|
||||||
/// Start a memory to memory transfer.
|
/// Start a memory to memory transfer.
|
||||||
pub fn start_transfer<'t, TXBUF, RXBUF>(
|
pub fn start_transfer<'t, TXBUF, RXBUF>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -58,6 +58,25 @@
|
|||||||
|
|
||||||
use core::{cmp::min, fmt::Debug, marker::PhantomData, sync::atomic::compiler_fence};
|
use core::{cmp::min, fmt::Debug, marker::PhantomData, sync::atomic::compiler_fence};
|
||||||
|
|
||||||
|
use enumset::{EnumSet, EnumSetType};
|
||||||
|
|
||||||
|
pub use self::buffers::*;
|
||||||
|
#[cfg(gdma)]
|
||||||
|
pub use self::gdma::*;
|
||||||
|
#[cfg(gdma)]
|
||||||
|
pub use self::m2m::*;
|
||||||
|
#[cfg(pdma)]
|
||||||
|
pub use self::pdma::*;
|
||||||
|
use crate::{
|
||||||
|
interrupt::InterruptHandler,
|
||||||
|
peripherals::Interrupt,
|
||||||
|
soc::is_slice_in_dram,
|
||||||
|
Async,
|
||||||
|
Blocking,
|
||||||
|
Cpu,
|
||||||
|
Mode,
|
||||||
|
};
|
||||||
|
|
||||||
trait Word: crate::private::Sealed {}
|
trait Word: crate::private::Sealed {}
|
||||||
|
|
||||||
macro_rules! impl_word {
|
macro_rules! impl_word {
|
||||||
@ -356,17 +375,6 @@ impl DmaDescriptor {
|
|||||||
// Send (where the compiler sees fit).
|
// Send (where the compiler sees fit).
|
||||||
unsafe impl Send for DmaDescriptor {}
|
unsafe impl Send for DmaDescriptor {}
|
||||||
|
|
||||||
use enumset::{EnumSet, EnumSetType};
|
|
||||||
|
|
||||||
pub use self::buffers::*;
|
|
||||||
#[cfg(gdma)]
|
|
||||||
pub use self::gdma::*;
|
|
||||||
#[cfg(gdma)]
|
|
||||||
pub use self::m2m::*;
|
|
||||||
#[cfg(pdma)]
|
|
||||||
pub use self::pdma::*;
|
|
||||||
use crate::{interrupt::InterruptHandler, soc::is_slice_in_dram, Mode};
|
|
||||||
|
|
||||||
mod buffers;
|
mod buffers;
|
||||||
#[cfg(gdma)]
|
#[cfg(gdma)]
|
||||||
mod gdma;
|
mod gdma;
|
||||||
@ -1562,21 +1570,24 @@ impl RxCircularState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A description of a DMA Channel.
|
/// A description of a DMA Channel.
|
||||||
pub trait DmaChannel: crate::private::Sealed {
|
pub trait DmaChannel: crate::private::Sealed + Sized {
|
||||||
/// A description of the RX half of a DMA Channel.
|
/// A description of the RX half of a DMA Channel.
|
||||||
type Rx: RxRegisterAccess + InterruptAccess<DmaRxInterrupt>;
|
type Rx: RxRegisterAccess + InterruptAccess<DmaRxInterrupt>;
|
||||||
|
|
||||||
/// A description of the TX half of a DMA Channel.
|
/// A description of the TX half of a DMA Channel.
|
||||||
type Tx: TxRegisterAccess + InterruptAccess<DmaTxInterrupt>;
|
type Tx: TxRegisterAccess + InterruptAccess<DmaTxInterrupt>;
|
||||||
|
|
||||||
|
/// Returns the async interrupt handler.
|
||||||
|
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler;
|
||||||
|
|
||||||
|
/// Returns the interrupt.
|
||||||
|
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait DmaChannelExt: DmaChannel {
|
pub trait DmaChannelExt: DmaChannel {
|
||||||
fn get_rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt>;
|
fn get_rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt>;
|
||||||
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt>;
|
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt>;
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn set_isr(handler: InterruptHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -1668,9 +1679,14 @@ impl<'a, CH> ChannelRx<'a, CH>
|
|||||||
where
|
where
|
||||||
CH: DmaChannel,
|
CH: DmaChannel,
|
||||||
{
|
{
|
||||||
fn new(rx_impl: CH::Rx, burst_mode: bool) -> Self {
|
fn new(rx_impl: CH::Rx) -> Self {
|
||||||
|
#[cfg(gdma)]
|
||||||
|
// clear the mem2mem mode to avoid failed DMA if this
|
||||||
|
// channel was previously used for a mem2mem transfer.
|
||||||
|
rx_impl.set_mem2mem_mode(false);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
burst_mode,
|
burst_mode: false,
|
||||||
rx_impl,
|
rx_impl,
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
@ -1688,6 +1704,12 @@ where
|
|||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure the channel.
|
||||||
|
pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) {
|
||||||
|
self.burst_mode = burst_mode;
|
||||||
|
self.rx_impl.configure(burst_mode, priority);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CH> crate::private::Sealed for ChannelRx<'_, CH> where CH: DmaChannel {}
|
impl<CH> crate::private::Sealed for ChannelRx<'_, CH> where CH: DmaChannel {}
|
||||||
@ -1886,9 +1908,9 @@ impl<'a, CH> ChannelTx<'a, CH>
|
|||||||
where
|
where
|
||||||
CH: DmaChannel,
|
CH: DmaChannel,
|
||||||
{
|
{
|
||||||
fn new(tx_impl: CH::Tx, burst_mode: bool) -> Self {
|
fn new(tx_impl: CH::Tx) -> Self {
|
||||||
Self {
|
Self {
|
||||||
burst_mode,
|
burst_mode: false,
|
||||||
tx_impl,
|
tx_impl,
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
@ -1906,6 +1928,12 @@ where
|
|||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure the channel.
|
||||||
|
pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) {
|
||||||
|
self.burst_mode = burst_mode;
|
||||||
|
self.tx_impl.configure(burst_mode, priority);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<CH> crate::private::Sealed for ChannelTx<'_, CH> where CH: DmaChannel {}
|
impl<CH> crate::private::Sealed for ChannelTx<'_, CH> where CH: DmaChannel {}
|
||||||
@ -2076,6 +2104,12 @@ pub trait RegisterAccess: crate::private::Sealed {
|
|||||||
|
|
||||||
#[cfg(pdma)]
|
#[cfg(pdma)]
|
||||||
fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool;
|
fn is_compatible_with(&self, peripheral: &impl PeripheralMarker) -> bool;
|
||||||
|
|
||||||
|
/// Configure the channel.
|
||||||
|
fn configure(&self, burst_mode: bool, priority: DmaPriority) {
|
||||||
|
self.set_burst_mode(burst_mode);
|
||||||
|
self.set_priority(priority);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -2114,31 +2148,38 @@ pub trait InterruptAccess<T: EnumSetType>: crate::private::Sealed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// DMA Channel
|
/// DMA Channel
|
||||||
pub struct Channel<'d, CH, MODE>
|
pub struct Channel<'d, CH, M>
|
||||||
where
|
where
|
||||||
CH: DmaChannel,
|
CH: DmaChannel,
|
||||||
MODE: Mode,
|
M: Mode,
|
||||||
{
|
{
|
||||||
/// RX half of the channel
|
/// RX half of the channel
|
||||||
pub rx: ChannelRx<'d, CH>,
|
pub rx: ChannelRx<'d, CH>,
|
||||||
/// TX half of the channel
|
/// TX half of the channel
|
||||||
pub tx: ChannelTx<'d, CH>,
|
pub tx: ChannelTx<'d, CH>,
|
||||||
phantom: PhantomData<MODE>,
|
pub(crate) phantom: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> Channel<'_, C, crate::Blocking>
|
impl<'d, C> Channel<'d, C, Blocking>
|
||||||
where
|
where
|
||||||
C: DmaChannel,
|
C: DmaChannel,
|
||||||
{
|
{
|
||||||
/// Sets the interrupt handler for RX and TX interrupts, enables them
|
/// Sets the interrupt handler for RX and TX interrupts.
|
||||||
/// with [crate::interrupt::Priority::max()]
|
|
||||||
///
|
///
|
||||||
/// Interrupts are not enabled at the peripheral level here.
|
/// Interrupts are not enabled at the peripheral level here.
|
||||||
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler)
|
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler)
|
||||||
where
|
where
|
||||||
C: DmaChannelExt,
|
C: DmaChannel,
|
||||||
{
|
{
|
||||||
C::set_isr(handler);
|
self.unlisten(EnumSet::all());
|
||||||
|
self.clear_interrupts(EnumSet::all());
|
||||||
|
for interrupt in C::interrupts(self).iter().copied() {
|
||||||
|
for core in crate::Cpu::other() {
|
||||||
|
crate::interrupt::disable(core, interrupt);
|
||||||
|
}
|
||||||
|
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
|
||||||
|
unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Listen for the given interrupts
|
/// Listen for the given interrupts
|
||||||
@ -2182,6 +2223,53 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure the channel.
|
||||||
|
pub fn configure(&mut self, burst_mode: bool, priority: DmaPriority) {
|
||||||
|
self.tx.configure(burst_mode, priority);
|
||||||
|
self.rx.configure(burst_mode, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a blocking channel to an async channel.
|
||||||
|
pub fn into_async(mut self) -> Channel<'d, C, Async> {
|
||||||
|
self.set_interrupt_handler(C::async_handler(&self));
|
||||||
|
|
||||||
|
Channel {
|
||||||
|
tx: self.tx,
|
||||||
|
rx: self.rx,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, C> Channel<'d, C, Async>
|
||||||
|
where
|
||||||
|
C: DmaChannel,
|
||||||
|
{
|
||||||
|
/// Converts an async channel to a blocking channel.
|
||||||
|
pub fn into_blocking(self) -> Channel<'d, C, Blocking> {
|
||||||
|
for interrupt in C::interrupts(&self).iter().copied() {
|
||||||
|
crate::interrupt::disable(Cpu::current(), interrupt);
|
||||||
|
}
|
||||||
|
|
||||||
|
Channel {
|
||||||
|
tx: self.tx,
|
||||||
|
rx: self.rx,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, C: DmaChannel> From<Channel<'d, C, Blocking>> for Channel<'d, C, Async> {
|
||||||
|
fn from(channel: Channel<'d, C, Blocking>) -> Self {
|
||||||
|
channel.into_async()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, C: DmaChannel> From<Channel<'d, C, Async>> for Channel<'d, C, Blocking> {
|
||||||
|
fn from(channel: Channel<'d, C, Async>) -> Self {
|
||||||
|
channel.into_blocking()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, CH, M: Mode> Channel<'d, CH, M>
|
impl<'d, CH, M: Mode> Channel<'d, CH, M>
|
||||||
@ -2906,13 +2994,13 @@ pub(crate) mod asynch {
|
|||||||
|
|
||||||
#[cfg(i2s0)]
|
#[cfg(i2s0)]
|
||||||
#[handler(priority = crate::interrupt::Priority::max())]
|
#[handler(priority = crate::interrupt::Priority::max())]
|
||||||
pub(crate) fn interrupt_handler_i2s0() {
|
pub(crate) fn interrupt_handler_i2s0_dma() {
|
||||||
handle_interrupt::<I2s0DmaChannel>();
|
handle_interrupt::<I2s0DmaChannel>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(i2s1)]
|
#[cfg(i2s1)]
|
||||||
#[handler(priority = crate::interrupt::Priority::max())]
|
#[handler(priority = crate::interrupt::Priority::max())]
|
||||||
pub(crate) fn interrupt_handler_i2s1() {
|
pub(crate) fn interrupt_handler_i2s1_dma() {
|
||||||
handle_interrupt::<I2s1DmaChannel>();
|
handle_interrupt::<I2s1DmaChannel>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,9 @@ use embassy_sync::waitqueue::AtomicWaker;
|
|||||||
use crate::{
|
use crate::{
|
||||||
dma::*,
|
dma::*,
|
||||||
peripheral::PeripheralRef,
|
peripheral::PeripheralRef,
|
||||||
|
peripherals::Interrupt,
|
||||||
system::{Peripheral, PeripheralClockControl},
|
system::{Peripheral, PeripheralClockControl},
|
||||||
|
Blocking,
|
||||||
};
|
};
|
||||||
|
|
||||||
type SpiRegisterBlock = crate::peripherals::spi2::RegisterBlock;
|
type SpiRegisterBlock = crate::peripherals::spi2::RegisterBlock;
|
||||||
@ -341,9 +343,27 @@ macro_rules! ImplSpiChannel {
|
|||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct [<Spi $num DmaChannel>] {}
|
pub struct [<Spi $num DmaChannel>] {}
|
||||||
|
|
||||||
|
impl [<Spi $num DmaChannel>] {
|
||||||
|
fn handler() -> InterruptHandler {
|
||||||
|
super::asynch::interrupt::[< interrupt_handler_spi $num _dma >]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isrs() -> &'static [Interrupt] {
|
||||||
|
&[Interrupt::[< SPI $num _DMA >]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl DmaChannel for [<Spi $num DmaChannel>] {
|
impl DmaChannel for [<Spi $num DmaChannel>] {
|
||||||
type Rx = SpiDmaRxChannelImpl<Self>;
|
type Rx = SpiDmaRxChannelImpl<Self>;
|
||||||
type Tx = SpiDmaTxChannelImpl<Self>;
|
type Tx = SpiDmaTxChannelImpl<Self>;
|
||||||
|
|
||||||
|
fn async_handler<M: Mode>(_ch: &Channel<'_, Self, M>) -> InterruptHandler {
|
||||||
|
Self::handler()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interrupts<M: Mode>(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
|
||||||
|
Self::isrs()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DmaChannelExt for [<Spi $num DmaChannel>] {
|
impl DmaChannelExt for [<Spi $num DmaChannel>] {
|
||||||
@ -353,14 +373,6 @@ macro_rules! ImplSpiChannel {
|
|||||||
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
|
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
|
||||||
SpiDmaTxChannelImpl(Self {})
|
SpiDmaTxChannelImpl(Self {})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_isr(handler: InterruptHandler) {
|
|
||||||
let interrupt = $crate::peripherals::Interrupt::[< SPI $num _DMA >];
|
|
||||||
unsafe {
|
|
||||||
crate::interrupt::bind_interrupt(interrupt, handler.handler());
|
|
||||||
}
|
|
||||||
crate::interrupt::enable(interrupt, handler.priority()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PdmaChannel for [<Spi $num DmaChannel>] {
|
impl PdmaChannel for [<Spi $num DmaChannel>] {
|
||||||
@ -399,59 +411,19 @@ macro_rules! ImplSpiChannel {
|
|||||||
pub struct [<Spi $num DmaChannelCreator>] {}
|
pub struct [<Spi $num DmaChannelCreator>] {}
|
||||||
|
|
||||||
impl [<Spi $num DmaChannelCreator>] {
|
impl [<Spi $num DmaChannelCreator>] {
|
||||||
fn do_configure<'a, M: $crate::Mode>(
|
|
||||||
self,
|
|
||||||
burst_mode: bool,
|
|
||||||
priority: DmaPriority,
|
|
||||||
) -> Channel<'a, [<Spi $num DmaChannel>], M> {
|
|
||||||
#[cfg(esp32)]
|
|
||||||
{
|
|
||||||
// (only) on ESP32 we need to configure DPORT for the SPI DMA channels
|
|
||||||
let dport = unsafe { &*crate::peripherals::DPORT::PTR };
|
|
||||||
dport
|
|
||||||
.spi_dma_chan_sel()
|
|
||||||
.modify(|_, w| unsafe { w.[< spi $num _dma_chan_sel>]().bits($num - 1) });
|
|
||||||
}
|
|
||||||
|
|
||||||
let tx_impl = SpiDmaTxChannelImpl([<Spi $num DmaChannel>] {});
|
|
||||||
tx_impl.set_burst_mode(burst_mode);
|
|
||||||
tx_impl.set_priority(priority);
|
|
||||||
|
|
||||||
let rx_impl = SpiDmaRxChannelImpl([<Spi $num DmaChannel>] {});
|
|
||||||
rx_impl.set_burst_mode(burst_mode);
|
|
||||||
rx_impl.set_priority(priority);
|
|
||||||
|
|
||||||
Channel {
|
|
||||||
tx: ChannelTx::new(tx_impl, burst_mode),
|
|
||||||
rx: ChannelRx::new(rx_impl, burst_mode),
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configure the channel for use with blocking APIs
|
/// Configure the channel for use with blocking APIs
|
||||||
///
|
|
||||||
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
|
||||||
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
|
||||||
pub fn configure<'a>(
|
pub fn configure<'a>(
|
||||||
self,
|
self,
|
||||||
burst_mode: bool,
|
burst_mode: bool,
|
||||||
priority: DmaPriority,
|
priority: DmaPriority,
|
||||||
) -> Channel<'a, [<Spi $num DmaChannel>], $crate::Blocking> {
|
) -> Channel<'a, [<Spi $num DmaChannel>], Blocking> {
|
||||||
Self::do_configure(self, burst_mode, priority)
|
let mut this = Channel {
|
||||||
}
|
tx: ChannelTx::new(SpiDmaTxChannelImpl([<Spi $num DmaChannel>] {})),
|
||||||
|
rx: ChannelRx::new(SpiDmaRxChannelImpl([<Spi $num DmaChannel>] {})),
|
||||||
|
phantom: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
/// Configure the channel for use with async APIs
|
this.configure(burst_mode, priority);
|
||||||
///
|
|
||||||
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
|
||||||
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
|
||||||
pub fn configure_for_async<'a>(
|
|
||||||
self,
|
|
||||||
burst_mode: bool,
|
|
||||||
priority: DmaPriority,
|
|
||||||
) -> Channel<'a, [<Spi $num DmaChannel>], $crate::Async> {
|
|
||||||
let this = Self::do_configure(self, burst_mode, priority);
|
|
||||||
|
|
||||||
[<Spi $num DmaChannel>]::set_isr(super::asynch::interrupt::[< interrupt_handler_spi $num _dma >]);
|
|
||||||
|
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
@ -784,9 +756,27 @@ macro_rules! ImplI2sChannel {
|
|||||||
|
|
||||||
impl $crate::private::Sealed for [<I2s $num DmaChannel>] {}
|
impl $crate::private::Sealed for [<I2s $num DmaChannel>] {}
|
||||||
|
|
||||||
|
impl [<I2s $num DmaChannel>] {
|
||||||
|
fn handler() -> InterruptHandler {
|
||||||
|
super::asynch::interrupt::[< interrupt_handler_i2s $num _dma >]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isrs() -> &'static [Interrupt] {
|
||||||
|
&[Interrupt::[< I2S $num >]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl DmaChannel for [<I2s $num DmaChannel>] {
|
impl DmaChannel for [<I2s $num DmaChannel>] {
|
||||||
type Rx = I2sDmaRxChannelImpl<Self>;
|
type Rx = I2sDmaRxChannelImpl<Self>;
|
||||||
type Tx = I2sDmaTxChannelImpl<Self>;
|
type Tx = I2sDmaTxChannelImpl<Self>;
|
||||||
|
|
||||||
|
fn async_handler<M: Mode>(_ch: &Channel<'_, Self, M>) -> InterruptHandler {
|
||||||
|
Self::handler()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interrupts<M: Mode>(_ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
|
||||||
|
Self::isrs()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DmaChannelExt for [<I2s $num DmaChannel>] {
|
impl DmaChannelExt for [<I2s $num DmaChannel>] {
|
||||||
@ -796,14 +786,6 @@ macro_rules! ImplI2sChannel {
|
|||||||
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
|
fn get_tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
|
||||||
I2sDmaTxChannelImpl(Self {})
|
I2sDmaTxChannelImpl(Self {})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_isr(handler: InterruptHandler) {
|
|
||||||
let interrupt = $crate::peripherals::Interrupt::[< I2S $num >];
|
|
||||||
unsafe {
|
|
||||||
crate::interrupt::bind_interrupt(interrupt, handler.handler());
|
|
||||||
}
|
|
||||||
crate::interrupt::enable(interrupt, handler.priority()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PdmaChannel for [<I2s $num DmaChannel>] {
|
impl PdmaChannel for [<I2s $num DmaChannel>] {
|
||||||
@ -838,50 +820,19 @@ macro_rules! ImplI2sChannel {
|
|||||||
pub struct [<I2s $num DmaChannelCreator>] {}
|
pub struct [<I2s $num DmaChannelCreator>] {}
|
||||||
|
|
||||||
impl [<I2s $num DmaChannelCreator>] {
|
impl [<I2s $num DmaChannelCreator>] {
|
||||||
fn do_configure<'a, M: $crate::Mode>(
|
|
||||||
self,
|
|
||||||
burst_mode: bool,
|
|
||||||
priority: DmaPriority,
|
|
||||||
) -> Channel<'a, [<I2s $num DmaChannel>], M> {
|
|
||||||
let tx_impl = I2sDmaTxChannelImpl([<I2s $num DmaChannel>] {});
|
|
||||||
tx_impl.set_burst_mode(burst_mode);
|
|
||||||
tx_impl.set_priority(priority);
|
|
||||||
|
|
||||||
let rx_impl = I2sDmaRxChannelImpl([<I2s $num DmaChannel>] {});
|
|
||||||
rx_impl.set_burst_mode(burst_mode);
|
|
||||||
rx_impl.set_priority(priority);
|
|
||||||
|
|
||||||
Channel {
|
|
||||||
tx: ChannelTx::new(tx_impl, burst_mode),
|
|
||||||
rx: ChannelRx::new(rx_impl, burst_mode),
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configure the channel for use with blocking APIs
|
/// Configure the channel for use with blocking APIs
|
||||||
///
|
|
||||||
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
|
||||||
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
|
||||||
pub fn configure<'a>(
|
pub fn configure<'a>(
|
||||||
self,
|
self,
|
||||||
burst_mode: bool,
|
burst_mode: bool,
|
||||||
priority: DmaPriority,
|
priority: DmaPriority,
|
||||||
) -> Channel<'a, [<I2s $num DmaChannel>], $crate::Blocking> {
|
) -> Channel<'a, [<I2s $num DmaChannel>], Blocking> {
|
||||||
Self::do_configure(self, burst_mode, priority)
|
let mut this = Channel {
|
||||||
}
|
tx: ChannelTx::new(I2sDmaTxChannelImpl([<I2s $num DmaChannel>] {})),
|
||||||
|
rx: ChannelRx::new(I2sDmaRxChannelImpl([<I2s $num DmaChannel>] {})),
|
||||||
|
phantom: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
/// Configure the channel for use with async APIs
|
this.configure(burst_mode, priority);
|
||||||
///
|
|
||||||
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
|
|
||||||
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
|
|
||||||
pub fn configure_for_async<'a>(
|
|
||||||
self,
|
|
||||||
burst_mode: bool,
|
|
||||||
priority: DmaPriority,
|
|
||||||
) -> Channel<'a, [<I2s $num DmaChannel>], $crate::Async> {
|
|
||||||
let this = Self::do_configure(self, burst_mode, priority);
|
|
||||||
|
|
||||||
[<I2s $num DmaChannel>]::set_isr(super::asynch::interrupt::[< interrupt_handler_i2s $num >]);
|
|
||||||
|
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
@ -929,6 +880,19 @@ impl<'d> Dma<'d> {
|
|||||||
) -> Dma<'d> {
|
) -> Dma<'d> {
|
||||||
PeripheralClockControl::enable(Peripheral::Dma);
|
PeripheralClockControl::enable(Peripheral::Dma);
|
||||||
|
|
||||||
|
#[cfg(esp32)]
|
||||||
|
{
|
||||||
|
// (only) on ESP32 we need to configure DPORT for the SPI DMA channels
|
||||||
|
// This assignes the DMA channels to the SPI peripherals, which is more
|
||||||
|
// restrictive than necessary but we currently support the same
|
||||||
|
// number of SPI peripherals as SPI DMA channels so it's not a big
|
||||||
|
// deal.
|
||||||
|
let dport = unsafe { &*crate::peripherals::DPORT::PTR };
|
||||||
|
dport.spi_dma_chan_sel().modify(|_, w| unsafe {
|
||||||
|
w.spi2_dma_chan_sel().bits(1).spi3_dma_chan_sel().bits(2)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Dma {
|
Dma {
|
||||||
_inner: dma.into_ref(),
|
_inner: dma.into_ref(),
|
||||||
spi2channel: Spi2DmaChannelCreator {},
|
spi2channel: Spi2DmaChannelCreator {},
|
||||||
@ -962,6 +926,20 @@ impl crate::private::Sealed for AnySpiDmaChannel {}
|
|||||||
impl DmaChannel for AnySpiDmaChannel {
|
impl DmaChannel for AnySpiDmaChannel {
|
||||||
type Rx = SpiDmaRxChannelImpl<AnySpiDmaChannelInner>;
|
type Rx = SpiDmaRxChannelImpl<AnySpiDmaChannelInner>;
|
||||||
type Tx = SpiDmaTxChannelImpl<AnySpiDmaChannelInner>;
|
type Tx = SpiDmaTxChannelImpl<AnySpiDmaChannelInner>;
|
||||||
|
|
||||||
|
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler {
|
||||||
|
match &ch.tx.tx_impl.0 {
|
||||||
|
AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::handler(),
|
||||||
|
AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::handler(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
|
||||||
|
match &ch.tx.tx_impl.0 {
|
||||||
|
AnySpiDmaChannelInner::Spi2(_) => Spi2DmaChannel::isrs(),
|
||||||
|
AnySpiDmaChannelInner::Spi3(_) => Spi3DmaChannel::isrs(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::any_enum! {
|
crate::any_enum! {
|
||||||
@ -998,6 +976,22 @@ impl crate::private::Sealed for AnyI2sDmaChannel {}
|
|||||||
impl DmaChannel for AnyI2sDmaChannel {
|
impl DmaChannel for AnyI2sDmaChannel {
|
||||||
type Rx = I2sDmaRxChannelImpl<AnyI2sDmaChannelInner>;
|
type Rx = I2sDmaRxChannelImpl<AnyI2sDmaChannelInner>;
|
||||||
type Tx = I2sDmaTxChannelImpl<AnyI2sDmaChannelInner>;
|
type Tx = I2sDmaTxChannelImpl<AnyI2sDmaChannelInner>;
|
||||||
|
|
||||||
|
fn async_handler<M: Mode>(ch: &Channel<'_, Self, M>) -> InterruptHandler {
|
||||||
|
match &ch.tx.tx_impl.0 {
|
||||||
|
AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::handler(),
|
||||||
|
#[cfg(i2s1)]
|
||||||
|
AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::handler(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interrupts<M: Mode>(ch: &Channel<'_, Self, M>) -> &'static [Interrupt] {
|
||||||
|
match &ch.tx.tx_impl.0 {
|
||||||
|
AnyI2sDmaChannelInner::I2s0(_) => I2s0DmaChannel::isrs(),
|
||||||
|
#[cfg(i2s1)]
|
||||||
|
AnyI2sDmaChannelInner::I2s1(_) => I2s1DmaChannel::isrs(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::any_enum! {
|
crate::any_enum! {
|
||||||
|
@ -30,7 +30,7 @@ use core::marker::PhantomData;
|
|||||||
use crate::{
|
use crate::{
|
||||||
interrupt::InterruptHandler,
|
interrupt::InterruptHandler,
|
||||||
peripheral::{Peripheral, PeripheralRef},
|
peripheral::{Peripheral, PeripheralRef},
|
||||||
peripherals::ECC,
|
peripherals::{Interrupt, ECC},
|
||||||
reg_access::{AlignmentHelper, SocDependentEndianess},
|
reg_access::{AlignmentHelper, SocDependentEndianess},
|
||||||
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
|
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
|
||||||
InterruptConfigurable,
|
InterruptConfigurable,
|
||||||
@ -117,11 +117,11 @@ impl crate::private::Sealed for Ecc<'_, crate::Blocking> {}
|
|||||||
|
|
||||||
impl InterruptConfigurable for Ecc<'_, crate::Blocking> {
|
impl InterruptConfigurable for Ecc<'_, crate::Blocking> {
|
||||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
unsafe {
|
for core in crate::Cpu::other() {
|
||||||
crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::ECC, handler.handler());
|
crate::interrupt::disable(core, Interrupt::ECC);
|
||||||
crate::interrupt::enable(crate::peripherals::Interrupt::ECC, handler.priority())
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
unsafe { crate::interrupt::bind_interrupt(Interrupt::ECC, handler.handler()) };
|
||||||
|
unwrap!(crate::interrupt::enable(Interrupt::ECC, handler.priority()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1448
esp-hal/src/i2c.rs
1448
esp-hal/src/i2c.rs
File diff suppressed because it is too large
Load Diff
@ -107,6 +107,8 @@ use crate::{
|
|||||||
interrupt::InterruptHandler,
|
interrupt::InterruptHandler,
|
||||||
peripheral::{Peripheral, PeripheralRef},
|
peripheral::{Peripheral, PeripheralRef},
|
||||||
system::PeripheralClockControl,
|
system::PeripheralClockControl,
|
||||||
|
Async,
|
||||||
|
Blocking,
|
||||||
InterruptConfigurable,
|
InterruptConfigurable,
|
||||||
Mode,
|
Mode,
|
||||||
};
|
};
|
||||||
@ -253,16 +255,16 @@ impl DataFormat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Instance of the I2S peripheral driver
|
/// Instance of the I2S peripheral driver
|
||||||
pub struct I2s<'d, DmaMode, T = AnyI2s>
|
pub struct I2s<'d, M, T = AnyI2s>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
DmaMode: Mode,
|
M: Mode,
|
||||||
{
|
{
|
||||||
/// Handles the reception (RX) side of the I2S peripheral.
|
/// Handles the reception (RX) side of the I2S peripheral.
|
||||||
pub i2s_rx: RxCreator<'d, DmaMode, T>,
|
pub i2s_rx: RxCreator<'d, M, T>,
|
||||||
/// Handles the transmission (TX) side of the I2S peripheral.
|
/// Handles the transmission (TX) side of the I2S peripheral.
|
||||||
pub i2s_tx: TxCreator<'d, DmaMode, T>,
|
pub i2s_tx: TxCreator<'d, M, T>,
|
||||||
phantom: PhantomData<DmaMode>,
|
phantom: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, DmaMode, T> I2s<'d, DmaMode, T>
|
impl<'d, DmaMode, T> I2s<'d, DmaMode, T>
|
||||||
@ -369,24 +371,23 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, DmaMode> I2s<'d, DmaMode>
|
impl<'d> I2s<'d, Blocking> {
|
||||||
where
|
|
||||||
DmaMode: Mode,
|
|
||||||
{
|
|
||||||
/// Construct a new I2S peripheral driver instance for the first I2S
|
/// Construct a new I2S peripheral driver instance for the first I2S
|
||||||
/// peripheral
|
/// peripheral
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new<CH>(
|
pub fn new<CH, DM>(
|
||||||
i2s: impl Peripheral<P = impl RegisterAccess> + 'd,
|
i2s: impl Peripheral<P = impl RegisterAccess> + 'd,
|
||||||
standard: Standard,
|
standard: Standard,
|
||||||
data_format: DataFormat,
|
data_format: DataFormat,
|
||||||
sample_rate: impl Into<fugit::HertzU32>,
|
sample_rate: impl Into<fugit::HertzU32>,
|
||||||
channel: Channel<'d, CH, DmaMode>,
|
channel: Channel<'d, CH, DM>,
|
||||||
rx_descriptors: &'static mut [DmaDescriptor],
|
rx_descriptors: &'static mut [DmaDescriptor],
|
||||||
tx_descriptors: &'static mut [DmaDescriptor],
|
tx_descriptors: &'static mut [DmaDescriptor],
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
CH: DmaChannelConvert<<AnyI2s as DmaEligible>::Dma>,
|
CH: DmaChannelConvert<<AnyI2s as DmaEligible>::Dma>,
|
||||||
|
DM: Mode,
|
||||||
|
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
|
||||||
{
|
{
|
||||||
Self::new_typed(
|
Self::new_typed(
|
||||||
i2s.map_into(),
|
i2s.map_into(),
|
||||||
@ -400,25 +401,26 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, DmaMode, T> I2s<'d, DmaMode, T>
|
impl<'d, T> I2s<'d, Blocking, T>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
DmaMode: Mode,
|
|
||||||
{
|
{
|
||||||
/// Construct a new I2S peripheral driver instance for the first I2S
|
/// Construct a new I2S peripheral driver instance for the first I2S
|
||||||
/// peripheral
|
/// peripheral
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new_typed<CH>(
|
pub fn new_typed<CH, DM>(
|
||||||
i2s: impl Peripheral<P = T> + 'd,
|
i2s: impl Peripheral<P = T> + 'd,
|
||||||
standard: Standard,
|
standard: Standard,
|
||||||
data_format: DataFormat,
|
data_format: DataFormat,
|
||||||
sample_rate: impl Into<fugit::HertzU32>,
|
sample_rate: impl Into<fugit::HertzU32>,
|
||||||
channel: Channel<'d, CH, DmaMode>,
|
channel: Channel<'d, CH, DM>,
|
||||||
rx_descriptors: &'static mut [DmaDescriptor],
|
rx_descriptors: &'static mut [DmaDescriptor],
|
||||||
tx_descriptors: &'static mut [DmaDescriptor],
|
tx_descriptors: &'static mut [DmaDescriptor],
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
CH: DmaChannelConvert<T::Dma>,
|
CH: DmaChannelConvert<T::Dma>,
|
||||||
|
DM: Mode,
|
||||||
|
Channel<'d, CH, Blocking>: From<Channel<'d, CH, DM>>,
|
||||||
{
|
{
|
||||||
crate::into_ref!(i2s);
|
crate::into_ref!(i2s);
|
||||||
Self::new_internal(
|
Self::new_internal(
|
||||||
@ -426,12 +428,43 @@ where
|
|||||||
standard,
|
standard,
|
||||||
data_format,
|
data_format,
|
||||||
sample_rate,
|
sample_rate,
|
||||||
channel,
|
channel.into(),
|
||||||
rx_descriptors,
|
rx_descriptors,
|
||||||
tx_descriptors,
|
tx_descriptors,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts the SPI instance into async mode.
|
||||||
|
pub fn into_async(self) -> I2s<'d, Async, T> {
|
||||||
|
let channel = Channel {
|
||||||
|
rx: self.i2s_rx.rx_channel,
|
||||||
|
tx: self.i2s_tx.tx_channel,
|
||||||
|
phantom: PhantomData::<Blocking>,
|
||||||
|
};
|
||||||
|
let channel = channel.into_async();
|
||||||
|
I2s {
|
||||||
|
i2s_rx: RxCreator {
|
||||||
|
i2s: self.i2s_rx.i2s,
|
||||||
|
rx_channel: channel.rx,
|
||||||
|
descriptors: self.i2s_rx.descriptors,
|
||||||
|
phantom: PhantomData,
|
||||||
|
},
|
||||||
|
i2s_tx: TxCreator {
|
||||||
|
i2s: self.i2s_tx.i2s,
|
||||||
|
tx_channel: channel.tx,
|
||||||
|
descriptors: self.i2s_tx.descriptors,
|
||||||
|
phantom: PhantomData,
|
||||||
|
},
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, M, T> I2s<'d, M, T>
|
||||||
|
where
|
||||||
|
T: RegisterAccess,
|
||||||
|
M: Mode,
|
||||||
|
{
|
||||||
/// Configures the I2S peripheral to use a master clock (MCLK) output pin.
|
/// Configures the I2S peripheral to use a master clock (MCLK) output pin.
|
||||||
pub fn with_mclk<P: PeripheralOutput>(self, pin: impl Peripheral<P = P> + 'd) -> Self {
|
pub fn with_mclk<P: PeripheralOutput>(self, pin: impl Peripheral<P = P> + 'd) -> Self {
|
||||||
crate::into_mapped_ref!(pin);
|
crate::into_mapped_ref!(pin);
|
||||||
@ -757,20 +790,20 @@ mod private {
|
|||||||
},
|
},
|
||||||
interrupt::InterruptHandler,
|
interrupt::InterruptHandler,
|
||||||
peripheral::{Peripheral, PeripheralRef},
|
peripheral::{Peripheral, PeripheralRef},
|
||||||
peripherals::I2S0,
|
peripherals::{Interrupt, I2S0},
|
||||||
private,
|
private,
|
||||||
Mode,
|
Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct TxCreator<'d, DmaMode, T>
|
pub struct TxCreator<'d, M, T>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
DmaMode: Mode,
|
M: Mode,
|
||||||
{
|
{
|
||||||
pub i2s: PeripheralRef<'d, T>,
|
pub i2s: PeripheralRef<'d, T>,
|
||||||
pub tx_channel: ChannelTx<'d, T::Dma>,
|
pub tx_channel: ChannelTx<'d, T::Dma>,
|
||||||
pub descriptors: &'static mut [DmaDescriptor],
|
pub descriptors: &'static mut [DmaDescriptor],
|
||||||
pub(crate) phantom: PhantomData<DmaMode>,
|
pub(crate) phantom: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, DmaMode, T> TxCreator<'d, DmaMode, T>
|
impl<'d, DmaMode, T> TxCreator<'d, DmaMode, T>
|
||||||
@ -821,23 +854,23 @@ mod private {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RxCreator<'d, DmaMode, T>
|
pub struct RxCreator<'d, M, T>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
DmaMode: Mode,
|
M: Mode,
|
||||||
{
|
{
|
||||||
pub i2s: PeripheralRef<'d, T>,
|
pub i2s: PeripheralRef<'d, T>,
|
||||||
pub rx_channel: ChannelRx<'d, T::Dma>,
|
pub rx_channel: ChannelRx<'d, T::Dma>,
|
||||||
pub descriptors: &'static mut [DmaDescriptor],
|
pub descriptors: &'static mut [DmaDescriptor],
|
||||||
pub(crate) phantom: PhantomData<DmaMode>,
|
pub(crate) phantom: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, DmaMode, T> RxCreator<'d, DmaMode, T>
|
impl<'d, M, T> RxCreator<'d, M, T>
|
||||||
where
|
where
|
||||||
T: RegisterAccess,
|
T: RegisterAccess,
|
||||||
DmaMode: Mode,
|
M: Mode,
|
||||||
{
|
{
|
||||||
pub fn build(self) -> I2sRx<'d, DmaMode, T> {
|
pub fn build(self) -> I2sRx<'d, M, T> {
|
||||||
I2sRx {
|
I2sRx {
|
||||||
i2s: self.i2s,
|
i2s: self.i2s,
|
||||||
rx_channel: self.rx_channel,
|
rx_channel: self.rx_channel,
|
||||||
@ -1582,9 +1615,14 @@ mod private {
|
|||||||
|
|
||||||
impl RegisterAccessPrivate for I2S0 {
|
impl RegisterAccessPrivate for I2S0 {
|
||||||
fn set_interrupt_handler(&self, handler: InterruptHandler) {
|
fn set_interrupt_handler(&self, handler: InterruptHandler) {
|
||||||
|
for core in crate::Cpu::other() {
|
||||||
|
crate::interrupt::disable(core, Interrupt::I2S0);
|
||||||
|
}
|
||||||
unsafe { crate::peripherals::I2S0::steal() }.bind_i2s0_interrupt(handler.handler());
|
unsafe { crate::peripherals::I2S0::steal() }.bind_i2s0_interrupt(handler.handler());
|
||||||
crate::interrupt::enable(crate::peripherals::Interrupt::I2S0, handler.priority())
|
unwrap!(crate::interrupt::enable(
|
||||||
.unwrap();
|
Interrupt::I2S0,
|
||||||
|
handler.priority()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1682,9 +1720,14 @@ mod private {
|
|||||||
#[cfg(i2s1)]
|
#[cfg(i2s1)]
|
||||||
impl RegisterAccessPrivate for I2S1 {
|
impl RegisterAccessPrivate for I2S1 {
|
||||||
fn set_interrupt_handler(&self, handler: InterruptHandler) {
|
fn set_interrupt_handler(&self, handler: InterruptHandler) {
|
||||||
|
for core in crate::Cpu::other() {
|
||||||
|
crate::interrupt::disable(core, Interrupt::I2S1);
|
||||||
|
}
|
||||||
unsafe { crate::peripherals::I2S1::steal() }.bind_i2s1_interrupt(handler.handler());
|
unsafe { crate::peripherals::I2S1::steal() }.bind_i2s1_interrupt(handler.handler());
|
||||||
crate::interrupt::enable(crate::peripherals::Interrupt::I2S1, handler.priority())
|
unwrap!(crate::interrupt::enable(
|
||||||
.unwrap();
|
Interrupt::I2S1,
|
||||||
|
handler.priority()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,10 +62,11 @@ impl<const NUM: u8> SoftwareInterrupt<NUM> {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
for core in crate::Cpu::other() {
|
||||||
crate::interrupt::bind_interrupt(interrupt, handler.handler());
|
crate::interrupt::disable(core, interrupt);
|
||||||
crate::interrupt::enable(interrupt, handler.priority()).unwrap();
|
|
||||||
}
|
}
|
||||||
|
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
|
||||||
|
unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trigger this software-interrupt
|
/// Trigger this software-interrupt
|
||||||
|
@ -81,7 +81,7 @@ use crate::{
|
|||||||
OutputSignal,
|
OutputSignal,
|
||||||
Pull,
|
Pull,
|
||||||
},
|
},
|
||||||
lcd_cam::{cam::private::RxPins, private::calculate_clkm, BitOrder, ByteOrder},
|
lcd_cam::{calculate_clkm, BitOrder, ByteOrder},
|
||||||
peripheral::{Peripheral, PeripheralRef},
|
peripheral::{Peripheral, PeripheralRef},
|
||||||
peripherals::LCD_CAM,
|
peripherals::LCD_CAM,
|
||||||
};
|
};
|
||||||
@ -604,8 +604,7 @@ impl RxPins for RxSixteenBits {
|
|||||||
const BUS_WIDTH: usize = 2;
|
const BUS_WIDTH: usize = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod private {
|
#[doc(hidden)]
|
||||||
pub trait RxPins {
|
pub trait RxPins {
|
||||||
const BUS_WIDTH: usize;
|
const BUS_WIDTH: usize;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -75,12 +75,13 @@ use crate::{
|
|||||||
OutputSignal,
|
OutputSignal,
|
||||||
},
|
},
|
||||||
lcd_cam::{
|
lcd_cam::{
|
||||||
asynch::LCD_DONE_WAKER,
|
calculate_clkm,
|
||||||
lcd::{i8080::private::TxPins, ClockMode, DelayMode, Phase, Polarity},
|
lcd::{ClockMode, DelayMode, Phase, Polarity},
|
||||||
private::{calculate_clkm, Instance},
|
|
||||||
BitOrder,
|
BitOrder,
|
||||||
ByteOrder,
|
ByteOrder,
|
||||||
|
Instance,
|
||||||
Lcd,
|
Lcd,
|
||||||
|
LCD_DONE_WAKER,
|
||||||
},
|
},
|
||||||
peripheral::{Peripheral, PeripheralRef},
|
peripheral::{Peripheral, PeripheralRef},
|
||||||
peripherals::LCD_CAM,
|
peripherals::LCD_CAM,
|
||||||
@ -703,8 +704,7 @@ impl<'d> TxPins for TxSixteenBits<'d> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod private {
|
#[doc(hidden)]
|
||||||
pub trait TxPins {
|
pub trait TxPins {
|
||||||
fn configure(&mut self);
|
fn configure(&mut self);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,18 @@ pub mod lcd;
|
|||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
interrupt::InterruptHandler,
|
interrupt::InterruptHandler,
|
||||||
lcd_cam::{cam::Cam, lcd::Lcd},
|
lcd_cam::{cam::Cam, lcd::Lcd},
|
||||||
|
macros::handler,
|
||||||
peripheral::Peripheral,
|
peripheral::Peripheral,
|
||||||
peripherals::LCD_CAM,
|
peripherals::{Interrupt, LCD_CAM},
|
||||||
system::{self, PeripheralClockControl},
|
system::{self, PeripheralClockControl},
|
||||||
|
Async,
|
||||||
|
Blocking,
|
||||||
|
Cpu,
|
||||||
InterruptConfigurable,
|
InterruptConfigurable,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,7 +33,7 @@ pub struct LcdCam<'d, DM: crate::Mode> {
|
|||||||
pub cam: Cam<'d>,
|
pub cam: Cam<'d>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> LcdCam<'d, crate::Blocking> {
|
impl<'d> LcdCam<'d, Blocking> {
|
||||||
/// Creates a new `LcdCam` instance.
|
/// Creates a new `LcdCam` instance.
|
||||||
pub fn new(lcd_cam: impl Peripheral<P = LCD_CAM> + 'd) -> Self {
|
pub fn new(lcd_cam: impl Peripheral<P = LCD_CAM> + 'd) -> Self {
|
||||||
crate::into_ref!(lcd_cam);
|
crate::into_ref!(lcd_cam);
|
||||||
@ -40,56 +46,49 @@ impl<'d> LcdCam<'d, crate::Blocking> {
|
|||||||
lcd_cam: unsafe { lcd_cam.clone_unchecked() },
|
lcd_cam: unsafe { lcd_cam.clone_unchecked() },
|
||||||
_mode: PhantomData,
|
_mode: PhantomData,
|
||||||
},
|
},
|
||||||
cam: Cam {
|
cam: Cam { lcd_cam },
|
||||||
lcd_cam: unsafe { lcd_cam.clone_unchecked() },
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d> crate::private::Sealed for LcdCam<'d, crate::Blocking> {}
|
/// Reconfigures the peripheral for asynchronous operation.
|
||||||
// TODO: This interrupt is shared with the Camera module, we should handle this
|
pub fn into_async(mut self) -> LcdCam<'d, Async> {
|
||||||
// in a similar way to the gpio::IO
|
self.set_interrupt_handler(interrupt_handler);
|
||||||
impl<'d> InterruptConfigurable for LcdCam<'d, crate::Blocking> {
|
LcdCam {
|
||||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
|
||||||
unsafe {
|
|
||||||
crate::interrupt::bind_interrupt(
|
|
||||||
crate::peripherals::Interrupt::LCD_CAM,
|
|
||||||
handler.handler(),
|
|
||||||
);
|
|
||||||
crate::interrupt::enable(crate::peripherals::Interrupt::LCD_CAM, handler.priority())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d> LcdCam<'d, crate::Async> {
|
|
||||||
/// Creates a new `LcdCam` instance for asynchronous operation.
|
|
||||||
pub fn new_async(lcd_cam: impl Peripheral<P = LCD_CAM> + 'd) -> Self {
|
|
||||||
crate::into_ref!(lcd_cam);
|
|
||||||
|
|
||||||
PeripheralClockControl::enable(system::Peripheral::LcdCam);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
crate::interrupt::bind_interrupt(
|
|
||||||
crate::peripherals::Interrupt::LCD_CAM,
|
|
||||||
asynch::interrupt_handler.handler(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
crate::interrupt::enable(
|
|
||||||
crate::peripherals::Interrupt::LCD_CAM,
|
|
||||||
asynch::interrupt_handler.priority(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
lcd: Lcd {
|
lcd: Lcd {
|
||||||
lcd_cam: unsafe { lcd_cam.clone_unchecked() },
|
lcd_cam: self.lcd.lcd_cam,
|
||||||
_mode: PhantomData,
|
_mode: PhantomData,
|
||||||
},
|
},
|
||||||
cam: Cam {
|
cam: self.cam,
|
||||||
lcd_cam: unsafe { lcd_cam.clone_unchecked() },
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::private::Sealed for LcdCam<'_, Blocking> {}
|
||||||
|
// TODO: This interrupt is shared with the Camera module, we should handle this
|
||||||
|
// in a similar way to the gpio::IO
|
||||||
|
impl InterruptConfigurable for LcdCam<'_, Blocking> {
|
||||||
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
for core in crate::Cpu::other() {
|
||||||
|
crate::interrupt::disable(core, Interrupt::LCD_CAM);
|
||||||
|
}
|
||||||
|
unsafe { crate::interrupt::bind_interrupt(Interrupt::LCD_CAM, handler.handler()) };
|
||||||
|
unwrap!(crate::interrupt::enable(
|
||||||
|
Interrupt::LCD_CAM,
|
||||||
|
handler.priority()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> LcdCam<'d, Async> {
|
||||||
|
/// Reconfigures the peripheral for blocking operation.
|
||||||
|
pub fn into_blocking(self) -> LcdCam<'d, Blocking> {
|
||||||
|
crate::interrupt::disable(Cpu::current(), Interrupt::LCD_CAM);
|
||||||
|
LcdCam {
|
||||||
|
lcd: Lcd {
|
||||||
|
lcd_cam: self.lcd.lcd_cam,
|
||||||
|
_mode: PhantomData,
|
||||||
},
|
},
|
||||||
|
cam: self.cam,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,205 +115,193 @@ pub enum ByteOrder {
|
|||||||
Inverted = 1,
|
Inverted = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
pub(crate) static LCD_DONE_WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
pub mod asynch {
|
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
|
||||||
use procmacros::handler;
|
|
||||||
|
|
||||||
use super::private::Instance;
|
#[handler]
|
||||||
|
fn interrupt_handler() {
|
||||||
pub(crate) static LCD_DONE_WAKER: AtomicWaker = AtomicWaker::new();
|
// TODO: this is a shared interrupt with Camera and here we ignore that!
|
||||||
|
if Instance::is_lcd_done_set() {
|
||||||
#[handler]
|
Instance::unlisten_lcd_done();
|
||||||
pub(crate) fn interrupt_handler() {
|
LCD_DONE_WAKER.wake()
|
||||||
// TODO: this is a shared interrupt with Camera and here we ignore that!
|
|
||||||
if Instance::is_lcd_done_set() {
|
|
||||||
Instance::unlisten_lcd_done();
|
|
||||||
LCD_DONE_WAKER.wake()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod private {
|
pub(crate) struct Instance;
|
||||||
use crate::peripherals::LCD_CAM;
|
|
||||||
|
|
||||||
pub(crate) struct Instance;
|
// NOTE: the LCD_CAM interrupt registers are shared between LCD and Camera and
|
||||||
|
// this is only implemented for the LCD side, when the Camera is implemented a
|
||||||
// NOTE: the LCD_CAM interrupt registers are shared between LCD and Camera and
|
// CriticalSection will be needed to protect these shared registers.
|
||||||
// this is only implemented for the LCD side, when the Camera is implemented a
|
impl Instance {
|
||||||
// CriticalSection will be needed to protect these shared registers.
|
pub(crate) fn listen_lcd_done() {
|
||||||
impl Instance {
|
let lcd_cam = unsafe { LCD_CAM::steal() };
|
||||||
pub(crate) fn listen_lcd_done() {
|
lcd_cam
|
||||||
let lcd_cam = unsafe { LCD_CAM::steal() };
|
.lc_dma_int_ena()
|
||||||
lcd_cam
|
.modify(|_, w| w.lcd_trans_done_int_ena().set_bit());
|
||||||
.lc_dma_int_ena()
|
|
||||||
.modify(|_, w| w.lcd_trans_done_int_ena().set_bit());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn unlisten_lcd_done() {
|
|
||||||
let lcd_cam = unsafe { LCD_CAM::steal() };
|
|
||||||
lcd_cam
|
|
||||||
.lc_dma_int_ena()
|
|
||||||
.modify(|_, w| w.lcd_trans_done_int_ena().clear_bit());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn is_lcd_done_set() -> bool {
|
|
||||||
let lcd_cam = unsafe { LCD_CAM::steal() };
|
|
||||||
lcd_cam
|
|
||||||
.lc_dma_int_raw()
|
|
||||||
.read()
|
|
||||||
.lcd_trans_done_int_raw()
|
|
||||||
.bit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct ClockDivider {
|
|
||||||
// Integral LCD clock divider value. (8 bits)
|
|
||||||
// Value 0 is treated as 256
|
|
||||||
// Value 1 is treated as 2
|
|
||||||
// Value N is treated as N
|
|
||||||
pub div_num: usize,
|
|
||||||
|
|
||||||
// Fractional clock divider numerator value. (6 bits)
|
|
||||||
pub div_b: usize,
|
|
||||||
|
|
||||||
// Fractional clock divider denominator value. (6 bits)
|
|
||||||
pub div_a: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_clkm(
|
pub(crate) fn unlisten_lcd_done() {
|
||||||
desired_frequency: usize,
|
let lcd_cam = unsafe { LCD_CAM::steal() };
|
||||||
source_frequencies: &[usize],
|
lcd_cam
|
||||||
) -> (usize, ClockDivider) {
|
.lc_dma_int_ena()
|
||||||
let mut result_freq = 0;
|
.modify(|_, w| w.lcd_trans_done_int_ena().clear_bit());
|
||||||
let mut result = None;
|
}
|
||||||
|
|
||||||
for (i, &source_frequency) in source_frequencies.iter().enumerate() {
|
pub(crate) fn is_lcd_done_set() -> bool {
|
||||||
let div = calculate_closest_divider(source_frequency, desired_frequency);
|
let lcd_cam = unsafe { LCD_CAM::steal() };
|
||||||
if let Some(div) = div {
|
lcd_cam
|
||||||
let freq = calculate_output_frequency(source_frequency, &div);
|
.lc_dma_int_raw()
|
||||||
if result.is_none() || freq > result_freq {
|
.read()
|
||||||
result = Some((i, div));
|
.lcd_trans_done_int_raw()
|
||||||
result_freq = freq;
|
.bit()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
pub(crate) struct ClockDivider {
|
||||||
|
// Integral LCD clock divider value. (8 bits)
|
||||||
|
// Value 0 is treated as 256
|
||||||
|
// Value 1 is treated as 2
|
||||||
|
// Value N is treated as N
|
||||||
|
pub div_num: usize,
|
||||||
|
|
||||||
|
// Fractional clock divider numerator value. (6 bits)
|
||||||
|
pub div_b: usize,
|
||||||
|
|
||||||
|
// Fractional clock divider denominator value. (6 bits)
|
||||||
|
pub div_a: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn calculate_clkm(
|
||||||
|
desired_frequency: usize,
|
||||||
|
source_frequencies: &[usize],
|
||||||
|
) -> (usize, ClockDivider) {
|
||||||
|
let mut result_freq = 0;
|
||||||
|
let mut result = None;
|
||||||
|
|
||||||
|
for (i, &source_frequency) in source_frequencies.iter().enumerate() {
|
||||||
|
let div = calculate_closest_divider(source_frequency, desired_frequency);
|
||||||
|
if let Some(div) = div {
|
||||||
|
let freq = calculate_output_frequency(source_frequency, &div);
|
||||||
|
if result.is_none() || freq > result_freq {
|
||||||
|
result = Some((i, div));
|
||||||
|
result_freq = freq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.expect("Desired frequency was too low for the dividers to divide to")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize {
|
result.expect("Desired frequency was too low for the dividers to divide to")
|
||||||
let n = match divider.div_num {
|
}
|
||||||
0 => 256,
|
|
||||||
1 => 2,
|
|
||||||
_ => divider.div_num.min(256),
|
|
||||||
};
|
|
||||||
|
|
||||||
if divider.div_b != 0 && divider.div_a != 0 {
|
fn calculate_output_frequency(source_frequency: usize, divider: &ClockDivider) -> usize {
|
||||||
// OUTPUT = SOURCE / (N + B/A)
|
let n = match divider.div_num {
|
||||||
// OUTPUT = SOURCE / ((NA + B)/A)
|
0 => 256,
|
||||||
// OUTPUT = (SOURCE * A) / (NA + B)
|
1 => 2,
|
||||||
|
_ => divider.div_num.min(256),
|
||||||
|
};
|
||||||
|
|
||||||
// u64 is required to fit the numbers from this arithmetic.
|
if divider.div_b != 0 && divider.div_a != 0 {
|
||||||
|
// OUTPUT = SOURCE / (N + B/A)
|
||||||
|
// OUTPUT = SOURCE / ((NA + B)/A)
|
||||||
|
// OUTPUT = (SOURCE * A) / (NA + B)
|
||||||
|
|
||||||
let source = source_frequency as u64;
|
// u64 is required to fit the numbers from this arithmetic.
|
||||||
let n = n as u64;
|
|
||||||
let a = divider.div_b as u64;
|
|
||||||
let b = divider.div_a as u64;
|
|
||||||
|
|
||||||
((source * a) / (n * a + b)) as _
|
let source = source_frequency as u64;
|
||||||
} else {
|
let n = n as u64;
|
||||||
source_frequency / n
|
let a = divider.div_b as u64;
|
||||||
}
|
let b = divider.div_a as u64;
|
||||||
|
|
||||||
|
((source * a) / (n * a + b)) as _
|
||||||
|
} else {
|
||||||
|
source_frequency / n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_closest_divider(
|
||||||
|
source_frequency: usize,
|
||||||
|
desired_frequency: usize,
|
||||||
|
) -> Option<ClockDivider> {
|
||||||
|
let div_num = source_frequency / desired_frequency;
|
||||||
|
if div_num < 2 {
|
||||||
|
// Source clock isn't fast enough to reach the desired frequency.
|
||||||
|
// Return max output.
|
||||||
|
return Some(ClockDivider {
|
||||||
|
div_num: 1,
|
||||||
|
div_b: 0,
|
||||||
|
div_a: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if div_num > 256 {
|
||||||
|
// Source is too fast to divide to the desired frequency. Return None.
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_closest_divider(
|
let div_num = if div_num == 256 { 0 } else { div_num };
|
||||||
source_frequency: usize,
|
|
||||||
desired_frequency: usize,
|
let div_fraction = {
|
||||||
) -> Option<ClockDivider> {
|
let div_remainder = source_frequency % desired_frequency;
|
||||||
let div_num = source_frequency / desired_frequency;
|
let gcd = hcf(div_remainder, desired_frequency);
|
||||||
if div_num < 2 {
|
Fraction {
|
||||||
// Source clock isn't fast enough to reach the desired frequency.
|
numerator: div_remainder / gcd,
|
||||||
// Return max output.
|
denominator: desired_frequency / gcd,
|
||||||
return Some(ClockDivider {
|
|
||||||
div_num: 1,
|
|
||||||
div_b: 0,
|
|
||||||
div_a: 0,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if div_num > 256 {
|
};
|
||||||
// Source is too fast to divide to the desired frequency. Return None.
|
|
||||||
|
let divider = if div_fraction.numerator == 0 {
|
||||||
|
ClockDivider {
|
||||||
|
div_num,
|
||||||
|
div_b: 0,
|
||||||
|
div_a: 0,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let target = div_fraction;
|
||||||
|
let closest = farey_sequence(63)
|
||||||
|
.find(|curr| {
|
||||||
|
// https://en.wikipedia.org/wiki/Fraction#Adding_unlike_quantities
|
||||||
|
|
||||||
|
let new_curr_num = curr.numerator * target.denominator;
|
||||||
|
let new_target_num = target.numerator * curr.denominator;
|
||||||
|
new_curr_num >= new_target_num
|
||||||
|
})
|
||||||
|
.expect("The fraction must be between 0 and 1");
|
||||||
|
|
||||||
|
ClockDivider {
|
||||||
|
div_num,
|
||||||
|
div_b: closest.numerator,
|
||||||
|
div_a: closest.denominator,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(divider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Euclidean_algorithm
|
||||||
|
const fn hcf(a: usize, b: usize) -> usize {
|
||||||
|
if b != 0 {
|
||||||
|
hcf(b, a % b)
|
||||||
|
} else {
|
||||||
|
a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Fraction {
|
||||||
|
pub numerator: usize,
|
||||||
|
pub denominator: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Farey_sequence#Next_term
|
||||||
|
fn farey_sequence(denominator: usize) -> impl Iterator<Item = Fraction> {
|
||||||
|
let mut a = 0;
|
||||||
|
let mut b = 1;
|
||||||
|
let mut c = 1;
|
||||||
|
let mut d = denominator;
|
||||||
|
core::iter::from_fn(move || {
|
||||||
|
if a > denominator {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
let next = Fraction {
|
||||||
let div_num = if div_num == 256 { 0 } else { div_num };
|
numerator: a,
|
||||||
|
denominator: b,
|
||||||
let div_fraction = {
|
|
||||||
let div_remainder = source_frequency % desired_frequency;
|
|
||||||
let gcd = hcf(div_remainder, desired_frequency);
|
|
||||||
Fraction {
|
|
||||||
numerator: div_remainder / gcd,
|
|
||||||
denominator: desired_frequency / gcd,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
let k = (denominator + b) / d;
|
||||||
let divider = if div_fraction.numerator == 0 {
|
(a, b, c, d) = (c, d, k * c - a, k * d - b);
|
||||||
ClockDivider {
|
Some(next)
|
||||||
div_num,
|
})
|
||||||
div_b: 0,
|
|
||||||
div_a: 0,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let target = div_fraction;
|
|
||||||
let closest = farey_sequence(63)
|
|
||||||
.find(|curr| {
|
|
||||||
// https://en.wikipedia.org/wiki/Fraction#Adding_unlike_quantities
|
|
||||||
|
|
||||||
let new_curr_num = curr.numerator * target.denominator;
|
|
||||||
let new_target_num = target.numerator * curr.denominator;
|
|
||||||
new_curr_num >= new_target_num
|
|
||||||
})
|
|
||||||
.expect("The fraction must be between 0 and 1");
|
|
||||||
|
|
||||||
ClockDivider {
|
|
||||||
div_num,
|
|
||||||
div_b: closest.numerator,
|
|
||||||
div_a: closest.denominator,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Some(divider)
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Euclidean_algorithm
|
|
||||||
const fn hcf(a: usize, b: usize) -> usize {
|
|
||||||
if b != 0 {
|
|
||||||
hcf(b, a % b)
|
|
||||||
} else {
|
|
||||||
a
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Fraction {
|
|
||||||
pub numerator: usize,
|
|
||||||
pub denominator: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Farey_sequence#Next_term
|
|
||||||
fn farey_sequence(denominator: usize) -> impl Iterator<Item = Fraction> {
|
|
||||||
let mut a = 0;
|
|
||||||
let mut b = 1;
|
|
||||||
let mut c = 1;
|
|
||||||
let mut d = denominator;
|
|
||||||
core::iter::from_fn(move || {
|
|
||||||
if a > denominator {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let next = Fraction {
|
|
||||||
numerator: a,
|
|
||||||
denominator: b,
|
|
||||||
};
|
|
||||||
let k = (denominator + b) / d;
|
|
||||||
(a, b, c, d) = (c, d, k * c - a, k * d - b);
|
|
||||||
Some(next)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -374,6 +374,21 @@ impl Cpu {
|
|||||||
pub fn current() -> Self {
|
pub fn current() -> Self {
|
||||||
get_core()
|
get_core()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the "other" cores.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn other() -> impl Iterator<Item = Self> {
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(multi_core)] {
|
||||||
|
match get_core() {
|
||||||
|
Cpu::ProCpu => [Cpu::AppCpu].into_iter(),
|
||||||
|
Cpu::AppCpu => [Cpu::ProCpu].into_iter(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
[].into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Which core the application is currently executing on
|
/// Which core the application is currently executing on
|
||||||
|
@ -52,7 +52,7 @@ use crate::{
|
|||||||
gpio::interconnect::{InputConnection, OutputConnection, PeripheralInput, PeripheralOutput},
|
gpio::interconnect::{InputConnection, OutputConnection, PeripheralInput, PeripheralOutput},
|
||||||
interrupt::InterruptHandler,
|
interrupt::InterruptHandler,
|
||||||
peripheral::{self, Peripheral},
|
peripheral::{self, Peripheral},
|
||||||
peripherals::{self, PARL_IO},
|
peripherals::{self, Interrupt, PARL_IO},
|
||||||
system::PeripheralClockControl,
|
system::PeripheralClockControl,
|
||||||
Blocking,
|
Blocking,
|
||||||
InterruptConfigurable,
|
InterruptConfigurable,
|
||||||
@ -923,42 +923,52 @@ where
|
|||||||
fn internal_set_interrupt_handler(handler: InterruptHandler) {
|
fn internal_set_interrupt_handler(handler: InterruptHandler) {
|
||||||
#[cfg(esp32c6)]
|
#[cfg(esp32c6)]
|
||||||
{
|
{
|
||||||
|
for core in crate::Cpu::other() {
|
||||||
|
crate::interrupt::disable(core, Interrupt::PARL_IO);
|
||||||
|
}
|
||||||
|
internal_listen(EnumSet::all(), false);
|
||||||
|
internal_clear_interrupts(EnumSet::all());
|
||||||
unsafe { PARL_IO::steal() }.bind_parl_io_interrupt(handler.handler());
|
unsafe { PARL_IO::steal() }.bind_parl_io_interrupt(handler.handler());
|
||||||
|
|
||||||
crate::interrupt::enable(crate::peripherals::Interrupt::PARL_IO, handler.priority())
|
unwrap!(crate::interrupt::enable(
|
||||||
.unwrap();
|
Interrupt::PARL_IO,
|
||||||
|
handler.priority()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
#[cfg(esp32h2)]
|
#[cfg(esp32h2)]
|
||||||
{
|
{
|
||||||
|
for core in crate::Cpu::other() {
|
||||||
|
crate::interrupt::disable(core, Interrupt::PARL_IO_RX);
|
||||||
|
crate::interrupt::disable(core, Interrupt::PARL_IO_TX);
|
||||||
|
}
|
||||||
|
internal_listen(EnumSet::all(), false);
|
||||||
|
internal_clear_interrupts(EnumSet::all());
|
||||||
unsafe { PARL_IO::steal() }.bind_parl_io_tx_interrupt(handler.handler());
|
unsafe { PARL_IO::steal() }.bind_parl_io_tx_interrupt(handler.handler());
|
||||||
unsafe { PARL_IO::steal() }.bind_parl_io_rx_interrupt(handler.handler());
|
unsafe { PARL_IO::steal() }.bind_parl_io_rx_interrupt(handler.handler());
|
||||||
|
|
||||||
crate::interrupt::enable(
|
unwrap!(crate::interrupt::enable(
|
||||||
crate::peripherals::Interrupt::PARL_IO_TX,
|
Interrupt::PARL_IO_TX,
|
||||||
handler.priority(),
|
handler.priority(),
|
||||||
)
|
));
|
||||||
.unwrap();
|
unwrap!(crate::interrupt::enable(
|
||||||
crate::interrupt::enable(
|
Interrupt::PARL_IO_RX,
|
||||||
crate::peripherals::Interrupt::PARL_IO_RX,
|
|
||||||
handler.priority(),
|
handler.priority(),
|
||||||
)
|
));
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_listen(interrupts: EnumSet<ParlIoInterrupt>, enable: bool) {
|
fn internal_listen(interrupts: EnumSet<ParlIoInterrupt>, enable: bool) {
|
||||||
let parl_io = unsafe { PARL_IO::steal() };
|
let parl_io = unsafe { PARL_IO::steal() };
|
||||||
for interrupt in interrupts {
|
parl_io.int_ena().write(|w| {
|
||||||
match interrupt {
|
for interrupt in interrupts {
|
||||||
ParlIoInterrupt::TxFifoReEmpty => parl_io
|
match interrupt {
|
||||||
.int_ena()
|
ParlIoInterrupt::TxFifoReEmpty => w.tx_fifo_rempty().bit(enable),
|
||||||
.modify(|_, w| w.tx_fifo_rempty().bit(enable)),
|
ParlIoInterrupt::RxFifoWOvf => w.rx_fifo_wovf().bit(enable),
|
||||||
ParlIoInterrupt::RxFifoWOvf => parl_io
|
ParlIoInterrupt::TxEof => w.tx_eof().bit(enable),
|
||||||
.int_ena()
|
};
|
||||||
.modify(|_, w| w.rx_fifo_wovf().bit(enable)),
|
|
||||||
ParlIoInterrupt::TxEof => parl_io.int_ena().write(|w| w.tx_eof().bit(enable)),
|
|
||||||
}
|
}
|
||||||
}
|
w
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_interrupts() -> EnumSet<ParlIoInterrupt> {
|
fn internal_interrupts() -> EnumSet<ParlIoInterrupt> {
|
||||||
@ -980,17 +990,16 @@ fn internal_interrupts() -> EnumSet<ParlIoInterrupt> {
|
|||||||
|
|
||||||
fn internal_clear_interrupts(interrupts: EnumSet<ParlIoInterrupt>) {
|
fn internal_clear_interrupts(interrupts: EnumSet<ParlIoInterrupt>) {
|
||||||
let parl_io = unsafe { PARL_IO::steal() };
|
let parl_io = unsafe { PARL_IO::steal() };
|
||||||
for interrupt in interrupts {
|
parl_io.int_clr().write(|w| {
|
||||||
match interrupt {
|
for interrupt in interrupts {
|
||||||
ParlIoInterrupt::TxFifoReEmpty => parl_io
|
match interrupt {
|
||||||
.int_clr()
|
ParlIoInterrupt::TxFifoReEmpty => w.tx_fifo_rempty().clear_bit_by_one(),
|
||||||
.write(|w| w.tx_fifo_rempty().clear_bit_by_one()),
|
ParlIoInterrupt::RxFifoWOvf => w.rx_fifo_wovf().clear_bit_by_one(),
|
||||||
ParlIoInterrupt::RxFifoWOvf => parl_io
|
ParlIoInterrupt::TxEof => w.tx_eof().clear_bit_by_one(),
|
||||||
.int_clr()
|
};
|
||||||
.write(|w| w.rx_fifo_wovf().clear_bit_by_one()),
|
|
||||||
ParlIoInterrupt::TxEof => parl_io.int_clr().write(|w| w.tx_eof().clear_bit_by_one()),
|
|
||||||
}
|
}
|
||||||
}
|
w
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parallel IO in full duplex mode
|
/// Parallel IO in full duplex mode
|
||||||
|
@ -113,9 +113,10 @@ impl crate::private::Sealed for Pcnt<'_> {}
|
|||||||
|
|
||||||
impl InterruptConfigurable for Pcnt<'_> {
|
impl InterruptConfigurable for Pcnt<'_> {
|
||||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
unsafe {
|
for core in crate::Cpu::other() {
|
||||||
interrupt::bind_interrupt(Interrupt::PCNT, handler.handler());
|
crate::interrupt::disable(core, Interrupt::PCNT);
|
||||||
interrupt::enable(Interrupt::PCNT, handler.priority()).unwrap();
|
|
||||||
}
|
}
|
||||||
|
unsafe { interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()) };
|
||||||
|
unwrap!(interrupt::enable(Interrupt::PCNT, handler.priority()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1142
esp-hal/src/rmt.rs
1142
esp-hal/src/rmt.rs
File diff suppressed because it is too large
Load Diff
@ -26,8 +26,11 @@ use core::{marker::PhantomData, ptr::copy_nonoverlapping};
|
|||||||
use crate::{
|
use crate::{
|
||||||
interrupt::InterruptHandler,
|
interrupt::InterruptHandler,
|
||||||
peripheral::{Peripheral, PeripheralRef},
|
peripheral::{Peripheral, PeripheralRef},
|
||||||
peripherals::RSA,
|
peripherals::{Interrupt, RSA},
|
||||||
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
|
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
|
||||||
|
Async,
|
||||||
|
Blocking,
|
||||||
|
Cpu,
|
||||||
InterruptConfigurable,
|
InterruptConfigurable,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -47,29 +50,44 @@ pub struct Rsa<'d, DM: crate::Mode> {
|
|||||||
phantom: PhantomData<DM>,
|
phantom: PhantomData<DM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> Rsa<'d, crate::Blocking> {
|
impl<'d> Rsa<'d, Blocking> {
|
||||||
/// Create a new instance in [crate::Blocking] mode.
|
/// Create a new instance in [crate::Blocking] mode.
|
||||||
///
|
///
|
||||||
/// Optionally an interrupt handler can be bound.
|
/// Optionally an interrupt handler can be bound.
|
||||||
pub fn new(rsa: impl Peripheral<P = RSA> + 'd) -> Self {
|
pub fn new(rsa: impl Peripheral<P = RSA> + 'd) -> Self {
|
||||||
Self::new_internal(rsa)
|
Self::new_internal(rsa)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::private::Sealed for Rsa<'_, crate::Blocking> {}
|
/// Reconfigures the RSA driver to operate in asynchronous mode.
|
||||||
|
pub fn into_async(mut self) -> Rsa<'d, Async> {
|
||||||
impl InterruptConfigurable for Rsa<'_, crate::Blocking> {
|
self.set_interrupt_handler(asynch::rsa_interrupt_handler);
|
||||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
Rsa {
|
||||||
self.internal_set_interrupt_handler(handler);
|
rsa: self.rsa,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> Rsa<'d, crate::Async> {
|
impl crate::private::Sealed for Rsa<'_, Blocking> {}
|
||||||
|
|
||||||
|
impl InterruptConfigurable for Rsa<'_, Blocking> {
|
||||||
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
|
for core in crate::Cpu::other() {
|
||||||
|
crate::interrupt::disable(core, Interrupt::RSA);
|
||||||
|
}
|
||||||
|
unsafe { crate::interrupt::bind_interrupt(Interrupt::RSA, handler.handler()) };
|
||||||
|
unwrap!(crate::interrupt::enable(Interrupt::RSA, handler.priority()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> Rsa<'d, Async> {
|
||||||
/// Create a new instance in [crate::Blocking] mode.
|
/// Create a new instance in [crate::Blocking] mode.
|
||||||
pub fn new_async(rsa: impl Peripheral<P = RSA> + 'd) -> Self {
|
pub fn into_blocking(self) -> Rsa<'d, Blocking> {
|
||||||
let mut this = Self::new_internal(rsa);
|
crate::interrupt::disable(Cpu::current(), Interrupt::RSA);
|
||||||
this.internal_set_interrupt_handler(asynch::rsa_interrupt_handler);
|
Rsa {
|
||||||
this
|
rsa: self.rsa,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,15 +147,6 @@ impl<'d, DM: crate::Mode> Rsa<'d, DM> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
|
||||||
unsafe {
|
|
||||||
crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::RSA, handler.handler());
|
|
||||||
crate::interrupt::enable(crate::peripherals::Interrupt::RSA, handler.priority())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wait_for_idle(&mut self) {
|
fn wait_for_idle(&mut self) {
|
||||||
while !self.is_idle() {}
|
while !self.is_idle() {}
|
||||||
self.clear_interrupt();
|
self.clear_interrupt();
|
||||||
|
@ -434,23 +434,18 @@ impl crate::private::Sealed for Rtc<'_> {}
|
|||||||
|
|
||||||
impl InterruptConfigurable for Rtc<'_> {
|
impl InterruptConfigurable for Rtc<'_> {
|
||||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
unsafe {
|
cfg_if::cfg_if! {
|
||||||
interrupt::bind_interrupt(
|
if #[cfg(any(esp32c6, esp32h2))] {
|
||||||
#[cfg(any(esp32c6, esp32h2))]
|
let interrupt = Interrupt::LP_WDT;
|
||||||
Interrupt::LP_WDT,
|
} else {
|
||||||
#[cfg(not(any(esp32c6, esp32h2)))]
|
let interrupt = Interrupt::RTC_CORE;
|
||||||
Interrupt::RTC_CORE,
|
}
|
||||||
handler.handler(),
|
|
||||||
);
|
|
||||||
interrupt::enable(
|
|
||||||
#[cfg(any(esp32c6, esp32h2))]
|
|
||||||
Interrupt::LP_WDT,
|
|
||||||
#[cfg(not(any(esp32c6, esp32h2)))]
|
|
||||||
Interrupt::RTC_CORE,
|
|
||||||
handler.priority(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
for core in crate::Cpu::other() {
|
||||||
|
crate::interrupt::disable(core, interrupt);
|
||||||
|
}
|
||||||
|
unsafe { interrupt::bind_interrupt(interrupt, handler.handler()) };
|
||||||
|
unwrap!(interrupt::enable(interrupt, handler.priority()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,8 @@ use core::{borrow::BorrowMut, convert::Infallible, marker::PhantomData, mem::siz
|
|||||||
#[cfg(feature = "digest")]
|
#[cfg(feature = "digest")]
|
||||||
pub use digest::Digest;
|
pub use digest::Digest;
|
||||||
|
|
||||||
|
#[cfg(not(esp32))]
|
||||||
|
use crate::peripherals::Interrupt;
|
||||||
use crate::{
|
use crate::{
|
||||||
peripheral::{Peripheral, PeripheralRef},
|
peripheral::{Peripheral, PeripheralRef},
|
||||||
peripherals::SHA,
|
peripherals::SHA,
|
||||||
@ -103,11 +105,11 @@ impl crate::private::Sealed for Sha<'_> {}
|
|||||||
#[cfg(not(esp32))]
|
#[cfg(not(esp32))]
|
||||||
impl crate::InterruptConfigurable for Sha<'_> {
|
impl crate::InterruptConfigurable for Sha<'_> {
|
||||||
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
|
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
|
||||||
unsafe {
|
for core in crate::Cpu::other() {
|
||||||
crate::interrupt::bind_interrupt(crate::peripherals::Interrupt::SHA, handler.handler());
|
crate::interrupt::disable(core, Interrupt::SHA);
|
||||||
crate::interrupt::enable(crate::peripherals::Interrupt::SHA, handler.priority())
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
unsafe { crate::interrupt::bind_interrupt(Interrupt::SHA, handler.handler()) };
|
||||||
|
unwrap!(crate::interrupt::enable(Interrupt::SHA, handler.priority()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,8 @@
|
|||||||
//! [`embedded-hal-bus`]: https://docs.rs/embedded-hal-bus/latest/embedded_hal_bus/spi/index.html
|
//! [`embedded-hal-bus`]: https://docs.rs/embedded-hal-bus/latest/embedded_hal_bus/spi/index.html
|
||||||
//! [`embassy-embedded-hal`]: https://docs.embassy.dev/embassy-embedded-hal/git/default/shared_bus/index.html
|
//! [`embassy-embedded-hal`]: https://docs.embassy.dev/embassy-embedded-hal/git/default/shared_bus/index.html
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
pub use dma::*;
|
pub use dma::*;
|
||||||
#[cfg(gdma)]
|
#[cfg(gdma)]
|
||||||
use enumset::EnumSet;
|
use enumset::EnumSet;
|
||||||
@ -73,7 +75,16 @@ use procmacros::ram;
|
|||||||
use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode};
|
use super::{DmaError, Error, SpiBitOrder, SpiDataMode, SpiMode};
|
||||||
use crate::{
|
use crate::{
|
||||||
clock::Clocks,
|
clock::Clocks,
|
||||||
dma::{DmaChannelConvert, DmaEligible, DmaRxBuffer, DmaTxBuffer, PeripheralMarker, Rx, Tx},
|
dma::{
|
||||||
|
Channel,
|
||||||
|
DmaChannelConvert,
|
||||||
|
DmaEligible,
|
||||||
|
DmaRxBuffer,
|
||||||
|
DmaTxBuffer,
|
||||||
|
PeripheralMarker,
|
||||||
|
Rx,
|
||||||
|
Tx,
|
||||||
|
},
|
||||||
gpio::{
|
gpio::{
|
||||||
interconnect::{OutputConnection, PeripheralOutput},
|
interconnect::{OutputConnection, PeripheralOutput},
|
||||||
InputSignal,
|
InputSignal,
|
||||||
@ -86,6 +97,8 @@ use crate::{
|
|||||||
private,
|
private,
|
||||||
spi::AnySpi,
|
spi::AnySpi,
|
||||||
system::PeripheralClockControl,
|
system::PeripheralClockControl,
|
||||||
|
Async,
|
||||||
|
Blocking,
|
||||||
Mode,
|
Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -423,12 +436,14 @@ impl Address {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// SPI peripheral driver
|
/// SPI peripheral driver
|
||||||
pub struct Spi<'d, T = AnySpi> {
|
pub struct Spi<'d, M, T = AnySpi> {
|
||||||
spi: PeripheralRef<'d, T>,
|
spi: PeripheralRef<'d, T>,
|
||||||
|
_mode: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T> Spi<'d, T>
|
impl<'d, M, T> Spi<'d, M, T>
|
||||||
where
|
where
|
||||||
|
M: Mode,
|
||||||
T: InstanceDma,
|
T: InstanceDma,
|
||||||
{
|
{
|
||||||
/// Configures the SPI instance to use DMA with the specified channel.
|
/// Configures the SPI instance to use DMA with the specified channel.
|
||||||
@ -436,19 +451,17 @@ where
|
|||||||
/// This method prepares the SPI instance for DMA transfers using SPI
|
/// This method prepares the SPI instance for DMA transfers using SPI
|
||||||
/// and returns an instance of `SpiDma` that supports DMA
|
/// and returns an instance of `SpiDma` that supports DMA
|
||||||
/// operations.
|
/// operations.
|
||||||
pub fn with_dma<CH, DmaMode>(
|
pub fn with_dma<CH, DM>(self, channel: Channel<'d, CH, DM>) -> SpiDma<'d, M, T>
|
||||||
self,
|
|
||||||
channel: crate::dma::Channel<'d, CH, DmaMode>,
|
|
||||||
) -> SpiDma<'d, DmaMode, T>
|
|
||||||
where
|
where
|
||||||
CH: DmaChannelConvert<T::Dma>,
|
CH: DmaChannelConvert<T::Dma>,
|
||||||
DmaMode: Mode,
|
DM: Mode,
|
||||||
|
Channel<'d, CH, M>: From<Channel<'d, CH, DM>>,
|
||||||
{
|
{
|
||||||
SpiDma::new(self.spi, channel)
|
SpiDma::new(self.spi, channel.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Spi<'_, T>
|
impl<M, T> Spi<'_, M, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -484,18 +497,36 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> Spi<'d> {
|
impl<'d> Spi<'d, Blocking> {
|
||||||
/// Constructs an SPI instance in 8bit dataframe mode.
|
/// Constructs an SPI instance in 8bit dataframe mode.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
spi: impl Peripheral<P = impl Instance> + 'd,
|
spi: impl Peripheral<P = impl Instance> + 'd,
|
||||||
frequency: HertzU32,
|
frequency: HertzU32,
|
||||||
mode: SpiMode,
|
mode: SpiMode,
|
||||||
) -> Spi<'d> {
|
) -> Spi<'d, Blocking> {
|
||||||
Self::new_typed(spi.map_into(), frequency, mode)
|
Self::new_typed(spi.map_into(), frequency, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Converts the SPI instance into async mode.
|
||||||
|
pub fn into_async(self) -> Spi<'d, Async> {
|
||||||
|
Spi {
|
||||||
|
spi: self.spi,
|
||||||
|
_mode: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T> Spi<'d, T>
|
impl<'d> Spi<'d, Async> {
|
||||||
|
/// Converts the SPI instance into blocking mode.
|
||||||
|
pub fn into_blocking(self) -> Spi<'d, Blocking> {
|
||||||
|
Spi {
|
||||||
|
spi: self.spi,
|
||||||
|
_mode: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, M, T> Spi<'d, M, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -504,10 +535,13 @@ where
|
|||||||
spi: impl Peripheral<P = T> + 'd,
|
spi: impl Peripheral<P = T> + 'd,
|
||||||
frequency: HertzU32,
|
frequency: HertzU32,
|
||||||
mode: SpiMode,
|
mode: SpiMode,
|
||||||
) -> Spi<'d, T> {
|
) -> Spi<'d, M, T> {
|
||||||
crate::into_ref!(spi);
|
crate::into_ref!(spi);
|
||||||
|
|
||||||
let mut spi = Spi { spi };
|
let mut spi = Spi {
|
||||||
|
spi,
|
||||||
|
_mode: PhantomData,
|
||||||
|
};
|
||||||
spi.spi.reset_peripheral();
|
spi.spi.reset_peripheral();
|
||||||
spi.spi.enable_peripheral();
|
spi.spi.enable_peripheral();
|
||||||
spi.spi.setup(frequency);
|
spi.spi.setup(frequency);
|
||||||
@ -616,7 +650,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T> Spi<'d, T>
|
impl<'d, M, T> Spi<'d, M, T>
|
||||||
where
|
where
|
||||||
T: QspiInstance,
|
T: QspiInstance,
|
||||||
{
|
{
|
||||||
@ -663,7 +697,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Spi<'_, T>
|
impl<M, T> Spi<'_, M, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -754,7 +788,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_hal_02::spi::FullDuplex<u8> for Spi<'_, T>
|
impl<M, T> embedded_hal_02::spi::FullDuplex<u8> for Spi<'_, M, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -769,7 +803,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'_, T>
|
impl<M, T> embedded_hal_02::blocking::spi::Transfer<u8> for Spi<'_, M, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -780,7 +814,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_hal_02::blocking::spi::Write<u8> for Spi<'_, T>
|
impl<M, T> embedded_hal_02::blocking::spi::Write<u8> for Spi<'_, M, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -812,9 +846,7 @@ mod dma {
|
|||||||
Rx,
|
Rx,
|
||||||
Tx,
|
Tx,
|
||||||
},
|
},
|
||||||
Blocking,
|
|
||||||
InterruptConfigurable,
|
InterruptConfigurable,
|
||||||
Mode,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A DMA capable SPI instance.
|
/// A DMA capable SPI instance.
|
||||||
@ -837,6 +869,40 @@ mod dma {
|
|||||||
address_buffer: DmaTxBuf,
|
address_buffer: DmaTxBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'d, T> SpiDma<'d, Blocking, T>
|
||||||
|
where
|
||||||
|
T: InstanceDma,
|
||||||
|
{
|
||||||
|
/// Converts the SPI instance into async mode.
|
||||||
|
pub fn into_async(self) -> SpiDma<'d, Async, T> {
|
||||||
|
SpiDma {
|
||||||
|
spi: self.spi,
|
||||||
|
channel: self.channel.into_async(),
|
||||||
|
tx_transfer_in_progress: self.tx_transfer_in_progress,
|
||||||
|
rx_transfer_in_progress: self.rx_transfer_in_progress,
|
||||||
|
#[cfg(all(esp32, spi_address_workaround))]
|
||||||
|
address_buffer: self.address_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T> SpiDma<'d, Async, T>
|
||||||
|
where
|
||||||
|
T: InstanceDma,
|
||||||
|
{
|
||||||
|
/// Converts the SPI instance into async mode.
|
||||||
|
pub fn into_blocking(self) -> SpiDma<'d, Blocking, T> {
|
||||||
|
SpiDma {
|
||||||
|
spi: self.spi,
|
||||||
|
channel: self.channel.into_blocking(),
|
||||||
|
tx_transfer_in_progress: self.tx_transfer_in_progress,
|
||||||
|
rx_transfer_in_progress: self.rx_transfer_in_progress,
|
||||||
|
#[cfg(all(esp32, spi_address_workaround))]
|
||||||
|
address_buffer: self.address_buffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(all(esp32, spi_address_workaround))]
|
#[cfg(all(esp32, spi_address_workaround))]
|
||||||
unsafe impl<'d, M, T> Send for SpiDma<'d, M, T>
|
unsafe impl<'d, M, T> Send for SpiDma<'d, M, T>
|
||||||
where
|
where
|
||||||
@ -868,6 +934,9 @@ mod dma {
|
|||||||
/// Interrupts are not enabled at the peripheral level here.
|
/// Interrupts are not enabled at the peripheral level here.
|
||||||
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
let interrupt = self.spi.interrupt();
|
let interrupt = self.spi.interrupt();
|
||||||
|
for core in crate::Cpu::other() {
|
||||||
|
crate::interrupt::disable(core, interrupt);
|
||||||
|
}
|
||||||
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
|
unsafe { crate::interrupt::bind_interrupt(interrupt, handler.handler()) };
|
||||||
unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
|
unwrap!(crate::interrupt::enable(interrupt, handler.priority()));
|
||||||
}
|
}
|
||||||
@ -1180,7 +1249,7 @@ mod dma {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, Buf> SpiDmaTransfer<'_, crate::Async, Buf, T>
|
impl<T, Buf> SpiDmaTransfer<'_, Async, Buf, T>
|
||||||
where
|
where
|
||||||
T: InstanceDma,
|
T: InstanceDma,
|
||||||
{
|
{
|
||||||
@ -1460,6 +1529,34 @@ mod dma {
|
|||||||
tx_buf: DmaTxBuf,
|
tx_buf: DmaTxBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'d, T> SpiDmaBus<'d, Blocking, T>
|
||||||
|
where
|
||||||
|
T: InstanceDma,
|
||||||
|
{
|
||||||
|
/// Converts the SPI instance into async mode.
|
||||||
|
pub fn into_async(self) -> SpiDmaBus<'d, Async, T> {
|
||||||
|
SpiDmaBus {
|
||||||
|
spi_dma: self.spi_dma.into_async(),
|
||||||
|
rx_buf: self.rx_buf,
|
||||||
|
tx_buf: self.tx_buf,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T> SpiDmaBus<'d, Async, T>
|
||||||
|
where
|
||||||
|
T: InstanceDma,
|
||||||
|
{
|
||||||
|
/// Converts the SPI instance into async mode.
|
||||||
|
pub fn into_blocking(self) -> SpiDmaBus<'d, Blocking, T> {
|
||||||
|
SpiDmaBus {
|
||||||
|
spi_dma: self.spi_dma.into_blocking(),
|
||||||
|
rx_buf: self.rx_buf,
|
||||||
|
tx_buf: self.tx_buf,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'d, M, T> SpiDmaBus<'d, M, T>
|
impl<'d, M, T> SpiDmaBus<'d, M, T>
|
||||||
where
|
where
|
||||||
T: InstanceDma,
|
T: InstanceDma,
|
||||||
@ -1699,7 +1796,7 @@ mod dma {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_hal_02::blocking::spi::Transfer<u8> for SpiDmaBus<'_, crate::Blocking, T>
|
impl<T> embedded_hal_02::blocking::spi::Transfer<u8> for SpiDmaBus<'_, Blocking, T>
|
||||||
where
|
where
|
||||||
T: InstanceDma,
|
T: InstanceDma,
|
||||||
{
|
{
|
||||||
@ -1711,7 +1808,7 @@ mod dma {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_hal_02::blocking::spi::Write<u8> for SpiDmaBus<'_, crate::Blocking, T>
|
impl<T> embedded_hal_02::blocking::spi::Write<u8> for SpiDmaBus<'_, Blocking, T>
|
||||||
where
|
where
|
||||||
T: InstanceDma,
|
T: InstanceDma,
|
||||||
{
|
{
|
||||||
@ -1731,6 +1828,7 @@ mod dma {
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::Async;
|
||||||
|
|
||||||
struct DropGuard<I, F: FnOnce(I)> {
|
struct DropGuard<I, F: FnOnce(I)> {
|
||||||
inner: ManuallyDrop<I>,
|
inner: ManuallyDrop<I>,
|
||||||
@ -1770,7 +1868,7 @@ mod dma {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SpiDmaBus<'_, crate::Async, T>
|
impl<T> SpiDmaBus<'_, Async, T>
|
||||||
where
|
where
|
||||||
T: InstanceDma,
|
T: InstanceDma,
|
||||||
{
|
{
|
||||||
@ -1884,7 +1982,7 @@ mod dma {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, crate::Async, T>
|
impl<T> embedded_hal_async::spi::SpiBus for SpiDmaBus<'_, Async, T>
|
||||||
where
|
where
|
||||||
T: InstanceDma,
|
T: InstanceDma,
|
||||||
{
|
{
|
||||||
@ -1959,11 +2057,11 @@ mod ehal1 {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl<T> embedded_hal::spi::ErrorType for Spi<'_, T> {
|
impl<M, T> embedded_hal::spi::ErrorType for Spi<'_, M, T> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> FullDuplex for Spi<'_, T>
|
impl<M, T> FullDuplex for Spi<'_, M, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -1976,7 +2074,7 @@ mod ehal1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SpiBus for Spi<'_, T>
|
impl<M, T> SpiBus for Spi<'_, M, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
|
@ -70,6 +70,8 @@
|
|||||||
//!
|
//!
|
||||||
//! See [tracking issue](https://github.com/esp-rs/esp-hal/issues/469) for more information.
|
//! See [tracking issue](https://github.com/esp-rs/esp-hal/issues/469) for more information.
|
||||||
|
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use super::{Error, SpiMode};
|
use super::{Error, SpiMode};
|
||||||
use crate::{
|
use crate::{
|
||||||
dma::{DescriptorChain, DmaChannelConvert, DmaEligible, PeripheralMarker, Rx, Tx},
|
dma::{DescriptorChain, DmaChannelConvert, DmaEligible, PeripheralMarker, Rx, Tx},
|
||||||
@ -83,6 +85,7 @@ use crate::{
|
|||||||
private,
|
private,
|
||||||
spi::AnySpi,
|
spi::AnySpi,
|
||||||
system::PeripheralClockControl,
|
system::PeripheralClockControl,
|
||||||
|
Blocking,
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_DMA_SIZE: usize = 32768 - 32;
|
const MAX_DMA_SIZE: usize = 32768 - 32;
|
||||||
@ -90,13 +93,14 @@ const MAX_DMA_SIZE: usize = 32768 - 32;
|
|||||||
/// SPI peripheral driver.
|
/// SPI peripheral driver.
|
||||||
///
|
///
|
||||||
/// See the [module-level documentation][self] for more details.
|
/// See the [module-level documentation][self] for more details.
|
||||||
pub struct Spi<'d, T = AnySpi> {
|
pub struct Spi<'d, M, T = AnySpi> {
|
||||||
spi: PeripheralRef<'d, T>,
|
spi: PeripheralRef<'d, T>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
data_mode: SpiMode,
|
data_mode: SpiMode,
|
||||||
|
_mode: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> Spi<'d> {
|
impl<'d> Spi<'d, Blocking> {
|
||||||
/// Constructs an SPI instance in 8bit dataframe mode.
|
/// Constructs an SPI instance in 8bit dataframe mode.
|
||||||
pub fn new<
|
pub fn new<
|
||||||
SCK: PeripheralInput,
|
SCK: PeripheralInput,
|
||||||
@ -110,12 +114,12 @@ impl<'d> Spi<'d> {
|
|||||||
miso: impl Peripheral<P = MISO> + 'd,
|
miso: impl Peripheral<P = MISO> + 'd,
|
||||||
cs: impl Peripheral<P = CS> + 'd,
|
cs: impl Peripheral<P = CS> + 'd,
|
||||||
mode: SpiMode,
|
mode: SpiMode,
|
||||||
) -> Spi<'d> {
|
) -> Spi<'d, Blocking> {
|
||||||
Self::new_typed(spi.map_into(), sclk, mosi, miso, cs, mode)
|
Self::new_typed(spi.map_into(), sclk, mosi, miso, cs, mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T> Spi<'d, T>
|
impl<'d, M, T> Spi<'d, M, T>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
@ -132,7 +136,7 @@ where
|
|||||||
miso: impl Peripheral<P = MISO> + 'd,
|
miso: impl Peripheral<P = MISO> + 'd,
|
||||||
cs: impl Peripheral<P = CS> + 'd,
|
cs: impl Peripheral<P = CS> + 'd,
|
||||||
mode: SpiMode,
|
mode: SpiMode,
|
||||||
) -> Spi<'d, T> {
|
) -> Spi<'d, M, T> {
|
||||||
crate::into_mapped_ref!(sclk, mosi, miso, cs);
|
crate::into_mapped_ref!(sclk, mosi, miso, cs);
|
||||||
|
|
||||||
let this = Self::new_internal(spi, mode);
|
let this = Self::new_internal(spi, mode);
|
||||||
@ -153,12 +157,13 @@ where
|
|||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new_internal(spi: impl Peripheral<P = T> + 'd, mode: SpiMode) -> Spi<'d, T> {
|
pub(crate) fn new_internal(spi: impl Peripheral<P = T> + 'd, mode: SpiMode) -> Spi<'d, M, T> {
|
||||||
crate::into_ref!(spi);
|
crate::into_ref!(spi);
|
||||||
|
|
||||||
let mut spi = Spi {
|
let mut spi = Spi {
|
||||||
spi,
|
spi,
|
||||||
data_mode: mode,
|
data_mode: mode,
|
||||||
|
_mode: PhantomData,
|
||||||
};
|
};
|
||||||
|
|
||||||
PeripheralClockControl::reset(spi.spi.peripheral());
|
PeripheralClockControl::reset(spi.spi.peripheral());
|
||||||
@ -193,36 +198,38 @@ pub mod dma {
|
|||||||
Mode,
|
Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'d, T> Spi<'d, T>
|
impl<'d, M, T> Spi<'d, M, T>
|
||||||
where
|
where
|
||||||
T: InstanceDma,
|
T: InstanceDma,
|
||||||
|
M: Mode,
|
||||||
{
|
{
|
||||||
/// Configures the SPI3 peripheral with the provided DMA channel and
|
/// Configures the SPI3 peripheral with the provided DMA channel and
|
||||||
/// descriptors.
|
/// descriptors.
|
||||||
#[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")]
|
#[cfg_attr(esp32, doc = "\n\n**Note**: ESP32 only supports Mode 1 and 3.")]
|
||||||
pub fn with_dma<CH, DmaMode>(
|
pub fn with_dma<CH, DM>(
|
||||||
mut self,
|
mut self,
|
||||||
channel: Channel<'d, CH, DmaMode>,
|
channel: Channel<'d, CH, DM>,
|
||||||
rx_descriptors: &'static mut [DmaDescriptor],
|
rx_descriptors: &'static mut [DmaDescriptor],
|
||||||
tx_descriptors: &'static mut [DmaDescriptor],
|
tx_descriptors: &'static mut [DmaDescriptor],
|
||||||
) -> SpiDma<'d, DmaMode, T>
|
) -> SpiDma<'d, M, T>
|
||||||
where
|
where
|
||||||
CH: DmaChannelConvert<T::Dma>,
|
CH: DmaChannelConvert<T::Dma>,
|
||||||
DmaMode: Mode,
|
DM: Mode,
|
||||||
|
Channel<'d, CH, M>: From<Channel<'d, CH, DM>>,
|
||||||
{
|
{
|
||||||
self.spi.set_data_mode(self.data_mode, true);
|
self.spi.set_data_mode(self.data_mode, true);
|
||||||
SpiDma::new(self.spi, channel, rx_descriptors, tx_descriptors)
|
SpiDma::new(self.spi, channel.into(), rx_descriptors, tx_descriptors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A DMA capable SPI instance.
|
/// A DMA capable SPI instance.
|
||||||
pub struct SpiDma<'d, DmaMode, T = AnySpi>
|
pub struct SpiDma<'d, M, T = AnySpi>
|
||||||
where
|
where
|
||||||
T: InstanceDma,
|
T: InstanceDma,
|
||||||
DmaMode: Mode,
|
M: Mode,
|
||||||
{
|
{
|
||||||
pub(crate) spi: PeripheralRef<'d, T>,
|
pub(crate) spi: PeripheralRef<'d, T>,
|
||||||
pub(crate) channel: Channel<'d, T::Dma, DmaMode>,
|
pub(crate) channel: Channel<'d, T::Dma, M>,
|
||||||
rx_chain: DescriptorChain,
|
rx_chain: DescriptorChain,
|
||||||
tx_chain: DescriptorChain,
|
tx_chain: DescriptorChain,
|
||||||
}
|
}
|
||||||
|
@ -549,6 +549,10 @@ pub trait Comparator {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for core in crate::Cpu::other() {
|
||||||
|
crate::interrupt::disable(core, interrupt);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(esp32s2))]
|
#[cfg(not(esp32s2))]
|
||||||
unsafe {
|
unsafe {
|
||||||
interrupt::bind_interrupt(interrupt, handler.handler());
|
interrupt::bind_interrupt(interrupt, handler.handler());
|
||||||
|
@ -553,10 +553,11 @@ where
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
for core in crate::Cpu::other() {
|
||||||
interrupt::bind_interrupt(interrupt, handler.handler());
|
crate::interrupt::disable(core, interrupt);
|
||||||
}
|
}
|
||||||
interrupt::enable(interrupt, handler.priority()).unwrap();
|
unsafe { interrupt::bind_interrupt(interrupt, handler.handler()) };
|
||||||
|
unwrap!(interrupt::enable(interrupt, handler.priority()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_interrupt_set(&self) -> bool {
|
fn is_interrupt_set(&self) -> bool {
|
||||||
|
@ -840,10 +840,15 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
fn internal_set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||||
unsafe {
|
for core in crate::Cpu::other() {
|
||||||
crate::interrupt::bind_interrupt(self.twai.interrupt(), handler.handler());
|
crate::interrupt::disable(core, self.twai.interrupt());
|
||||||
crate::interrupt::enable(self.twai.interrupt(), handler.priority()).unwrap();
|
|
||||||
}
|
}
|
||||||
|
unsafe { crate::interrupt::bind_interrupt(self.twai.interrupt(), handler.handler()) };
|
||||||
|
|
||||||
|
unwrap!(crate::interrupt::enable(
|
||||||
|
self.twai.interrupt(),
|
||||||
|
handler.priority()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the bitrate of the bus.
|
/// Set the bitrate of the bus.
|
||||||
@ -1027,17 +1032,6 @@ where
|
|||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the configuration into an async configuration.
|
|
||||||
fn into_async(self) -> TwaiConfiguration<'d, Async, T> {
|
|
||||||
let mut this = TwaiConfiguration {
|
|
||||||
twai: self.twai,
|
|
||||||
phantom: PhantomData,
|
|
||||||
mode: self.mode,
|
|
||||||
};
|
|
||||||
this.internal_set_interrupt_handler(this.twai.async_handler());
|
|
||||||
this
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> TwaiConfiguration<'d, Blocking> {
|
impl<'d> TwaiConfiguration<'d, Blocking> {
|
||||||
@ -1101,35 +1095,15 @@ where
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new_internal(peripheral, rx_pin, tx_pin, baud_rate, true, mode)
|
Self::new_internal(peripheral, rx_pin, tx_pin, baud_rate, true, mode)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d> TwaiConfiguration<'d, Async> {
|
/// Convert the configuration into an async configuration.
|
||||||
/// Create a new instance of [TwaiConfiguration]
|
pub fn into_async(mut self) -> TwaiConfiguration<'d, Async, T> {
|
||||||
///
|
self.set_interrupt_handler(self.twai.async_handler());
|
||||||
/// You will need to use a transceiver to connect to the TWAI bus
|
TwaiConfiguration {
|
||||||
pub fn new_async<RX: PeripheralInput, TX: PeripheralOutput>(
|
twai: self.twai,
|
||||||
peripheral: impl Peripheral<P = impl Instance> + 'd,
|
phantom: PhantomData,
|
||||||
rx_pin: impl Peripheral<P = RX> + 'd,
|
mode: self.mode,
|
||||||
tx_pin: impl Peripheral<P = TX> + 'd,
|
}
|
||||||
baud_rate: BaudRate,
|
|
||||||
mode: TwaiMode,
|
|
||||||
) -> Self {
|
|
||||||
Self::new_async_typed(peripheral.map_into(), rx_pin, tx_pin, baud_rate, mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new instance of [TwaiConfiguration] meant to connect two ESP32s
|
|
||||||
/// directly
|
|
||||||
///
|
|
||||||
/// You don't need a transceiver by following the description in the
|
|
||||||
/// `twai.rs` example
|
|
||||||
pub fn new_async_no_transceiver<RX: PeripheralInput, TX: PeripheralOutput>(
|
|
||||||
peripheral: impl Peripheral<P = impl Instance> + 'd,
|
|
||||||
rx_pin: impl Peripheral<P = RX> + 'd,
|
|
||||||
tx_pin: impl Peripheral<P = TX> + 'd,
|
|
||||||
baud_rate: BaudRate,
|
|
||||||
mode: TwaiMode,
|
|
||||||
) -> Self {
|
|
||||||
Self::new_async_no_transceiver_typed(peripheral.map_into(), rx_pin, tx_pin, baud_rate, mode)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1137,33 +1111,18 @@ impl<'d, T> TwaiConfiguration<'d, Async, T>
|
|||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
{
|
{
|
||||||
/// Create a new instance of [TwaiConfiguration] in async mode
|
/// Convert the configuration into a blocking configuration.
|
||||||
///
|
pub fn into_blocking(self) -> TwaiConfiguration<'d, Blocking, T> {
|
||||||
/// You will need to use a transceiver to connect to the TWAI bus
|
use crate::{interrupt, Cpu};
|
||||||
pub fn new_async_typed<RX: PeripheralInput, TX: PeripheralOutput>(
|
|
||||||
peripheral: impl Peripheral<P = T> + 'd,
|
|
||||||
rx_pin: impl Peripheral<P = RX> + 'd,
|
|
||||||
tx_pin: impl Peripheral<P = TX> + 'd,
|
|
||||||
baud_rate: BaudRate,
|
|
||||||
mode: TwaiMode,
|
|
||||||
) -> Self {
|
|
||||||
TwaiConfiguration::new_typed(peripheral, rx_pin, tx_pin, baud_rate, mode).into_async()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new instance of [TwaiConfiguration] meant to connect two ESP32s
|
interrupt::disable(Cpu::current(), self.twai.interrupt());
|
||||||
/// directly in async mode
|
|
||||||
///
|
// Re-create in blocking mode
|
||||||
/// You don't need a transceiver by following the description in the
|
TwaiConfiguration {
|
||||||
/// `twai.rs` example
|
twai: self.twai,
|
||||||
pub fn new_async_no_transceiver_typed<RX: PeripheralInput, TX: PeripheralOutput>(
|
phantom: PhantomData,
|
||||||
peripheral: impl Peripheral<P = T> + 'd,
|
mode: self.mode,
|
||||||
rx_pin: impl Peripheral<P = RX> + 'd,
|
}
|
||||||
tx_pin: impl Peripheral<P = TX> + 'd,
|
|
||||||
baud_rate: BaudRate,
|
|
||||||
mode: TwaiMode,
|
|
||||||
) -> Self {
|
|
||||||
TwaiConfiguration::new_no_transceiver_typed(peripheral, rx_pin, tx_pin, baud_rate, mode)
|
|
||||||
.into_async()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1113
esp-hal/src/uart.rs
1113
esp-hal/src/uart.rs
File diff suppressed because it is too large
Load Diff
@ -75,14 +75,18 @@
|
|||||||
//! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/
|
//! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/
|
||||||
//! [embedded-io-async]: https://docs.rs/embedded-io-async/latest/embedded_io_async/
|
//! [embedded-io-async]: https://docs.rs/embedded-io-async/latest/embedded_io_async/
|
||||||
|
|
||||||
use core::{convert::Infallible, marker::PhantomData};
|
use core::{convert::Infallible, marker::PhantomData, task::Poll};
|
||||||
|
|
||||||
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
use procmacros::handler;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
interrupt::InterruptHandler,
|
peripheral::{Peripheral, PeripheralRef},
|
||||||
peripheral::Peripheral,
|
|
||||||
peripherals::{usb_device::RegisterBlock, Interrupt, USB_DEVICE},
|
peripherals::{usb_device::RegisterBlock, Interrupt, USB_DEVICE},
|
||||||
system::PeripheralClockControl,
|
system::PeripheralClockControl,
|
||||||
|
Async,
|
||||||
Blocking,
|
Blocking,
|
||||||
|
Cpu,
|
||||||
InterruptConfigurable,
|
InterruptConfigurable,
|
||||||
Mode,
|
Mode,
|
||||||
};
|
};
|
||||||
@ -98,20 +102,24 @@ pub struct UsbSerialJtag<'d, M> {
|
|||||||
|
|
||||||
/// USB Serial/JTAG (Transmit)
|
/// USB Serial/JTAG (Transmit)
|
||||||
pub struct UsbSerialJtagTx<'d, M> {
|
pub struct UsbSerialJtagTx<'d, M> {
|
||||||
phantom: PhantomData<(&'d mut USB_DEVICE, M)>,
|
peripheral: PeripheralRef<'d, USB_DEVICE>,
|
||||||
|
phantom: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// USB Serial/JTAG (Receive)
|
/// USB Serial/JTAG (Receive)
|
||||||
pub struct UsbSerialJtagRx<'d, M> {
|
pub struct UsbSerialJtagRx<'d, M> {
|
||||||
phantom: PhantomData<(&'d mut USB_DEVICE, M)>,
|
peripheral: PeripheralRef<'d, USB_DEVICE>,
|
||||||
|
phantom: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> UsbSerialJtagTx<'_, M>
|
impl<'d, M> UsbSerialJtagTx<'d, M>
|
||||||
where
|
where
|
||||||
M: Mode,
|
M: Mode,
|
||||||
{
|
{
|
||||||
fn new_inner() -> Self {
|
fn new_inner(peripheral: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
|
||||||
|
crate::into_ref!(peripheral);
|
||||||
Self {
|
Self {
|
||||||
|
peripheral,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,12 +191,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> UsbSerialJtagRx<'_, M>
|
impl<'d, M> UsbSerialJtagRx<'d, M>
|
||||||
where
|
where
|
||||||
M: Mode,
|
M: Mode,
|
||||||
{
|
{
|
||||||
fn new_inner() -> Self {
|
fn new_inner(peripheral: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
|
||||||
|
crate::into_ref!(peripheral);
|
||||||
Self {
|
Self {
|
||||||
|
peripheral,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,13 +273,37 @@ impl<'d> UsbSerialJtag<'d, Blocking> {
|
|||||||
pub fn new(usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
|
pub fn new(usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
|
||||||
Self::new_inner(usb_device)
|
Self::new_inner(usb_device)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reconfigure the USB Serial JTAG peripheral to operate in asynchronous
|
||||||
|
/// mode.
|
||||||
|
pub fn into_async(mut self) -> UsbSerialJtag<'d, Async> {
|
||||||
|
self.set_interrupt_handler(async_interrupt_handler);
|
||||||
|
|
||||||
|
UsbSerialJtag {
|
||||||
|
rx: UsbSerialJtagRx {
|
||||||
|
peripheral: self.rx.peripheral,
|
||||||
|
phantom: PhantomData,
|
||||||
|
},
|
||||||
|
tx: UsbSerialJtagTx {
|
||||||
|
peripheral: self.tx.peripheral,
|
||||||
|
phantom: PhantomData,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::private::Sealed for UsbSerialJtag<'_, Blocking> {}
|
impl crate::private::Sealed for UsbSerialJtag<'_, Blocking> {}
|
||||||
|
|
||||||
impl InterruptConfigurable for UsbSerialJtag<'_, Blocking> {
|
impl InterruptConfigurable for UsbSerialJtag<'_, Blocking> {
|
||||||
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
|
fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) {
|
||||||
self.inner_set_interrupt_handler(handler);
|
for core in crate::Cpu::other() {
|
||||||
|
crate::interrupt::disable(core, Interrupt::USB_DEVICE);
|
||||||
|
}
|
||||||
|
unsafe { crate::interrupt::bind_interrupt(Interrupt::USB_DEVICE, handler.handler()) };
|
||||||
|
unwrap!(crate::interrupt::enable(
|
||||||
|
Interrupt::USB_DEVICE,
|
||||||
|
handler.priority()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,7 +311,7 @@ impl<'d, M> UsbSerialJtag<'d, M>
|
|||||||
where
|
where
|
||||||
M: Mode,
|
M: Mode,
|
||||||
{
|
{
|
||||||
fn new_inner(_usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
|
fn new_inner(usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
|
||||||
// Do NOT reset the peripheral. Doing so will result in a broken USB JTAG
|
// Do NOT reset the peripheral. Doing so will result in a broken USB JTAG
|
||||||
// connection.
|
// connection.
|
||||||
PeripheralClockControl::enable(crate::system::Peripheral::UsbDevice);
|
PeripheralClockControl::enable(crate::system::Peripheral::UsbDevice);
|
||||||
@ -293,29 +327,20 @@ where
|
|||||||
// doesn't swap the pullups too, this works around that.
|
// doesn't swap the pullups too, this works around that.
|
||||||
if Efuse::read_bit(USB_EXCHG_PINS) {
|
if Efuse::read_bit(USB_EXCHG_PINS) {
|
||||||
USB_DEVICE::register_block().conf0().modify(|_, w| {
|
USB_DEVICE::register_block().conf0().modify(|_, w| {
|
||||||
w.pad_pull_override()
|
w.pad_pull_override().set_bit();
|
||||||
.set_bit()
|
w.dm_pullup().clear_bit();
|
||||||
.dm_pullup()
|
w.dp_pullup().set_bit()
|
||||||
.clear_bit()
|
|
||||||
.dp_pullup()
|
|
||||||
.set_bit()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate::into_ref!(usb_device);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
rx: UsbSerialJtagRx::new_inner(),
|
rx: UsbSerialJtagRx::new_inner(unsafe { usb_device.clone_unchecked() }),
|
||||||
tx: UsbSerialJtagTx::new_inner(),
|
tx: UsbSerialJtagTx::new_inner(usb_device),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner_set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
|
||||||
unsafe {
|
|
||||||
crate::interrupt::bind_interrupt(Interrupt::USB_DEVICE, handler.handler());
|
|
||||||
crate::interrupt::enable(Interrupt::USB_DEVICE, handler.priority()).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Split the USB Serial JTAG peripheral into a transmitter and receiver,
|
/// Split the USB Serial JTAG peripheral into a transmitter and receiver,
|
||||||
/// which is particularly useful when having two tasks correlating to
|
/// which is particularly useful when having two tasks correlating to
|
||||||
/// transmitting and receiving.
|
/// transmitting and receiving.
|
||||||
@ -652,224 +677,221 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod asynch {
|
// Static instance of the waker for each component of the peripheral:
|
||||||
use core::{marker::PhantomData, task::Poll};
|
static WAKER_TX: AtomicWaker = AtomicWaker::new();
|
||||||
|
static WAKER_RX: AtomicWaker = AtomicWaker::new();
|
||||||
|
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
use procmacros::handler;
|
struct UsbSerialJtagWriteFuture<'d> {
|
||||||
|
_peripheral: PeripheralRef<'d, USB_DEVICE>,
|
||||||
|
}
|
||||||
|
|
||||||
use super::{Error, Instance, UsbSerialJtag, UsbSerialJtagRx, UsbSerialJtagTx};
|
impl<'d> UsbSerialJtagWriteFuture<'d> {
|
||||||
use crate::{peripheral::Peripheral, peripherals::USB_DEVICE, Async};
|
fn new(_peripheral: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
|
||||||
|
crate::into_ref!(_peripheral);
|
||||||
|
// Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT
|
||||||
|
// interrupt
|
||||||
|
USB_DEVICE::register_block()
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.serial_in_empty().set_bit());
|
||||||
|
|
||||||
// Static instance of the waker for each component of the peripheral:
|
Self { _peripheral }
|
||||||
static WAKER_TX: AtomicWaker = AtomicWaker::new();
|
|
||||||
static WAKER_RX: AtomicWaker = AtomicWaker::new();
|
|
||||||
|
|
||||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
|
||||||
pub(crate) struct UsbSerialJtagWriteFuture<'d> {
|
|
||||||
phantom: PhantomData<&'d mut USB_DEVICE>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsbSerialJtagWriteFuture<'_> {
|
fn event_bit_is_clear(&self) -> bool {
|
||||||
pub fn new() -> Self {
|
USB_DEVICE::register_block()
|
||||||
// Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_IN_EMPTY_INT
|
.int_ena()
|
||||||
// interrupt
|
.read()
|
||||||
USB_DEVICE::register_block()
|
.serial_in_empty()
|
||||||
.int_ena()
|
.bit_is_clear()
|
||||||
.modify(|_, w| w.serial_in_empty().set_bit());
|
|
||||||
|
|
||||||
Self {
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event_bit_is_clear(&self) -> bool {
|
|
||||||
USB_DEVICE::register_block()
|
|
||||||
.int_ena()
|
|
||||||
.read()
|
|
||||||
.serial_in_empty()
|
|
||||||
.bit_is_clear()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl core::future::Future for UsbSerialJtagWriteFuture<'_> {
|
impl core::future::Future for UsbSerialJtagWriteFuture<'_> {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
fn poll(
|
fn poll(
|
||||||
self: core::pin::Pin<&mut Self>,
|
self: core::pin::Pin<&mut Self>,
|
||||||
cx: &mut core::task::Context<'_>,
|
cx: &mut core::task::Context<'_>,
|
||||||
) -> core::task::Poll<Self::Output> {
|
) -> core::task::Poll<Self::Output> {
|
||||||
WAKER_TX.register(cx.waker());
|
WAKER_TX.register(cx.waker());
|
||||||
if self.event_bit_is_clear() {
|
if self.event_bit_is_clear() {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
|
||||||
pub(crate) struct UsbSerialJtagReadFuture<'d> {
|
|
||||||
phantom: PhantomData<&'d mut USB_DEVICE>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UsbSerialJtagReadFuture<'_> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
// Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT
|
|
||||||
// interrupt
|
|
||||||
USB_DEVICE::register_block()
|
|
||||||
.int_ena()
|
|
||||||
.modify(|_, w| w.serial_out_recv_pkt().set_bit());
|
|
||||||
|
|
||||||
Self {
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event_bit_is_clear(&self) -> bool {
|
|
||||||
USB_DEVICE::register_block()
|
|
||||||
.int_ena()
|
|
||||||
.read()
|
|
||||||
.serial_out_recv_pkt()
|
|
||||||
.bit_is_clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl core::future::Future for UsbSerialJtagReadFuture<'_> {
|
|
||||||
type Output = ();
|
|
||||||
|
|
||||||
fn poll(
|
|
||||||
self: core::pin::Pin<&mut Self>,
|
|
||||||
cx: &mut core::task::Context<'_>,
|
|
||||||
) -> core::task::Poll<Self::Output> {
|
|
||||||
WAKER_RX.register(cx.waker());
|
|
||||||
if self.event_bit_is_clear() {
|
|
||||||
Poll::Ready(())
|
|
||||||
} else {
|
|
||||||
Poll::Pending
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d> UsbSerialJtag<'d, Async> {
|
|
||||||
/// Create a new USB serial/JTAG instance in asynchronous mode
|
|
||||||
pub fn new_async(usb_device: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
|
|
||||||
let mut this = Self::new_inner(usb_device);
|
|
||||||
this.inner_set_interrupt_handler(async_interrupt_handler);
|
|
||||||
this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UsbSerialJtagTx<'_, Async> {
|
|
||||||
async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> {
|
|
||||||
let reg_block = USB_DEVICE::register_block();
|
|
||||||
|
|
||||||
for chunk in words.chunks(64) {
|
|
||||||
for byte in chunk {
|
|
||||||
reg_block
|
|
||||||
.ep1()
|
|
||||||
.write(|w| unsafe { w.rdwr_byte().bits(*byte) });
|
|
||||||
}
|
|
||||||
reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit());
|
|
||||||
|
|
||||||
UsbSerialJtagWriteFuture::new().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn flush_tx_async(&mut self) -> Result<(), Error> {
|
|
||||||
if USB_DEVICE::register_block()
|
|
||||||
.jfifo_st()
|
|
||||||
.read()
|
|
||||||
.out_fifo_empty()
|
|
||||||
.bit_is_clear()
|
|
||||||
{
|
|
||||||
UsbSerialJtagWriteFuture::new().await;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UsbSerialJtagRx<'_, Async> {
|
|
||||||
async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
|
||||||
if buf.is_empty() {
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let read_bytes = self.drain_rx_fifo(buf);
|
|
||||||
if read_bytes > 0 {
|
|
||||||
return Ok(read_bytes);
|
|
||||||
}
|
|
||||||
UsbSerialJtagReadFuture::new().await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl embedded_io_async::Write for UsbSerialJtag<'_, Async> {
|
|
||||||
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
|
||||||
embedded_io_async::Write::write(&mut self.tx, buf).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn flush(&mut self) -> Result<(), Self::Error> {
|
|
||||||
embedded_io_async::Write::flush(&mut self.tx).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> {
|
|
||||||
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
|
||||||
self.write_bytes_async(buf).await?;
|
|
||||||
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn flush(&mut self) -> Result<(), Self::Error> {
|
|
||||||
self.flush_tx_async().await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl embedded_io_async::Read for UsbSerialJtag<'_, Async> {
|
|
||||||
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
|
||||||
embedded_io_async::Read::read(&mut self.rx, buf).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> {
|
|
||||||
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
|
||||||
self.read_bytes_async(buf).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[handler]
|
|
||||||
fn async_interrupt_handler() {
|
|
||||||
let usb = USB_DEVICE::register_block();
|
|
||||||
let interrupts = usb.int_st().read();
|
|
||||||
|
|
||||||
let tx = interrupts.serial_in_empty().bit_is_set();
|
|
||||||
let rx = interrupts.serial_out_recv_pkt().bit_is_set();
|
|
||||||
|
|
||||||
if tx {
|
|
||||||
usb.int_ena().modify(|_, w| w.serial_in_empty().clear_bit());
|
|
||||||
}
|
|
||||||
if rx {
|
|
||||||
usb.int_ena()
|
|
||||||
.modify(|_, w| w.serial_out_recv_pkt().clear_bit());
|
|
||||||
}
|
|
||||||
|
|
||||||
usb.int_clr().write(|w| {
|
|
||||||
w.serial_in_empty()
|
|
||||||
.clear_bit_by_one()
|
|
||||||
.serial_out_recv_pkt()
|
|
||||||
.clear_bit_by_one()
|
|
||||||
});
|
|
||||||
|
|
||||||
if rx {
|
|
||||||
WAKER_RX.wake();
|
|
||||||
}
|
|
||||||
if tx {
|
|
||||||
WAKER_TX.wake();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
|
struct UsbSerialJtagReadFuture<'d> {
|
||||||
|
_peripheral: PeripheralRef<'d, USB_DEVICE>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> UsbSerialJtagReadFuture<'d> {
|
||||||
|
fn new(_peripheral: impl Peripheral<P = USB_DEVICE> + 'd) -> Self {
|
||||||
|
crate::into_ref!(_peripheral);
|
||||||
|
// Set the interrupt enable bit for the USB_SERIAL_JTAG_SERIAL_OUT_RECV_PKT
|
||||||
|
// interrupt
|
||||||
|
USB_DEVICE::register_block()
|
||||||
|
.int_ena()
|
||||||
|
.modify(|_, w| w.serial_out_recv_pkt().set_bit());
|
||||||
|
|
||||||
|
Self { _peripheral }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn event_bit_is_clear(&self) -> bool {
|
||||||
|
USB_DEVICE::register_block()
|
||||||
|
.int_ena()
|
||||||
|
.read()
|
||||||
|
.serial_out_recv_pkt()
|
||||||
|
.bit_is_clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::future::Future for UsbSerialJtagReadFuture<'_> {
|
||||||
|
type Output = ();
|
||||||
|
|
||||||
|
fn poll(
|
||||||
|
self: core::pin::Pin<&mut Self>,
|
||||||
|
cx: &mut core::task::Context<'_>,
|
||||||
|
) -> core::task::Poll<Self::Output> {
|
||||||
|
WAKER_RX.register(cx.waker());
|
||||||
|
if self.event_bit_is_clear() {
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> UsbSerialJtag<'d, Async> {
|
||||||
|
/// Reconfigure the USB Serial JTAG peripheral to operate in blocking
|
||||||
|
/// mode.
|
||||||
|
pub fn into_blocking(self) -> UsbSerialJtag<'d, Blocking> {
|
||||||
|
crate::interrupt::disable(Cpu::current(), Interrupt::USB_DEVICE);
|
||||||
|
UsbSerialJtag {
|
||||||
|
rx: UsbSerialJtagRx {
|
||||||
|
peripheral: self.rx.peripheral,
|
||||||
|
phantom: PhantomData,
|
||||||
|
},
|
||||||
|
tx: UsbSerialJtagTx {
|
||||||
|
peripheral: self.tx.peripheral,
|
||||||
|
phantom: PhantomData,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsbSerialJtagTx<'_, Async> {
|
||||||
|
async fn write_bytes_async(&mut self, words: &[u8]) -> Result<(), Error> {
|
||||||
|
let reg_block = USB_DEVICE::register_block();
|
||||||
|
|
||||||
|
for chunk in words.chunks(64) {
|
||||||
|
for byte in chunk {
|
||||||
|
reg_block
|
||||||
|
.ep1()
|
||||||
|
.write(|w| unsafe { w.rdwr_byte().bits(*byte) });
|
||||||
|
}
|
||||||
|
reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit());
|
||||||
|
|
||||||
|
UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn flush_tx_async(&mut self) -> Result<(), Error> {
|
||||||
|
if USB_DEVICE::register_block()
|
||||||
|
.jfifo_st()
|
||||||
|
.read()
|
||||||
|
.out_fifo_empty()
|
||||||
|
.bit_is_clear()
|
||||||
|
{
|
||||||
|
UsbSerialJtagWriteFuture::new(self.peripheral.reborrow()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsbSerialJtagRx<'_, Async> {
|
||||||
|
async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
|
if buf.is_empty() {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let read_bytes = self.drain_rx_fifo(buf);
|
||||||
|
if read_bytes > 0 {
|
||||||
|
return Ok(read_bytes);
|
||||||
|
}
|
||||||
|
UsbSerialJtagReadFuture::new(self.peripheral.reborrow()).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl embedded_io_async::Write for UsbSerialJtag<'_, Async> {
|
||||||
|
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
|
embedded_io_async::Write::write(&mut self.tx, buf).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
embedded_io_async::Write::flush(&mut self.tx).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl embedded_io_async::Write for UsbSerialJtagTx<'_, Async> {
|
||||||
|
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
|
||||||
|
self.write_bytes_async(buf).await?;
|
||||||
|
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
self.flush_tx_async().await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl embedded_io_async::Read for UsbSerialJtag<'_, Async> {
|
||||||
|
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
|
embedded_io_async::Read::read(&mut self.rx, buf).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl embedded_io_async::Read for UsbSerialJtagRx<'_, Async> {
|
||||||
|
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
|
self.read_bytes_async(buf).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[handler]
|
||||||
|
fn async_interrupt_handler() {
|
||||||
|
let usb = USB_DEVICE::register_block();
|
||||||
|
let interrupts = usb.int_st().read();
|
||||||
|
|
||||||
|
let tx = interrupts.serial_in_empty().bit_is_set();
|
||||||
|
let rx = interrupts.serial_out_recv_pkt().bit_is_set();
|
||||||
|
|
||||||
|
if tx {
|
||||||
|
usb.int_ena().modify(|_, w| w.serial_in_empty().clear_bit());
|
||||||
|
}
|
||||||
|
if rx {
|
||||||
|
usb.int_ena()
|
||||||
|
.modify(|_, w| w.serial_out_recv_pkt().clear_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
usb.int_clr().write(|w| {
|
||||||
|
w.serial_in_empty()
|
||||||
|
.clear_bit_by_one()
|
||||||
|
.serial_out_recv_pkt()
|
||||||
|
.clear_bit_by_one()
|
||||||
|
});
|
||||||
|
|
||||||
|
if rx {
|
||||||
|
WAKER_RX.wake();
|
||||||
|
}
|
||||||
|
if tx {
|
||||||
|
WAKER_TX.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||||
|
|
||||||
let i2c0 = I2c::new_async(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz());
|
let i2c0 = I2c::new(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz()).into_async();
|
||||||
|
|
||||||
let mut lis3dh = Lis3dh::new_i2c(i2c0, SlaveAddr::Alternate).await.unwrap();
|
let mut lis3dh = Lis3dh::new_i2c(i2c0, SlaveAddr::Alternate).await.unwrap();
|
||||||
lis3dh.set_range(Range::G8).await.unwrap();
|
lis3dh.set_range(Range::G8).await.unwrap();
|
||||||
|
@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||||
|
|
||||||
let mut i2c = I2c::new_async(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz());
|
let mut i2c = I2c::new(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 400.kHz()).into_async();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut data = [0u8; 22];
|
let mut data = [0u8; 22];
|
||||||
|
@ -60,7 +60,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE);
|
let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, BUFFER_SIZE);
|
||||||
let mut parallel = I2sParallel::new(
|
let mut parallel = I2sParallel::new(
|
||||||
i2s,
|
i2s,
|
||||||
dma_channel.configure_for_async(false, DmaPriority::Priority0),
|
dma_channel
|
||||||
|
.configure(false, DmaPriority::Priority0)
|
||||||
|
.into_async(),
|
||||||
1.MHz(),
|
1.MHz(),
|
||||||
pins,
|
pins,
|
||||||
clock,
|
clock,
|
||||||
|
@ -52,10 +52,11 @@ async fn main(_spawner: Spawner) {
|
|||||||
Standard::Philips,
|
Standard::Philips,
|
||||||
DataFormat::Data16Channel16,
|
DataFormat::Data16Channel16,
|
||||||
44100u32.Hz(),
|
44100u32.Hz(),
|
||||||
dma_channel.configure_for_async(false, DmaPriority::Priority0),
|
dma_channel.configure(false, DmaPriority::Priority0),
|
||||||
rx_descriptors,
|
rx_descriptors,
|
||||||
tx_descriptors,
|
tx_descriptors,
|
||||||
);
|
)
|
||||||
|
.into_async();
|
||||||
|
|
||||||
#[cfg(not(feature = "esp32"))]
|
#[cfg(not(feature = "esp32"))]
|
||||||
let i2s = i2s.with_mclk(io.pins.gpio0);
|
let i2s = i2s.with_mclk(io.pins.gpio0);
|
||||||
|
@ -74,10 +74,11 @@ async fn main(_spawner: Spawner) {
|
|||||||
Standard::Philips,
|
Standard::Philips,
|
||||||
DataFormat::Data16Channel16,
|
DataFormat::Data16Channel16,
|
||||||
44100u32.Hz(),
|
44100u32.Hz(),
|
||||||
dma_channel.configure_for_async(false, DmaPriority::Priority0),
|
dma_channel.configure(false, DmaPriority::Priority0),
|
||||||
rx_descriptors,
|
rx_descriptors,
|
||||||
tx_descriptors,
|
tx_descriptors,
|
||||||
);
|
)
|
||||||
|
.into_async();
|
||||||
|
|
||||||
let i2s_tx = i2s
|
let i2s_tx = i2s
|
||||||
.i2s_tx
|
.i2s_tx
|
||||||
|
@ -42,7 +42,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let parl_io = ParlIoRxOnly::new(
|
let parl_io = ParlIoRxOnly::new(
|
||||||
peripherals.PARL_IO,
|
peripherals.PARL_IO,
|
||||||
dma_channel.configure_for_async(false, DmaPriority::Priority0),
|
dma_channel
|
||||||
|
.configure(false, DmaPriority::Priority0)
|
||||||
|
.into_async(),
|
||||||
rx_descriptors,
|
rx_descriptors,
|
||||||
1.MHz(),
|
1.MHz(),
|
||||||
)
|
)
|
||||||
|
@ -55,7 +55,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let parl_io = ParlIoTxOnly::new(
|
let parl_io = ParlIoTxOnly::new(
|
||||||
peripherals.PARL_IO,
|
peripherals.PARL_IO,
|
||||||
dma_channel.configure_for_async(false, DmaPriority::Priority0),
|
dma_channel
|
||||||
|
.configure(false, DmaPriority::Priority0)
|
||||||
|
.into_async(),
|
||||||
tx_descriptors,
|
tx_descriptors,
|
||||||
1.MHz(),
|
1.MHz(),
|
||||||
)
|
)
|
||||||
|
@ -15,7 +15,7 @@ use esp_backtrace as _;
|
|||||||
use esp_hal::{
|
use esp_hal::{
|
||||||
gpio::{Io, Level, Output},
|
gpio::{Io, Level, Output},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreatorAsync},
|
rmt::{PulseCode, Rmt, RxChannelAsync, RxChannelConfig, RxChannelCreatorAsync},
|
||||||
timer::timg::TimerGroup,
|
timer::timg::TimerGroup,
|
||||||
};
|
};
|
||||||
use esp_println::{print, println};
|
use esp_println::{print, println};
|
||||||
@ -54,7 +54,7 @@ async fn main(spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let rmt = Rmt::new_async(peripherals.RMT, freq).unwrap();
|
let rmt = Rmt::new(peripherals.RMT, freq).unwrap().into_async();
|
||||||
let rx_config = RxChannelConfig {
|
let rx_config = RxChannelConfig {
|
||||||
clk_divider: 255,
|
clk_divider: 255,
|
||||||
idle_threshold: 10000,
|
idle_threshold: 10000,
|
||||||
|
@ -17,7 +17,7 @@ use esp_backtrace as _;
|
|||||||
use esp_hal::{
|
use esp_hal::{
|
||||||
gpio::Io,
|
gpio::Io,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
rmt::{asynch::TxChannelAsync, PulseCode, Rmt, TxChannelConfig, TxChannelCreatorAsync},
|
rmt::{PulseCode, Rmt, TxChannelAsync, TxChannelConfig, TxChannelCreatorAsync},
|
||||||
timer::timg::TimerGroup,
|
timer::timg::TimerGroup,
|
||||||
};
|
};
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
@ -40,7 +40,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let rmt = Rmt::new_async(peripherals.RMT, freq).unwrap();
|
let rmt = Rmt::new(peripherals.RMT, freq).unwrap().into_async();
|
||||||
|
|
||||||
let mut channel = rmt
|
let mut channel = rmt
|
||||||
.channel0
|
.channel0
|
||||||
|
@ -97,7 +97,9 @@ async fn main(spawner: Spawner) {
|
|||||||
|
|
||||||
let config = Config::default().rx_fifo_full_threshold(READ_BUF_SIZE as u16);
|
let config = Config::default().rx_fifo_full_threshold(READ_BUF_SIZE as u16);
|
||||||
|
|
||||||
let mut uart0 = Uart::new_async_with_config(peripherals.UART0, config, rx_pin, tx_pin).unwrap();
|
let mut uart0 = Uart::new_with_config(peripherals.UART0, config, rx_pin, tx_pin)
|
||||||
|
.unwrap()
|
||||||
|
.into_async();
|
||||||
uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None));
|
uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None));
|
||||||
|
|
||||||
let (rx, tx) = uart0.split();
|
let (rx, tx) = uart0.split();
|
||||||
|
@ -63,8 +63,9 @@ async fn main(_spawner: Spawner) {
|
|||||||
.with_mosi(mosi)
|
.with_mosi(mosi)
|
||||||
.with_miso(miso)
|
.with_miso(miso)
|
||||||
.with_cs(cs)
|
.with_cs(cs)
|
||||||
.with_dma(dma_channel.configure_for_async(false, DmaPriority::Priority0))
|
.with_dma(dma_channel.configure(false, DmaPriority::Priority0))
|
||||||
.with_buffers(dma_rx_buf, dma_tx_buf);
|
.with_buffers(dma_rx_buf, dma_tx_buf)
|
||||||
|
.into_async();
|
||||||
|
|
||||||
let send_buffer = [0, 1, 2, 3, 4, 5, 6, 7];
|
let send_buffer = [0, 1, 2, 3, 4, 5, 6, 7];
|
||||||
loop {
|
loop {
|
||||||
|
@ -103,17 +103,18 @@ async fn main(spawner: Spawner) {
|
|||||||
// The speed of the bus.
|
// The speed of the bus.
|
||||||
const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K;
|
const TWAI_BAUDRATE: twai::BaudRate = twai::BaudRate::B125K;
|
||||||
|
|
||||||
// !!! Use `new_async` when using a transceiver. `new_async_no_transceiver` sets TX to open-drain
|
// !!! Use `new` when using a transceiver. `new_no_transceiver` sets TX to open-drain
|
||||||
|
|
||||||
// Begin configuring the TWAI peripheral. The peripheral is in a reset like
|
// Begin configuring the TWAI peripheral. The peripheral is in a reset like
|
||||||
// state that prevents transmission but allows configuration.
|
// state that prevents transmission but allows configuration.
|
||||||
let mut twai_config = twai::TwaiConfiguration::new_async_no_transceiver(
|
let mut twai_config = twai::TwaiConfiguration::new_no_transceiver(
|
||||||
peripherals.TWAI0,
|
peripherals.TWAI0,
|
||||||
rx_pin,
|
rx_pin,
|
||||||
tx_pin,
|
tx_pin,
|
||||||
TWAI_BAUDRATE,
|
TWAI_BAUDRATE,
|
||||||
TwaiMode::Normal,
|
TwaiMode::Normal,
|
||||||
);
|
)
|
||||||
|
.into_async();
|
||||||
|
|
||||||
// Partially filter the incoming messages to reduce overhead of receiving
|
// Partially filter the incoming messages to reduce overhead of receiving
|
||||||
// undesired messages. Note that due to how the hardware filters messages,
|
// undesired messages. Note that due to how the hardware filters messages,
|
||||||
|
@ -68,7 +68,9 @@ async fn main(spawner: Spawner) {
|
|||||||
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
||||||
esp_hal_embassy::init(timg0.timer0);
|
esp_hal_embassy::init(timg0.timer0);
|
||||||
|
|
||||||
let (rx, tx) = UsbSerialJtag::new_async(peripherals.USB_DEVICE).split();
|
let (rx, tx) = UsbSerialJtag::new(peripherals.USB_DEVICE)
|
||||||
|
.into_async()
|
||||||
|
.split();
|
||||||
|
|
||||||
static SIGNAL: StaticCell<Signal<NoopRawMutex, heapless::String<MAX_BUFFER_SIZE>>> =
|
static SIGNAL: StaticCell<Signal<NoopRawMutex, heapless::String<MAX_BUFFER_SIZE>>> =
|
||||||
StaticCell::new();
|
StaticCell::new();
|
||||||
|
@ -81,11 +81,13 @@ mod test {
|
|||||||
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
|
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
|
||||||
|
|
||||||
let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0)
|
let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0)
|
||||||
.with_dma(dma_channel1.configure_for_async(false, DmaPriority::Priority0))
|
.with_dma(dma_channel1.configure(false, DmaPriority::Priority0))
|
||||||
.with_buffers(dma_rx_buf, dma_tx_buf);
|
.with_buffers(dma_rx_buf, dma_tx_buf)
|
||||||
|
.into_async();
|
||||||
|
|
||||||
let spi2 = Spi::new(peripherals.SPI3, 100.kHz(), SpiMode::Mode0)
|
let spi2 = Spi::new(peripherals.SPI3, 100.kHz(), SpiMode::Mode0)
|
||||||
.with_dma(dma_channel2.configure_for_async(false, DmaPriority::Priority0));
|
.with_dma(dma_channel2.configure(false, DmaPriority::Priority0))
|
||||||
|
.into_async();
|
||||||
|
|
||||||
let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
|
let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
|
||||||
|
|
||||||
@ -144,9 +146,10 @@ mod test {
|
|||||||
.with_dma(
|
.with_dma(
|
||||||
peripherals
|
peripherals
|
||||||
.dma_channel
|
.dma_channel
|
||||||
.configure_for_async(false, DmaPriority::Priority0),
|
.configure(false, DmaPriority::Priority0),
|
||||||
)
|
)
|
||||||
.with_buffers(dma_rx_buf, dma_tx_buf);
|
.with_buffers(dma_rx_buf, dma_tx_buf)
|
||||||
|
.into_async();
|
||||||
|
|
||||||
let send_buffer = mk_static!([u8; BUFFER_SIZE], [0u8; BUFFER_SIZE]);
|
let send_buffer = mk_static!([u8; BUFFER_SIZE], [0u8; BUFFER_SIZE]);
|
||||||
loop {
|
loop {
|
||||||
|
@ -143,11 +143,11 @@ mod tests {
|
|||||||
Standard::Philips,
|
Standard::Philips,
|
||||||
DataFormat::Data16Channel16,
|
DataFormat::Data16Channel16,
|
||||||
16000.Hz(),
|
16000.Hz(),
|
||||||
ctx.dma_channel
|
ctx.dma_channel.configure(false, DmaPriority::Priority0),
|
||||||
.configure_for_async(false, DmaPriority::Priority0),
|
|
||||||
rx_descriptors,
|
rx_descriptors,
|
||||||
tx_descriptors,
|
tx_descriptors,
|
||||||
);
|
)
|
||||||
|
.into_async();
|
||||||
|
|
||||||
let (_, dout) = hil_test::common_test_pins!(ctx.io);
|
let (_, dout) = hil_test::common_test_pins!(ctx.io);
|
||||||
|
|
||||||
|
@ -19,13 +19,14 @@ use esp_hal::{
|
|||||||
Pcnt,
|
Pcnt,
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
Blocking,
|
||||||
};
|
};
|
||||||
use hil_test as _;
|
use hil_test as _;
|
||||||
|
|
||||||
const DATA_SIZE: usize = 1024 * 10;
|
const DATA_SIZE: usize = 1024 * 10;
|
||||||
|
|
||||||
struct Context<'d> {
|
struct Context<'d> {
|
||||||
lcd_cam: LcdCam<'d, esp_hal::Blocking>,
|
lcd_cam: LcdCam<'d, Blocking>,
|
||||||
pcnt: Pcnt<'d>,
|
pcnt: Pcnt<'d>,
|
||||||
io: Io,
|
io: Io,
|
||||||
dma: Dma<'d>,
|
dma: Dma<'d>,
|
||||||
@ -79,7 +80,8 @@ mod tests {
|
|||||||
let channel = ctx
|
let channel = ctx
|
||||||
.dma
|
.dma
|
||||||
.channel0
|
.channel0
|
||||||
.configure_for_async(false, DmaPriority::Priority0);
|
.configure(false, DmaPriority::Priority0)
|
||||||
|
.into_async();
|
||||||
let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin);
|
let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin);
|
||||||
|
|
||||||
let i8080 = I8080::new(
|
let i8080 = I8080::new(
|
||||||
|
@ -15,13 +15,14 @@ use esp_hal::{
|
|||||||
LcdCam,
|
LcdCam,
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
Async,
|
||||||
};
|
};
|
||||||
use hil_test as _;
|
use hil_test as _;
|
||||||
|
|
||||||
const DATA_SIZE: usize = 1024 * 10;
|
const DATA_SIZE: usize = 1024 * 10;
|
||||||
|
|
||||||
struct Context<'d> {
|
struct Context<'d> {
|
||||||
lcd_cam: LcdCam<'d, esp_hal::Async>,
|
lcd_cam: LcdCam<'d, Async>,
|
||||||
dma: Dma<'d>,
|
dma: Dma<'d>,
|
||||||
dma_buf: DmaTxBuf,
|
dma_buf: DmaTxBuf,
|
||||||
}
|
}
|
||||||
@ -36,7 +37,7 @@ mod tests {
|
|||||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||||
|
|
||||||
let dma = Dma::new(peripherals.DMA);
|
let dma = Dma::new(peripherals.DMA);
|
||||||
let lcd_cam = LcdCam::new_async(peripherals.LCD_CAM);
|
let lcd_cam = LcdCam::new(peripherals.LCD_CAM).into_async();
|
||||||
let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, DATA_SIZE);
|
let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, DATA_SIZE);
|
||||||
let dma_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
|
let dma_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
|
||||||
|
|
||||||
@ -75,7 +76,8 @@ mod tests {
|
|||||||
let channel = ctx
|
let channel = ctx
|
||||||
.dma
|
.dma
|
||||||
.channel0
|
.channel0
|
||||||
.configure_for_async(false, DmaPriority::Priority0);
|
.configure(false, DmaPriority::Priority0)
|
||||||
|
.into_async();
|
||||||
let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin);
|
let pins = TxEightBits::new(NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin, NoPin);
|
||||||
|
|
||||||
let i8080 = I8080::new(
|
let i8080 = I8080::new(
|
||||||
|
@ -92,7 +92,8 @@ mod tests {
|
|||||||
let pio = ParlIoTxOnly::new(
|
let pio = ParlIoTxOnly::new(
|
||||||
ctx.parl_io,
|
ctx.parl_io,
|
||||||
ctx.dma_channel
|
ctx.dma_channel
|
||||||
.configure_for_async(false, DmaPriority::Priority0),
|
.configure(false, DmaPriority::Priority0)
|
||||||
|
.into_async(),
|
||||||
tx_descriptors,
|
tx_descriptors,
|
||||||
10.MHz(),
|
10.MHz(),
|
||||||
)
|
)
|
||||||
@ -159,7 +160,8 @@ mod tests {
|
|||||||
let pio = ParlIoTxOnly::new(
|
let pio = ParlIoTxOnly::new(
|
||||||
ctx.parl_io,
|
ctx.parl_io,
|
||||||
ctx.dma_channel
|
ctx.dma_channel
|
||||||
.configure_for_async(false, DmaPriority::Priority0),
|
.configure(false, DmaPriority::Priority0)
|
||||||
|
.into_async(),
|
||||||
tx_descriptors,
|
tx_descriptors,
|
||||||
10.MHz(),
|
10.MHz(),
|
||||||
)
|
)
|
||||||
|
@ -56,7 +56,7 @@ mod tests {
|
|||||||
#[init]
|
#[init]
|
||||||
fn init() -> Context<'static> {
|
fn init() -> Context<'static> {
|
||||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
let peripherals = esp_hal::init(esp_hal::Config::default());
|
||||||
let mut rsa = Rsa::new_async(peripherals.RSA);
|
let mut rsa = Rsa::new(peripherals.RSA).into_async();
|
||||||
nb::block!(rsa.ready()).unwrap();
|
nb::block!(rsa.ready()).unwrap();
|
||||||
|
|
||||||
Context { rsa }
|
Context { rsa }
|
||||||
|
@ -18,6 +18,7 @@ use esp_hal::{
|
|||||||
peripheral::Peripheral,
|
peripheral::Peripheral,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
spi::{master::Spi, SpiMode},
|
spi::{master::Spi, SpiMode},
|
||||||
|
Blocking,
|
||||||
};
|
};
|
||||||
#[cfg(pcnt)]
|
#[cfg(pcnt)]
|
||||||
use esp_hal::{
|
use esp_hal::{
|
||||||
@ -35,7 +36,7 @@ cfg_if::cfg_if! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
spi: Spi<'static>,
|
spi: Spi<'static, Blocking>,
|
||||||
dma_channel: DmaChannelCreator,
|
dma_channel: DmaChannelCreator,
|
||||||
// Reuse the really large buffer so we don't run out of DRAM with many tests
|
// Reuse the really large buffer so we don't run out of DRAM with many tests
|
||||||
rx_buffer: &'static mut [u8],
|
rx_buffer: &'static mut [u8],
|
||||||
@ -392,11 +393,9 @@ mod tests {
|
|||||||
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
|
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
|
||||||
let mut spi = ctx
|
let mut spi = ctx
|
||||||
.spi
|
.spi
|
||||||
.with_dma(
|
.with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0))
|
||||||
ctx.dma_channel
|
.with_buffers(dma_rx_buf, dma_tx_buf)
|
||||||
.configure_for_async(false, DmaPriority::Priority0),
|
.into_async();
|
||||||
)
|
|
||||||
.with_buffers(dma_rx_buf, dma_tx_buf);
|
|
||||||
|
|
||||||
ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source);
|
ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source);
|
||||||
ctx.pcnt_unit
|
ctx.pcnt_unit
|
||||||
@ -428,11 +427,9 @@ mod tests {
|
|||||||
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
|
let dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();
|
||||||
let mut spi = ctx
|
let mut spi = ctx
|
||||||
.spi
|
.spi
|
||||||
.with_dma(
|
.with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0))
|
||||||
ctx.dma_channel
|
.with_buffers(dma_rx_buf, dma_tx_buf)
|
||||||
.configure_for_async(false, DmaPriority::Priority0),
|
.into_async();
|
||||||
)
|
|
||||||
.with_buffers(dma_rx_buf, dma_tx_buf);
|
|
||||||
|
|
||||||
ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source);
|
ctx.pcnt_unit.channel0.set_edge_signal(ctx.pcnt_source);
|
||||||
ctx.pcnt_unit
|
ctx.pcnt_unit
|
||||||
@ -557,10 +554,10 @@ mod tests {
|
|||||||
let dma_rx_buf = DmaRxBuf::new(ctx.rx_descriptors, ctx.rx_buffer).unwrap();
|
let dma_rx_buf = DmaRxBuf::new(ctx.rx_descriptors, ctx.rx_buffer).unwrap();
|
||||||
let dma_tx_buf = DmaTxBuf::new(ctx.tx_descriptors, ctx.tx_buffer).unwrap();
|
let dma_tx_buf = DmaTxBuf::new(ctx.tx_descriptors, ctx.tx_buffer).unwrap();
|
||||||
|
|
||||||
let spi = ctx.spi.with_dma(
|
let spi = ctx
|
||||||
ctx.dma_channel
|
.spi
|
||||||
.configure_for_async(false, DmaPriority::Priority0),
|
.with_dma(ctx.dma_channel.configure(false, DmaPriority::Priority0))
|
||||||
);
|
.into_async();
|
||||||
|
|
||||||
let mut transfer = spi
|
let mut transfer = spi
|
||||||
.transfer(dma_rx_buf, dma_tx_buf)
|
.transfer(dma_rx_buf, dma_tx_buf)
|
||||||
|
@ -13,6 +13,7 @@ use esp_hal::{
|
|||||||
dma_buffers,
|
dma_buffers,
|
||||||
gpio::{interconnect::InputSignal, Io, Level, Output},
|
gpio::{interconnect::InputSignal, Io, Level, Output},
|
||||||
spi::{slave::Spi, SpiMode},
|
spi::{slave::Spi, SpiMode},
|
||||||
|
Blocking,
|
||||||
};
|
};
|
||||||
use hil_test as _;
|
use hil_test as _;
|
||||||
|
|
||||||
@ -25,7 +26,7 @@ cfg_if::cfg_if! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
spi: Spi<'static>,
|
spi: Spi<'static, Blocking>,
|
||||||
dma_channel: DmaChannelCreator,
|
dma_channel: DmaChannelCreator,
|
||||||
bitbang_spi: BitbangSpi,
|
bitbang_spi: BitbangSpi,
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ mod tests {
|
|||||||
|
|
||||||
let (rx, tx) = hil_test::common_test_pins!(io);
|
let (rx, tx) = hil_test::common_test_pins!(io);
|
||||||
|
|
||||||
let uart = Uart::new_async(peripherals.UART0, rx, tx).unwrap();
|
let uart = Uart::new(peripherals.UART0, rx, tx).unwrap().into_async();
|
||||||
|
|
||||||
Context { uart }
|
Context { uart }
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,8 @@ mod tests {
|
|||||||
|
|
||||||
let (rx, tx) = hil_test::common_test_pins!(io);
|
let (rx, tx) = hil_test::common_test_pins!(io);
|
||||||
|
|
||||||
let tx = UartTx::new_async(peripherals.UART0, tx).unwrap();
|
let tx = UartTx::new(peripherals.UART0, tx).unwrap().into_async();
|
||||||
let rx = UartRx::new_async(peripherals.UART1, rx).unwrap();
|
let rx = UartRx::new(peripherals.UART1, rx).unwrap().into_async();
|
||||||
|
|
||||||
Context { rx, tx }
|
Context { rx, tx }
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ mod tests {
|
|||||||
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
||||||
esp_hal_embassy::init(timg0.timer0);
|
esp_hal_embassy::init(timg0.timer0);
|
||||||
|
|
||||||
_ = UsbSerialJtag::new_async(peripherals.USB_DEVICE).split();
|
_ = UsbSerialJtag::new(peripherals.USB_DEVICE)
|
||||||
|
.into_async()
|
||||||
|
.split();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user