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 a36253ea4..63e201ea8 100644 Binary files a/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a and b/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a differ 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