mirror of
https://github.com/arduino/Arduino.git
synced 2025-02-18 12:54:25 +01:00
Audio lib: added DAC class and DMA interrupt handling
This commit is contained in:
parent
6695518cff
commit
de30e38843
@ -151,21 +151,6 @@ uint32_t analogRead(uint32_t ulPin)
|
||||
return ulValue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void TC_SetCMR_ChannelA(Tc *tc, uint32_t chan, uint32_t v)
|
||||
{
|
||||
tc->TC_CHANNEL[chan].TC_CMR = (tc->TC_CHANNEL[chan].TC_CMR & 0xFFF0FFFF) | v;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
133
hardware/arduino/sam/libraries/Audio/DAC.cpp
Normal file
133
hardware/arduino/sam/libraries/Audio/DAC.cpp
Normal 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();
|
||||
}
|
||||
|
30
hardware/arduino/sam/libraries/Audio/DAC.h
Normal file
30
hardware/arduino/sam/libraries/Audio/DAC.h
Normal 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
|
@ -68,6 +68,12 @@ extern void TC_Stop( Tc *pTc, uint32_t dwChannel ) ;
|
||||
|
||||
extern uint32_t TC_FindMckDivisor( uint32_t dwFreq, uint32_t dwMCk, uint32_t *dwDiv, uint32_t *dwTcClks, uint32_t dwBoardMCK ) ;
|
||||
|
||||
extern void TC_SetRA(Tc *tc, uint32_t chan, uint32_t v) ;
|
||||
|
||||
extern void TC_SetRB(Tc *tc, uint32_t chan, uint32_t v) ;
|
||||
|
||||
extern void TC_SetRC(Tc *tc, uint32_t chan, uint32_t v) ;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -173,3 +173,15 @@ extern uint32_t TC_FindMckDivisor( uint32_t dwFreq, uint32_t dwMCk, uint32_t *dw
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
void TC_SetRA(Tc *tc, uint32_t chan, uint32_t v) {
|
||||
tc->TC_CHANNEL[chan].TC_RA = v;
|
||||
}
|
||||
|
||||
void TC_SetRB(Tc *tc, uint32_t chan, uint32_t v) {
|
||||
tc->TC_CHANNEL[chan].TC_RB = v;
|
||||
}
|
||||
|
||||
void TC_SetRC(Tc *tc, uint32_t chan, uint32_t v) {
|
||||
tc->TC_CHANNEL[chan].TC_RC = v;
|
||||
}
|
||||
|
||||
|
Binary file not shown.
@ -72,7 +72,7 @@ pmc.o:
|
||||
00000000 T pmc_switch_udpck_to_upllck
|
||||
|
||||
pwmc.o:
|
||||
00000000 r C.9.7204
|
||||
00000000 r C.9.7219
|
||||
00000000 t FindClockConfiguration
|
||||
00000000 T PWMC_ConfigureChannel
|
||||
00000000 T PWMC_ConfigureChannelExt
|
||||
@ -100,14 +100,14 @@ pwmc.o:
|
||||
00000000 T PWMC_SetSyncChannelUpdateUnlock
|
||||
00000000 T PWMC_WriteBuffer
|
||||
U __assert_func
|
||||
00000000 r __func__.5914
|
||||
00000000 r __func__.5925
|
||||
00000000 r __func__.5940
|
||||
00000000 r __func__.5951
|
||||
00000000 r __func__.5962
|
||||
00000000 r __func__.5969
|
||||
00000000 r __func__.6053
|
||||
00000000 r __func__.6059
|
||||
00000000 r __func__.5926
|
||||
00000000 r __func__.5937
|
||||
00000000 r __func__.5952
|
||||
00000000 r __func__.5963
|
||||
00000000 r __func__.5974
|
||||
00000000 r __func__.5981
|
||||
00000000 r __func__.6065
|
||||
00000000 r __func__.6071
|
||||
|
||||
rtc.o:
|
||||
00000000 T RTC_ClearSCCR
|
||||
@ -123,9 +123,9 @@ rtc.o:
|
||||
00000000 T RTC_SetTime
|
||||
00000000 T RTC_SetTimeAlarm
|
||||
U __assert_func
|
||||
00000000 r __func__.5911
|
||||
00000000 r __func__.5920
|
||||
00000000 r __func__.5925
|
||||
00000000 r __func__.5923
|
||||
00000000 r __func__.5932
|
||||
00000000 r __func__.5937
|
||||
|
||||
rtt.o:
|
||||
00000000 T RTT_EnableIT
|
||||
@ -134,8 +134,8 @@ rtt.o:
|
||||
00000000 T RTT_SetAlarm
|
||||
00000000 T RTT_SetPrescaler
|
||||
U __assert_func
|
||||
00000000 r __func__.5918
|
||||
00000000 r __func__.5926
|
||||
00000000 r __func__.5930
|
||||
00000000 r __func__.5938
|
||||
|
||||
spi.o:
|
||||
00000000 T SPI_Configure
|
||||
@ -153,12 +153,15 @@ spi.o:
|
||||
tc.o:
|
||||
00000000 T TC_Configure
|
||||
00000000 T TC_FindMckDivisor
|
||||
00000000 T TC_SetRA
|
||||
00000000 T TC_SetRB
|
||||
00000000 T TC_SetRC
|
||||
00000000 T TC_Start
|
||||
00000000 T TC_Stop
|
||||
U __assert_func
|
||||
00000000 r __func__.5913
|
||||
00000000 r __func__.5919
|
||||
00000000 r __func__.5925
|
||||
00000000 r __func__.5931
|
||||
00000000 r __func__.5937
|
||||
|
||||
timetick.o:
|
||||
00000000 T GetTickCount
|
||||
@ -185,18 +188,18 @@ twi.o:
|
||||
00000000 T TWI_TransferComplete
|
||||
00000000 T TWI_WriteByte
|
||||
U __assert_func
|
||||
00000000 r __func__.6286
|
||||
00000000 r __func__.6301
|
||||
00000000 r __func__.6305
|
||||
00000000 r __func__.6312
|
||||
00000000 r __func__.6316
|
||||
00000000 r __func__.6321
|
||||
00000000 r __func__.6329
|
||||
00000000 r __func__.6343
|
||||
00000000 r __func__.6348
|
||||
00000000 r __func__.6352
|
||||
00000000 r __func__.6357
|
||||
00000000 r __func__.6361
|
||||
00000000 r __func__.6298
|
||||
00000000 r __func__.6313
|
||||
00000000 r __func__.6317
|
||||
00000000 r __func__.6324
|
||||
00000000 r __func__.6328
|
||||
00000000 r __func__.6333
|
||||
00000000 r __func__.6341
|
||||
00000000 r __func__.6355
|
||||
00000000 r __func__.6360
|
||||
00000000 r __func__.6364
|
||||
00000000 r __func__.6369
|
||||
00000000 r __func__.6373
|
||||
|
||||
usart.o:
|
||||
00000000 T USART_Configure
|
||||
@ -215,7 +218,7 @@ usart.o:
|
||||
00000000 T USART_Write
|
||||
00000000 T USART_WriteBuffer
|
||||
U __assert_func
|
||||
00000000 r __func__.6207
|
||||
00000000 r __func__.6219
|
||||
|
||||
wdt.o:
|
||||
00000000 T WDT_Disable
|
||||
|
@ -171,6 +171,8 @@ static const uint8_t CANTX0 = 69;
|
||||
*/
|
||||
#define DACC_INTERFACE DACC
|
||||
#define DACC_INTERFACE_ID ID_DACC
|
||||
#define DACC_ISR_HANDLER DACC_Handler
|
||||
#define DACC_ISR_ID DACC_IRQn
|
||||
|
||||
/*
|
||||
* PWM
|
||||
|
Loading…
x
Reference in New Issue
Block a user