From edd2fdd023fffab8c816349a4ddf4c7bb5d79661 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Sun, 17 Jun 2012 18:20:01 +0200 Subject: [PATCH 1/4] Audio: first draft --- .../arduino/sam/libraries/Audio/Audio.cpp | 104 ++++++++++++++++++ hardware/arduino/sam/libraries/Audio/Audio.h | 24 ++++ .../arduino/sam/libraries/Audio/keywords.txt | 0 3 files changed, 128 insertions(+) create mode 100644 hardware/arduino/sam/libraries/Audio/Audio.cpp create mode 100644 hardware/arduino/sam/libraries/Audio/Audio.h create mode 100644 hardware/arduino/sam/libraries/Audio/keywords.txt diff --git a/hardware/arduino/sam/libraries/Audio/Audio.cpp b/hardware/arduino/sam/libraries/Audio/Audio.cpp new file mode 100644 index 000000000..23051045d --- /dev/null +++ b/hardware/arduino/sam/libraries/Audio/Audio.cpp @@ -0,0 +1,104 @@ + +#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_TC0); + TC_Configure(TC0, 1, + TC_CMR_TCCLKS_TIMER_CLOCK2 | + 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 (1 = TC0 Output Chan. 1) + dacc_set_trigger(dac, 1); +} + +void AudioClass::end() { + TC_Stop(TC0, 1); + dacc_disable_channel(dac, 0); + dacc_disable_channel(dac, 1); +} + +size_t AudioClass::write(const uint8_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; + 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; + return size; + } + + // PDC buffers full, try again later... + return 0; +} + +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); +// } +//} diff --git a/hardware/arduino/sam/libraries/Audio/Audio.h b/hardware/arduino/sam/libraries/Audio/Audio.h new file mode 100644 index 000000000..aae6f1363 --- /dev/null +++ b/hardware/arduino/sam/libraries/Audio/Audio.h @@ -0,0 +1,24 @@ +#ifndef AUDIO_H +#define AUDIO_H + +#include "Arduino.h" +//#include +#include "Print.h" + +class AudioClass : public Print { +public: + AudioClass(Dacc *_dac, uint32_t _dacId) : dac(_dac), dacId(_dacId) { }; + void begin(uint32_t sampleRate); + void end(); + + virtual size_t write(uint8_t c) { write(&c, 1); }; + virtual size_t write(const uint8_t *buffer, size_t size); + +private: + Dacc *dac; + uint32_t dacId; +}; + +extern AudioClass Audio; + +#endif diff --git a/hardware/arduino/sam/libraries/Audio/keywords.txt b/hardware/arduino/sam/libraries/Audio/keywords.txt new file mode 100644 index 000000000..e69de29bb From 6695518cffb527ec58417aceb8b131cb98da3e5e Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 18 Jun 2012 01:53:53 +0200 Subject: [PATCH 2/4] Audio library: improved DMA transfers. Stereo output. --- .../arduino/sam/libraries/Audio/Audio.cpp | 56 +++++++++++++++---- hardware/arduino/sam/libraries/Audio/Audio.h | 24 +++++++- 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/hardware/arduino/sam/libraries/Audio/Audio.cpp b/hardware/arduino/sam/libraries/Audio/Audio.cpp index 23051045d..0831d1876 100644 --- a/hardware/arduino/sam/libraries/Audio/Audio.cpp +++ b/hardware/arduino/sam/libraries/Audio/Audio.cpp @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2012 by Cristian Maglie + * Audio library for Arduino Due. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ #include "Audio.h" @@ -49,19 +58,31 @@ void AudioClass::begin(uint32_t sampleRate) { // Configure Timer Counter to trigger DAC // -------------------------------------- - pmc_enable_periph_clk(ID_TC0); + pmc_enable_periph_clk(ID_TC1); TC_Configure(TC0, 1, - TC_CMR_TCCLKS_TIMER_CLOCK2 | - TC_CMR_WAVE | // Waveform mode - TC_CMR_WAVSEL_UP_RC | // Counter running up and reset when equals to RC + 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 (1 = TC0 Output Chan. 1) - dacc_set_trigger(dac, 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); + + currentBuffer = 0; } void AudioClass::end() { @@ -70,11 +91,10 @@ void AudioClass::end() { dacc_disable_channel(dac, 1); } -size_t AudioClass::write(const uint8_t *buffer, size_t size) { - +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) buffer; + dac->DACC_TPR = (uint32_t) cook(buffer, size); dac->DACC_TCR = size; dac->DACC_PTCR = DACC_PTCR_TXTEN; return size; @@ -82,7 +102,7 @@ size_t AudioClass::write(const uint8_t *buffer, size_t size) { // Try the second PDC buffer if (dac->DACC_TNCR == 0) { - dac->DACC_TNPR = (uint32_t) buffer; + dac->DACC_TNPR = (uint32_t) cook(buffer, size); dac->DACC_TNCR = size; dac->DACC_PTCR = DACC_PTCR_TXTEN; return size; @@ -92,6 +112,22 @@ size_t AudioClass::write(const uint8_t *buffer, size_t size) { return 0; } +uint32_t *AudioClass::cook(const uint32_t *buffer, size_t size) { + if (currentBuffer == 0) { + // Use buffer0 + for (int i = 0; i < size; i++) + buffer0[i] = buffer[i] | 0x10000000; + currentBuffer = 1; + return buffer0; + } else { + // Use buffer1 + for (int i = 0; i < size; i++) + buffer1[i] = buffer[i] | 0x10000000; + currentBuffer = 0; + return buffer1; + } +} + AudioClass Audio(DACC_INTERFACE, DACC_INTERFACE_ID); //void DACC_IrqHandler(void) { diff --git a/hardware/arduino/sam/libraries/Audio/Audio.h b/hardware/arduino/sam/libraries/Audio/Audio.h index aae6f1363..39f0f289e 100644 --- a/hardware/arduino/sam/libraries/Audio/Audio.h +++ b/hardware/arduino/sam/libraries/Audio/Audio.h @@ -1,8 +1,17 @@ +/* + * Copyright (c) 2012 by Cristian Maglie + * Audio library for Arduino Due. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + #ifndef AUDIO_H #define AUDIO_H #include "Arduino.h" -//#include #include "Print.h" class AudioClass : public Print { @@ -11,10 +20,19 @@ public: void begin(uint32_t sampleRate); void end(); - virtual size_t write(uint8_t c) { write(&c, 1); }; - virtual size_t write(const uint8_t *buffer, size_t size); + virtual size_t write(uint8_t c) { /* not implemented */ }; + 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); private: + uint32_t buffer0[1024]; + uint32_t buffer1[1024]; + int currentBuffer; + + uint32_t *cook(const uint32_t *buffer, size_t size); + Dacc *dac; uint32_t dacId; }; From de30e388438397133751a4bfe10a457a3523b061 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Sun, 29 Jul 2012 01:57:12 +0200 Subject: [PATCH 3/4] Audio lib: added DAC class and DMA interrupt handling --- .../arduino/sam/cores/arduino/wiring_analog.c | 15 -- .../arduino/sam/libraries/Audio/Audio.cpp | 108 +------------- hardware/arduino/sam/libraries/Audio/Audio.h | 8 +- hardware/arduino/sam/libraries/Audio/DAC.cpp | 133 ++++++++++++++++++ hardware/arduino/sam/libraries/Audio/DAC.h | 30 ++++ .../arduino/sam/system/libsam/include/tc.h | 6 + .../arduino/sam/system/libsam/source/tc.c | 12 ++ .../arduino_due_x/libsam_sam3x8e_gcc_rel.a | Bin 80258 -> 80658 bytes .../libsam_sam3x8e_gcc_rel.a.txt | 61 ++++---- .../sam/variants/arduino_due_x/variant.h | 2 + 10 files changed, 223 insertions(+), 152 deletions(-) create mode 100644 hardware/arduino/sam/libraries/Audio/DAC.cpp create mode 100644 hardware/arduino/sam/libraries/Audio/DAC.h diff --git a/hardware/arduino/sam/cores/arduino/wiring_analog.c b/hardware/arduino/sam/cores/arduino/wiring_analog.c index d5bf6dd2b..34e8d57df 100644 --- a/hardware/arduino/sam/cores/arduino/wiring_analog.c +++ b/hardware/arduino/sam/cores/arduino/wiring_analog.c @@ -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; diff --git a/hardware/arduino/sam/libraries/Audio/Audio.cpp b/hardware/arduino/sam/libraries/Audio/Audio.cpp index 0831d1876..cee8d77c0 100644 --- a/hardware/arduino/sam/libraries/Audio/Audio.cpp +++ b/hardware/arduino/sam/libraries/Audio/Audio.cpp @@ -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); diff --git a/hardware/arduino/sam/libraries/Audio/Audio.h b/hardware/arduino/sam/libraries/Audio/Audio.h index 39f0f289e..4eedd5717 100644 --- a/hardware/arduino/sam/libraries/Audio/Audio.h +++ b/hardware/arduino/sam/libraries/Audio/Audio.h @@ -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; diff --git a/hardware/arduino/sam/libraries/Audio/DAC.cpp b/hardware/arduino/sam/libraries/Audio/DAC.cpp new file mode 100644 index 000000000..ae9056db0 --- /dev/null +++ b/hardware/arduino/sam/libraries/Audio/DAC.cpp @@ -0,0 +1,133 @@ + +#include + +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(); +} + diff --git a/hardware/arduino/sam/libraries/Audio/DAC.h b/hardware/arduino/sam/libraries/Audio/DAC.h new file mode 100644 index 000000000..925fb2164 --- /dev/null +++ b/hardware/arduino/sam/libraries/Audio/DAC.h @@ -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 diff --git a/hardware/arduino/sam/system/libsam/include/tc.h b/hardware/arduino/sam/system/libsam/include/tc.h index 92c0b0367..dc0aa43b6 100644 --- a/hardware/arduino/sam/system/libsam/include/tc.h +++ b/hardware/arduino/sam/system/libsam/include/tc.h @@ -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 diff --git a/hardware/arduino/sam/system/libsam/source/tc.c b/hardware/arduino/sam/system/libsam/source/tc.c index 35439db5a..87f5dd800 100644 --- a/hardware/arduino/sam/system/libsam/source/tc.c +++ b/hardware/arduino/sam/system/libsam/source/tc.c @@ -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; +} + diff --git a/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a b/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a index a36253ea4e6caaf6178117c815d1a2c3ca880655..63e201ea8c9b84212ba8348008b004607e991b60 100644 GIT binary patch delta 5064 zcmcIn4Qx}_6~6b`k2oeyUT_>IArL2FKt?dJpJOLo){>t>p(Mp?1ZV{%Ch=C96hdM~ z5FpcvQmCS|;Y`cgWQ9~)xBg6|dIhGDp|Y`!Rg8hes!U}PXi|sPNn2KFllFhk^?kv9 zFi|G@r0a9P@0|O8&bimmequlRSNlsP$&g+fs1NB8pRdM8U;3}l7mn1V2w$g@F&<*9 z^1`Pt{)>#=r6liW@EPlqcb(zv1U9W>?7o+zrPJMq8M~Kq2)Ec;hA%VrY079PV@dkC zQ<*r=n6>UE_g?V)@4eA|Y?HjptUt!{ z{VYrJK6cJ?2id)rBS+#H4YzMt#IXviG3e`EEH#Tg!!eO(s$l0GI}&34 z{vF-1M9kmpulGlSfqK!dE&#_CHpArpA>(lOdX;;jyvz-M+@`5twKG--{HaQHKh}x` z-|&>Cegn}0h$3%bt(5pLj@j_az{m|^q3>6yxk!Zks7mEcX{ShjYz|`{>cR7#MKg(- zc|!AnMROiC)$mMJL4if_XH?`vV^5{RvtWB!A?)kXlvQ>HbxRhlCc4TEmn$^m zTF;tj)ckLNY1gXU|JqEi6XbaQvMPHD91}ZEj;|=XIV8hFM3)S9Wdh>ge#- z*6WdUR2#g7!g%88C=$4Z=2w`6i46?I`x9bBwti!)@$o=VNk$p##c3() z7{mL3DNT$eBpxKWi7`|O{d$rujI~RQD#33iiC|LVcS){d><1E0N%x)caEki^4WDKU=8lvc(bkyuO!JF1gd*gs~mN4>DaA2D&9^&KYOA!f8vb|ePE zQLF>`q<#^}wTvy5xSAvm)Su|`?^q#TT;eC7%VZ(afY%t={h|#H?41w3y`7_5o%{%e zI4s}yH~4bbTtyF>QJxCtppNm{VodIzRk)cSM-tO%q{BXkBt?u`4Zp|2farxYS~qi(2Ur@Jibs* zb5g4V<06KiI}`mJrVnhSEN09{60z9CWsDU`EcE4f(N~&!c;!&3CCOer^e?XHbut<1 zHMD!+8yPY#9BHs?dR=-Tp!V-M%iy8my_QaP zD}e8g{-^2)Z!B6H>sw9o1u5T0N%u@5)}IjfOkzhLgV(XaG7ql7S-9p&3+)Wl=Mw;%H{c4*bH~NFGVu;dzcwtGN%Z~@^Uy^ zQQ^9PQ|v=nh!$lqQ#N0%!}Y!h`Mv?T{;f$q2d=zd#^;Rg2=OviEC-_1#dC96j_fiU zZoKYwl}O}3$zkRZH!NDCxhSUT6Ttw{HF!f-YoHxlzaoJwZ4lYdV{_U544lIbWndR{ z94pfFj2w;U_WZHd5p*8up=dMesCuIYGqdu(fOd<{B10%6;ThCndGCFe8&mXfh zjCr*8lv^}iLc>p0s=Kk~5`8wD($s^9av_TRQBk9@hLAsws1PQQKZP~7u)l`MG+lbr@0{x`X?d^D-QS&g3>96O4k7gdIU8fO10x{?$OC|t{J^k#XOnz zV8H_n-Ac1`oarc(77SrMT%V@HBThqlZTdq;*VCRh*e+v)h+dlBFpz0lWBAUhG(*;j z%TOL*teYg_C#CEq`KXL9y&!2uv*K)QsX3rVL}=XO1Y2ZdYNg^ zP-L10%T6GVlxQz9l4-Z&rkQv&tI!k?BpP{M+|H{qjSj+;qMSQQ$_FMUn5P@$_EW>cT+ z>x~b;lWSVZe|)`v`1b6}Bb6Xe`?L55ifJaf3MZeoaz!p4EH>>@-JO1NG4H$er}8we I;I+K}0`+7&v;Y7A delta 4637 zcmcgweQ;FO6+idwuIz?vvSD|#5Tb0@3_*hHd;67aNh_6zLdh63wEPh!37c3kA#9Qt z!8W)=k*TeLmh(qy!5S1Pok0Yil5|K4wGPwiWK>4m>1gRRQ|&nDOr`Az9bxRbckga? zAGXlO_D#+^?{|LZe!g?hd7HhTSRebF_4{S1a6G2gM&e<=U-k1V_wM({VzIQr-&z2` zG=RX!jZ5$#z;z^bJ%|4>pStc0vlCcf3GjtW%GBxBR)GIRcF`7_W%pr#83hqpWCMp^+@>wb*4!RELw*tn|b! z@7OXHO<0V}fj<|ROjm*%Z#9_));C+xrF*fZz>R;{ScJ=!6D;Vd!vob zL-tU>wuw&E&DgWRjdc&XY`X|~aV^>R(NnpwKSlO2LQApd4v)t|RR91K5`Mi$#2oJS z0*FGomEQp ztl^}SEn>~a`Oaspw4&|F1?*;ghVEXRpnExzb3P!^9MTL+ zdfday1I*>nrMUzfdVG$@B=X_*o&~Jbc&6tP+Z<7$rR9PC?nFyVFh=iX8b#w#Z5k05 zhs?{FHb>*JP#%isA}x}OLQ#Y1^-5|rKo?C#xfg)aBPjO)@QHFvi3F7O0Ba;}Y?5(ClAJdj`Vm0T0KSYUi~YkA%g^%+0gy2pZv zZ@1$6Pt3>1kM6~F1DEhSi84jg_<3P!-l=JSbdBQ7g!fJg)<&#Y;x36$RP(@ANciFdXc5du|d@Ub0ro$8UHQ6=vuy4 z*MnPb7oU&friEn+)%<=-Q-{A*%?gbxyRI@N6rP_$Z{O02-o&JGzLKUrsW zg<`o8Pi)=pLzx#AO6TG|z4m;IH57`ddn*>ZKT2=EEkaA-Z`?yk<&ELb@X`<4@Lgv~ zCYKiAhflA@!9)cP9`{(IagFE4Y+}S6`zjr+_Vfbh;EVh2cI?QatAs|fsA2yd*;oiM z3RWHq-aRxnfov@7A|T$n_XQJ!#5izp%;PZ;`-!mgKw;un5;f2$_;=4QahPJ-Wj`pt$(IRjR0HsD*@z)=-?kVLW)E*2ChW{jwcCeJ(UXJMZ#+UzMZ8wyTO#>>`e;sxf+p(*Yj~M{)u_7LMjrW8!LaJ!5%&s`)5dp6jaRbrY>Ij-9r#R2-m{c0h>& zv~x}PL8-gA{u+QdQDhf&ayfvglZ5F}@FGhS7ANjbdEy9HN}fun=(m~cdO05Pe7sb4 zKpIF4NJLUL$m{s_YdhvU&f5z=`WJwh0AWA3Q-7_J7YhrU7M30-B^-6>xJ~K-t{Y`; zAxD+t8q-dYy^h;yAd!PIeq_wsu^hj=1$~K6l=hmhAhT6@E1*vmVJBWBEgC3~|H`#| ze_vZ~ZpoWYTD(sAjN`9h~+u3iGjGMHbn9Y7?wjC~Fp?Mj<^pBa*%T+9y{mG+^ J()6Dz{wHH<^u7Q9 diff --git a/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt b/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt index 1ed7a440f..32b563e76 100644 --- a/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt +++ b/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt @@ -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 diff --git a/hardware/arduino/sam/variants/arduino_due_x/variant.h b/hardware/arduino/sam/variants/arduino_due_x/variant.h index a99f7807a..e8101b438 100644 --- a/hardware/arduino/sam/variants/arduino_due_x/variant.h +++ b/hardware/arduino/sam/variants/arduino_due_x/variant.h @@ -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 From 5131431d966f599fca4d41ce0440aeb9141aada5 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 1 Aug 2012 11:51:29 +0200 Subject: [PATCH 4/4] Some experiments about Audio buffering. DAC class added. --- .../arduino/sam/libraries/Audio/Audio.cpp | 127 +++++++++++++++--- hardware/arduino/sam/libraries/Audio/Audio.h | 32 +++-- hardware/arduino/sam/libraries/Audio/DAC.cpp | 29 ++-- hardware/arduino/sam/libraries/Audio/DAC.h | 20 ++- 4 files changed, 172 insertions(+), 36 deletions(-) diff --git a/hardware/arduino/sam/libraries/Audio/Audio.cpp b/hardware/arduino/sam/libraries/Audio/Audio.cpp index cee8d77c0..bd8d99186 100644 --- a/hardware/arduino/sam/libraries/Audio/Audio.cpp +++ b/hardware/arduino/sam/libraries/Audio/Audio.cpp @@ -10,31 +10,126 @@ #include "Audio.h" -void AudioClass::begin(uint32_t sampleRate) { - const uint32_t T = VARIANT_MCK / sampleRate; - dac->begin(T); +class LockDAC { +public: + LockDAC(DACClass *_dac) : dac(_dac) + { dac->disableInterrupts(); }; + ~LockDAC() { dac->enableInterrupts(); }; + DACClass *dac; +}; - currentBuffer = 0; +void AudioClass::begin(uint32_t sampleRate, uint32_t msPreBuffer) { + // Allocate a buffer to keep msPreBuffer milliseconds of audio + bufferSize = msPreBuffer * sampleRate / 1000; + if (bufferSize < 2048) + bufferSize = 2048; + buffer = (uint32_t *) malloc(bufferSize * sizeof(uint32_t)); + last = buffer + bufferSize; + + // Buffering starts from the beginning + running = last; + current = buffer; + next = buffer; + + // Run DAC + dac->begin(VARIANT_MCK / sampleRate); + dac->setOnTransmitEnd_CB(onTransmitEnd, this); } void AudioClass::end() { dac->end(); + free(buffer); } -uint32_t *AudioClass::cook(const uint32_t *buffer, size_t size) { - if (currentBuffer == 0) { - // Use buffer0 - for (int i = 0; i < size; i++) - buffer0[i] = buffer[i] | 0x10000000; - currentBuffer = 1; - return buffer0; +size_t AudioClass::write(const uint32_t *data, size_t size) { + LockDAC lock(dac); + //Serial1.print("WRI("); + const uint32_t TAG = 0x10000000; + int i; + for (i=0; i < size && next != running; i++) { + *next = data[i] | TAG; + next++; + + // Wrap around circular buffer + if (next == last) + next = buffer; + } + debug(); + if (dac->canQueue()) { + enqueue(); + debug(); + } + //Serial1.print(")"); + return i; +} + +void AudioClass::enqueue() { + if (!dac->canQueue()) + // DMA queue full + 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; + uint32_t size = next - current; + + // If buffered data is less than 512 bytes + if (size < 512) { + + // Enqueue all + dac->queueBuffer(current, size); + + if (aboutToWrap) + next = buffer; + current = next; + } else { - // Use buffer1 - for (int i = 0; i < size; i++) - buffer1[i] = buffer[i] | 0x10000000; - currentBuffer = 0; - return buffer1; + + if (aboutToWrap && size < 1024) { + // Enqueue all + 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) { + AudioClass *audio = reinterpret_cast(me); + + //Serial1.print("INT("); + audio->enqueue(); + + // Update running pointer + audio->running = audio->dac->getCurrentQueuePointer(); + + audio->debug(); + //Serial1.print(")"); +} + AudioClass Audio(DAC); diff --git a/hardware/arduino/sam/libraries/Audio/Audio.h b/hardware/arduino/sam/libraries/Audio/Audio.h index 4eedd5717..93ae0e780 100644 --- a/hardware/arduino/sam/libraries/Audio/Audio.h +++ b/hardware/arduino/sam/libraries/Audio/Audio.h @@ -18,19 +18,33 @@ class AudioClass : public Print { public: AudioClass(DACClass &_dac) : dac(&_dac) { }; - void begin(uint32_t sampleRate); + void begin(uint32_t sampleRate, uint32_t msPreBuffer); void end(); - virtual size_t write(uint8_t c) { /* not implemented */ }; - 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) { return dac->queueBuffer(cook(buffer,size), size); }; + virtual size_t write(uint8_t c) { /* not implemented */ }; + virtual size_t write(const uint8_t *data, size_t size) { return write(reinterpret_cast(data), size/4) * 4; }; + virtual size_t write(const uint16_t *data, size_t size) { return write(reinterpret_cast(data), size/2) * 2; }; + virtual size_t write(const int16_t *data, size_t size) { return write(reinterpret_cast(data), size/2) * 2; }; + virtual size_t write(const uint32_t *data, size_t size); + void debug() { +// Serial1.print(running-buffer, DEC); +// Serial1.print(" "); +// Serial1.print(current-buffer, DEC); +// Serial1.print(" "); +// Serial1.print(next-buffer, DEC); +// Serial1.print(" "); +// Serial1.println(last-buffer, DEC); + } private: - uint32_t buffer0[1024]; - uint32_t buffer1[1024]; - int currentBuffer; + void enqueue(); + static void onTransmitEnd(void *me); + uint32_t bufferSize; + uint32_t *buffer; + uint32_t *last; + uint32_t * volatile running; + uint32_t * volatile current; + uint32_t * volatile next; uint32_t *cook(const uint32_t *buffer, size_t size); diff --git a/hardware/arduino/sam/libraries/Audio/DAC.cpp b/hardware/arduino/sam/libraries/Audio/DAC.cpp index ae9056db0..766d7e4c4 100644 --- a/hardware/arduino/sam/libraries/Audio/DAC.cpp +++ b/hardware/arduino/sam/libraries/Audio/DAC.cpp @@ -1,3 +1,12 @@ +/* + * Copyright (c) 2012 by Cristian Maglie + * DAC library for Arduino Due. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ #include @@ -108,21 +117,25 @@ size_t DACClass::queueBuffer(const uint32_t *buffer, size_t size) { return 0; } -void DACClass::setOnQueueFree_CB(OnQueueFree_CB _cb) { +uint32_t *DACClass::getCurrentQueuePointer() { + return reinterpret_cast(dac->DACC_TPR); +} + +void DACClass::setOnTransmitEnd_CB(OnTransmitEnd_CB _cb, void *_data) { cb = _cb; - if (cb) { - dacc_enable_interrupt(dac, DACC_IER_ENDTX); - } else { + cbData = _data; + if (!cb) dacc_disable_interrupt(dac, DACC_IDR_ENDTX); - } } void DACClass::onService() { uint32_t sr = dac->DACC_ISR; - if (sr & DACC_ISR_ENDTX) { +// if (sr & DACC_ISR_ENDTX) { + // There is a free slot, enqueue data dacc_disable_interrupt(dac, DACC_IDR_ENDTX); - if (cb) cb(); - } + if (cb) + cb(cbData); +// } } DACClass DAC(DACC_INTERFACE, DACC_INTERFACE_ID, DACC_ISR_ID); diff --git a/hardware/arduino/sam/libraries/Audio/DAC.h b/hardware/arduino/sam/libraries/Audio/DAC.h index 925fb2164..d49658415 100644 --- a/hardware/arduino/sam/libraries/Audio/DAC.h +++ b/hardware/arduino/sam/libraries/Audio/DAC.h @@ -1,10 +1,19 @@ +/* + * Copyright (c) 2012 by Cristian Maglie + * DAC library for Arduino Due. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ #ifndef DAC_INCLUDED #define DAC_INCLUDED #include "Arduino.h" -typedef void (*OnQueueFree_CB)(void); +typedef void (*OnTransmitEnd_CB)(void *data); class DACClass { @@ -15,14 +24,19 @@ public: void end(); bool canQueue(); size_t queueBuffer(const uint32_t *buffer, size_t size); - void setOnQueueFree_CB(OnQueueFree_CB _cb); + uint32_t *getCurrentQueuePointer(); + void setOnTransmitEnd_CB(OnTransmitEnd_CB _cb, void *data); void onService(); + void enableInterrupts() { NVIC_EnableIRQ(isrId); }; + void disableInterrupts() { NVIC_DisableIRQ(isrId); }; + private: Dacc *dac; uint32_t dacId; IRQn_Type isrId; - OnQueueFree_CB cb; + OnTransmitEnd_CB cb; + void *cbData; }; extern DACClass DAC;