1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-01-17 06:52:18 +01:00

Audio library improved. (experiments with PDC)

This commit is contained in:
Cristian Maglie 2012-09-29 00:12:25 +02:00
parent 2071c00ba0
commit 51797757e1
3 changed files with 32 additions and 98 deletions

View File

@ -10,126 +10,68 @@
#include "Audio.h" #include "Audio.h"
class LockDAC {
public:
LockDAC(DACClass *_dac) : dac(_dac)
{ dac->disableInterrupts(); };
~LockDAC() { dac->enableInterrupts(); };
DACClass *dac;
};
void AudioClass::begin(uint32_t sampleRate, uint32_t msPreBuffer) { void AudioClass::begin(uint32_t sampleRate, uint32_t msPreBuffer) {
// Allocate a buffer to keep msPreBuffer milliseconds of audio // Allocate a buffer to keep msPreBuffer milliseconds of audio
bufferSize = msPreBuffer * sampleRate / 1000; bufferSize = msPreBuffer * sampleRate / 1000;
if (bufferSize < 2048) if (bufferSize < 1024)
bufferSize = 2048; bufferSize = 1024;
buffer = (uint32_t *) malloc(bufferSize * sizeof(uint32_t)); buffer = (uint32_t *) malloc(bufferSize * sizeof(uint32_t));
half = buffer + bufferSize / 2;
last = buffer + bufferSize; last = buffer + bufferSize;
// Buffering starts from the beginning // Buffering starts from the beginning
running = last; running = buffer;
current = buffer;
next = buffer; next = buffer;
// Run DAC // Start DAC
dac->begin(VARIANT_MCK / sampleRate); dac->begin(VARIANT_MCK / sampleRate);
dac->setOnTransmitEnd_CB(onTransmitEnd, this); dac->setOnTransmitEnd_CB(onTransmitEnd, this);
} }
void AudioClass::end() { void AudioClass::end() {
dac->end(); dac->end();
free(buffer); free( buffer);
} }
size_t AudioClass::write(const uint32_t *data, size_t size) { size_t AudioClass::write(const uint32_t *data, size_t size) {
LockDAC lock(dac);
//Serial1.print("WRI(");
const uint32_t TAG = 0x10000000; const uint32_t TAG = 0x10000000;
int i; int i;
for (i=0; i < size && next != running; i++) { for (i = 0; i < size; i++) {
*next = data[i] | TAG; *next = data[i] | TAG;
next++; next++;
// Wrap around circular buffer if (next == half || next == last) {
if (next == last) enqueue();
next = buffer; while (next == running)
;
}
} }
debug();
if (dac->canQueue()) {
enqueue();
debug();
}
//Serial1.print(")");
return i; return i;
} }
void AudioClass::enqueue() { void AudioClass::enqueue() {
if (!dac->canQueue()) if (!dac->canQueue()) {
// DMA queue full // DMA queue full
return; return;
if (current == next)
// No data to enqueue
return;
// If wrapping happened
if (next < current) {
uint32_t size = last - current;
if (size < 1024) {
// enqueue the last part of the circular buffer
dac->queueBuffer(current, size);
current = buffer;
next = buffer;
} else {
// Enqueue only a block of 512
dac->queueBuffer(current, 512);
current += 512;
}
return;
} }
bool aboutToWrap = (last - next) < 512; if (next == half) {
uint32_t size = next - current; // Enqueue the first half
dac->queueBuffer(buffer, bufferSize / 2);
// If buffered data is less than 512 bytes
if (size < 512) {
// Enqueue all
dac->queueBuffer(current, size);
if (aboutToWrap)
next = buffer;
current = next;
} else { } else {
// Enqueue the second half
if (aboutToWrap && size < 1024) { dac->queueBuffer(half, bufferSize / 2);
// Enqueue all next = buffer; // wrap around
dac->queueBuffer(current, size);
next = buffer;
current = buffer;
} else {
// Enqueue only a block of 512
dac->queueBuffer(current, 512);
current += 512;
}
} }
} }
void AudioClass::onTransmitEnd(void *me) { void AudioClass::onTransmitEnd(void *_me) {
AudioClass *audio = reinterpret_cast<AudioClass *>(me); AudioClass *me = reinterpret_cast<AudioClass *> (_me);
if (me->running == me->buffer)
//Serial1.print("INT("); me->running = me->half;
audio->enqueue(); else
me->running = me->buffer;
// Update running pointer
audio->running = audio->dac->getCurrentQueuePointer();
audio->debug();
//Serial1.print(")");
} }
AudioClass Audio(DAC); AudioClass Audio(DAC);

View File

@ -41,10 +41,10 @@ private:
static void onTransmitEnd(void *me); static void onTransmitEnd(void *me);
uint32_t bufferSize; uint32_t bufferSize;
uint32_t *buffer; uint32_t *buffer;
uint32_t *half;
uint32_t *last; uint32_t *last;
uint32_t * volatile running; uint32_t *volatile running;
uint32_t * volatile current; uint32_t *volatile next;
uint32_t * volatile next;
uint32_t *cook(const uint32_t *buffer, size_t size); uint32_t *cook(const uint32_t *buffer, size_t size);

View File

@ -85,11 +85,7 @@ void DACClass::end() {
} }
bool DACClass::canQueue() { bool DACClass::canQueue() {
if ((dac->DACC_TCR == 0) && (dac->DACC_TNCR == 0)) return (dac->DACC_TNCR == 0);
return true;
if (dac->DACC_TNCR == 0)
return true;
return false;
} }
size_t DACClass::queueBuffer(const uint32_t *buffer, size_t size) { size_t DACClass::queueBuffer(const uint32_t *buffer, size_t size) {
@ -117,10 +113,6 @@ size_t DACClass::queueBuffer(const uint32_t *buffer, size_t size) {
return 0; return 0;
} }
uint32_t *DACClass::getCurrentQueuePointer() {
return reinterpret_cast<uint32_t *>(dac->DACC_TPR);
}
void DACClass::setOnTransmitEnd_CB(OnTransmitEnd_CB _cb, void *_data) { void DACClass::setOnTransmitEnd_CB(OnTransmitEnd_CB _cb, void *_data) {
cb = _cb; cb = _cb;
cbData = _data; cbData = _data;
@ -130,12 +122,12 @@ void DACClass::setOnTransmitEnd_CB(OnTransmitEnd_CB _cb, void *_data) {
void DACClass::onService() { void DACClass::onService() {
uint32_t sr = dac->DACC_ISR; uint32_t sr = dac->DACC_ISR;
// if (sr & DACC_ISR_ENDTX) { if (sr & DACC_ISR_ENDTX) {
// There is a free slot, enqueue data // There is a free slot, enqueue data
dacc_disable_interrupt(dac, DACC_IDR_ENDTX); dacc_disable_interrupt(dac, DACC_IDR_ENDTX);
if (cb) if (cb)
cb(cbData); cb(cbData);
// } }
} }
DACClass DAC(DACC_INTERFACE, DACC_INTERFACE_ID, DACC_ISR_ID); DACClass DAC(DACC_INTERFACE, DACC_INTERFACE_ID, DACC_ISR_ID);