diff --git a/lib_xua/src/core/audiohub/xua_audiohub.xc b/lib_xua/src/core/audiohub/xua_audiohub.xc index 78d75c7b..d8da4438 100755 --- a/lib_xua/src/core/audiohub/xua_audiohub.xc +++ b/lib_xua/src/core/audiohub/xua_audiohub.xc @@ -312,10 +312,180 @@ static inline unsigned DoSampleTransfer(chanend ?c_out, const int readBuffNo, co } #endif /* NO_USB */ -static inline void InitPorts(unsigned divide) + +/* This function performs the DSD native loop and outputs a 32b DSD stream per loop */ +static inline void DoDsdNative(unsigned samplesOut[], unsigned &dsdSample_l, unsigned &dsdSample_r, unsigned divide) +{ +#if (DSD_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT > 0) + /* 8 bits per chan, 1st 1-bit sample in MSB */ + dsdSample_l = samplesOut[0]; + dsdSample_r = samplesOut[1]; + dsdSample_r = bitrev(byterev(dsdSample_r)); + dsdSample_l = bitrev(byterev(dsdSample_l)); + + asm volatile("out res[%0], %1"::"r"(p_dsd_dac[0]),"r"(dsdSample_l)); + asm volatile("out res[%0], %1"::"r"(p_dsd_dac[1]),"r"(dsdSample_r)); + +#ifndef __XS2A__ + /* Output DSD data to ports then 32 clocks */ + switch (divide) + { + case 4: + p_dsd_clk <: 0xCCCCCCCC; + p_dsd_clk <: 0xCCCCCCCC; + p_dsd_clk <: 0xCCCCCCCC; + p_dsd_clk <: 0xCCCCCCCC; + break; + + case 2: + p_dsd_clk <: 0xAAAAAAAA; + p_dsd_clk <: 0xAAAAAAAA; + break; + + default: + /* Do some clocks anyway - this will stop us interrupting decouple too much */ + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + break; + } +#endif // __XS2A__ +#endif +} + +/* This function performs the DOP loop and collects 16b of DSD per loop + and outputs a 32b word into the port buffer every other cycle. */ +static inline void DoDsdDop(int &everyOther, unsigned samplesOut[], unsigned &dsdSample_l, unsigned &dsdSample_r, unsigned divide) +{ +#if (DSD_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT > 0) + if(!everyOther) + { + dsdSample_l = ((samplesOut[0] & 0xffff00) << 8); + dsdSample_r = ((samplesOut[1] & 0xffff00) << 8); + + everyOther = 1; + +#ifndef __XS2A__ + switch (divide) + { + case 8: + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + break; + + case 4: + p_dsd_clk <: 0xCCCCCCCC; + p_dsd_clk <: 0xCCCCCCCC; + break; + + case 2: + p_dsd_clk <: 0xAAAAAAAA; + break; + } +#endif // __XS2A__ + } +else // everyOther + { + everyOther = 0; + dsdSample_l = dsdSample_l | ((samplesOut[0] & 0xffff00) >> 8); + dsdSample_r = dsdSample_r | ((samplesOut[1] & 0xffff00) >> 8); + + // Output 16 clocks DSD to all + //p_dsd_dac[0] <: bitrev(dsdSample_l); + //p_dsd_dac[1] <: bitrev(dsdSample_r); + asm volatile("out res[%0], %1"::"r"(p_dsd_dac[0]),"r"(bitrev(dsdSample_l))); + asm volatile("out res[%0], %1"::"r"(p_dsd_dac[1]),"r"(bitrev(dsdSample_r))); + +#ifndef __XS2A__ + switch (divide) + { + case 8: + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + p_dsd_clk <: 0xF0F0F0F0; + break; + + case 4: + p_dsd_clk <: 0xCCCCCCCC; + p_dsd_clk <: 0xCCCCCCCC; + break; + + case 2: + p_dsd_clk <: 0xAAAAAAAA; + break; + } +#endif // __XS2A__ + } +#endif +} + +/* When DSD is enabled and streaming is normal I2S, this function checks for a series of DoP markers in the upper byte. + If found it will exit deliver() with the command to restart in DoP mode. + When in DoP mode, this function will check for a single absence of the DoP marker and exit deliver() with the command + to restart in I2S mode. */ + +static inline int DoDsdDopCheck(unsigned &dsdMode, int &dsdCount, unsigned curSamFreq, unsigned samplesOut[], unsigned &dsdMarker){ +#if (DSD_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT > 0) + /* Check for DSD - note we only move into DoP mode if valid DoP Freq */ + /* Currently we only check on channel 0 - we get all 0's on channels without data */ + if((dsdMode == DSD_MODE_OFF) && (curSamFreq > 96000)) + { + if((DSD_MASK(samplesOut[0]) == dsdMarker) && (DSD_MASK(samplesOut[1]) == dsdMarker)) + { + dsdCount++; + dsdMarker ^= DSD_MARKER_XOR; + if(dsdCount == DSD_EN_THRESH) + { + dsdMode = DSD_MODE_DOP; + dsdCount = 0; + dsdMarker = DSD_MARKER_2; + + // Set clocks low + p_lrclk <: 0; + p_bclk <: 0; + p_dsd_clk <: 0; + return 0; + } + } + else + { + dsdCount = 0; + dsdMarker = DSD_MARKER_2; + } + } + else if(dsdMode == DSD_MODE_DOP) // DSD DoP Mode + { + /* If we are running in DOP mode, check if we need to come out */ + if((DSD_MASK(samplesOut[0]) != DSD_MARKER_1) && (DSD_MASK(samplesOut[1]) != DSD_MARKER_1)) + { + if((DSD_MASK(samplesOut[0]) != DSD_MARKER_2) && (DSD_MASK(samplesOut[1]) != DSD_MARKER_2)) + { + dsdMode = DSD_MODE_OFF; + // Set clocks low + p_lrclk <: 0; + p_bclk <: 0; + p_dsd_clk <: 0; + return 0; + } + } + } +#endif + return 1; +} + + +#ifndef CODEC_MASTER +static inline void InitPorts_master(unsigned divide) { unsigned tmp; -#ifndef CODEC_MASTER #if (DSD_CHANS_DAC > 0) if(dsdMode == DSD_MODE_OFF) { @@ -409,45 +579,10 @@ static inline void InitPorts(unsigned divide) p_dsd_clk <: 0x80000000; } #endif -#else /* ifndef CODEC_MASTER */ - - /* Wait for LRCLK edge (in I2S LRCLK = 0 is left, TDM rising edge is start of frame) */ - p_lrclk when pinseq(0) :> void; - p_lrclk when pinseq(1) :> void; - p_lrclk when pinseq(0) :> void; - p_lrclk when pinseq(1) :> void; -#ifdef I2S_MODE_TDM - p_lrclk when pinseq(0) :> void; - p_lrclk when pinseq(1) :> void @ tmp; -#else - p_lrclk when pinseq(0) :> void @ tmp; -#endif - - tmp += (I2S_CHANS_PER_FRAME * 32) - 32 + 1 ; - /* E.g. 2 * 32 - 32 + 1 = 33 for stereo */ - /* E.g. 8 * 32 - 32 + 1 = 225 for 8 chan TDM */ - -#if (I2S_CHANS_DAC != 0) -#pragma loop unroll - for(int i = 0; i < I2S_WIRES_DAC; i++) - { - p_i2s_dac[i] @ tmp <: 0; - } -#endif - -#if (I2S_CHANS_ADC != 0) -#pragma loop unroll - for(int i = 0; i < I2S_WIRES_ADC; i++) - { - asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1)); - } -#endif -#endif } -/* I2S delivery thread */ #pragma unsafe arrays -unsigned static deliver(chanend ?c_out, chanend ?c_spd_out +unsigned static deliver_master(chanend ?c_out, chanend ?c_spd_out #ifdef ADAT_TX , chanend c_adat_out , unsigned adatSmuxMode @@ -471,13 +606,9 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out int started = 0; #endif -#ifdef CODEC_MASTER - int firstIteration = 1; -#endif - -#if (DSD_CHANS_DAC != 0) unsigned dsdMarker = DSD_MARKER_2; /* This alternates between DSD_MARKER_1 and DSD_MARKER_2 */ int dsdCount = 0; +#if (DSD_CHANS_DAC != 0) int everyOther = 1; unsigned dsdSample_l = 0x96960000; unsigned dsdSample_r = 0x96960000; @@ -555,135 +686,15 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out return command; } - InitPorts(divide); + InitPorts_master(divide); /* Main Audio I/O loop */ while (1) { -#ifdef CODEC_MASTER - /* In CODEC master mode, the I/O loop assumes L/RCLK = 32bit clocks. - * Check this every iteration and resync if we get a bclk glitch. - */ - int syncError = 0; - - if (!firstIteration) - { - InitPorts(divide); - } - else - { - firstIteration = 0; - } - - while (!syncError) -#endif // CODEC_MASTER { #if (DSD_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT > 0) - if(dsdMode == DSD_MODE_NATIVE) - { - /* 8 bits per chan, 1st 1-bit sample in MSB */ - dsdSample_l = samplesOut[0]; - dsdSample_r = samplesOut[1]; - dsdSample_r = bitrev(byterev(dsdSample_r)); - dsdSample_l = bitrev(byterev(dsdSample_l)); - - /* Output DSD data to ports (then 32 clocks if we don't have the HW clock divider of X200 */ - asm volatile("out res[%0], %1"::"r"(p_dsd_dac[0]),"r"(dsdSample_l)); - asm volatile("out res[%0], %1"::"r"(p_dsd_dac[1]),"r"(dsdSample_r)); -#ifndef __XS2A__ - switch (divide) - { - case 4: - p_dsd_clk <: 0xCCCCCCCC; - p_dsd_clk <: 0xCCCCCCCC; - p_dsd_clk <: 0xCCCCCCCC; - p_dsd_clk <: 0xCCCCCCCC; - break; - - case 2: - p_dsd_clk <: 0xAAAAAAAA; - p_dsd_clk <: 0xAAAAAAAA; - break; - - default: - /* Do some clocks anyway - this will stop us interrupting decouple too much */ - /* (And stop the data outputs above pausing forever) */ - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - break; - } -#endif /* __XS2A__ */ - } - else if(dsdMode == DSD_MODE_DOP) - { - if(!everyOther) - { - dsdSample_l = ((samplesOut[0] & 0xffff00) << 8); - dsdSample_r = ((samplesOut[1] & 0xffff00) << 8); - - everyOther = 1; - -#ifndef __XS2A__ - switch (divide) - { - case 8: - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - break; - - case 4: - p_dsd_clk <: 0xCCCCCCCC; - p_dsd_clk <: 0xCCCCCCCC; - break; - - case 2: - p_dsd_clk <: 0xAAAAAAAA; - break; - } -#endif - } - else // everyOther - { - everyOther = 0; - dsdSample_l = dsdSample_l | ((samplesOut[0] & 0xffff00) >> 8); - dsdSample_r = dsdSample_r | ((samplesOut[1] & 0xffff00) >> 8); - - // Output 16 clocks DSD to all - //p_dsd_dac[0] <: bitrev(dsdSample_l); - //p_dsd_dac[1] <: bitrev(dsdSample_r); - asm volatile("out res[%0], %1"::"r"(p_dsd_dac[0]),"r"(bitrev(dsdSample_l))); - asm volatile("out res[%0], %1"::"r"(p_dsd_dac[1]),"r"(bitrev(dsdSample_r))); - -#ifndef __XS2A__ - switch (divide) - { - case 8: - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - p_dsd_clk <: 0xF0F0F0F0; - break; - - case 4: - p_dsd_clk <: 0xCCCCCCCC; - p_dsd_clk <: 0xCCCCCCCC; - break; - - case 2: - p_dsd_clk <: 0xAAAAAAAA; - break; - } -#endif - } - } + if(dsdMode == DSD_MODE_NATIVE) DoDsdNative(samplesOut, dsdSample_l, dsdSample_r, divide); + else if(dsdMode == DSD_MODE_DOP) DoDsdDop(everyOther, samplesOut, dsdSample_l, dsdSample_r, divide); else #endif { @@ -707,16 +718,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out // Manual IN instruction since compiler generates an extra setc per IN (bug #15256) unsigned sample; asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index++])); -#ifdef CODEC_MASTER - unsigned lrval; - p_lrclk :> lrval; -#ifdef I2S_MODE_TDM - syncError += (lrval != 0x00000000); -#else - syncError += (lrval != 0x80000000); -#endif // I2S_MODE_TDM -#endif // CODEC_MASTER - sample = bitrev(sample); int chanIndex = ((frameCount-2)&(I2S_CHANS_PER_FRAME-1))+i; // channels 0, 2, 4.. on each line. #if (AUD_TO_USB_RATIO > 1) @@ -744,10 +745,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out } #endif - - - -#ifndef CODEC_MASTER /* LR clock delayed by one clock, This is so MSB is output on the falling edge of BCLK * after the falling edge on which LRCLK was toggled. (see I2S spec) */ /* Generate clocks LR Clock low - LEFT */ @@ -756,7 +753,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out #else p_lrclk <: 0x80000000; #endif -#endif #pragma xta endpoint "i2s_output_l" @@ -783,10 +779,8 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out } #endif // (I2S_CHANS_DAC != 0) -#ifndef CODEC_MASTER /* Clock out the LR Clock, the DAC data and Clock in the next sample into ADC */ doI2SClocks(divide); -#endif // !CODEC_MASTER #ifdef ADAT_TX TransferAdatTxSamples(c_adat_out, samplesOut, adatSmuxMode, 1); @@ -857,23 +851,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out /* Manual IN instruction since compiler generates an extra setc per IN (bug #15256) */ unsigned sample; asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index++])); -#ifdef CODEC_MASTER - unsigned lrval; - p_lrclk :> lrval; -#ifdef I2S_MODE_TDM - if (frameCount == (I2S_CHANS_PER_FRAME-2)) - { - syncError += (lrval != 0x80000000); - } - else - { - syncError += (lrval != 0x00000000); - } -#else - syncError += (lrval != 0x7FFFFFFF); -#endif // I2S_MODE_TDM -#endif // CODEC_MASTER - sample = bitrev(sample); int chanIndex = ((frameCount-1)&(I2S_CHANS_PER_FRAME-1))+i; // channels 1, 3, 5.. on each line. #if (AUD_TO_USB_RATIO > 1 && !I2S_DOWNSAMPLE_MONO_IN) @@ -901,7 +878,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out } #endif -#ifndef CODEC_MASTER #ifdef I2S_MODE_TDM if(frameCount == (I2S_CHANS_PER_FRAME-2)) p_lrclk <: 0x80000000; @@ -909,7 +885,6 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out p_lrclk <: 0x00000000; #else p_lrclk <: 0x7FFFFFFF; -#endif #endif index = 0; @@ -936,58 +911,11 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out } #endif // (I2S_CHANS_DAC != 0) -#ifndef CODEC_MASTER doI2SClocks(divide); -#endif // !CODEC_MASTER - - } // !dsdMode -#if (DSD_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT > 0) - /* Check for DSD - note we only move into DoP mode if valid DoP Freq */ - /* Currently we only check on channel 0 - we get all 0's on channels without data */ - if((dsdMode == DSD_MODE_OFF) && (curSamFreq > 96000)) - { - if((DSD_MASK(samplesOut[0]) == dsdMarker) && (DSD_MASK(samplesOut[1]) == dsdMarker)) - { - dsdCount++; - dsdMarker ^= DSD_MARKER_XOR; - if(dsdCount == DSD_EN_THRESH) - { - dsdMode = DSD_MODE_DOP; - dsdCount = 0; - dsdMarker = DSD_MARKER_2; - - // Set clocks low - p_lrclk <: 0; - p_bclk <: 0; - p_dsd_clk <: 0; - return 0; - } - } - else - { - dsdCount = 0; - dsdMarker = DSD_MARKER_2; - } - } - else if(dsdMode == DSD_MODE_DOP) // DSD DoP Mode - { - /* If we are running in DOP mode, check if we need to come out */ - if((DSD_MASK(samplesOut[0]) != DSD_MARKER_1) && (DSD_MASK(samplesOut[1]) != DSD_MARKER_1)) - { - if((DSD_MASK(samplesOut[0]) != DSD_MARKER_2) && (DSD_MASK(samplesOut[1]) != DSD_MARKER_2)) - { - dsdMode = DSD_MODE_OFF; - // Set clocks low - p_lrclk <: 0; - p_bclk <: 0; - p_dsd_clk <: 0; - return 0; - } - } - } -#endif + int ret = DoDsdDopCheck(dsdMode, dsdCount, curSamFreq, samplesOut, dsdMarker); + if (ret == 0) return 0; #ifdef I2S_MODE_TDM /* Increase frameCount by 2 since we have output two channels (per data line) */ @@ -1022,10 +950,437 @@ unsigned static deliver(chanend ?c_out, chanend ?c_spd_out } } } - #pragma xta endpoint "deliver_return" return 0; } +#endif //ndef CODEC_MASTER + + +#ifdef CODEC_MASTER +static inline void InitPorts_slave(unsigned divide) +{ + unsigned tmp; + + /* Wait for LRCLK edge (in I2S LRCLK = 0 is left, TDM rising edge is start of frame) */ + p_lrclk when pinseq(0) :> void; + p_lrclk when pinseq(1) :> void; + p_lrclk when pinseq(0) :> void; + p_lrclk when pinseq(1) :> void; +#ifdef I2S_MODE_TDM + p_lrclk when pinseq(0) :> void; + p_lrclk when pinseq(1) :> void @ tmp; +#else + p_lrclk when pinseq(0) :> void @ tmp; +#endif + + tmp += (I2S_CHANS_PER_FRAME * 32) - 32 + 1 ; + /* E.g. 2 * 32 - 32 + 1 = 33 for stereo */ + /* E.g. 8 * 32 - 32 + 1 = 225 for 8 chan TDM */ + +#if (I2S_CHANS_DAC != 0) +#pragma loop unroll + for(int i = 0; i < I2S_WIRES_DAC; i++) + { + p_i2s_dac[i] @ tmp <: 0; + } +#endif + +#if (I2S_CHANS_ADC != 0) +#pragma loop unroll + for(int i = 0; i < I2S_WIRES_ADC; i++) + { + asm("setpt res[%0], %1"::"r"(p_i2s_adc[i]),"r"(tmp-1)); + } +#endif +} + + +/* I2S delivery thread */ +#pragma unsafe arrays +unsigned static deliver_slave(chanend ?c_out, chanend ?c_spd_out +#ifdef ADAT_TX + , chanend c_adat_out + , unsigned adatSmuxMode +#endif + , unsigned divide, unsigned curSamFreq +#if(defined(SPDIF_RX) || defined(ADAT_RX)) + , chanend c_dig_rx +#endif +#if (NUM_PDM_MICS > 0) + , chanend c_pdm_pcm +#endif +) +{ + /* Since DAC and ADC buffered ports off by one sample we buffer previous ADC frame */ + unsigned readBuffNo = 0; + unsigned index; + +#ifdef RAMP_CHECK + unsigned prev=0; + int started = 0; +#endif + + int firstIteration = 1; + unsigned underflowWord = 0; + unsigned frameCount = 0; +#ifdef ADAT_TX + adatCounter = 0; +#endif + + unsigned audioToUsbRatioCounter = 0; +#if (NUM_PDM_MICS > 0) + unsigned audioToMicsRatioCounter = 0; +#endif + +#if (AUD_TO_USB_RATIO > 1) + union i2sInDs3 + { + long long doubleWordAlignmentEnsured; + int32_t delayLine[I2S_DOWNSAMPLE_CHANS_IN][SRC_FF3V_FIR_NUM_PHASES][SRC_FF3V_FIR_TAPS_PER_PHASE]; + } i2sInDs3; + memset(&i2sInDs3.delayLine, 0, sizeof i2sInDs3.delayLine); + int64_t i2sInDs3Sum[I2S_DOWNSAMPLE_CHANS_IN]; + + union i2sOutUs3 + { + long long doubleWordAlignmentEnsured; + int32_t delayLine[I2S_CHANS_DAC][SRC_FF3V_FIR_TAPS_PER_PHASE]; + } i2sOutUs3; + memset(&i2sOutUs3.delayLine, 0, sizeof i2sOutUs3.delayLine); +#endif /* (AUD_TO_USB_RATIO > 1) */ + + +#if ((DEBUG_MIC_ARRAY == 1) && (NUM_PDM_MICS > 0)) + /* Get initial samples from PDM->PCM converter to avoid stalling the decimators */ + c_pdm_pcm <: 1; + master + { +#pragma loop unroll + for(int i = PDM_MIC_INDEX; i < (NUM_PDM_MICS + PDM_MIC_INDEX); i++) + { + c_pdm_pcm :> samplesIn[readBuffNo][i]; + } + } +#endif // ((DEBUG_MIC_ARRAY == 1) && (NUM_PDM_MICS > 0)) + + UserBufferManagementInit(); + + unsigned command = DoSampleTransfer(c_out, readBuffNo, underflowWord); + + // Reinitialise user state before entering the main loop + UserBufferManagementInit(); + +#ifdef ADAT_TX + unsafe{ + //TransferAdatTxSamples(c_adat_out, samplesOut, adatSmuxMode, 0); + volatile unsigned * unsafe samplePtr = &samplesOut[ADAT_TX_INDEX]; + outuint(c_adat_out, (unsigned) samplePtr); + } +#endif + if(command) + { + return command; + } + + InitPorts_slave(divide); + + /* Main Audio I/O loop */ + while (1) + { + /* In CODEC master mode, the I/O loop assumes L/RCLK = 32bit clocks. + * Check this every iteration and resync if we get a bclk glitch. + */ + int syncError = 0; + unsigned lrval; + + if (!firstIteration) + { + InitPorts_slave(divide); + } + else + { + firstIteration = 0; + } + + while (!syncError) + { +#if (I2S_CHANS_ADC != 0) +#if (AUD_TO_USB_RATIO > 1) + if (0 == audioToUsbRatioCounter) + { + memset(&i2sInDs3Sum, 0, sizeof i2sInDs3Sum); + } +#endif /* (AUD_TO_USB_RATIO > 1) */ + /* Input previous L sample into L in buffer */ + index = 0; + /* First input (i.e. frameCount == 0) we read last ADC channel of previous frame.. */ + unsigned buffIndex = (frameCount > 1) ? !readBuffNo : readBuffNo; + +#pragma loop unroll + /* First time around we get channel 7 of TDM8 */ + for(int i = 0; i < I2S_CHANS_ADC; i+=I2S_CHANS_PER_FRAME) + { + // p_i2s_adc[index++] :> sample; + // Manual IN instruction since compiler generates an extra setc per IN (bug #15256) + unsigned sample; + asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index++])); + + if (i == 0){ + p_lrclk :> lrval; +#ifdef I2S_MODE_TDM + //We do not check this part of the frame because TDM frame sync falling egde timing + //is not defined. We only care about rising edge which is checked in first half of frame +#else + syncError += (lrval != 0x80000000); +#endif // I2S_MODE_TDM + } + + sample = bitrev(sample); + int chanIndex = ((frameCount-2)&(I2S_CHANS_PER_FRAME-1))+i; // channels 0, 2, 4.. on each line. +#if (AUD_TO_USB_RATIO > 1) + if ((AUD_TO_USB_RATIO - 1) == audioToUsbRatioCounter) + { + samplesIn[buffIndex][chanIndex] = + src_ds3_voice_add_final_sample( + i2sInDs3Sum[chanIndex], + i2sInDs3.delayLine[chanIndex][audioToUsbRatioCounter], + src_ff3v_fir_coefs[audioToUsbRatioCounter], + sample); + } + else + { + i2sInDs3Sum[chanIndex] = + src_ds3_voice_add_sample( + i2sInDs3Sum[chanIndex], + i2sInDs3.delayLine[chanIndex][audioToUsbRatioCounter], + src_ff3v_fir_coefs[audioToUsbRatioCounter], + sample); + } +#else + samplesIn[buffIndex][chanIndex] = sample; +#endif /* (AUD_TO_USB_RATIO > 1) */ + } +#else //(I2S_CHANS_ADC != 0) //If no ADC channels then just check lrclk for sync + p_lrclk :> lrval; +#ifdef I2S_MODE_TDM + //We do not check this part of the frame because TDM frame sync falling egde timing + //is not defined. We only care about rising edge which is checked in first half of frame +#else + syncError += (lrval != 0x80000000); +#endif // I2S_MODE_TDM +#endif //(I2S_CHANS_ADC != 0) + + +#pragma xta endpoint "i2s_output_l" + +#if (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0) + index = 0; +#pragma loop unroll + /* Output "even" channel to DAC (i.e. left) */ + for(int i = 0; i < I2S_CHANS_DAC; i+=I2S_CHANS_PER_FRAME) + { +#if (AUD_TO_USB_RATIO > 1) + if (0 == audioToUsbRatioCounter) + { + samplesOut[frameCount+i] = src_us3_voice_input_sample(i2sOutUs3.delayLine[i], + src_ff3v_fir_coefs[2], + samplesOut[frameCount+i]); + } + else /* audioToUsbRatioCounter == 1 or 2 */ + { + samplesOut[frameCount+i] = src_us3_voice_get_next_sample(i2sOutUs3.delayLine[i], + src_ff3v_fir_coefs[2-audioToUsbRatioCounter]); + } +#endif /* (AUD_TO_USB_RATIO > 1) */ + p_i2s_dac[index++] <: bitrev(samplesOut[frameCount +i]); + } +#endif // (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0) + +#ifdef ADAT_TX + TransferAdatTxSamples(c_adat_out, samplesOut, adatSmuxMode, 1); +#endif + + if(frameCount == 0) + { + +#if defined(SPDIF_RX) || defined(ADAT_RX) + /* Sync with clockgen */ + inuint(c_dig_rx); + + /* Note, digi-data we just store in samplesIn[readBuffNo] - we only double buffer the I2S input data */ +#endif +#ifdef SPDIF_RX + asm("ldw %0, dp[g_digData]" :"=r"(samplesIn[readBuffNo][SPDIF_RX_INDEX + 0])); + asm("ldw %0, dp[g_digData+4]":"=r"(samplesIn[readBuffNo][SPDIF_RX_INDEX + 1])); +#endif +#ifdef ADAT_RX + asm("ldw %0, dp[g_digData+8]" :"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX])); + asm("ldw %0, dp[g_digData+12]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 1])); + asm("ldw %0, dp[g_digData+16]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 2])); + asm("ldw %0, dp[g_digData+20]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 3])); + asm("ldw %0, dp[g_digData+24]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 4])); + asm("ldw %0, dp[g_digData+28]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 5])); + asm("ldw %0, dp[g_digData+32]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 6])); + asm("ldw %0, dp[g_digData+36]":"=r"(samplesIn[readBuffNo][ADAT_RX_INDEX + 7])); +#endif + +#if defined(SPDIF_RX) || defined(ADAT_RX) + /* Request digital data (with prefill) */ + outuint(c_dig_rx, 0); +#endif +#if ((XUA_SPDIF_TX_EN) && (NUM_USB_CHAN_OUT > 0)) + outuint(c_spd_out, samplesOut[SPDIF_TX_INDEX]); /* Forward sample to S/PDIF Tx thread */ + unsigned sample = samplesOut[SPDIF_TX_INDEX + 1]; + outuint(c_spd_out, sample); /* Forward sample to S/PDIF Tx thread */ +#endif + +#if (NUM_PDM_MICS > 0) + if ((AUD_TO_MICS_RATIO - 1) == audioToMicsRatioCounter) + { + /* Get samples from PDM->PCM converter */ + c_pdm_pcm <: 1; + master + { +#pragma loop unroll + for(int i = PDM_MIC_INDEX; i < (NUM_PDM_MICS + PDM_MIC_INDEX); i++) + { + c_pdm_pcm :> samplesIn[readBuffNo][i]; + } + } + audioToMicsRatioCounter = 0; + } + else + { + ++audioToMicsRatioCounter; + } +#endif + } + +#if (I2S_CHANS_ADC != 0) + index = 0; + /* Channels 0, 2, 4.. on each line */ +#pragma loop unroll + for(int i = 0; i < I2S_CHANS_ADC; i += I2S_CHANS_PER_FRAME) + { + /* Manual IN instruction since compiler generates an extra setc per IN (bug #15256) */ + unsigned sample; + asm volatile("in %0, res[%1]" : "=r"(sample) : "r"(p_i2s_adc[index++])); + if (i == 0) { + p_lrclk :> lrval; +#ifdef I2S_MODE_TDM + //Just check for the rising edge of frame synch being in the right place because falling edge timing not specified + if (frameCount == 0) { + lrval &= 0xc0000000; //Mask off last two (MSB) frame clock bits which are the most recently sampled + syncError += (lrval != 0x80000000); //We need MSB = 1 and MSB-1 = 0 to signify rising edge + } +#else + syncError += (lrval != 0x7FFFFFFF); +#endif // I2S_MODE_TDM + } + + sample = bitrev(sample); + int chanIndex = ((frameCount-1)&(I2S_CHANS_PER_FRAME-1))+i; // channels 1, 3, 5.. on each line. +#if (AUD_TO_USB_RATIO > 1 && !I2S_DOWNSAMPLE_MONO_IN) + if ((AUD_TO_USB_RATIO - 1) == audioToUsbRatioCounter) + { + samplesIn[buffIndex][chanIndex] = + src_ds3_voice_add_final_sample( + i2sInDs3Sum[chanIndex], + i2sInDs3.delayLine[chanIndex][audioToUsbRatioCounter], + src_ff3v_fir_coefs[audioToUsbRatioCounter], + sample); + } + else + { + i2sInDs3Sum[chanIndex] = + src_ds3_voice_add_sample( + i2sInDs3Sum[chanIndex], + i2sInDs3.delayLine[chanIndex][audioToUsbRatioCounter], + src_ff3v_fir_coefs[audioToUsbRatioCounter], + sample); + } +#else + samplesIn[buffIndex][chanIndex] = sample; +#endif /* (AUD_TO_USB_RATIO > 1) && !I2S_DOWNSAMPLE_MONO_IN */ + } +#else //(I2S_CHANS_ADC != 0) //No ADC so just do lrclk sync check only + p_lrclk :> lrval; +#ifdef I2S_MODE_TDM + if (frameCount == (I2S_CHANS_PER_FRAME-2)) + { + syncError += (lrval != 0x80000000); + } + else + { + syncError += (lrval != 0x00000000); + } +#else + syncError += (lrval != 0x7FFFFFFF); +#endif //I2S_MODE_TDM +#endif //(I2S_CHANS_ADC != 0) + + index = 0; +#pragma xta endpoint "i2s_output_r" +#if (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0) + /* Output "odd" channel to DAC (i.e. right) */ +#pragma loop unroll + for(int i = 1; i < I2S_CHANS_DAC; i+=I2S_CHANS_PER_FRAME) + { +#if (AUD_TO_USB_RATIO > 1) + if (audioToUsbRatioCounter == 0) + { + samplesOut[frameCount+i] = src_us3_voice_input_sample(i2sOutUs3.delayLine[i], + src_ff3v_fir_coefs[2], + samplesOut[frameCount+i]); + } + else + { /* audioToUsbRatioCounter is 1 or 2 */ + samplesOut[frameCount+i] = src_us3_voice_get_next_sample(i2sOutUs3.delayLine[i], + src_ff3v_fir_coefs[2-audioToUsbRatioCounter]); + } +#endif /* (AUD_TO_USB_RATIO > 1) */ + p_i2s_dac[index++] <: bitrev(samplesOut[frameCount + i]); + } +#endif // (I2S_CHANS_DAC != 0) && (NUM_USB_CHAN_OUT != 0) + + +#ifdef I2S_MODE_TDM + /* Increase frameCount by 2 since we have output two channels (per data line) */ + frameCount+=2; + if(frameCount == I2S_CHANS_PER_FRAME) +#endif + { + if ((AUD_TO_USB_RATIO - 1) == audioToUsbRatioCounter) + { + /* 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); + else + command = DoSampleTransfer(c_out, 0, underflowWord); + + if(command) + { + return command; + } + + /* Reset frame counter and flip the ADC buffer */ + audioToUsbRatioCounter = 0; + frameCount = 0; + readBuffNo = !readBuffNo; + } + else + { + ++audioToUsbRatioCounter; + } + } + } + } +#pragma xta endpoint "deliver_return" + return 0; +} +#endif //CODEC_MASTER #if (XUA_SPDIF_TX_EN) && (SPDIF_TX_TILE != AUDIO_IO_TILE) void SpdifTxWrapper(chanend c_spdif_tx) @@ -1048,6 +1403,11 @@ void SpdifTxWrapper(chanend c_spdif_tx) } #endif +#if XUA_DFU_EN +[[distributable]] +void DFUHandler(server interface i_dfu i, chanend ?c_user_cmd); +#endif + /* This function is a dummy version of the deliver thread that does not connect to the codec ports. It is used during DFU reset. */ @@ -1059,6 +1419,7 @@ void testct_byref(chanend c, int &returnVal) returnVal = 1; } +#if (XUA_DFU_EN == 1) [[combinable]] static void dummy_deliver(chanend ?c_out, unsigned &command) { @@ -1104,6 +1465,7 @@ static void dummy_deliver(chanend ?c_out, unsigned &command) } } } +#endif #if XUA_DFU_EN [[distributable]] @@ -1360,7 +1722,11 @@ void XUA_AudioHub(chanend ?c_mix_out outuint(c_adat_out, adatMultiple); outuint(c_adat_out, adatSmuxMode); #endif - command = deliver(c_mix_out +#if CODEC_MASTER + command = deliver_slave(c_mix_out +#else + command = deliver_master(c_mix_out +#endif #if (XUA_SPDIF_TX_EN) , c_spdif_out #else