Refactor I2S driver to take DmaDescriptors later in construction (#3324)

* Refactor I2S driver to take `DmaDescriptor`s later in construction

* unused import

* stray test
This commit is contained in:
Dominic Fischer 2025-04-03 08:53:56 +01:00 committed by GitHub
parent faf7115b0c
commit 5cec008506
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 59 additions and 57 deletions

View File

@ -22,7 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `esp_hal::i2c::master::AnyI2c` has been moved to `esp_hal::i2c::AnyI2c` (#3226) - `esp_hal::i2c::master::AnyI2c` has been moved to `esp_hal::i2c::AnyI2c` (#3226)
- `SpiDmaBus` no longer adjusts the DMA buffer length for each transfer (#3263) - `SpiDmaBus` no longer adjusts the DMA buffer length for each transfer (#3263)
- `SpiDma<Async>` now uses the SPI interrupt (instead of DMA) to wait for completion (#3303) - `SpiDma<Async>` now uses the SPI interrupt (instead of DMA) to wait for completion (#3303)
- I2S driver now takes `DmaDescriptor`s later in construction (#3324)
- `gpio::interconnect` types now have a lifetime associated with them (#3302) - `gpio::interconnect` types now have a lifetime associated with them (#3302)
- The `critical-section` implementation is now gated behind the `critical-section-impl` feature (#3293) - The `critical-section` implementation is now gated behind the `critical-section-impl` feature (#3293)

View File

@ -21,3 +21,33 @@ traits are now implemented for GPIO pins (stably) and driver structs (unstably)
This change means it's no longer possible to pass a reference to a GPIO driver to a peripheral This change means it's no longer possible to pass a reference to a GPIO driver to a peripheral
driver. For example, it's no longer possible to pass an `&mut Input` to `Spi::with_miso`. driver. For example, it's no longer possible to pass an `&mut Input` to `Spi::with_miso`.
## I2S driver now takes `DmaDescriptor`s later in construction
```diff
let i2s = I2s::new(
peripherals.I2S0,
Standard::Philips,
DataFormat::Data16Channel16,
Rate::from_hz(44100),
dma_channel,
- rx_descriptors,
- tx_descriptors,
);
let i2s_tx = i2s
.i2s_tx
.with_bclk(peripherals.GPIO2)
.with_ws(peripherals.GPIO4)
.with_dout(peripherals.GPIO5)
- .build();
+ .build(tx_descriptors);
let i2s_rx = i2s
.i2s_rx
.with_bclk(peripherals.GPIO2)
.with_ws(peripherals.GPIO4)
.with_din(peripherals.GPIO5)
- .build();
+ .build(rx_descriptors);
```

View File

@ -36,8 +36,7 @@
not(any(esp32, esp32s2)), not(any(esp32, esp32s2)),
doc = "let dma_channel = peripherals.DMA_CH0;" doc = "let dma_channel = peripherals.DMA_CH0;"
)] )]
//! let (mut rx_buffer, rx_descriptors, _, tx_descriptors) = //! let (mut rx_buffer, rx_descriptors, _, _) = dma_buffers!(4 * 4092, 0);
//! dma_buffers!(0, 4 * 4092);
//! //!
//! let i2s = I2s::new( //! let i2s = I2s::new(
//! peripherals.I2S0, //! peripherals.I2S0,
@ -45,15 +44,13 @@
//! DataFormat::Data16Channel16, //! DataFormat::Data16Channel16,
//! Rate::from_hz(44100), //! Rate::from_hz(44100),
//! dma_channel, //! dma_channel,
//! rx_descriptors,
//! tx_descriptors,
//! ); //! );
#![cfg_attr(not(esp32), doc = "let i2s = i2s.with_mclk(peripherals.GPIO0);")] #![cfg_attr(not(esp32), doc = "let i2s = i2s.with_mclk(peripherals.GPIO0);")]
//! let mut i2s_rx = i2s.i2s_rx //! let mut i2s_rx = i2s.i2s_rx
//! .with_bclk(peripherals.GPIO1) //! .with_bclk(peripherals.GPIO1)
//! .with_ws(peripherals.GPIO2) //! .with_ws(peripherals.GPIO2)
//! .with_din(peripherals.GPIO5) //! .with_din(peripherals.GPIO5)
//! .build(); //! .build(rx_descriptors);
//! //!
//! let mut transfer = i2s_rx.read_dma_circular(&mut rx_buffer)?; //! let mut transfer = i2s_rx.read_dma_circular(&mut rx_buffer)?;
//! //!
@ -83,7 +80,6 @@ use crate::{
ChannelTx, ChannelTx,
DescriptorChain, DescriptorChain,
DmaChannelFor, DmaChannelFor,
DmaDescriptor,
DmaEligible, DmaEligible,
DmaError, DmaError,
DmaTransferRx, DmaTransferRx,
@ -336,8 +332,6 @@ impl<'d> I2s<'d, Blocking> {
data_format: DataFormat, data_format: DataFormat,
sample_rate: Rate, sample_rate: Rate,
channel: impl Peripheral<P = CH> + 'd, channel: impl Peripheral<P = CH> + 'd,
rx_descriptors: &'static mut [DmaDescriptor],
tx_descriptors: &'static mut [DmaDescriptor],
) -> Self ) -> Self
where where
CH: DmaChannelFor<AnyI2s>, CH: DmaChannelFor<AnyI2s>,
@ -367,13 +361,11 @@ impl<'d> I2s<'d, Blocking> {
i2s_rx: RxCreator { i2s_rx: RxCreator {
i2s: unsafe { i2s.clone_unchecked() }, i2s: unsafe { i2s.clone_unchecked() },
rx_channel: channel.rx, rx_channel: channel.rx,
descriptors: rx_descriptors,
guard: rx_guard, guard: rx_guard,
}, },
i2s_tx: TxCreator { i2s_tx: TxCreator {
i2s, i2s,
tx_channel: channel.tx, tx_channel: channel.tx,
descriptors: tx_descriptors,
guard: tx_guard, guard: tx_guard,
}, },
} }
@ -385,13 +377,11 @@ impl<'d> I2s<'d, Blocking> {
i2s_rx: RxCreator { i2s_rx: RxCreator {
i2s: self.i2s_rx.i2s, i2s: self.i2s_rx.i2s,
rx_channel: self.i2s_rx.rx_channel.into_async(), rx_channel: self.i2s_rx.rx_channel.into_async(),
descriptors: self.i2s_rx.descriptors,
guard: self.i2s_rx.guard, guard: self.i2s_rx.guard,
}, },
i2s_tx: TxCreator { i2s_tx: TxCreator {
i2s: self.i2s_tx.i2s, i2s: self.i2s_tx.i2s,
tx_channel: self.i2s_tx.tx_channel.into_async(), tx_channel: self.i2s_tx.tx_channel.into_async(),
descriptors: self.i2s_tx.descriptors,
guard: self.i2s_tx.guard, guard: self.i2s_tx.guard,
}, },
} }
@ -711,7 +701,6 @@ mod private {
{ {
pub i2s: PeripheralRef<'d, AnyI2s>, pub i2s: PeripheralRef<'d, AnyI2s>,
pub tx_channel: ChannelTx<'d, Dm, PeripheralTxChannel<AnyI2s>>, pub tx_channel: ChannelTx<'d, Dm, PeripheralTxChannel<AnyI2s>>,
pub descriptors: &'static mut [DmaDescriptor],
pub(crate) guard: PeripheralGuard, pub(crate) guard: PeripheralGuard,
} }
@ -719,12 +708,12 @@ mod private {
where where
Dm: DriverMode, Dm: DriverMode,
{ {
pub fn build(self) -> I2sTx<'d, Dm> { pub fn build(self, descriptors: &'static mut [DmaDescriptor]) -> I2sTx<'d, Dm> {
let peripheral = self.i2s.peripheral(); let peripheral = self.i2s.peripheral();
I2sTx { I2sTx {
i2s: self.i2s, i2s: self.i2s,
tx_channel: self.tx_channel, tx_channel: self.tx_channel,
tx_chain: DescriptorChain::new(self.descriptors), tx_chain: DescriptorChain::new(descriptors),
_guard: PeripheralGuard::new(peripheral), _guard: PeripheralGuard::new(peripheral),
} }
} }
@ -760,7 +749,6 @@ mod private {
{ {
pub i2s: PeripheralRef<'d, AnyI2s>, pub i2s: PeripheralRef<'d, AnyI2s>,
pub rx_channel: ChannelRx<'d, Dm, PeripheralRxChannel<AnyI2s>>, pub rx_channel: ChannelRx<'d, Dm, PeripheralRxChannel<AnyI2s>>,
pub descriptors: &'static mut [DmaDescriptor],
pub(crate) guard: PeripheralGuard, pub(crate) guard: PeripheralGuard,
} }
@ -768,12 +756,12 @@ mod private {
where where
Dm: DriverMode, Dm: DriverMode,
{ {
pub fn build(self) -> I2sRx<'d, Dm> { pub fn build(self, descriptors: &'static mut [DmaDescriptor]) -> I2sRx<'d, Dm> {
let peripheral = self.i2s.peripheral(); let peripheral = self.i2s.peripheral();
I2sRx { I2sRx {
i2s: self.i2s, i2s: self.i2s,
rx_channel: self.rx_channel, rx_channel: self.rx_channel,
rx_chain: DescriptorChain::new(self.descriptors), rx_chain: DescriptorChain::new(descriptors),
_guard: PeripheralGuard::new(peripheral), _guard: PeripheralGuard::new(peripheral),
} }
} }

View File

@ -67,7 +67,9 @@ async fn interrupt_driven_task(spi: esp_hal::spi::master::SpiDma<'static, Blocki
#[cfg(not(any(esp32, esp32s2, esp32s3)))] #[cfg(not(any(esp32, esp32s2, esp32s3)))]
#[embassy_executor::task] #[embassy_executor::task]
async fn interrupt_driven_task(i2s_tx: esp_hal::i2s::master::I2s<'static, Blocking>) { async fn interrupt_driven_task(i2s_tx: esp_hal::i2s::master::I2s<'static, Blocking>) {
let mut i2s_tx = i2s_tx.into_async().i2s_tx.build(); let (_, _, _, tx_descriptors) = dma_buffers!(128);
let mut i2s_tx = i2s_tx.into_async().i2s_tx.build(tx_descriptors);
loop { loop {
let mut buffer: [u8; 8] = [0; 8]; let mut buffer: [u8; 8] = [0; 8];
@ -151,19 +153,13 @@ mod test {
.with_dma(dma_channel2); .with_dma(dma_channel2);
#[cfg(not(any(esp32, esp32s2, esp32s3)))] #[cfg(not(any(esp32, esp32s2, esp32s3)))]
let other_peripheral = { let other_peripheral = esp_hal::i2s::master::I2s::new(
let (_, rx_descriptors, _, tx_descriptors) = dma_buffers!(128);
esp_hal::i2s::master::I2s::new(
peripherals.I2S0, peripherals.I2S0,
esp_hal::i2s::master::Standard::Philips, esp_hal::i2s::master::Standard::Philips,
esp_hal::i2s::master::DataFormat::Data8Channel8, esp_hal::i2s::master::DataFormat::Data8Channel8,
Rate::from_khz(8), Rate::from_khz(8),
dma_channel2, dma_channel2,
rx_descriptors, );
tx_descriptors,
)
};
let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);

View File

@ -141,8 +141,6 @@ mod tests {
DataFormat::Data16Channel16, DataFormat::Data16Channel16,
Rate::from_hz(16000), Rate::from_hz(16000),
ctx.dma_channel, ctx.dma_channel,
rx_descriptors,
tx_descriptors,
) )
.into_async(); .into_async();
@ -153,14 +151,14 @@ mod tests {
.with_bclk(NoPin) .with_bclk(NoPin)
.with_ws(NoPin) .with_ws(NoPin)
.with_dout(dout) .with_dout(dout)
.build(); .build(tx_descriptors);
let i2s_rx = i2s let i2s_rx = i2s
.i2s_rx .i2s_rx
.with_bclk(NoPin) .with_bclk(NoPin)
.with_ws(NoPin) .with_ws(NoPin)
.with_din(din) .with_din(din)
.build(); .build(rx_descriptors);
enable_loopback(); enable_loopback();
@ -194,8 +192,6 @@ mod tests {
DataFormat::Data16Channel16, DataFormat::Data16Channel16,
Rate::from_hz(16000), Rate::from_hz(16000),
ctx.dma_channel, ctx.dma_channel,
rx_descriptors,
tx_descriptors,
); );
let (din, dout) = ctx.dout.split(); let (din, dout) = ctx.dout.split();
@ -205,14 +201,14 @@ mod tests {
.with_bclk(NoPin) .with_bclk(NoPin)
.with_ws(NoPin) .with_ws(NoPin)
.with_dout(dout) .with_dout(dout)
.build(); .build(tx_descriptors);
let mut i2s_rx = i2s let mut i2s_rx = i2s
.i2s_rx .i2s_rx
.with_bclk(NoPin) .with_bclk(NoPin)
.with_ws(NoPin) .with_ws(NoPin)
.with_din(din) .with_din(din)
.build(); .build(rx_descriptors);
enable_loopback(); enable_loopback();
@ -295,7 +291,7 @@ mod tests {
#[test] #[test]
fn test_i2s_push_too_late(ctx: Context) { fn test_i2s_push_too_late(ctx: Context) {
let (_, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(0, 16000); let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 16000);
let i2s = I2s::new( let i2s = I2s::new(
ctx.i2s, ctx.i2s,
@ -303,8 +299,6 @@ mod tests {
DataFormat::Data16Channel16, DataFormat::Data16Channel16,
Rate::from_hz(16000), Rate::from_hz(16000),
ctx.dma_channel, ctx.dma_channel,
rx_descriptors,
tx_descriptors,
); );
let mut i2s_tx = i2s let mut i2s_tx = i2s
@ -312,7 +306,7 @@ mod tests {
.with_bclk(NoPin) .with_bclk(NoPin)
.with_ws(NoPin) .with_ws(NoPin)
.with_dout(ctx.dout) .with_dout(ctx.dout)
.build(); .build(tx_descriptors);
let mut tx_transfer = i2s_tx.write_dma_circular(tx_buffer).unwrap(); let mut tx_transfer = i2s_tx.write_dma_circular(tx_buffer).unwrap();
@ -325,7 +319,7 @@ mod tests {
#[test] #[test]
#[timeout(1)] #[timeout(1)]
fn test_i2s_read_too_late(ctx: Context) { fn test_i2s_read_too_late(ctx: Context) {
let (rx_buffer, rx_descriptors, _, tx_descriptors) = dma_buffers!(16000, 0); let (rx_buffer, rx_descriptors, _, _) = dma_buffers!(16000, 0);
let i2s = I2s::new( let i2s = I2s::new(
ctx.i2s, ctx.i2s,
@ -333,8 +327,6 @@ mod tests {
DataFormat::Data16Channel16, DataFormat::Data16Channel16,
Rate::from_hz(16000), Rate::from_hz(16000),
ctx.dma_channel, ctx.dma_channel,
rx_descriptors,
tx_descriptors,
); );
let mut i2s_rx = i2s let mut i2s_rx = i2s
@ -342,7 +334,7 @@ mod tests {
.with_bclk(NoPin) .with_bclk(NoPin)
.with_ws(NoPin) .with_ws(NoPin)
.with_din(ctx.dout) // not a typo .with_din(ctx.dout) // not a typo
.build(); .build(rx_descriptors);
let mut buffer = [0u8; 1024]; let mut buffer = [0u8; 1024];
let mut rx_transfer = i2s_rx.read_dma_circular(rx_buffer).unwrap(); let mut rx_transfer = i2s_rx.read_dma_circular(rx_buffer).unwrap();

View File

@ -42,7 +42,7 @@ async fn main(_spawner: Spawner) {
} }
} }
let (rx_buffer, rx_descriptors, _, tx_descriptors) = dma_buffers!(4092 * 4, 0); let (rx_buffer, rx_descriptors, _, _) = dma_buffers!(4092 * 4, 0);
let i2s = I2s::new( let i2s = I2s::new(
peripherals.I2S0, peripherals.I2S0,
@ -50,8 +50,6 @@ async fn main(_spawner: Spawner) {
DataFormat::Data16Channel16, DataFormat::Data16Channel16,
Rate::from_hz(44100), Rate::from_hz(44100),
dma_channel, dma_channel,
rx_descriptors,
tx_descriptors,
) )
.into_async(); .into_async();
@ -63,7 +61,7 @@ async fn main(_spawner: Spawner) {
.with_bclk(peripherals.GPIO2) .with_bclk(peripherals.GPIO2)
.with_ws(peripherals.GPIO4) .with_ws(peripherals.GPIO4)
.with_din(peripherals.GPIO5) .with_din(peripherals.GPIO5)
.build(); .build(rx_descriptors);
let buffer = rx_buffer; let buffer = rx_buffer;
println!("Start"); println!("Start");

View File

@ -64,7 +64,7 @@ async fn main(_spawner: Spawner) {
} }
} }
let (_, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000); let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000);
let i2s = I2s::new( let i2s = I2s::new(
peripherals.I2S0, peripherals.I2S0,
@ -72,8 +72,6 @@ async fn main(_spawner: Spawner) {
DataFormat::Data16Channel16, DataFormat::Data16Channel16,
Rate::from_hz(44100), Rate::from_hz(44100),
dma_channel, dma_channel,
rx_descriptors,
tx_descriptors,
) )
.into_async(); .into_async();
@ -82,7 +80,7 @@ async fn main(_spawner: Spawner) {
.with_bclk(peripherals.GPIO2) .with_bclk(peripherals.GPIO2)
.with_ws(peripherals.GPIO4) .with_ws(peripherals.GPIO4)
.with_dout(peripherals.GPIO5) .with_dout(peripherals.GPIO5)
.build(); .build(tx_descriptors);
let data = let data =
unsafe { core::slice::from_raw_parts(&SINE as *const _ as *const u8, SINE.len() * 2) }; unsafe { core::slice::from_raw_parts(&SINE as *const _ as *const u8, SINE.len() * 2) };