-
Notifications
You must be signed in to change notification settings - Fork 425
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make the AudioRingBuffer list-based #1064
Conversation
@DatanoiseTV can you give this branch a spin? The whole buffer management was redone and the CB seems to be working as well as the ::available(forWrite) seems stable and should be at least close to clearing up #939 .
|
The ring buffer worked but had issues with IRQs and the available() procesing. Because it was a pain to debug, move to a linked list setup where there are filled and empty buffers to work from, simplifying the underlying logic. Allow I2S::available() to return free writing space in OUTPUT mode to make it saner.
292e98b
to
13e23bb
Compare
Fix typo causing the wrong active buffer to be freed causing infinite looping when underflow happened and potentially messing up normal operation if the 'freed' buffer was overwritten before being played.
For some reason, @DatanoiseTV , your comment hit my email box but not the GH repo... In any case, this current patch was tested using the logic analyzer for 10s using a stream of incrementing samples. Both with a manually forced underflow and w/o any underflow worked for me when I post-processed the CSVs. No missing samples detected and 0s sent on underflow. I was unable to build your PicoVult sketch because it needs some add'l library or files (`#include "vultin.h") which isn't in the repo. |
|
I've run the code and it seems to be crashing in DSP code, not in I2S handling. With the optimizer it's hard to tell exactly what's going one but I was able to get a dump by connecting GDB after the hang:
|
The volatile was improperly assigned allowing GCC to cache the first read of the list heads in ::read/::write causing, potentially, an infinite loop. Adjust so the data pointed at by the pointer will be the volatile bit causes GCC to emit re-reads ever pass of the bust-wait.
@earlephilhower Please try again with a fresh https://github.com/DatanoiseOrg/VultArduino |
With the latest one what I see is that it is the callback is taking longer than a full DMA cycle and that it's breaking the DMA ping pong structure and no more DMA IRQs happen. Looking at the waveform I can see the Bclk/Wclk freeze which means the PIO isn't getting any FIFO data and stalling. I can repro it by taking the simple CB test and GDB breaking while running. The clocks continue until the final DMA finishes but at that point it's all busted inside. |
That is a bit weird, as I am successfully running that code and much much more complex patches in my firmware:https://github.com/DatanoiseTV/PicoADK-Firmware-Template |
Maybe try setting different buffer sizes? |
Could be, as I am using pretty small default buffer sizes (which are configurable). If sample generation time is linear, though, it may not really change things. That said, the core should probably be able to recognize and recover from this kind of programming error. Basically what we have now is DMA 1 fires the trigger to DMA 2 (HW chaining) and cause an IRQ to happen. In the IRQ we reset DMA1 to point to the next bit of data after DMA2 but don't trigger it (DMA2 is wired to trigger DMA1). You service IRQs in time, all works fine. You don't, DMA 2 tries to trigger DMA1 but DMA1 is already done so it's a no-op and no more triggers. You get both IRQs and update DMA addresses, but nobody's going to actually trigger the transfer start. Interesting corner case! |
I am using between 16 and 32 samples in my examples. But also used a buffer size of 32 and 64 samples today without any issues. |
Gives 2x the time between interrutps to handle I2S callbacks.
Looks like stack overflow errors are causing some crashes/weirdness in your code, but with the latest push it's at least not crashing and adjusted to 16 samples @ 32bps. Here:
So you're allocating 88KB of data on a 4KB stack and things get weird. Some of the I2S internals get overwritten, it looks like, causing garbage. Also, what you're doing is illegal C code. You're returning a stack local variable ( |
I would also suggest maybe doing a |
The ring buffer worked but had issues with IRQs and the available() procesing. Because it was a pain to debug, move to a linked list setup where there are filled and empty buffers to work from, simplifying the underlying logic.
Allow I2S::available() to return free writing space in OUTPUT mode to make it saner.