1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-10-15 11:26:40 +03:00

Audio lib: added DAC class and DMA interrupt handling

This commit is contained in:
Cristian Maglie
2012-07-29 01:57:12 +02:00
parent 6695518cff
commit de30e38843
10 changed files with 223 additions and 152 deletions

View File

@@ -10,106 +10,15 @@
#include "Audio.h"
static void TC_SetRA(Tc *tc, uint32_t chan, uint32_t v) {
tc->TC_CHANNEL[chan].TC_RA = v;
}
static void TC_SetRB(Tc *tc, uint32_t chan, uint32_t v) {
tc->TC_CHANNEL[chan].TC_RB = v;
}
static void TC_SetRC(Tc *tc, uint32_t chan, uint32_t v) {
tc->TC_CHANNEL[chan].TC_RC = v;
}
void AudioClass::begin(uint32_t sampleRate) {
// Enable clock for DAC
pmc_enable_periph_clk(dacId);
dacc_reset(dac);
// Set transfer mode to double word
dacc_set_transfer_mode(dac, 1);
// Power save:
// sleep mode - 0 (disabled)
// fast wakeup - 0 (disabled)
dacc_set_power_save(dac, 0, 0);
// ADC refresh/startup timings:
// refresh - 0x08 (1024*8 dacc clocks)
// max speed mode - 0 (disabled)
// startup time - 0x10 (1024 dacc clocks)
dacc_set_timing(dac, 0x08, 0, DACC_MR_STARTUP_1024);
// Flexible channel selection with tags
dacc_enable_flexible_selection(dac);
// Set up analog current
dacc_set_analog_control(dac,
DACC_ACR_IBCTLCH0(0x02) |
DACC_ACR_IBCTLCH1(0x02) |
DACC_ACR_IBCTLDACCORE(0x01));
// Enable output channels
dacc_enable_channel(dac, 0);
dacc_enable_channel(dac, 1);
// Configure Timer Counter to trigger DAC
// --------------------------------------
pmc_enable_periph_clk(ID_TC1);
TC_Configure(TC0, 1,
TC_CMR_TCCLKS_TIMER_CLOCK2 | // Clock at MCR/8
TC_CMR_WAVE | // Waveform mode
TC_CMR_WAVSEL_UP_RC | // Counter running up and reset when equals to RC
TC_CMR_ACPA_SET | TC_CMR_ACPC_CLEAR);
const uint32_t TC = VARIANT_MCK / 8 / sampleRate;
TC_SetRA(TC0, 1, TC / 2);
TC_SetRC(TC0, 1, TC);
TC_Start(TC0, 1);
// Configure clock source for DAC (2 = TC0 Output Chan. 1)
dacc_set_trigger(dac, 2);
// Configure pins
PIO_Configure(g_APinDescription[DA0].pPort,
g_APinDescription[DA0].ulPinType,
g_APinDescription[DA0].ulPin,
g_APinDescription[DA0].ulPinConfiguration);
PIO_Configure(g_APinDescription[DA1].pPort,
g_APinDescription[DA1].ulPinType,
g_APinDescription[DA1].ulPin,
g_APinDescription[DA1].ulPinConfiguration);
const uint32_t T = VARIANT_MCK / sampleRate;
dac->begin(T);
currentBuffer = 0;
}
void AudioClass::end() {
TC_Stop(TC0, 1);
dacc_disable_channel(dac, 0);
dacc_disable_channel(dac, 1);
}
size_t AudioClass::write(const uint32_t *buffer, size_t size) {
// Try the first PDC buffer
if ((dac->DACC_TCR == 0) && (dac->DACC_TNCR == 0)) {
dac->DACC_TPR = (uint32_t) cook(buffer, size);
dac->DACC_TCR = size;
dac->DACC_PTCR = DACC_PTCR_TXTEN;
return size;
}
// Try the second PDC buffer
if (dac->DACC_TNCR == 0) {
dac->DACC_TNPR = (uint32_t) cook(buffer, size);
dac->DACC_TNCR = size;
dac->DACC_PTCR = DACC_PTCR_TXTEN;
return size;
}
// PDC buffers full, try again later...
return 0;
dac->end();
}
uint32_t *AudioClass::cook(const uint32_t *buffer, size_t size) {
@@ -128,13 +37,4 @@ uint32_t *AudioClass::cook(const uint32_t *buffer, size_t size) {
}
}
AudioClass Audio(DACC_INTERFACE, DACC_INTERFACE_ID);
//void DACC_IrqHandler(void) {
// uint32_t sr = DACC_INTERFACE->DACC_ISR;
//
// if (sr & DACC_ISR_ENDTX) {
// /* End of transmission */
// Audio.write(wBuffer, SAMPLES);
// }
//}
AudioClass Audio(DAC);

View File

@@ -13,10 +13,11 @@
#include "Arduino.h"
#include "Print.h"
#include "DAC.h"
class AudioClass : public Print {
public:
AudioClass(Dacc *_dac, uint32_t _dacId) : dac(_dac), dacId(_dacId) { };
AudioClass(DACClass &_dac) : dac(&_dac) { };
void begin(uint32_t sampleRate);
void end();
@@ -24,7 +25,7 @@ public:
virtual size_t write(const uint8_t *buffer, size_t size) { return write((uint32_t*) buffer, size/4) * 4; };
virtual size_t write(const uint16_t *buffer, size_t size) { return write((uint32_t*) buffer, size/2) * 2; };
virtual size_t write(const int16_t *buffer, size_t size) { return write((uint32_t*) buffer, size/2) * 2; };
virtual size_t write(const uint32_t *buffer, size_t size);
virtual size_t write(const uint32_t *buffer, size_t size) { return dac->queueBuffer(cook(buffer,size), size); };
private:
uint32_t buffer0[1024];
@@ -33,8 +34,7 @@ private:
uint32_t *cook(const uint32_t *buffer, size_t size);
Dacc *dac;
uint32_t dacId;
DACClass *dac;
};
extern AudioClass Audio;

