@@ -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; |