From acf9482c1d19f5d6dc2f7261e73e45ccc8becffd Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 5 Dec 2024 10:08:54 +0000 Subject: [PATCH] Ensure STM32_I2S_AddSamples starts playback if there isn't enough space, fix issue where calling AddSamples with too big a buffer would always cause failure --- libs/pipboy/stm32_i2s.c | 28 +++++++++++++++++++++++----- libs/pipboy/stm32_i2s.h | 6 ++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/libs/pipboy/stm32_i2s.c b/libs/pipboy/stm32_i2s.c index 90c0d906f..b2fc17ec6 100644 --- a/libs/pipboy/stm32_i2s.c +++ b/libs/pipboy/stm32_i2s.c @@ -244,10 +244,13 @@ int STM32_I2S_GetFreeSamples() { // Add samples to the ringbuffer void STM32_I2S_AddSamples(int16_t *data, unsigned int count) { - int timeout = 1000000; - while ((STM32_I2S_GetFreeSamples() < (int)count+32) && --timeout); // wait here for space - + // Try and fill until ringbuffer is full + unsigned int freeSamples = STM32_I2S_GetFreeSamples(); unsigned int c = count; + if (c > freeSamples) { + c = freeSamples; + count -= freeSamples; + } else count = 0; while (c--) { audioRingBuf[audioRingIdxIn] = *(data++) + (audioRingIdxIn&1); // add 1 bit of noise to stop DAC from turning off! @@ -255,8 +258,8 @@ void STM32_I2S_AddSamples(int16_t *data, unsigned int count) { } //jsiConsolePrintf("add %d %d %d %d\n", i2sDMAidx, i2sStatus, count, audioRingBufGetSamples()); - // start playback when we have enough - if (i2sStatus == STM32_I2S_STOPPED && audioRingBufGetSamples()>I2S_DMA_BUFFER_SIZE*3) { + // start playback if we have enough + if (i2sStatus == STM32_I2S_STOPPED && audioRingBufGetSamples()>=I2S_DMA_BUFFER_SIZE*3) { // if audioRingBufGetSamples()>I2S_DMA_BUFFER_SIZE*3 we should have enough here to fill 6 buffers i2sDMAidx = !DMA_GetCurrentMemoryTarget(DMA1_Stream4); fillDMAFromRingBuffer(); // fill the first buffer with what we're currently reading from! @@ -264,6 +267,21 @@ void STM32_I2S_AddSamples(int16_t *data, unsigned int count) { fillDMAFromRingBuffer(); // fill the second buffer STM32_I2S_Start(); } + + if (!count) return; + // otherwise we still have more to put in - try and wait a bit + if (STM32_I2S_GetFreeSamples() < (int)count) { + // wait until we have space + int timeout = 1000000; + while ((STM32_I2S_GetFreeSamples() < (int)count) && --timeout); // wait here for space + } + // now attempt to put in the rest but drop any we don't have space for + c = count; + while (c-- && STM32_I2S_GetFreeSamples()) { + audioRingBuf[audioRingIdxIn] = *(data++) + + (audioRingIdxIn&1); // add 1 bit of noise to stop DAC from turning off! + audioRingIdxIn = (audioRingIdxIn+1) & (I2S_RING_BUFFER_SIZE-1); + } } void STM32_I2S_Start() { diff --git a/libs/pipboy/stm32_i2s.h b/libs/pipboy/stm32_i2s.h index d26319c67..a26330e6f 100644 --- a/libs/pipboy/stm32_i2s.h +++ b/libs/pipboy/stm32_i2s.h @@ -22,6 +22,12 @@ #define I2S_RING_BUFFER_SIZE 8192 // size of ringbuffer used for audio input in u16 // 8192 seems fine to use - still enough for 8 DMA packets worth/0.5sec... +/* jswrap_pb_audioFrame sends data in 2048 byte chunks and STM32_I2S_AddSamples +starts playback at 3*I2S_DMA_BUFFER_SIZE. So I2S_RING_BUFFER_SIZE=8192 +is the least we can use, since any less and 3*I2S_DMA_BUFFER_SIZE would be +big enough that the next sample from jswrap_pb_audioFrame would fill the buffer */ + + typedef enum { STM32_I2S_STOPPED, STM32_I2S_PLAYING