Skip to content

Commit

Permalink
damc: fix rare glitches on usb buffers
Browse files Browse the repository at this point in the history
There was a cache invalidate done in USB interrupt while the SAI interrupt was writing to usb circular buffer.
This caused memory corruption as the data not yet commited to memory was thrown away by the cache invalidate.
The fix is to not use cache management functions when not using the buffer with the DMA.
  • Loading branch information
amurzeau committed Apr 12, 2024
1 parent 4dcbc86 commit 72727ae
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Core/Src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,7 @@ void MPU_Config(int enable_psram)

HAL_MPU_ConfigRegion(&MPU_InitStruct);

/* Configure the MPU as cacheable non executable SRAM */
/* Configure the MPU as cacheable non executable SRAM (write back, read/write allocate) */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x20000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_512MB;
Expand Down
2 changes: 1 addition & 1 deletion damc/damc_simple_lib/AudioCApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ extern "C" void BSP_AUDIO_OUT_TransferComplete_CallBack(void) {
BSP_AUDIO_OUT_HalfTransfer_CallBack();
}

__attribute__((used)) CircularBuffer<uint32_t, 3> usbBuffers[3];
__attribute__((used)) CircularBuffer<uint32_t, 3, false> usbBuffers[3];
__attribute__((used)) int32_t diff_usb[3];
__attribute__((used)) int32_t expected_buff[3];
__attribute__((used)) int32_t usb_buff[3];
Expand Down
29 changes: 20 additions & 9 deletions damc/damc_simple_lib/CircularBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <stm32f7xx.h>
#include <string.h>

template<typename T, int N> class CircularBuffer {
template<typename T, int N, bool do_manage_cache> class CircularBuffer {
public:
CircularBuffer();

Expand All @@ -38,12 +38,12 @@ template<typename T, int N> class CircularBuffer {
size_t in_read_offset;
};

template<typename T, int N> CircularBuffer<T, N>::CircularBuffer() {
template<typename T, int N, bool do_manage_cache> CircularBuffer<T, N, do_manage_cache>::CircularBuffer() {
memset(buffer.data(), 0, buffer.size() * sizeof(buffer[0]));
}

template<typename T, int N>
void CircularBuffer<T, N>::writeOutBuffer(uint32_t dma_read_offset, const T* data, size_t nframes) {
template<typename T, int N, bool do_manage_cache>
void CircularBuffer<T, N, do_manage_cache>::writeOutBuffer(uint32_t dma_read_offset, const T* data, size_t nframes) {
uint16_t start = out_write_offset;
uint16_t size = nframes;

Expand All @@ -70,12 +70,17 @@ void CircularBuffer<T, N>::writeOutBuffer(uint32_t dma_read_offset, const T* dat
}

assert(end < buffer.size());
SCB_CleanDCache_by_Addr((uint32_t*) buffer.data(), buffer.size() * sizeof(buffer[0]));
if(do_manage_cache) {
SCB_CleanDCache_by_Addr((uint32_t*) buffer.data(), buffer.size() * sizeof(buffer[0]));
} else {
__DSB();
}
assert(out_write_offset == start);
out_write_offset = end;
}

template<typename T, int N>
size_t CircularBuffer<T, N>::readInBuffer(uint32_t dma_write_offset, T* data, size_t nframes) {
template<typename T, int N, bool do_manage_cache>
size_t CircularBuffer<T, N, do_manage_cache>::readInBuffer(uint32_t dma_write_offset, T* data, size_t nframes) {
uint16_t start = in_read_offset;

uint16_t end = dma_write_offset;
Expand All @@ -86,13 +91,15 @@ size_t CircularBuffer<T, N>::readInBuffer(uint32_t dma_write_offset, T* data, si

if(size > nframes) {
size = nframes;
end = (in_read_offset + size) % buffer.size();
end = (start + size) % buffer.size();
}
assert(end < buffer.size());

uint16_t total_size = 0;

SCB_InvalidateDCache_by_Addr((uint32_t*) buffer.data(), buffer.size() * sizeof(buffer[0]));
if(do_manage_cache) {
SCB_InvalidateDCache_by_Addr((uint32_t*) buffer.data(), buffer.size() * sizeof(buffer[0]));
}

if(end < start) {
// Copy between start and end of buffer
Expand All @@ -118,6 +125,10 @@ size_t CircularBuffer<T, N>::readInBuffer(uint32_t dma_write_offset, T* data, si
data[i] = fill_sample;
}

if(!do_manage_cache) {
__DSB();
}
assert(in_read_offset == start);
in_read_offset = end;

return size;
Expand Down
4 changes: 2 additions & 2 deletions damc/damc_simple_lib/CodecAudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class CodecAudio {
struct CodecFrame {
int16_t headphone[2];
};
CircularBuffer<CodecFrame, 2> out_buffer;
CircularBuffer<CodecFrame, 2> in_buffer;
CircularBuffer<CodecFrame, 2, true> out_buffer;
CircularBuffer<CodecFrame, 2, true> in_buffer;
CodecInit codecInit;
};

0 comments on commit 72727ae

Please sign in to comment.