|
|
|
|
|
|
|
|
|
|
|
|
|
|
void AudioOutputAnalog::begin(void) |
|
|
void AudioOutputAnalog::begin(void) |
|
|
{ |
|
|
{ |
|
|
|
|
|
dma(); // Allocate the DMA channel first |
|
|
|
|
|
|
|
|
SIM_SCGC2 |= SIM_SCGC2_DAC0; |
|
|
SIM_SCGC2 |= SIM_SCGC2_DAC0; |
|
|
DAC0_C0 = DAC_C0_DACEN; // 1.2V VDDA is DACREF_2 |
|
|
DAC0_C0 = DAC_C0_DACEN; // 1.2V VDDA is DACREF_2 |
|
|
//DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2 |
|
|
|
|
|
// slowly ramp up to DC voltage, approx 1/4 second |
|
|
// slowly ramp up to DC voltage, approx 1/4 second |
|
|
for (int16_t i=0; i<2048; i+=8) { |
|
|
for (int16_t i=0; i<2048; i+=8) { |
|
|
*(int16_t *)&(DAC0_DAT0L) = i; |
|
|
*(int16_t *)&(DAC0_DAT0L) = i; |
|
|
|
|
|
|
|
|
PDB0_MOD = PDB_PERIOD; |
|
|
PDB0_MOD = PDB_PERIOD; |
|
|
PDB0_SC = PDB_CONFIG | PDB_SC_LDOK; |
|
|
PDB0_SC = PDB_CONFIG | PDB_SC_LDOK; |
|
|
PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG | PDB_SC_PDBIE | PDB_SC_DMAEN; |
|
|
PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG | PDB_SC_PDBIE | PDB_SC_DMAEN; |
|
|
SIM_SCGC7 |= SIM_SCGC7_DMA; |
|
|
|
|
|
SIM_SCGC6 |= SIM_SCGC6_DMAMUX; |
|
|
|
|
|
DMA_CR = 0; |
|
|
|
|
|
DMA_TCD4_SADDR = dac_buffer; |
|
|
|
|
|
DMA_TCD4_SOFF = 2; |
|
|
|
|
|
DMA_TCD4_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); |
|
|
|
|
|
DMA_TCD4_NBYTES_MLNO = 2; |
|
|
|
|
|
DMA_TCD4_SLAST = -sizeof(dac_buffer); |
|
|
|
|
|
DMA_TCD4_DADDR = &DAC0_DAT0L; |
|
|
|
|
|
DMA_TCD4_DOFF = 0; |
|
|
|
|
|
DMA_TCD4_CITER_ELINKNO = sizeof(dac_buffer) / 2; |
|
|
|
|
|
DMA_TCD4_DLASTSGA = 0; |
|
|
|
|
|
DMA_TCD4_BITER_ELINKNO = sizeof(dac_buffer) / 2; |
|
|
|
|
|
DMA_TCD4_CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; |
|
|
|
|
|
DMAMUX0_CHCFG4 = DMAMUX_DISABLE; |
|
|
|
|
|
DMAMUX0_CHCFG4 = DMAMUX_SOURCE_PDB | DMAMUX_ENABLE; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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(); |
|
|
update_responsibility = update_setup(); |
|
|
DMA_SERQ = 4; |
|
|
|
|
|
NVIC_ENABLE_IRQ(IRQ_DMA_CH4); |
|
|
|
|
|
|
|
|
dma().enable(); |
|
|
|
|
|
dma().attachInterrupt(isr); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void AudioOutputAnalog::analogReference(int ref) |
|
|
void AudioOutputAnalog::analogReference(int ref) |
|
|
|
|
|
|
|
|
// TODO: the DAC has much higher bandwidth than the datasheet says |
|
|
// TODO: the DAC has much higher bandwidth than the datasheet says |
|
|
// can we output a 2X oversampled output, for easier filtering? |
|
|
// can we output a 2X oversampled output, for easier filtering? |
|
|
|
|
|
|
|
|
void dma_ch4_isr(void) |
|
|
|
|
|
|
|
|
void AudioOutputAnalog::isr(void) |
|
|
{ |
|
|
{ |
|
|
const int16_t *src, *end; |
|
|
const int16_t *src, *end; |
|
|
int16_t *dest; |
|
|
int16_t *dest; |
|
|
audio_block_t *block; |
|
|
audio_block_t *block; |
|
|
uint32_t saddr; |
|
|
uint32_t saddr; |
|
|
|
|
|
|
|
|
saddr = (uint32_t)DMA_TCD4_SADDR; |
|
|
|
|
|
DMA_CINT = 4; |
|
|
|
|
|
|
|
|
//saddr = (uint32_t)DMA_TCD4_SADDR; |
|
|
|
|
|
//DMA_CINT = 4; |
|
|
|
|
|
saddr = (uint32_t)(dma().TCD->SADDR); |
|
|
|
|
|
dma().clearInterrupt(); |
|
|
if (saddr < (uint32_t)dac_buffer + sizeof(dac_buffer) / 2) { |
|
|
if (saddr < (uint32_t)dac_buffer + sizeof(dac_buffer) / 2) { |
|
|
// DMA is transmitting the first half of the buffer |
|
|
// DMA is transmitting the first half of the buffer |
|
|
// so we must fill the second half |
|
|
// so we must fill the second half |