| @@ -34,6 +34,13 @@ | |||
| #error "The Audio Library only works with Teensy 3.X. Teensy 2.0 is unsupported." | |||
| #endif | |||
| #include "DMAChannel.h" | |||
| #ifndef DMACHANNEL_HAS_BEGIN | |||
| #error "You need to update DMAChannel.h & DMAChannel.cpp" | |||
| #error "https://github.com/PaulStoffregen/cores/blob/master/teensy3/DMAChannel.h" | |||
| #error "https://github.com/PaulStoffregen/cores/blob/master/teensy3/DMAChannel.cpp" | |||
| #endif | |||
| // When changing multiple audio object settings that must update at | |||
| // the same time, these functions allow the audio library interrupt | |||
| // to be disabled. For example, you may wish to begin playing a note | |||
| @@ -32,11 +32,12 @@ audio_block_t * AudioInputI2S::block_left = NULL; | |||
| audio_block_t * AudioInputI2S::block_right = NULL; | |||
| uint16_t AudioInputI2S::block_offset = 0; | |||
| bool AudioInputI2S::update_responsibility = false; | |||
| DMAChannel AudioInputI2S::dma; | |||
| void AudioInputI2S::begin(void) | |||
| { | |||
| dma(); // Allocate the DMA channel first | |||
| dma.begin(true); // Allocate the DMA channel first | |||
| //block_left_1st = NULL; | |||
| //block_right_1st = NULL; | |||
| @@ -46,25 +47,25 @@ void AudioInputI2S::begin(void) | |||
| CORE_PIN13_CONFIG = PORT_PCR_MUX(4); // pin 13, PTC5, I2S0_RXD0 | |||
| dma().TCD->SADDR = &I2S0_RDR0; | |||
| dma().TCD->SOFF = 0; | |||
| dma().TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| dma().TCD->NBYTES_MLNO = 2; | |||
| dma().TCD->SLAST = 0; | |||
| dma().TCD->DADDR = i2s_rx_buffer; | |||
| dma().TCD->DOFF = 2; | |||
| dma().TCD->CITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; | |||
| dma().TCD->DLASTSGA = -sizeof(i2s_rx_buffer); | |||
| dma().TCD->BITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; | |||
| dma().TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| dma().triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_RX); | |||
| dma.TCD->SADDR = &I2S0_RDR0; | |||
| dma.TCD->SOFF = 0; | |||
| dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| dma.TCD->NBYTES_MLNO = 2; | |||
| dma.TCD->SLAST = 0; | |||
| dma.TCD->DADDR = i2s_rx_buffer; | |||
| dma.TCD->DOFF = 2; | |||
| dma.TCD->CITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; | |||
| dma.TCD->DLASTSGA = -sizeof(i2s_rx_buffer); | |||
| dma.TCD->BITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; | |||
| dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_RX); | |||
| update_responsibility = update_setup(); | |||
| dma().enable(); | |||
| dma.enable(); | |||
| I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR; | |||
| I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE; // TX clock enable, because sync'd to TX | |||
| dma().attachInterrupt(isr); | |||
| dma.attachInterrupt(isr); | |||
| } | |||
| void AudioInputI2S::isr(void) | |||
| @@ -75,8 +76,8 @@ void AudioInputI2S::isr(void) | |||
| audio_block_t *left, *right; | |||
| //digitalWriteFast(3, HIGH); | |||
| daddr = (uint32_t)(dma().TCD->DADDR); | |||
| dma().clearInterrupt(); | |||
| daddr = (uint32_t)(dma.TCD->DADDR); | |||
| dma.clearInterrupt(); | |||
| if (daddr < (uint32_t)i2s_rx_buffer + sizeof(i2s_rx_buffer) / 2) { | |||
| // DMA is receiving to the first half of the buffer | |||
| @@ -170,7 +171,7 @@ void AudioInputI2S::update(void) | |||
| void AudioInputI2Sslave::begin(void) | |||
| { | |||
| dma(); // Allocate the DMA channel first | |||
| dma.begin(true); // Allocate the DMA channel first | |||
| //block_left_1st = NULL; | |||
| //block_right_1st = NULL; | |||
| @@ -179,25 +180,25 @@ void AudioInputI2Sslave::begin(void) | |||
| CORE_PIN13_CONFIG = PORT_PCR_MUX(4); // pin 13, PTC5, I2S0_RXD0 | |||
| dma().TCD->SADDR = &I2S0_RDR0; | |||
| dma().TCD->SOFF = 0; | |||
| dma().TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| dma().TCD->NBYTES_MLNO = 2; | |||
| dma().TCD->SLAST = 0; | |||
| dma().TCD->DADDR = i2s_rx_buffer; | |||
| dma().TCD->DOFF = 2; | |||
| dma().TCD->CITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; | |||
| dma().TCD->DLASTSGA = -sizeof(i2s_rx_buffer); | |||
| dma().TCD->BITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; | |||
| dma().TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| dma().triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_RX); | |||
| dma.TCD->SADDR = &I2S0_RDR0; | |||
| dma.TCD->SOFF = 0; | |||
| dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| dma.TCD->NBYTES_MLNO = 2; | |||
| dma.TCD->SLAST = 0; | |||
| dma.TCD->DADDR = i2s_rx_buffer; | |||
| dma.TCD->DOFF = 2; | |||
| dma.TCD->CITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; | |||
| dma.TCD->DLASTSGA = -sizeof(i2s_rx_buffer); | |||
| dma.TCD->BITER_ELINKNO = sizeof(i2s_rx_buffer) / 2; | |||
| dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_RX); | |||
| update_responsibility = update_setup(); | |||
| dma().enable(); | |||
| dma.enable(); | |||
| I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR; | |||
| I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE; // TX clock enable, because sync'd to TX | |||
| dma().attachInterrupt(isr); | |||
| dma.attachInterrupt(isr); | |||
| } | |||
| @@ -39,10 +39,7 @@ public: | |||
| protected: | |||
| AudioInputI2S(int dummy): AudioStream(0, NULL) {} // to be used only inside AudioInputI2Sslave !! | |||
| static bool update_responsibility; | |||
| static inline DMAChannel &dma() __attribute__((always_inline)) { | |||
| static DMAChannel mydma; | |||
| return mydma; | |||
| } | |||
| static DMAChannel dma; | |||
| static void isr(void); | |||
| private: | |||
| static audio_block_t *block_left; | |||
| @@ -33,10 +33,11 @@ DMAMEM static uint16_t dac_buffer[AUDIO_BLOCK_SAMPLES*2]; | |||
| audio_block_t * AudioOutputAnalog::block_left_1st = NULL; | |||
| audio_block_t * AudioOutputAnalog::block_left_2nd = NULL; | |||
| bool AudioOutputAnalog::update_responsibility = false; | |||
| DMAChannel AudioOutputAnalog::dma; | |||
| void AudioOutputAnalog::begin(void) | |||
| { | |||
| dma(); // Allocate the DMA channel first | |||
| dma.begin(true); // Allocate the DMA channel first | |||
| SIM_SCGC2 |= SIM_SCGC2_DAC0; | |||
| DAC0_C0 = DAC_C0_DACEN; // 1.2V VDDA is DACREF_2 | |||
| @@ -53,21 +54,21 @@ void AudioOutputAnalog::begin(void) | |||
| PDB0_SC = PDB_CONFIG | PDB_SC_LDOK; | |||
| PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG | PDB_SC_PDBIE | PDB_SC_DMAEN; | |||
| dma().TCD->SADDR = dac_buffer; | |||
| dma().TCD->SOFF = 2; | |||
| dma().TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| dma().TCD->NBYTES_MLNO = 2; | |||
| dma().TCD->SLAST = -sizeof(dac_buffer); | |||
| dma().TCD->DADDR = &DAC0_DAT0L; | |||
| dma().TCD->DOFF = 0; | |||
| dma().TCD->CITER_ELINKNO = sizeof(dac_buffer) / 2; | |||
| dma().TCD->DLASTSGA = 0; | |||
| dma().TCD->BITER_ELINKNO = sizeof(dac_buffer) / 2; | |||
| dma().TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| dma().triggerAtHardwareEvent(DMAMUX_SOURCE_PDB); | |||
| dma.TCD->SADDR = dac_buffer; | |||
| dma.TCD->SOFF = 2; | |||
| dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| dma.TCD->NBYTES_MLNO = 2; | |||
| dma.TCD->SLAST = -sizeof(dac_buffer); | |||
| dma.TCD->DADDR = &DAC0_DAT0L; | |||
| dma.TCD->DOFF = 0; | |||
| dma.TCD->CITER_ELINKNO = sizeof(dac_buffer) / 2; | |||
| dma.TCD->DLASTSGA = 0; | |||
| dma.TCD->BITER_ELINKNO = sizeof(dac_buffer) / 2; | |||
| dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| dma.triggerAtHardwareEvent(DMAMUX_SOURCE_PDB); | |||
| update_responsibility = update_setup(); | |||
| dma().enable(); | |||
| dma().attachInterrupt(isr); | |||
| dma.enable(); | |||
| dma.attachInterrupt(isr); | |||
| } | |||
| void AudioOutputAnalog::analogReference(int ref) | |||
| @@ -113,10 +114,8 @@ void AudioOutputAnalog::isr(void) | |||
| audio_block_t *block; | |||
| uint32_t saddr; | |||
| //saddr = (uint32_t)DMA_TCD4_SADDR; | |||
| //DMA_CINT = 4; | |||
| saddr = (uint32_t)(dma().TCD->SADDR); | |||
| dma().clearInterrupt(); | |||
| saddr = (uint32_t)(dma.TCD->SADDR); | |||
| dma.clearInterrupt(); | |||
| if (saddr < (uint32_t)dac_buffer + sizeof(dac_buffer) / 2) { | |||
| // DMA is transmitting the first half of the buffer | |||
| // so we must fill the second half | |||
| @@ -42,10 +42,7 @@ private: | |||
| static audio_block_t *block_left_2nd; | |||
| static bool update_responsibility; | |||
| audio_block_t *inputQueueArray[1]; | |||
| static inline DMAChannel &dma() __attribute__((always_inline)) { | |||
| static DMAChannel mydma; | |||
| return mydma; | |||
| } | |||
| static DMAChannel dma; | |||
| static void isr(void); | |||
| }; | |||
| @@ -34,10 +34,11 @@ uint16_t AudioOutputI2S::block_left_offset = 0; | |||
| uint16_t AudioOutputI2S::block_right_offset = 0; | |||
| bool AudioOutputI2S::update_responsibility = false; | |||
| DMAMEM static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES]; | |||
| DMAChannel AudioOutputI2S::dma; | |||
| void AudioOutputI2S::begin(void) | |||
| { | |||
| dma(); // Allocate the DMA channel first | |||
| dma.begin(true); // Allocate the DMA channel first | |||
| block_left_1st = NULL; | |||
| block_right_1st = NULL; | |||
| @@ -46,23 +47,23 @@ void AudioOutputI2S::begin(void) | |||
| config_i2s(); | |||
| CORE_PIN22_CONFIG = PORT_PCR_MUX(6); // pin 22, PTC1, I2S0_TXD0 | |||
| dma().TCD->SADDR = i2s_tx_buffer; | |||
| dma().TCD->SOFF = 2; | |||
| dma().TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| dma().TCD->NBYTES_MLNO = 2; | |||
| dma().TCD->SLAST = -sizeof(i2s_tx_buffer); | |||
| dma().TCD->DADDR = &I2S0_TDR0; | |||
| dma().TCD->DOFF = 0; | |||
| dma().TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | |||
| dma().TCD->DLASTSGA = 0; | |||
| dma().TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | |||
| dma().TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| dma().triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX); | |||
| dma.TCD->SADDR = i2s_tx_buffer; | |||
| dma.TCD->SOFF = 2; | |||
| dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| dma.TCD->NBYTES_MLNO = 2; | |||
| dma.TCD->SLAST = -sizeof(i2s_tx_buffer); | |||
| dma.TCD->DADDR = &I2S0_TDR0; | |||
| dma.TCD->DOFF = 0; | |||
| dma.TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | |||
| dma.TCD->DLASTSGA = 0; | |||
| dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | |||
| dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX); | |||
| update_responsibility = update_setup(); | |||
| dma().enable(); | |||
| dma.enable(); | |||
| I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE | I2S_TCSR_FR; | |||
| dma().attachInterrupt(isr); | |||
| dma.attachInterrupt(isr); | |||
| } | |||
| @@ -73,8 +74,8 @@ void AudioOutputI2S::isr(void) | |||
| audio_block_t *block; | |||
| uint32_t saddr, offset; | |||
| saddr = (uint32_t)(dma().TCD->SADDR); | |||
| dma().clearInterrupt(); | |||
| saddr = (uint32_t)(dma.TCD->SADDR); | |||
| dma.clearInterrupt(); | |||
| if (saddr < (uint32_t)i2s_tx_buffer + sizeof(i2s_tx_buffer) / 2) { | |||
| // DMA is transmitting the first half of the buffer | |||
| // so we must fill the second half | |||
| @@ -267,7 +268,7 @@ void AudioOutputI2S::config_i2s(void) | |||
| void AudioOutputI2Sslave::begin(void) | |||
| { | |||
| dma(); // Allocate the DMA channel first | |||
| dma.begin(true); // Allocate the DMA channel first | |||
| //pinMode(2, OUTPUT); | |||
| block_left_1st = NULL; | |||
| @@ -276,24 +277,24 @@ void AudioOutputI2Sslave::begin(void) | |||
| AudioOutputI2Sslave::config_i2s(); | |||
| CORE_PIN22_CONFIG = PORT_PCR_MUX(6); // pin 22, PTC1, I2S0_TXD0 | |||
| dma().TCD->SADDR = i2s_tx_buffer; | |||
| dma().TCD->SOFF = 2; | |||
| dma().TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| dma().TCD->NBYTES_MLNO = 2; | |||
| dma().TCD->SLAST = -sizeof(i2s_tx_buffer); | |||
| dma().TCD->DADDR = &I2S0_TDR0; | |||
| dma().TCD->DOFF = 0; | |||
| dma().TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | |||
| dma().TCD->DLASTSGA = 0; | |||
| dma().TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | |||
| dma().TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| dma().triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX); | |||
| dma.TCD->SADDR = i2s_tx_buffer; | |||
| dma.TCD->SOFF = 2; | |||
| dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| dma.TCD->NBYTES_MLNO = 2; | |||
| dma.TCD->SLAST = -sizeof(i2s_tx_buffer); | |||
| dma.TCD->DADDR = &I2S0_TDR0; | |||
| dma.TCD->DOFF = 0; | |||
| dma.TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | |||
| dma.TCD->DLASTSGA = 0; | |||
| dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | |||
| dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX); | |||
| update_responsibility = update_setup(); | |||
| dma().enable(); | |||
| dma.enable(); | |||
| I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE | I2S_TCSR_FR; | |||
| dma().attachInterrupt(isr); | |||
| dma.attachInterrupt(isr); | |||
| } | |||
| void AudioOutputI2Sslave::config_i2s(void) | |||
| @@ -43,10 +43,7 @@ protected: | |||
| static audio_block_t *block_left_1st; | |||
| static audio_block_t *block_right_1st; | |||
| static bool update_responsibility; | |||
| static inline DMAChannel &dma() __attribute__((always_inline)) { | |||
| static DMAChannel mydma; | |||
| return mydma; | |||
| } | |||
| static DMAChannel dma; | |||
| static void isr(void); | |||
| private: | |||
| static audio_block_t *block_left_2nd; | |||