Skip to content

Commit

Permalink
stm32,esp32: In machine_i2s, send null samples in underflow situations.
Browse files Browse the repository at this point in the history
Eliminate noise data from being sent to the I2S peripheral when the
transmitted sample stream is stopped.

Signed-off-by: Mike Teachman <mike.teachman@gmail.com>
  • Loading branch information
miketeachman authored and dpgeorge committed Nov 12, 2021
1 parent 6d9da27 commit 0be3b91
Show file tree
Hide file tree
Showing 2 changed files with 4 additions and 0 deletions.
1 change: 1 addition & 0 deletions ports/esp32/machine_i2s.c
Expand Up @@ -448,6 +448,7 @@ STATIC void machine_i2s_init_helper(machine_i2s_obj_t *self, size_t n_pos_args,
i2s_config.dma_buf_count = get_dma_buf_count(mode, bits, format, self->ibuf);
i2s_config.dma_buf_len = DMA_BUF_LEN_IN_I2S_FRAMES;
i2s_config.use_apll = false;
i2s_config.tx_desc_auto_clear = true;

This comment has been minimized.

Copy link
@cherrydev

cherrydev Dec 2, 2021

@miketeachman Unfortunately I can confirm that there is still "noise" being sent over the line after the ibuf empties. The difference now is that previously, when using async mode, it would endlessly repeat the entire buffer, but now it behaves in the same way as blocking and non-blocking mode, where it repeats only the first several bytes of the buffer, pauses a few ms, then repeats this twice before finally stopping. Here's a LA trace where I'm driving WS2812 LEDs with the i2s driver, similarly to the FastLED library. The gap between the main signal and the 3 additional ones corresponds to the part of the buffer that is empty. The workaround that I've found is to deinit() the entire i2s driver during that gap. Since I'm not sending a continuous stream, it might be appropriate for me to send some sort of explicit stop signal, but I currently have no way of knowing when the buffer is empty. I only know when the data has been finished copied from python code into the buffer (by awaiting on stream.drain(). So I need to guess based on the size of the buffer, the rate, and some slop for latency.
I'm eager to help out fixing this, but honestly, the ESP32 docs on the i2s interface are very sparse. I can look into the FastLED library to see how they do it, when I get a chance.
image


// I2S queue size equals the number of DMA buffers
check_esp_err(i2s_driver_install(self->port, &i2s_config, i2s_config.dma_buf_count, &self->i2s_event_queue));
Expand Down
3 changes: 3 additions & 0 deletions ports/stm32/machine_i2s.c
Expand Up @@ -509,6 +509,9 @@ STATIC void feed_dma(machine_i2s_obj_t *self, ping_pong_t dma_ping_pong) {
if (self->bits == 32) {
reformat_32_bit_samples((int32_t *)dma_buffer_p, SIZEOF_HALF_DMA_BUFFER_IN_BYTES / (sizeof(uint32_t)));
}
} else {
// underflow. clear buffer to transmit "silence" on the I2S bus
memset(dma_buffer_p, 0, SIZEOF_HALF_DMA_BUFFER_IN_BYTES);
}

// flush cache to RAM so DMA can read the sample data
Expand Down

0 comments on commit 0be3b91

Please sign in to comment.