delay(400); | delay(400); | ||||
write(CHIP_LINE_OUT_VOL, 0x1D1D); // default approx 1.3 volts peak-to-peak | write(CHIP_LINE_OUT_VOL, 0x1D1D); // default approx 1.3 volts peak-to-peak | ||||
write(CHIP_CLK_CTRL, 0x0004); // 44.1 kHz, 256*Fs | write(CHIP_CLK_CTRL, 0x0004); // 44.1 kHz, 256*Fs | ||||
write(CHIP_I2S_CTRL, 0x0130); // SCLK=32*Fs, 16bit, I2S format | |||||
write(CHIP_I2S_CTRL, 0x0030); // SCLK=64*Fs, 16bit, I2S format | |||||
// default signal routing is ok? | // default signal routing is ok? | ||||
write(CHIP_SSS_CTRL, 0x0010); // ADC->I2S, I2S->DAC | write(CHIP_SSS_CTRL, 0x0010); // ADC->I2S, I2S->DAC | ||||
write(CHIP_ADCDAC_CTRL, 0x0000); // disable dac mute | write(CHIP_ADCDAC_CTRL, 0x0000); // disable dac mute |
/* | |||||
* A simple hardware test which receives audio on the A2 analog pin | |||||
* and sends it to the audio shield (I2S digital audio) | |||||
* | |||||
* This example code is in the public domain. | |||||
*/ | |||||
#include <Audio.h> | |||||
#include <Wire.h> | |||||
#include <SPI.h> | |||||
#include <SD.h> | |||||
#include <SerialFlash.h> | |||||
// GUItool: begin automatically generated code | |||||
AudioInputAnalog adc1; //xy=197,73 | |||||
AudioOutputI2S i2s1; //xy=375,85 | |||||
AudioConnection patchCord1(adc1, 0, i2s1, 0); | |||||
AudioConnection patchCord2(adc1, 0, i2s1, 1); | |||||
AudioControlSGTL5000 sgtl5000_1; //xy=314,158 | |||||
// GUItool: end automatically generated code | |||||
void setup() { | |||||
// Audio connections require memory to work. For more | |||||
// detailed information, see the MemoryAndCpuUsage example | |||||
AudioMemory(12); | |||||
// Enable the audio shield | |||||
sgtl5000_1.enable(); | |||||
sgtl5000_1.volume(0.5); | |||||
} | |||||
void loop() { | |||||
// Do nothing here. The Audio flows automatically | |||||
// When AudioInputAnalog is running, analogRead() must NOT be used. | |||||
} | |||||
at altered speed. The grainLength is specified in milliseconds, up to | at altered speed. The grainLength is specified in milliseconds, up to | ||||
one third of the memory from begin(); | one third of the memory from begin(); | ||||
</p> | </p> | ||||
<p class=func><span class=keyword>end</span>();</p> | |||||
<p class=func><span class=keyword>stop</span>();</p> | |||||
<p class=desc>Stop granual processing. The input signal is passed to the | <p class=desc>Stop granual processing. The input signal is passed to the | ||||
output without any changes. | output without any changes. | ||||
</p> | </p> |
* THE SOFTWARE. | * THE SOFTWARE. | ||||
*/ | */ | ||||
#if !defined(__IMXRT1052__) && !defined(__IMXRT1062__) | |||||
#if defined(KINETISK) | |||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include "input_adc.h" | #include "input_adc.h" | ||||
#define COEF_HPF_DCBLOCK (1048300<<10) // DC Removal filter coefficient in S1.30 | #define COEF_HPF_DCBLOCK (1048300<<10) // DC Removal filter coefficient in S1.30 | ||||
DMAMEM static uint16_t analog_rx_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
DMAMEM __attribute__((aligned(32))) static uint16_t analog_rx_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
audio_block_t * AudioInputAnalog::block_left = NULL; | audio_block_t * AudioInputAnalog::block_left = NULL; | ||||
uint16_t AudioInputAnalog::block_offset = 0; | uint16_t AudioInputAnalog::block_offset = 0; | ||||
int32_t AudioInputAnalog::hpf_y1 = 0; | int32_t AudioInputAnalog::hpf_y1 = 0; | ||||
void AudioInputAnalog::init(uint8_t pin) | void AudioInputAnalog::init(uint8_t pin) | ||||
{ | { | ||||
int32_t tmp; | |||||
int32_t tmp; | |||||
// Configure the ADC and run at least one software-triggered | // Configure the ADC and run at least one software-triggered | ||||
// conversion. This completes the self calibration stuff and | // conversion. This completes the self calibration stuff and | ||||
analogReadAveraging(4); | analogReadAveraging(4); | ||||
#endif | #endif | ||||
// Note for review: | // Note for review: | ||||
// Probably not useful to spin cycles here stabilizing | |||||
// since DC blocking is similar to te external analog filters | |||||
tmp = (uint16_t) analogRead(pin); | |||||
tmp = ( ((int32_t) tmp) << 14); | |||||
hpf_x1 = tmp; // With constant DC level x1 would be x0 | |||||
hpf_y1 = 0; // Output will settle here when stable | |||||
// Probably not useful to spin cycles here stabilizing | |||||
// since DC blocking is similar to te external analog filters | |||||
tmp = (uint16_t) analogRead(pin); | |||||
tmp = ( ((int32_t) tmp) << 14); | |||||
hpf_x1 = tmp; // With constant DC level x1 would be x0 | |||||
hpf_y1 = 0; // Output will settle here when stable | |||||
// set the programmable delay block to trigger the ADC at 44.1 kHz | // set the programmable delay block to trigger the ADC at 44.1 kHz | ||||
#if defined(KINETISK) | |||||
if (!(SIM_SCGC6 & SIM_SCGC6_PDB) | if (!(SIM_SCGC6 & SIM_SCGC6_PDB) | ||||
|| (PDB0_SC & PDB_CONFIG) != PDB_CONFIG | || (PDB0_SC & PDB_CONFIG) != PDB_CONFIG | ||||
|| PDB0_MOD != PDB_PERIOD | || PDB0_MOD != PDB_PERIOD | ||||
PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG; | PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG; | ||||
PDB0_CH0C1 = 0x0101; | PDB0_CH0C1 = 0x0101; | ||||
} | } | ||||
#endif | |||||
// enable the ADC for hardware trigger and DMA | // enable the ADC for hardware trigger and DMA | ||||
ADC0_SC2 |= ADC_SC2_ADTRG | ADC_SC2_DMAEN; | ADC0_SC2 |= ADC_SC2_ADTRG | ADC_SC2_DMAEN; | ||||
// set up a DMA channel to store the ADC data | // set up a DMA channel to store the ADC data | ||||
dma.begin(true); | dma.begin(true); | ||||
#if defined(KINETISK) | |||||
dma.TCD->SADDR = &ADC0_RA; | dma.TCD->SADDR = &ADC0_RA; | ||||
dma.TCD->SOFF = 0; | dma.TCD->SOFF = 0; | ||||
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | ||||
dma.TCD->DLASTSGA = -sizeof(analog_rx_buffer); | dma.TCD->DLASTSGA = -sizeof(analog_rx_buffer); | ||||
dma.TCD->BITER_ELINKNO = sizeof(analog_rx_buffer) / 2; | dma.TCD->BITER_ELINKNO = sizeof(analog_rx_buffer) / 2; | ||||
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | ||||
#endif | |||||
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_ADC0); | dma.triggerAtHardwareEvent(DMAMUX_SOURCE_ADC0); | ||||
update_responsibility = update_setup(); | update_responsibility = update_setup(); | ||||
dma.enable(); | dma.enable(); | ||||
uint16_t *dest_left; | uint16_t *dest_left; | ||||
audio_block_t *left; | audio_block_t *left; | ||||
#if defined(KINETISK) | |||||
daddr = (uint32_t)(dma.TCD->DADDR); | daddr = (uint32_t)(dma.TCD->DADDR); | ||||
#endif | |||||
dma.clearInterrupt(); | dma.clearInterrupt(); | ||||
if (daddr < (uint32_t)analog_rx_buffer + sizeof(analog_rx_buffer) / 2) { | if (daddr < (uint32_t)analog_rx_buffer + sizeof(analog_rx_buffer) / 2) { | ||||
transmit(out_left); | transmit(out_left); | ||||
release(out_left); | release(out_left); | ||||
} | } | ||||
#endif | |||||
#endif | |||||
#if defined(__IMXRT1062__) | |||||
#include <Arduino.h> | |||||
#include "input_adc.h" | |||||
extern "C" void xbar_connect(unsigned int input, unsigned int output); | |||||
#define FILTERLEN 15 | |||||
DMAChannel AudioInputAnalog::dma(false); | |||||
// TODO: how much extra space is needed to avoid wrap-around timing? 200 seems a safe guess | |||||
static __attribute__((aligned(32))) uint16_t adc_buffer[AUDIO_BLOCK_SAMPLES*4+200]; | |||||
static int16_t capture_buffer[AUDIO_BLOCK_SAMPLES*4+FILTERLEN]; | |||||
// TODO: these big buffers should be in DMAMEM, rather than consuming precious DTCM | |||||
PROGMEM static const uint8_t adc2_pin_to_channel[] = { | |||||
7, // 0/A0 AD_B1_02 | |||||
8, // 1/A1 AD_B1_03 | |||||
12, // 2/A2 AD_B1_07 | |||||
11, // 3/A3 AD_B1_06 | |||||
6, // 4/A4 AD_B1_01 | |||||
5, // 5/A5 AD_B1_00 | |||||
15, // 6/A6 AD_B1_10 | |||||
0, // 7/A7 AD_B1_11 | |||||
13, // 8/A8 AD_B1_08 | |||||
14, // 9/A9 AD_B1_09 | |||||
255, // 10/A10 AD_B0_12 - only on ADC1, 1 - can't use for audio | |||||
255, // 11/A11 AD_B0_13 - only on ADC1, 2 - can't use for audio | |||||
3, // 12/A12 AD_B1_14 | |||||
4, // 13/A13 AD_B1_15 | |||||
7, // 14/A0 AD_B1_02 | |||||
8, // 15/A1 AD_B1_03 | |||||
12, // 16/A2 AD_B1_07 | |||||
11, // 17/A3 AD_B1_06 | |||||
6, // 18/A4 AD_B1_01 | |||||
5, // 19/A5 AD_B1_00 | |||||
15, // 20/A6 AD_B1_10 | |||||
0, // 21/A7 AD_B1_11 | |||||
13, // 22/A8 AD_B1_08 | |||||
14, // 23/A9 AD_B1_09 | |||||
255, // 24/A10 AD_B0_12 - only on ADC1, 1 - can't use for audio | |||||
255, // 25/A11 AD_B0_13 - only on ADC1, 2 - can't use for audio | |||||
3, // 26/A12 AD_B1_14 - only on ADC2, do not use analogRead() | |||||
4, // 27/A13 AD_B1_15 - only on ADC2, do not use analogRead() | |||||
#ifdef ARDUINO_TEENSY41 | |||||
255, // 28 | |||||
255, // 29 | |||||
255, // 30 | |||||
255, // 31 | |||||
255, // 32 | |||||
255, // 33 | |||||
255, // 34 | |||||
255, // 35 | |||||
255, // 36 | |||||
255, // 37 | |||||
1, // 38/A14 AD_B1_12 - only on ADC2, do not use analogRead() | |||||
2, // 39/A15 AD_B1_13 - only on ADC2, do not use analogRead() | |||||
9, // 40/A16 AD_B1_04 | |||||
10, // 41/A17 AD_B1_05 | |||||
#endif | |||||
}; | |||||
static const int16_t filter[FILTERLEN] = { | |||||
1449, | |||||
3676, | |||||
6137, | |||||
9966, | |||||
13387, | |||||
16896, | |||||
18951, | |||||
19957, | |||||
18951, | |||||
16896, | |||||
13387, | |||||
9966, | |||||
6137, | |||||
3676, | |||||
1449 | |||||
}; | |||||
void AudioInputAnalog::init(uint8_t pin) | |||||
{ | |||||
if (pin >= sizeof(adc2_pin_to_channel)) return; | |||||
const uint8_t adc_channel = adc2_pin_to_channel[pin]; | |||||
if (adc_channel == 255) return; | |||||
// configure a timer to trigger ADC | |||||
// TODO: sample rate should be slightly lower than 4X AUDIO_SAMPLE_RATE_EXACT | |||||
// linear interpolation is supposed to resample it to exactly 4X | |||||
// the sample rate, so we avoid artifacts boundaries between captures | |||||
const int comp1 = ((float)F_BUS_ACTUAL) / (AUDIO_SAMPLE_RATE_EXACT * 4.0f) / 2.0f + 0.5f; | |||||
TMR4_ENBL &= ~(1<<3); | |||||
TMR4_SCTRL3 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE; | |||||
TMR4_CSCTRL3 = TMR_CSCTRL_CL1(1) | TMR_CSCTRL_TCF1EN; | |||||
TMR4_CNTR3 = 0; | |||||
TMR4_LOAD3 = 0; | |||||
TMR4_COMP13 = comp1; | |||||
TMR4_CMPLD13 = comp1; | |||||
TMR4_CTRL3 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(3); | |||||
TMR4_DMA3 = TMR_DMA_CMPLD1DE; | |||||
TMR4_CNTR3 = 0; | |||||
TMR4_ENBL |= (1<<3); | |||||
// connect the timer output the ADC_ETC input | |||||
const int trigger = 4; // 0-3 for ADC1, 4-7 for ADC2 | |||||
CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON); | |||||
xbar_connect(XBARA1_IN_QTIMER4_TIMER3, XBARA1_OUT_ADC_ETC_TRIG00 + trigger); | |||||
// turn on ADC_ETC and configure to receive trigger | |||||
if (ADC_ETC_CTRL & (ADC_ETC_CTRL_SOFTRST | ADC_ETC_CTRL_TSC_BYPASS)) { | |||||
ADC_ETC_CTRL = 0; // clears SOFTRST only | |||||
ADC_ETC_CTRL = 0; // clears TSC_BYPASS | |||||
} | |||||
ADC_ETC_CTRL |= ADC_ETC_CTRL_TRIG_ENABLE(1 << trigger) | ADC_ETC_CTRL_DMA_MODE_SEL; | |||||
ADC_ETC_DMA_CTRL |= ADC_ETC_DMA_CTRL_TRIQ_ENABLE(trigger); | |||||
// configure ADC_ETC trigger4 to make one ADC2 measurement on pin A2 | |||||
const int len = 1; | |||||
IMXRT_ADC_ETC.TRIG[trigger].CTRL = ADC_ETC_TRIG_CTRL_TRIG_CHAIN(len - 1) | | |||||
ADC_ETC_TRIG_CTRL_TRIG_PRIORITY(7); | |||||
IMXRT_ADC_ETC.TRIG[trigger].CHAIN_1_0 = ADC_ETC_TRIG_CHAIN_HWTS0(1) | | |||||
ADC_ETC_TRIG_CHAIN_CSEL0(adc2_pin_to_channel[pin]) | ADC_ETC_TRIG_CHAIN_B2B0; | |||||
// set up ADC2 for 12 bit mode, hardware trigger | |||||
Serial.printf("ADC2_CFG = %08X\n", ADC2_CFG); | |||||
ADC2_CFG |= ADC_CFG_ADTRG; | |||||
ADC2_CFG = ADC_CFG_MODE(2) | ADC_CFG_ADSTS(3) | ADC_CFG_ADLSMP | ADC_CFG_ADTRG | | |||||
ADC_CFG_ADICLK(1) | ADC_CFG_ADIV(0) /*| ADC_CFG_ADHSC*/; | |||||
ADC2_GC &= ~ADC_GC_AVGE; // single sample, no averaging | |||||
ADC2_HC0 = ADC_HC_ADCH(16); // 16 = controlled by ADC_ETC | |||||
// use a DMA channel to capture ADC_ETC output | |||||
dma.begin(); | |||||
dma.TCD->SADDR = &(IMXRT_ADC_ETC.TRIG[4].RESULT_1_0); | |||||
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 = adc_buffer; | |||||
dma.TCD->DOFF = 2; | |||||
dma.TCD->CITER_ELINKNO = sizeof(adc_buffer) / 2; | |||||
dma.TCD->DLASTSGA = -sizeof(adc_buffer); | |||||
dma.TCD->BITER_ELINKNO = sizeof(adc_buffer) / 2; | |||||
dma.TCD->CSR = 0; | |||||
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_ADC_ETC); | |||||
dma.enable(); | |||||
// TODO: configure I2S1 to interrupt every 128 audio samples | |||||
} | |||||
static int16_t fir(const int16_t *data, const int16_t *impulse, int len) | |||||
{ | |||||
int64_t sum=0; | |||||
while (len > 0) { | |||||
sum += *data++ * *impulse++; // TODO: optimize with DSP inst and filter symmetry | |||||
len --; | |||||
} | |||||
sum = sum >> 15; // TODO: adjust filter coefficients for proper gain, 12 to 16 bits | |||||
if (sum > 32767) return 32767; | |||||
if (sum < -32768) return -32768; | |||||
return sum; | |||||
} | |||||
void AudioInputAnalog::update(void) | |||||
{ | |||||
audio_block_t *output=NULL; | |||||
output = allocate(); | |||||
if (output == NULL) return; | |||||
uint16_t *p = (uint16_t *)dma.TCD->DADDR; | |||||
//int offset = p - adc_buffer; | |||||
//if (--offset < 0) offset = sizeof(adc_buffer) / 2 - 1; | |||||
//Serial.printf("offset = %4d, val = %4d\n", offset + 1, adc_buffer[offset]); | |||||
// copy adc buffer to capture buffer | |||||
// FIXME: this should be done from the I2S interrupt, for precise capture timing | |||||
const unsigned int capture_len = sizeof(capture_buffer) / 2; | |||||
for (unsigned int i=0; i < capture_len; i++) { | |||||
// TODO: linear interpolate to exactly 4X sample rate | |||||
if (--p < adc_buffer) p = adc_buffer + (sizeof(adc_buffer) / 2 - 1); | |||||
// remove DC offset | |||||
// TODO: very slow low pass filter for DC offset | |||||
int dc_offset = 550; // FIXME: quick kludge for testing!! | |||||
int n = (int)*p - dc_offset; | |||||
if (n > 4095) n = 4095; | |||||
if (n < -4095) n = -4095; | |||||
capture_buffer[i] = n; | |||||
} | |||||
//printbuf(capture_buffer, 8); | |||||
// low pass filter and subsample (this part belongs here) | |||||
int16_t *dest = output->data + AUDIO_BLOCK_SAMPLES - 1; | |||||
for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) { | |||||
#if 1 | |||||
// proper low-pass filter sounds pretty good | |||||
*dest-- = fir(capture_buffer + i * 4, filter, sizeof(filter)/2); | |||||
#else | |||||
// just averge 4 samples together, lower quality but much faster | |||||
*dest-- = capture_buffer[i * 4] + capture_buffer[i * 4 + 1] | |||||
+ capture_buffer[i * 4 + 2] + capture_buffer[i * 4 + 3]; | |||||
#endif | |||||
} | |||||
transmit(output); | |||||
release(output); | |||||
} | |||||
#endif |
AudioInputAnalog() : AudioStream(0, NULL) { init(A2); } | AudioInputAnalog() : AudioStream(0, NULL) { init(A2); } | ||||
AudioInputAnalog(uint8_t pin) : AudioStream(0, NULL) { init(pin); } | AudioInputAnalog(uint8_t pin) : AudioStream(0, NULL) { init(pin); } | ||||
virtual void update(void); | virtual void update(void); | ||||
friend void dma_ch9_isr(void); | |||||
private: | private: | ||||
static audio_block_t *block_left; | static audio_block_t *block_left; | ||||
static uint16_t block_offset; | static uint16_t block_offset; |
#define COEF_HPF_DCBLOCK (1048300<<10) // DC Removal filter coefficient in S1.30 | #define COEF_HPF_DCBLOCK (1048300<<10) // DC Removal filter coefficient in S1.30 | ||||
DMAMEM static uint16_t left_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
DMAMEM static uint16_t right_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
DMAMEM __attribute__((aligned(32))) static uint16_t left_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
DMAMEM __attribute__((aligned(32))) static uint16_t right_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
audio_block_t * AudioInputAnalogStereo::block_left = NULL; | audio_block_t * AudioInputAnalogStereo::block_left = NULL; | ||||
audio_block_t * AudioInputAnalogStereo::block_right = NULL; | audio_block_t * AudioInputAnalogStereo::block_right = NULL; | ||||
uint16_t AudioInputAnalogStereo::offset_left = 0; | uint16_t AudioInputAnalogStereo::offset_left = 0; |
#include "input_i2s.h" | #include "input_i2s.h" | ||||
#include "output_i2s.h" | #include "output_i2s.h" | ||||
static uint32_t i2s_rx_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
DMAMEM __attribute__((aligned(32))) static uint32_t i2s_rx_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
audio_block_t * AudioInputI2S::block_left = NULL; | audio_block_t * AudioInputI2S::block_left = NULL; | ||||
audio_block_t * AudioInputI2S::block_right = NULL; | audio_block_t * AudioInputI2S::block_right = NULL; | ||||
uint16_t AudioInputI2S::block_offset = 0; | uint16_t AudioInputI2S::block_offset = 0; | ||||
dest_left = &(left->data[offset]); | dest_left = &(left->data[offset]); | ||||
dest_right = &(right->data[offset]); | dest_right = &(right->data[offset]); | ||||
AudioInputI2S::block_offset = offset + AUDIO_BLOCK_SAMPLES/2; | AudioInputI2S::block_offset = offset + AUDIO_BLOCK_SAMPLES/2; | ||||
#if IMXRT_CACHE_ENABLED >=1 | |||||
arm_dcache_delete(src, sizeof(i2s_rx_buffer) / 2); | |||||
#endif | |||||
arm_dcache_delete((void*)src, sizeof(i2s_rx_buffer) / 2); | |||||
do { | do { | ||||
*dest_left++ = *src++; | *dest_left++ = *src++; | ||||
*dest_right++ = *src++; | *dest_right++ = *src++; |
#include "input_i2s2.h" | #include "input_i2s2.h" | ||||
#include "output_i2s2.h" | #include "output_i2s2.h" | ||||
static uint32_t i2s2_rx_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
DMAMEM __attribute__((aligned(32))) static uint32_t i2s2_rx_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
audio_block_t * AudioInputI2S2::block_left = NULL; | audio_block_t * AudioInputI2S2::block_left = NULL; | ||||
audio_block_t * AudioInputI2S2::block_right = NULL; | audio_block_t * AudioInputI2S2::block_right = NULL; | ||||
uint16_t AudioInputI2S2::block_offset = 0; | uint16_t AudioInputI2S2::block_offset = 0; | ||||
dest_left = &(left->data[offset]); | dest_left = &(left->data[offset]); | ||||
dest_right = &(right->data[offset]); | dest_right = &(right->data[offset]); | ||||
AudioInputI2S2::block_offset = offset + AUDIO_BLOCK_SAMPLES/2; | AudioInputI2S2::block_offset = offset + AUDIO_BLOCK_SAMPLES/2; | ||||
#if IMXRT_CACHE_ENABLED >=1 | |||||
arm_dcache_delete(src, sizeof(i2s_rx_buffer) / 2); | |||||
#endif | |||||
arm_dcache_delete((void*)src, sizeof(i2s2_rx_buffer) / 2); | |||||
do { | do { | ||||
*dest_left++ = *src++; | *dest_left++ = *src++; | ||||
*dest_right++ = *src++; | *dest_right++ = *src++; |
if (block_ch1) { | if (block_ch1) { | ||||
offset = block_offset; | offset = block_offset; | ||||
if (offset <= AUDIO_BLOCK_SAMPLES/2) { | if (offset <= AUDIO_BLOCK_SAMPLES/2) { | ||||
arm_dcache_delete(src, sizeof(i2s_rx_buffer) / 2); | |||||
arm_dcache_delete((void*)src, sizeof(i2s_rx_buffer) / 2); | |||||
block_offset = offset + AUDIO_BLOCK_SAMPLES/2; | block_offset = offset + AUDIO_BLOCK_SAMPLES/2; | ||||
dest1 = &(block_ch1->data[offset]); | dest1 = &(block_ch1->data[offset]); | ||||
dest2 = &(block_ch2->data[offset]); | dest2 = &(block_ch2->data[offset]); |
if (block_ch1) { | if (block_ch1) { | ||||
offset = block_offset; | offset = block_offset; | ||||
if (offset <= AUDIO_BLOCK_SAMPLES/2) { | if (offset <= AUDIO_BLOCK_SAMPLES/2) { | ||||
arm_dcache_delete(src, sizeof(i2s_rx_buffer) / 2); | |||||
arm_dcache_delete((void*)src, sizeof(i2s_rx_buffer) / 2); | |||||
block_offset = offset + AUDIO_BLOCK_SAMPLES/2; | block_offset = offset + AUDIO_BLOCK_SAMPLES/2; | ||||
dest1 = &(block_ch1->data[offset]); | dest1 = &(block_ch1->data[offset]); | ||||
dest2 = &(block_ch2->data[offset]); | dest2 = &(block_ch2->data[offset]); |
// but its performance should be *much* better than the rapid passband rolloff | // but its performance should be *much* better than the rapid passband rolloff | ||||
// of Cascaded Integrator Comb (CIC) or moving average filters. | // of Cascaded Integrator Comb (CIC) or moving average filters. | ||||
DMAMEM static uint32_t pdm_buffer[AUDIO_BLOCK_SAMPLES*4]; | |||||
DMAMEM __attribute__((aligned(32))) static uint32_t pdm_buffer[AUDIO_BLOCK_SAMPLES*4]; | |||||
static uint32_t leftover[14]; | static uint32_t leftover[14]; | ||||
audio_block_t * AudioInputPDM::block_left = NULL; | audio_block_t * AudioInputPDM::block_left = NULL; | ||||
bool AudioInputPDM::update_responsibility = false; | bool AudioInputPDM::update_responsibility = false; |
bool AudioOutputADAT::update_responsibility = false; | bool AudioOutputADAT::update_responsibility = false; | ||||
//uint32_t AudioOutputADAT::vucp = VUCP_VALID; | //uint32_t AudioOutputADAT::vucp = VUCP_VALID; | ||||
DMAMEM static uint32_t ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8]; //4 KB, AUDIO_BLOCK_SAMPLES is usually 128 | |||||
DMAMEM __attribute__((aligned(32))) static uint32_t ADAT_tx_buffer[AUDIO_BLOCK_SAMPLES * 8]; //4 KB, AUDIO_BLOCK_SAMPLES is usually 128 | |||||
DMAChannel AudioOutputADAT::dma(false); | DMAChannel AudioOutputADAT::dma(false); | ||||
#if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | #if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) | ||||
DMAMEM static uint16_t dac_buffer[AUDIO_BLOCK_SAMPLES*2]; | |||||
DMAMEM __attribute__((aligned(32))) static uint16_t dac_buffer[AUDIO_BLOCK_SAMPLES*2]; | |||||
audio_block_t * AudioOutputAnalog::block_left_1st = NULL; | audio_block_t * AudioOutputAnalog::block_left_1st = NULL; | ||||
audio_block_t * AudioOutputAnalog::block_left_2nd = NULL; | audio_block_t * AudioOutputAnalog::block_left_2nd = NULL; | ||||
bool AudioOutputAnalog::update_responsibility = false; | bool AudioOutputAnalog::update_responsibility = false; |
#if defined(__MK64FX512__) || defined(__MK66FX1M0__) | #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | ||||
DMAMEM static uint32_t dac_buffer[AUDIO_BLOCK_SAMPLES*2]; | |||||
DMAMEM __attribute__((aligned(32))) static uint32_t dac_buffer[AUDIO_BLOCK_SAMPLES*2]; | |||||
audio_block_t * AudioOutputAnalogStereo::block_left_1st = NULL; | audio_block_t * AudioOutputAnalogStereo::block_left_1st = NULL; | ||||
audio_block_t * AudioOutputAnalogStereo::block_left_2nd = NULL; | audio_block_t * AudioOutputAnalogStereo::block_left_2nd = NULL; | ||||
audio_block_t * AudioOutputAnalogStereo::block_right_1st = NULL; | audio_block_t * AudioOutputAnalogStereo::block_right_1st = NULL; |
dma.TCD->DLASTSGA = 0; | dma.TCD->DLASTSGA = 0; | ||||
dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | ||||
dma.TCD->DADDR = (void *)((uint32_t)&I2S1_TDR0 + 2); | dma.TCD->DADDR = (void *)((uint32_t)&I2S1_TDR0 + 2); | ||||
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||||
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX); | dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX); | ||||
dma.enable(); | dma.enable(); | ||||
uint16_t AudioOutputPT8211::block_right_offset = 0; | uint16_t AudioOutputPT8211::block_right_offset = 0; | ||||
bool AudioOutputPT8211::update_responsibility = false; | bool AudioOutputPT8211::update_responsibility = false; | ||||
#if defined(AUDIO_PT8211_OVERSAMPLING) | #if defined(AUDIO_PT8211_OVERSAMPLING) | ||||
static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES*4]; | |||||
DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES*4]; | |||||
#else | #else | ||||
static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
#endif | #endif | ||||
DMAChannel AudioOutputPT8211::dma(false); | DMAChannel AudioOutputPT8211::dma(false); | ||||
uint16_t AudioOutputPT8211_2::block_right_offset = 0; | uint16_t AudioOutputPT8211_2::block_right_offset = 0; | ||||
bool AudioOutputPT8211_2::update_responsibility = false; | bool AudioOutputPT8211_2::update_responsibility = false; | ||||
#if defined(AUDIO_PT8211_OVERSAMPLING) | #if defined(AUDIO_PT8211_OVERSAMPLING) | ||||
static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES*4]; | |||||
DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES*4]; | |||||
#else | #else | ||||
static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES]; | |||||
#endif | #endif | ||||
DMAChannel AudioOutputPT8211_2::dma(false); | DMAChannel AudioOutputPT8211_2::dma(false); | ||||
extern const struct _pwm_pin_info_struct pwm_pin_info[]; | extern const struct _pwm_pin_info_struct pwm_pin_info[]; | ||||
audio_block_t * AudioOutputPWM::block = NULL; | audio_block_t * AudioOutputPWM::block = NULL; | ||||
DMAMEM __attribute__((aligned(32))) static uint16_t pwm_tx_buffer[2][AUDIO_BLOCK_SAMPLES * 2]; | DMAMEM __attribute__((aligned(32))) static uint16_t pwm_tx_buffer[2][AUDIO_BLOCK_SAMPLES * 2]; | ||||
DMAChannel AudioOutputPWM::dma[2](false); | |||||
DMAChannel AudioOutputPWM::dma[2]; | |||||
_audio_info_flexpwm AudioOutputPWM::apins[2]; | _audio_info_flexpwm AudioOutputPWM::apins[2]; | ||||
FLASHMEM | FLASHMEM |