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