Skip to content

Commit bdc8a16

Browse files
committed
fix: i2s pushing not respecting available size
1 parent 37d75b8 commit bdc8a16

File tree

2 files changed

+17
-8
lines changed

2 files changed

+17
-8
lines changed

esp-hal/src/dma/buffers.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1435,6 +1435,7 @@ impl DmaTxStreamBuf {
14351435
let mut chunks = buffer.chunks_exact_mut(chunk_size);
14361436
for (desc, chunk) in descriptors.iter_mut().zip(chunks.by_ref()) {
14371437
desc.buffer = chunk.as_mut_ptr();
1438+
desc.set_owner(Owner::Dma);
14381439
desc.set_size(chunk.len());
14391440
}
14401441
let remainder = chunks.into_remainder();
@@ -1529,7 +1530,8 @@ impl DmaTxStreamBufView {
15291530
pub fn push_with(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> usize {
15301531
let chunk_size = self.buf.descriptors[0].size();
15311532
let dma_start = self.descriptor_idx * chunk_size + self.descriptor_offset;
1532-
let bytes_pushed = f(&mut self.buf.buffer[dma_start..]);
1533+
let dma_end = (dma_start + self.available_bytes()).min(self.buf.buffer.len());
1534+
let bytes_pushed = f(&mut self.buf.buffer[dma_start..dma_end]);
15331535

15341536
let mut bytes_filled = 0;
15351537
for d in (self.descriptor_idx..self.buf.descriptors.len()).chain(core::iter::once(0)) {

hil-test/tests/i2s.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use esp_hal::{
1414
Async,
1515
delay::Delay,
1616
dma::{DmaDescriptor, DmaTxStreamBuf},
17-
dma_buffers,
1817
gpio::{AnyPin, NoPin, Pin},
1918
i2s::master::{DataFormat, I2s, I2sTx, Standard},
2019
peripherals::I2S0,
@@ -75,7 +74,9 @@ async fn writer(
7574
.unwrap();
7675

7776
loop {
78-
tx_transfer.wait_for_available().await.unwrap();
77+
while tx_transfer.available_bytes() == 0 {
78+
tx_transfer.wait_for_available().await.unwrap();
79+
}
7980
tx_transfer.push_with(|buffer| {
8081
for b in buffer.iter_mut() {
8182
*b = samples.next().unwrap();
@@ -104,7 +105,7 @@ fn enable_loopback() {
104105
#[cfg(test)]
105106
#[embedded_test::tests(default_timeout = 3, executor = hil_test::Executor::new())]
106107
mod tests {
107-
use esp_hal::dma::DmaRxStreamBuf;
108+
use esp_hal::{dma::DmaRxStreamBuf, dma_buffers_chunk_size};
108109

109110
use super::*;
110111

@@ -141,8 +142,9 @@ mod tests {
141142
async fn test_i2s_loopback_async(ctx: Context) {
142143
let spawner = embassy_executor::Spawner::for_current_executor().await;
143144

145+
// We need more than 3 descriptors for continuous transfer to work
144146
let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) =
145-
esp_hal::dma_circular_buffers!(BUFFER_SIZE, BUFFER_SIZE);
147+
esp_hal::dma_buffers_chunk_size!(BUFFER_SIZE, BUFFER_SIZE, BUFFER_SIZE / 3);
146148

147149
let i2s = I2s::new(
148150
ctx.i2s,
@@ -179,11 +181,12 @@ mod tests {
179181
.unwrap();
180182
spawner.must_spawn(writer(tx_buffer, tx_descriptors, i2s_tx));
181183

182-
// let mut rcv = [0u8; BUFFER_SIZE];
183184
let mut sample_idx = 0;
184185
let mut samples = SampleSource::new();
185186
for _ in 0..30 {
186-
rx_transfer.wait_for_available().await.unwrap();
187+
while rx_transfer.available_bytes() == 0 {
188+
rx_transfer.wait_for_available().await.unwrap();
189+
}
187190
let data = rx_transfer.peek();
188191
let len = data.len();
189192
for &b in data {
@@ -201,7 +204,11 @@ mod tests {
201204

202205
#[test]
203206
fn test_i2s_loopback(ctx: Context) {
204-
let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) = dma_buffers!(16000, 16000);
207+
// NOTE: 32000 bits of buffer maybe too large, but for some reason it fails with buffer
208+
// size 16000 as it seems DMA can be quick enough to run out of descriptors in that
209+
// case.
210+
let (rx_buffer, rx_descriptors, tx_buffer, tx_descriptors) =
211+
dma_buffers_chunk_size!(32000, 32000, 4000);
205212

206213
let i2s = I2s::new(
207214
ctx.i2s,

0 commit comments

Comments
 (0)