11/*
2- AudioRingBuffer for Raspnerry Pi Pico RP2040
3- Implements a ring buffer for PIO DMA for I2S read or write
2+ AudioBufferManager for Raspnerry Pi Pico RP2040
3+ Implements a DMA controlled linked-list series of buffers
44
55 Copyright (c) 2022 Earle F. Philhower, III <[email protected] > 66
2222#include < Arduino.h>
2323#include " hardware/dma.h"
2424#include " hardware/irq.h"
25- #include " AudioRingBuffer .h"
25+ #include " AudioBufferManager .h"
2626
27- static int __channelCount = 0 ; // # of channels left. When we hit 0, then remove our handler
28- static AudioRingBuffer * __channelMap[12 ]; // Lets the IRQ handler figure out where to dispatch to
27+ static int __channelCount = 0 ; // # of channels left. When we hit 0, then remove our handler
28+ static AudioBufferManager * __channelMap[12 ]; // Lets the IRQ handler figure out where to dispatch to
2929
30- AudioRingBuffer::AudioRingBuffer (size_t bufferCount, size_t bufferWords, int32_t silenceSample, PinMode direction) {
30+ AudioBufferManager::AudioBufferManager (size_t bufferCount, size_t bufferWords, int32_t silenceSample, PinMode direction, enum dma_channel_transfer_size dmaSize ) {
3131 _running = false ;
3232
3333 // Need at least 2 DMA buffers and 1 user or this isn't going to work at all
@@ -38,6 +38,7 @@ AudioRingBuffer::AudioRingBuffer(size_t bufferCount, size_t bufferWords, int32_t
3838 _bufferCount = bufferCount;
3939 _wordsPerBuffer = bufferWords;
4040 _isOutput = direction == OUTPUT;
41+ _dmaSize = dmaSize;
4142 _overunderflow = false ;
4243 _callback = nullptr ;
4344 _userOff = 0 ;
@@ -66,7 +67,7 @@ AudioRingBuffer::AudioRingBuffer(size_t bufferCount, size_t bufferWords, int32_t
6667 _active[1 ] = _silence;
6768}
6869
69- AudioRingBuffer ::~AudioRingBuffer () {
70+ AudioBufferManager ::~AudioBufferManager () {
7071 if (_running) {
7172 for (auto i = 0 ; i < 2 ; i++) {
7273 dma_channel_set_irq0_enabled (_channelDMA[i], false );
@@ -98,11 +99,11 @@ AudioRingBuffer::~AudioRingBuffer() {
9899 _deleteAudioBuffer (_silence);
99100}
100101
101- void AudioRingBuffer ::setCallback (void (*fn)()) {
102+ void AudioBufferManager ::setCallback (void (*fn)()) {
102103 _callback = fn;
103104}
104105
105- bool AudioRingBuffer ::begin (int dreq, volatile void *pioFIFOAddr) {
106+ bool AudioBufferManager ::begin (int dreq, volatile void *pioFIFOAddr) {
106107 _running = true ;
107108
108109 // Get ping and pong DMA channels
@@ -119,7 +120,7 @@ bool AudioRingBuffer::begin(int dreq, volatile void *pioFIFOAddr) {
119120 // Need to know both channels to set up ping-pong, so do in 2 stages
120121 for (auto i = 0 ; i < 2 ; i++) {
121122 dma_channel_config c = dma_channel_get_default_config (_channelDMA[i]);
122- channel_config_set_transfer_data_size (&c, DMA_SIZE_32 ); // 32b transfers into PIO FIFO
123+ channel_config_set_transfer_data_size (&c, _dmaSize ); // 16b/ 32b transfers into PIO FIFO
123124 if (_isOutput) {
124125 channel_config_set_read_increment (&c, true ); // Reading incrementing addresses
125126 channel_config_set_write_increment (&c, false ); // Writing to the same FIFO address
@@ -155,7 +156,7 @@ bool AudioRingBuffer::begin(int dreq, volatile void *pioFIFOAddr) {
155156// cause GCC to keep re-reading from memory and not use cached value read
156157// on the first pass.
157158
158- bool AudioRingBuffer ::write (uint32_t v, bool sync) {
159+ bool AudioBufferManager ::write (uint32_t v, bool sync) {
159160 if (!_running || !_isOutput) {
160161 return false ;
161162 }
@@ -177,7 +178,7 @@ bool AudioRingBuffer::write(uint32_t v, bool sync) {
177178 return true ;
178179}
179180
180- bool AudioRingBuffer ::read (uint32_t *v, bool sync) {
181+ bool AudioBufferManager ::read (uint32_t *v, bool sync) {
181182 if (!_running || _isOutput) {
182183 return false ;
183184 }
@@ -201,13 +202,13 @@ bool AudioRingBuffer::read(uint32_t *v, bool sync) {
201202 return true ;
202203}
203204
204- bool AudioRingBuffer ::getOverUnderflow () {
205+ bool AudioBufferManager ::getOverUnderflow () {
205206 bool hold = _overunderflow;
206207 _overunderflow = false ;
207208 return hold;
208209}
209210
210- int AudioRingBuffer ::available () {
211+ int AudioBufferManager ::available () {
211212 AudioBuffer *p = _isOutput ? _empty : _filled;
212213
213214 if (!_running || !p) {
@@ -226,7 +227,7 @@ int AudioRingBuffer::available() {
226227 return avail;
227228}
228229
229- void AudioRingBuffer ::flush () {
230+ void AudioBufferManager ::flush () {
230231 AudioBuffer ** volatile a = (AudioBuffer ** volatile )&_active[0 ];
231232 AudioBuffer ** volatile b = (AudioBuffer ** volatile )&_active[1 ];
232233 AudioBuffer ** volatile c = (AudioBuffer ** volatile )&_filled;
@@ -235,7 +236,7 @@ void AudioRingBuffer::flush() {
235236 }
236237}
237238
238- void __not_in_flash_func (AudioRingBuffer ::_dmaIRQ)(int channel) {
239+ void __not_in_flash_func (AudioBufferManager ::_dmaIRQ)(int channel) {
239240 if (_isOutput) {
240241 if (_active[0 ] != _silence) {
241242 _addToList (&_empty, _active[0 ]);
@@ -265,7 +266,7 @@ void __not_in_flash_func(AudioRingBuffer::_dmaIRQ)(int channel) {
265266 }
266267}
267268
268- void __not_in_flash_func (AudioRingBuffer ::_irq)() {
269+ void __not_in_flash_func (AudioBufferManager ::_irq)() {
269270 for (size_t i = 0 ; i < sizeof (__channelMap); i++) {
270271 if (dma_channel_get_irq0_status (i) && __channelMap[i]) {
271272 __channelMap[i]->_dmaIRQ (i);
0 commit comments