View File

@@ -0,0 +1,133 @@
#include <DAC.h>
void DACClass::begin(uint32_t period) {
// Enable clock for DAC
pmc_enable_periph_clk(dacId);
dacc_reset(dac);
// Set transfer mode to double word
dacc_set_transfer_mode(dac, 1);
// Power save:
// sleep mode - 0 (disabled)
// fast wakeup - 0 (disabled)
dacc_set_power_save(dac, 0, 0);
// DAC refresh/startup timings:
// refresh - 0x08 (1024*8 dacc clocks)
// max speed mode - 0 (disabled)
// startup time - 0x10 (1024 dacc clocks)
dacc_set_timing(dac, 0x08, 0, DACC_MR_STARTUP_1024);
// Flexible channel selection with tags
dacc_enable_flexible_selection(dac);
// Set up analog current
dacc_set_analog_control(dac,
DACC_ACR_IBCTLCH0(0x02) |
DACC_ACR_IBCTLCH1(0x02) |
DACC_ACR_IBCTLDACCORE(0x01));
// Enable output channels
dacc_enable_channel(dac, 0);
dacc_enable_channel(dac, 1);
// Configure Timer Counter to trigger DAC
// --------------------------------------
pmc_enable_periph_clk(ID_TC1);
TC_Configure(TC0, 1,
TC_CMR_TCCLKS_TIMER_CLOCK2 | // Clock at MCR/8
TC_CMR_WAVE | // Waveform mode
TC_CMR_WAVSEL_UP_RC | // Counter running up and reset when equals to RC
TC_CMR_ACPA_SET | TC_CMR_ACPC_CLEAR);
const uint32_t TC = period / 8;
TC_SetRA(TC0, 1, TC / 2);
TC_SetRC(TC0, 1, TC);
TC_Start(TC0, 1);
// Configure clock source for DAC (2 = TC0 Output Chan. 1)
dacc_set_trigger(dac, 2);
// Configure pins
PIO_Configure(g_APinDescription[DA0].pPort,
g_APinDescription[DA0].ulPinType,
g_APinDescription[DA0].ulPin,
g_APinDescription[DA0].ulPinConfiguration);
PIO_Configure(g_APinDescription[DA1].pPort,
g_APinDescription[DA1].ulPinType,
g_APinDescription[DA1].ulPin,
g_APinDescription[DA1].ulPinConfiguration);
// Enable interrupt controller for DAC
dacc_disable_interrupt(dac, 0xFFFFFFFF);
NVIC_DisableIRQ(isrId);
NVIC_ClearPendingIRQ(isrId);
NVIC_SetPriority(isrId, 0);
NVIC_EnableIRQ(isrId);
}
void DACClass::end() {
TC_Stop(TC0, 1);
NVIC_DisableIRQ(isrId);
dacc_disable_channel(dac, 0);
dacc_disable_channel(dac, 1);
}
bool DACClass::canQueue() {
if ((dac->DACC_TCR == 0) && (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) {
// Try the first PDC buffer
if ((dac->DACC_TCR == 0) && (dac->DACC_TNCR == 0)) {
dac->DACC_TPR = (uint32_t) buffer;
dac->DACC_TCR = size;
dac->DACC_PTCR = DACC_PTCR_TXTEN;
if (cb)
dacc_enable_interrupt(dac, DACC_IER_ENDTX);
return size;
}
// Try the second PDC buffer
if (dac->DACC_TNCR == 0) {
dac->DACC_TNPR = (uint32_t) buffer;
dac->DACC_TNCR = size;
dac->DACC_PTCR = DACC_PTCR_TXTEN;
if (cb)
dacc_enable_interrupt(dac, DACC_IER_ENDTX);
return size;
}
// PDC buffers full, try again later...
return 0;
}
void DACClass::setOnQueueFree_CB(OnQueueFree_CB _cb) {
cb = _cb;
if (cb) {
dacc_enable_interrupt(dac, DACC_IER_ENDTX);
} else {
dacc_disable_interrupt(dac, DACC_IDR_ENDTX);
}
}
void DACClass::onService() {
uint32_t sr = dac->DACC_ISR;
if (sr & DACC_ISR_ENDTX) {
dacc_disable_interrupt(dac, DACC_IDR_ENDTX);
if (cb) cb();
}
}
DACClass DAC(DACC_INTERFACE, DACC_INTERFACE_ID, DACC_ISR_ID);
void DACC_ISR_HANDLER(void) {
DAC.onService();
}

View File

@@ -0,0 +1,30 @@
#ifndef DAC_INCLUDED
#define DAC_INCLUDED
#include "Arduino.h"
typedef void (*OnQueueFree_CB)(void);
class DACClass
{
public:
DACClass(Dacc *_dac, uint32_t _dacId, IRQn_Type _isrId) :
dac(_dac), dacId(_dacId), isrId(_isrId), cb(NULL) { };
void begin(uint32_t period);
void end();
bool canQueue();
size_t queueBuffer(const uint32_t *buffer, size_t size);
void setOnQueueFree_CB(OnQueueFree_CB _cb);
void onService();
private:
Dacc *dac;
uint32_t dacId;
IRQn_Type isrId;
OnQueueFree_CB cb;
};
extern DACClass DAC;
#endif