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:
parent
2071c00ba0
commit
51797757e1
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user