diff --git a/module_usb_audio/audio_io/audio_io.xc b/module_usb_audio/audio_io/audio_io.xc index 671cd911..45eab08c 100755 --- a/module_usb_audio/audio_io/audio_io.xc +++ b/module_usb_audio/audio_io/audio_io.xc @@ -31,11 +31,31 @@ #include "commands.h" #include "xc_ptr.h" +#ifndef I2S_DOWNSAMPLE_FACTOR +#define I2S_DOWNSAMPLE_FACTOR (1) +#endif +#define I2S_RATE_SCALING (I2S_DOWNSAMPLE_FACTOR) + +#if I2S_RATE_SCALING != I2S_DOWNSAMPLE_FACTOR +#error "Unsupported I2S rate scaling and downsampling configuration" +#endif + +// I2S channels for stereo AEC reference input +#define I2S_CHANS_DIGI_IN (2) +// The PDM mic channels start after the I2S AEC reference channels +#define PDM_RX_INDEX (I2S_CHANS_DIGI_IN) + +#if (NUM_USB_CHAN_IN < (I2S_CHANS_DIGI_IN + NUM_PDM_MICS)) +#error "Not enough USB input channels to support number of I2S and PDM inputs" +#endif + /* TODO 32 is max expected channels */ static unsigned samplesOut[32]; /* Two buffers for ADC data to allow for DAC and ADC ports being offset */ -static unsigned samplesIn[2][32]; +static unsigned samplesIn[2][I2S_DOWNSAMPLE_FACTOR][32]; + +static int downsamplingCounter = 0; #if (DSD_CHANS_DAC != 0) extern buffered out port:32 p_dsd_dac[DSD_CHANS_DAC]; @@ -266,16 +286,24 @@ static inline unsigned DoSampleTransfer(chanend c_out, const int readBuffNo, con #else inuint(c_out); #endif - UserBufferManagement(samplesOut, samplesIn[readBuffNo], i_audMan); + } + unsigned downsampledI2S[2]; + // TODO: run ds3 here + // Pass samplesIn[readBuffNo][0,I2S_DOWNSAMPLE_FACTOR][i]) to ds3() + UserBufferManagement(samplesOut, samplesIn[readBuffNo][downsamplingCounter], i_audMan); #if NUM_USB_CHAN_IN > 0 #pragma loop unroll - for(int i = 0; i < NUM_USB_CHAN_IN; i++) - { - outuint(c_out, samplesIn[readBuffNo][i]); - } -#endif + for(int i = 0; i < I2S_CHANS_DIGI_IN; i++) + { + outuint(c_out, downsampledI2S[i]); } +#pragma loop unroll + for (int i = PDM_RX_INDEX; i < (NUM_PDM_MICS + PDM_RX_INDEX); i++) + { + outuint(c_out, samplesIn[readBuffNo][downsamplingCounter][i]); + } +#endif return 0; } @@ -479,6 +507,8 @@ unsigned static deliver(chanend c_out, chanend ?c_spd_out, return command; } + downsamplingCounter = 0; + InitPorts(divide); /* TODO In master mode, the i/o loop assumes L/RCLK = 32bit clocks. We should check this every interation @@ -684,20 +714,22 @@ unsigned static deliver(chanend c_out, chanend ?c_spd_out, #endif #if (NUM_PDM_MICS > 0) - /* Get samples from PDM->PCM comverter */ - c_pdm_pcm <: 1; - master + if ((I2S_DOWNSAMPLE_FACTOR - 1) == downsamplingCounter) { + /* Get samples from PDM->PCM comverter */ + c_pdm_pcm <: 1; + master + { #pragma loop unroll - for(int i = 0; i < NUM_PDM_MICS; i++) - { - c_pdm_pcm :> samplesIn[readBuffNo][i]; - } + for(int i = PDM_RX_INDEX; i < (NUM_PDM_MICS + PDM_RX_INDEX); i++) + { + c_pdm_pcm :> samplesIn[readBuffNo][downsamplingCounter][i]; + } + } } #endif } - #if (I2S_CHANS_ADC != 0) index = 0; /* Channels 0, 2, 4.. on each line */ @@ -794,22 +826,30 @@ unsigned static deliver(chanend c_out, chanend ?c_spd_out, if(frameCount == I2S_CHANS_PER_FRAME) #endif { - /* Do samples transfer */ - /* The below looks a bit odd but forces the compiler to inline twice */ - unsigned command; - if(readBuffNo) - command = DoSampleTransfer(c_out, 1, underflowWord, i_audMan); - else - command = DoSampleTransfer(c_out, 0, underflowWord, i_audMan); - - if(command) + if ((I2S_DOWNSAMPLE_FACTOR - 1) == downsamplingCounter) { - return command; - } + /* Do samples transfer */ + /* The below looks a bit odd but forces the compiler to inline twice */ + unsigned command; + if(readBuffNo) + command = DoSampleTransfer(c_out, 1, underflowWord, i_audMan); + else + command = DoSampleTransfer(c_out, 0, underflowWord, i_audMan); - /* Reset frame counter and flip the ADC buffer */ - frameCount = 0; - readBuffNo = !readBuffNo; + if(command) + { + return command; + } + + /* Reset frame counter and flip the ADC buffer */ + downsamplingCounter = 0; + frameCount = 0; + readBuffNo = !readBuffNo; + } + else + { + ++downsamplingCounter; + } } } @@ -924,7 +964,7 @@ chanend ?c_config, chanend ?c unsigned adatMultiple = 0; #endif - unsigned curSamFreq = DEFAULT_FREQ; + unsigned curSamFreq = DEFAULT_FREQ * I2S_RATE_SCALING; unsigned curSamRes_DAC = STREAM_FORMAT_OUTPUT_1_RESOLUTION_BITS; /* Default to something reasonable */ unsigned curSamRes_ADC = STREAM_FORMAT_INPUT_1_RESOLUTION_BITS; /* Default to something reasonable - note, currently this never changes*/ unsigned command; @@ -1079,7 +1119,7 @@ chanend ?c_config, chanend ?c { /* TODO wait for good mclk instead of delay */ /* No delay for DFU modes */ - if ((curSamFreq != AUDIO_REBOOT_FROM_DFU) && (curSamFreq != AUDIO_STOP_FOR_DFU) && command) + if (((curSamFreq / I2S_RATE_SCALING) != AUDIO_REBOOT_FROM_DFU) && ((curSamFreq / I2S_RATE_SCALING) != AUDIO_STOP_FOR_DFU) && command) { #if 0 /* User should ensure MCLK is stable in AudioHwConfig */ @@ -1122,7 +1162,7 @@ chanend ?c_config, chanend ?c #if NUM_PDM_MICS > 0 /* Send decimation factor to PDM task(s) */ - c_pdm_in <: curSamFreq; + c_pdm_in <: curSamFreq / I2S_DOWNSAMPLE_FACTOR; #endif #ifdef ADAT_TX @@ -1163,7 +1203,7 @@ chanend ?c_config, chanend ?c if(command == SET_SAMPLE_FREQ) { - curSamFreq = inuint(c_mix_out); + curSamFreq = inuint(c_mix_out) * I2S_RATE_SCALING; } else if(command == SET_STREAM_FORMAT_OUT) { @@ -1176,7 +1216,7 @@ chanend ?c_config, chanend ?c } /* Currently no more audio will happen after this point */ - if (curSamFreq == AUDIO_STOP_FOR_DFU) + if ((curSamFreq / I2S_RATE_SCALING) == AUDIO_STOP_FOR_DFU) { outct(c_mix_out, XS1_CT_END);