diff --git a/lib_xua/api/xua_clocking.h b/lib_xua/api/xua_clocking.h index f2a80c1c..c0240035 100644 --- a/lib_xua/api/xua_clocking.h +++ b/lib_xua/api/xua_clocking.h @@ -6,6 +6,8 @@ #include +#include "sw_pll_wrapper.h" + interface pll_ref_if { void toggle(); @@ -26,9 +28,10 @@ void PllRefPinTask(server interface pll_ref_if i_pll_ref, out port p_sync); * clock * \param c_clk_int channel connected to the decouple() thread for clock * interrupts - * \param p_for_mclk_count_aud port used for counting mclk and providing a timestamp - * * \param c_mclk_change channel to notify of master clock change + * \param p_for_mclk_count_aud port used for counting mclk and providing a timestamp + * \param c_sw_pll channel used to communicate with software PLL task + * */ void clockGen( streaming chanend ?c_spdif_rx, chanend ?c_adat_rx, @@ -36,8 +39,9 @@ void clockGen( streaming chanend ?c_spdif_rx, chanend c_audio, chanend c_clk_ctl, chanend c_clk_int, + chanend c_mclk_change, port ?p_for_mclk_count_aud, - chanend c_mclk_change); + chanend ?c_sw_pll); #if (XUA_USE_APP_PLL) diff --git a/lib_xua/src/core/audiohub/xua_audiohub.xc b/lib_xua/src/core/audiohub/xua_audiohub.xc index 279ef608..35751848 100755 --- a/lib_xua/src/core/audiohub/xua_audiohub.xc +++ b/lib_xua/src/core/audiohub/xua_audiohub.xc @@ -636,9 +636,9 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk, buffered _XUA_CLK_DIR port:32 ?p_bclk, buffered out port:32 (&?p_i2s_dac)[I2S_WIRES_DAC], buffered in port:32 (&?p_i2s_adc)[I2S_WIRES_ADC] - #if (XUA_USE_APP_PLL) - , client interface SoftPll_if i_softPll - #endif +#if (XUA_USE_APP_PLL) + , client interface SoftPll_if i_softPll +#endif #if (XUA_SPDIF_TX_EN) //&& (SPDIF_TX_TILE != AUDIO_IO_TILE) , chanend c_spdif_out #endif @@ -814,11 +814,6 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk, /* User should mute audio hardware */ AudioHwConfig_Mute(); -#if (USE_SW_PLL) - // i_softPll.init(mClk); - #warning SORT THIS -#endif - /* User code should configure audio harware for SampleFreq/MClk etc */ AudioHwConfig(curFreq, mClk, dsdMode, curSamRes_DAC, curSamRes_ADC); #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) diff --git a/lib_xua/src/core/clocking/clockgen.xc b/lib_xua/src/core/clocking/clockgen.xc index 08040504..479b56d7 100644 --- a/lib_xua/src/core/clocking/clockgen.xc +++ b/lib_xua/src/core/clocking/clockgen.xc @@ -7,7 +7,6 @@ #include "xua.h" #include "xua_commands.h" #include "xua_clocking.h" -#include "sw_pll_wrapper.h" #if (XUA_SPDIF_RX_EN) #include "spdif.h" @@ -201,8 +200,6 @@ static inline int validSamples(Counter &counter, int clockIndex) #endif #if USE_SW_PLL -/* Pointer to sw_pll struct to allow it to be used in separate SDM thread */ -extern sw_pll_state_t * unsafe sw_pll_ptr; unsafe { unsigned * unsafe selected_mclk_rate_ptr = NULL; @@ -225,8 +222,9 @@ void clockGen ( streaming chanend ?c_spdif_rx, chanend c_dig_rx, chanend c_clk_ctl, chanend c_clk_int, + chanend c_mclk_change, port ?p_for_mclk_count_aud, - chanend c_mclk_change) + chanend ?c_sw_pll) { timer t_local; unsigned timeNextEdge, timeLastEdge, timeNextClockDetection; @@ -343,568 +341,551 @@ void clockGen ( streaming chanend ?c_spdif_rx, /* Initial ref clock output and get timestamp */ i_pll_ref.init(); -#if (USE_SW_PLL && (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)) - chan c_sigma_delta; +#if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) int reset_sw_pll_pfd = 1; int require_ack_to_audio = 0; - - /* Set selected_mclk_rate_ptr to point at local var selected_mclk_rate */ - unsafe { - selected_mclk_rate_ptr = &selected_mclk_rate; - } - - par - { - while(1) - { - unsafe - { - SigmaDeltaTask(c_sigma_delta, selected_mclk_rate_ptr); - } - } -#else - { + restart_sigma_delta(c_sw_pll, MCLK_48); /* default to 48kHz - this will be reset shortly when host selects rate */ #endif - while(1) + + while(1) + { + select { - select - { #ifdef LEVEL_METER_LEDS #warning Level metering enabled - case t_level when timerafter(levelTime) :> void: + case t_level when timerafter(levelTime) :> void: - levelTime += LEVEL_UPDATE_RATE; + levelTime += LEVEL_UPDATE_RATE; - /* Copy over level data and reset */ - for(int i = 0; i< NUM_USB_CHAN_IN; i++) + /* Copy over level data and reset */ + for(int i = 0; i< NUM_USB_CHAN_IN; i++) + { + int tmp; + + /* Read level data */ + //g_inputLevelData[i] = samples_to_host_inputs[i]; + asm volatile("ldw %0, %1[%2]":"=r"(tmp):"r"((const int *)samples_to_host_inputs),"r"(i)); + g_inputLevelData[i] = tmp; + + /* Reset level data */ + //samples_to_host_inputs[i] = 0; + asm volatile("stw %0, %1[%2]"::"r"(0),"r"((const int *)samples_to_host_inputs),"r"(i)); + + /* Guard against host polling slower than timer and missing peaks */ + asm volatile("ldw %0, %1[%2]":"=r"(tmp):"r"((const int *)samples_to_host_inputs_buff),"r"(i)); + + if (g_inputLevelData[i] > tmp) + //if(g_inputLevelData[i] > samples_to_host_inputs_buff[i]) { - int tmp; - - /* Read level data */ - //g_inputLevelData[i] = samples_to_host_inputs[i]; - asm volatile("ldw %0, %1[%2]":"=r"(tmp):"r"((const int *)samples_to_host_inputs),"r"(i)); - g_inputLevelData[i] = tmp; - - /* Reset level data */ - //samples_to_host_inputs[i] = 0; - asm volatile("stw %0, %1[%2]"::"r"(0),"r"((const int *)samples_to_host_inputs),"r"(i)); - - /* Guard against host polling slower than timer and missing peaks */ - asm volatile("ldw %0, %1[%2]":"=r"(tmp):"r"((const int *)samples_to_host_inputs_buff),"r"(i)); - - if (g_inputLevelData[i] > tmp) - //if(g_inputLevelData[i] > samples_to_host_inputs_buff[i]) - { - //samples_to_host_inputs_buff[i] = g_inputLevelData[i]; - asm volatile("stw %0, %1[%2]"::"r"(tmp),"r"((const int *)samples_to_host_inputs),"r"(i)); - } + //samples_to_host_inputs_buff[i] = g_inputLevelData[i]; + asm volatile("stw %0, %1[%2]"::"r"(tmp),"r"((const int *)samples_to_host_inputs),"r"(i)); } + } - /* Call user LED refresh */ - VendorLedRefresh(g_inputLevelData); + /* Call user LED refresh */ + VendorLedRefresh(g_inputLevelData); - break; + break; #endif - /* Updates to clock settings from endpoint 0 */ - case inuint_byref(c_clk_ctl, tmp): - switch(tmp) - { - case GET_SEL: - chkct(c_clk_ctl, XS1_CT_END); + /* Updates to clock settings from endpoint 0 */ + case inuint_byref(c_clk_ctl, tmp): + switch(tmp) + { + case GET_SEL: + chkct(c_clk_ctl, XS1_CT_END); - /* Send back current clock mode */ - outuint(c_clk_ctl, clkMode); - outct(c_clk_ctl, XS1_CT_END); + /* Send back current clock mode */ + outuint(c_clk_ctl, clkMode); + outct(c_clk_ctl, XS1_CT_END); - break; + break; - case SET_SEL: - /* Update clock mode */ - clkMode = inuint(c_clk_ctl); - chkct(c_clk_ctl, XS1_CT_END); + case SET_SEL: + /* Update clock mode */ + clkMode = inuint(c_clk_ctl); + chkct(c_clk_ctl, XS1_CT_END); #ifdef CLOCK_VALIDITY_CALL - switch(clkMode) - { - case CLOCK_INTERNAL: - VendorClockValidity(1); - break; + switch(clkMode) + { + case CLOCK_INTERNAL: + VendorClockValidity(1); + break; #if (XUA_ADAT_RX_EN) - case CLOCK_ADAT: - VendorClockValidity(clockValid[CLOCK_ADAT]); - break; + case CLOCK_ADAT: + VendorClockValidity(clockValid[CLOCK_ADAT]); + break; #endif #if (XUA_SPDIF_RX_EN) - case CLOCK_SPDIF: - VendorClockValidity(clockValid[CLOCK_SPDIF]); - break; + case CLOCK_SPDIF: + VendorClockValidity(clockValid[CLOCK_SPDIF]); + break; #endif - } + } #endif - break; + break; - case GET_VALID: - /* Clock Unit Index */ - tmp = inuint(c_clk_ctl); - chkct(c_clk_ctl, XS1_CT_END); - outuint(c_clk_ctl, clockValid[tmp]); - outct(c_clk_ctl, XS1_CT_END); - break; + case GET_VALID: + /* Clock Unit Index */ + tmp = inuint(c_clk_ctl); + chkct(c_clk_ctl, XS1_CT_END); + outuint(c_clk_ctl, clockValid[tmp]); + outct(c_clk_ctl, XS1_CT_END); + break; - case GET_FREQ: - tmp = inuint(c_clk_ctl); - chkct(c_clk_ctl, XS1_CT_END); - outuint(c_clk_ctl, clockFreq[tmp]); - outct(c_clk_ctl, XS1_CT_END); - break; + case GET_FREQ: + tmp = inuint(c_clk_ctl); + chkct(c_clk_ctl, XS1_CT_END); + outuint(c_clk_ctl, clockFreq[tmp]); + outct(c_clk_ctl, XS1_CT_END); + break; - case SET_SMUX: - smux = inuint(c_clk_ctl); + case SET_SMUX: + smux = inuint(c_clk_ctl); #if (XUA_ADAT_RX_EN) - adatRd = 0; /* Reset adat FIFO */ - adatWr = 0; - adatSamps = 0; + adatRd = 0; /* Reset adat FIFO */ + adatWr = 0; + adatSamps = 0; #endif - chkct(c_clk_ctl, XS1_CT_END); - break; + chkct(c_clk_ctl, XS1_CT_END); + break; - default: + default: #ifdef VENDOR_AUDCORE_REQS - if(VendorAudCoreReqs(tmp, c_clk_ctl)) + if(VendorAudCoreReqs(tmp, c_clk_ctl)) #endif - printstrln("ERR: Bad req in clockgen\n"); - break; - } + printstrln("ERR: Bad req in clockgen\n"); + break; + } - break; + break; - /* Generate local clock from timer */ - case t_local when timerafter(timeNextEdge) :> void: + /* Generate local clock from timer */ + case t_local when timerafter(timeNextEdge) :> void: #if USE_SW_PLL - /* Do nothing - hold the most recent sw_pll setting */ + /* Do nothing - hold the most recent sw_pll setting */ #else - /* Setup next local clock edge */ - i_pll_ref.toggle_timed(0); + /* Setup next local clock edge */ + i_pll_ref.toggle_timed(0); #endif - /* Record time of edge */ - timeLastEdge = timeNextEdge; + /* Record time of edge */ + timeLastEdge = timeNextEdge; - /* Setup for next edge */ - timeNextClockDetection = timeNextEdge + (LOCAL_CLOCK_INCREMENT/2); - timeNextEdge += LOCAL_CLOCK_INCREMENT; + /* Setup for next edge */ + timeNextClockDetection = timeNextEdge + (LOCAL_CLOCK_INCREMENT/2); + timeNextEdge += LOCAL_CLOCK_INCREMENT; - /* If we are in an external clock mode and this fire, then clock invalid - * reset counters in case we are moved to digital clock - we want a well timed - * first edge */ + /* If we are in an external clock mode and this fire, then clock invalid + * reset counters in case we are moved to digital clock - we want a well timed + * first edge */ #if (XUA_SPDIF_RX_EN) - spdifCounters.receivedSamples = 0; + spdifCounters.receivedSamples = 0; #endif #if (XUA_ADAT_RX_EN) - adatCounters.receivedSamples = 0; + adatCounters.receivedSamples = 0; #endif #ifdef CLOCK_VALIDITY_CALL - if(clkMode == CLOCK_INTERNAL) - { - /* Internal clock always valid */ - VendorClockValidity(1); - } + if(clkMode == CLOCK_INTERNAL) + { + /* Internal clock always valid */ + VendorClockValidity(1); + } #endif - break; + break; #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) - case t_external when timerafter(timeNextClockDetection) :> void: - { - int valid; - timeNextClockDetection += (LOCAL_CLOCK_INCREMENT); + case t_external when timerafter(timeNextClockDetection) :> void: + { + int valid; + timeNextClockDetection += (LOCAL_CLOCK_INCREMENT); #if (XUA_SPDIF_RX_EN) - /* Returns 1 if valid clock found */ - valid = validSamples(spdifCounters, CLOCK_SPDIF); - setClockValidity(c_clk_int, CLOCK_SPDIF, valid, clkMode); + /* Returns 1 if valid clock found */ + valid = validSamples(spdifCounters, CLOCK_SPDIF); + setClockValidity(c_clk_int, CLOCK_SPDIF, valid, clkMode); #endif #if (XUA_ADAT_RX_EN) - /* Returns 1 if valid clock found */ - valid = validSamples(adatCounters, CLOCK_ADAT); - setClockValidity(c_clk_int, CLOCK_ADAT, valid, clkMode); + /* Returns 1 if valid clock found */ + valid = validSamples(adatCounters, CLOCK_ADAT); + setClockValidity(c_clk_int, CLOCK_ADAT, valid, clkMode); #endif - } - break; + } + break; #endif #if ((XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) - case inuint_byref(c_sigma_delta, tmp): - /* Send ACK back to audiohub to allow I2S to start - This happens only on SDM restart and only once */ - if(require_ack_to_audio) - { - c_mclk_change <: tmp; - require_ack_to_audio = 0; - } - break; + case inuint_byref(c_sw_pll, tmp): + /* Send ACK back to audiohub to allow I2S to start + This happens only on SDM restart and only once */ + if(require_ack_to_audio) + { + c_mclk_change <: tmp; + require_ack_to_audio = 0; + } + break; #endif #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) - /* Receive notification of audio streaming settings change and store */ - case c_mclk_change :> selected_mclk_rate: - c_mclk_change :> selected_sample_rate; + /* Receive notification of audio streaming settings change and store */ + case c_mclk_change :> selected_mclk_rate: + c_mclk_change :> selected_sample_rate; #if USE_SW_PLL - mclks_per_sample = selected_mclk_rate / selected_sample_rate; - restart_sigma_delta(c_sigma_delta); - reset_sw_pll_pfd = 1; - /* We will shedule an ACK when sigma delta is up and running */ - require_ack_to_audio = 1; + mclks_per_sample = selected_mclk_rate / selected_sample_rate; + restart_sigma_delta(c_sw_pll, selected_mclk_rate); + reset_sw_pll_pfd = 1; + /* We will shedule an ACK when sigma delta is up and running */ + require_ack_to_audio = 1; #else - /* Send ACK immediately as we are good to go if not using SW_PLL */ - c_mclk_change <: 0; + /* Send ACK immediately as we are good to go if not using SW_PLL */ + c_mclk_change <: 0; #endif - break; + break; #endif #if (XUA_SPDIF_RX_EN) - /* Receive sample from S/PDIF RX thread (streaming chan) */ - case c_spdif_rx :> spdifRxData: + /* Receive sample from S/PDIF RX thread (streaming chan) */ + case c_spdif_rx :> spdifRxData: - /* Record time of sample */ + /* Record time of sample */ + if(!isnull(p_for_mclk_count_aud)) + { + asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); + } + t_local :> spdifRxTime; + + /* Check parity and ignore if bad */ + if(spdif_rx_check_parity(spdifRxData)) + continue; + + /* Get preamble */ + unsigned preamble = spdifRxData & SPDIF_RX_PREAMBLE_MASK; + + switch(preamble) + { + /* LEFT */ + case SPDIF_FRAME_X: + case SPDIF_FRAME_Z: + spdifLeft = SPDIF_RX_EXTRACT_SAMPLE(spdifRxData); + break; + + /* RIGHT */ + case SPDIF_FRAME_Y: + + /* Only store sample if not in overflow and stream is reasonably valid */ + if(!spdifOverflow && clockValid[CLOCK_SPDIF]) + { + /* Store left and right sample pair to buffer */ + spdifSamples[spdifWr] = spdifLeft; + spdifSamples[spdifWr+1] = SPDIF_RX_EXTRACT_SAMPLE(spdifRxData); + + spdifWr = (spdifWr + 2) & (MAX_SPDIF_SAMPLES - 1); + + spdifSamps += 2; + + /* Check for over flow */ + if(spdifSamps > MAX_SPDIF_SAMPLES-1) + { + spdifOverflow = 1; + } + + /* Check for coming out of under flow */ + if(spdifUnderflow && (spdifSamps >= (MAX_SPDIF_SAMPLES >> 1))) + { + spdifUnderflow = 0; + } + } + break; + + default: + /* Bad sample, skip */ + continue; + break; + } + + spdifCounters.samples += 1; + + if(clkMode == CLOCK_SPDIF && clockValid[CLOCK_SPDIF]) + { + spdifCounters.receivedSamples+=1; + + /* Inspect for if we need to produce an edge */ + if((spdifCounters.receivedSamples >= spdifCounters.samplesPerTick)) + { + /* Check edge is about right... S/PDIF may have changed freq... */ + if(timeafter(spdifRxTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN))) + { + /* Record edge time */ + timeLastEdge = spdifRxTime; + + /* Setup for next edge */ + timeNextEdge = spdifRxTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; + +#if USE_SW_PLL + do_sw_pll_phase_frequency_detector_dig_rx( mclk_time_stamp, + mclks_per_sample, + c_sw_pll, + spdifCounters.receivedSamples, + reset_sw_pll_pfd); +#else + /* Toggle edge */ + i_pll_ref.toggle_timed(1); +#endif + /* Reset counters */ + spdifCounters.receivedSamples = 0; + } + } + } + break; +#endif +#if (XUA_ADAT_RX_EN) + /* receive sample from ADAT rx thread (streaming channel with CT_END) */ + case inuint_byref(c_adat_rx, tmp): + /* record time of sample */ if(!isnull(p_for_mclk_count_aud)) { asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); } - t_local :> spdifRxTime; + t_local :> adatReceivedTime; - /* Check parity and ignore if bad */ - if(spdif_rx_check_parity(spdifRxData)) + /* Sync is: 1 | (user_byte << 4) */ + if(tmp&1) + { + /* user bits - start of frame */ + adatChannel = 0; continue; - - /* Get preamble */ - unsigned preamble = spdifRxData & SPDIF_RX_PREAMBLE_MASK; - - switch(preamble) - { - /* LEFT */ - case SPDIF_FRAME_X: - case SPDIF_FRAME_Z: - spdifLeft = SPDIF_RX_EXTRACT_SAMPLE(spdifRxData); - break; - - /* RIGHT */ - case SPDIF_FRAME_Y: - - /* Only store sample if not in overflow and stream is reasonably valid */ - if(!spdifOverflow && clockValid[CLOCK_SPDIF]) - { - /* Store left and right sample pair to buffer */ - spdifSamples[spdifWr] = spdifLeft; - spdifSamples[spdifWr+1] = SPDIF_RX_EXTRACT_SAMPLE(spdifRxData); - - spdifWr = (spdifWr + 2) & (MAX_SPDIF_SAMPLES - 1); - - spdifSamps += 2; - - /* Check for over flow */ - if(spdifSamps > MAX_SPDIF_SAMPLES-1) - { - spdifOverflow = 1; - } - - /* Check for coming out of under flow */ - if(spdifUnderflow && (spdifSamps >= (MAX_SPDIF_SAMPLES >> 1))) - { - spdifUnderflow = 0; - } - } - break; - - default: - /* Bad sample, skip */ - continue; - break; - } - - spdifCounters.samples += 1; - - if(clkMode == CLOCK_SPDIF && clockValid[CLOCK_SPDIF]) - { - spdifCounters.receivedSamples+=1; - - /* Inspect for if we need to produce an edge */ - if((spdifCounters.receivedSamples >= spdifCounters.samplesPerTick)) - { - /* Check edge is about right... S/PDIF may have changed freq... */ - if(timeafter(spdifRxTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN))) - { - /* Record edge time */ - timeLastEdge = spdifRxTime; - - /* Setup for next edge */ - timeNextEdge = spdifRxTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; - -#if USE_SW_PLL - do_sw_pll_phase_frequency_detector_dig_rx( mclk_time_stamp, - mclks_per_sample, - c_sigma_delta, - spdifCounters.receivedSamples, - reset_sw_pll_pfd); -#else - /* Toggle edge */ - i_pll_ref.toggle_timed(1); -#endif - /* Reset counters */ - spdifCounters.receivedSamples = 0; - } - } } - break; -#endif -#if (XUA_ADAT_RX_EN) - /* receive sample from ADAT rx thread (streaming channel with CT_END) */ - case inuint_byref(c_adat_rx, tmp): - /* record time of sample */ - if(!isnull(p_for_mclk_count_aud)) - { - asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); - } - t_local :> adatReceivedTime; + else + { + /* audio sample */ + adatSamplesEver++; + adatFrame[adatChannel] = tmp; - /* Sync is: 1 | (user_byte << 4) */ - if(tmp&1) + adatChannel++; + if (adatChannel == 8) { - /* user bits - start of frame */ - adatChannel = 0; - continue; - } - else - { - /* audio sample */ - adatSamplesEver++; - adatFrame[adatChannel] = tmp; - - adatChannel++; - if (adatChannel == 8) + /* only store left samples if not in overflow and stream is reasonably valid */ + if (!adatOverflow && clockValid[CLOCK_ADAT]) { - /* only store left samples if not in overflow and stream is reasonably valid */ - if (!adatOverflow && clockValid[CLOCK_ADAT]) + /* Unpick the SMUX.. */ + if(smux == 2) { - /* Unpick the SMUX.. */ - if(smux == 2) + adatSamples[adatWr + 0] = adatFrame[0]; + adatSamples[adatWr + 1] = adatFrame[4]; + adatSamples[adatWr + 2] = adatFrame[1]; + adatSamples[adatWr + 3] = adatFrame[5]; + adatSamples[adatWr + 4] = adatFrame[2]; + adatSamples[adatWr + 5] = adatFrame[6]; + adatSamples[adatWr + 6] = adatFrame[3]; + adatSamples[adatWr + 7] = adatFrame[7]; + } + else if(smux) + { + + adatSamples[adatWr + 0] = adatFrame[0]; + adatSamples[adatWr + 1] = adatFrame[2]; + adatSamples[adatWr + 2] = adatFrame[4]; + adatSamples[adatWr + 3] = adatFrame[6]; + adatSamples[adatWr + 4] = adatFrame[1]; + adatSamples[adatWr + 5] = adatFrame[3]; + adatSamples[adatWr + 6] = adatFrame[5]; + adatSamples[adatWr + 7] = adatFrame[7]; + } + else + { + adatSamples[adatWr + 0] = adatFrame[0]; + adatSamples[adatWr + 1] = adatFrame[1]; + adatSamples[adatWr + 2] = adatFrame[2]; + adatSamples[adatWr + 3] = adatFrame[3]; + adatSamples[adatWr + 4] = adatFrame[4]; + adatSamples[adatWr + 5] = adatFrame[5]; + adatSamples[adatWr + 6] = adatFrame[6]; + adatSamples[adatWr + 7] = adatFrame[7]; + } + adatWr = (adatWr + 8) & (MAX_ADAT_SAMPLES - 1); + adatSamps += 8; + + /* check for overflow */ + if (adatSamps > MAX_ADAT_SAMPLES - 1) { - adatSamples[adatWr + 0] = adatFrame[0]; - adatSamples[adatWr + 1] = adatFrame[4]; - adatSamples[adatWr + 2] = adatFrame[1]; - adatSamples[adatWr + 3] = adatFrame[5]; - adatSamples[adatWr + 4] = adatFrame[2]; - adatSamples[adatWr + 5] = adatFrame[6]; - adatSamples[adatWr + 6] = adatFrame[3]; - adatSamples[adatWr + 7] = adatFrame[7]; + adatOverflow = 1; } - else if(smux) - { - adatSamples[adatWr + 0] = adatFrame[0]; - adatSamples[adatWr + 1] = adatFrame[2]; - adatSamples[adatWr + 2] = adatFrame[4]; - adatSamples[adatWr + 3] = adatFrame[6]; - adatSamples[adatWr + 4] = adatFrame[1]; - adatSamples[adatWr + 5] = adatFrame[3]; - adatSamples[adatWr + 6] = adatFrame[5]; - adatSamples[adatWr + 7] = adatFrame[7]; + /* check for coming out of underflow */ + if (adatUnderflow && (adatSamps >= (MAX_ADAT_SAMPLES >> 1))) + { + adatUnderflow = 0; } - else + } + } + if(adatChannel == 4 || adatChannel == 8) + { + adatCounters.samples += 1; + + if (clkMode == CLOCK_ADAT && clockValid[CLOCK_ADAT]) + { + adatCounters.receivedSamples += 1; + + /* Inspect for if we need to produce an edge */ + if ((adatCounters.receivedSamples >= adatCounters.samplesPerTick)) { - adatSamples[adatWr + 0] = adatFrame[0]; - adatSamples[adatWr + 1] = adatFrame[1]; - adatSamples[adatWr + 2] = adatFrame[2]; - adatSamples[adatWr + 3] = adatFrame[3]; - adatSamples[adatWr + 4] = adatFrame[4]; - adatSamples[adatWr + 5] = adatFrame[5]; - adatSamples[adatWr + 6] = adatFrame[6]; - adatSamples[adatWr + 7] = adatFrame[7]; - } - adatWr = (adatWr + 8) & (MAX_ADAT_SAMPLES - 1); - adatSamps += 8; - - /* check for overflow */ - if (adatSamps > MAX_ADAT_SAMPLES - 1) + /* Check edge is about right... ADAT may have changed freq... */ + if (timeafter(adatReceivedTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN))) { - adatOverflow = 1; - } + /* Record edge time */ + timeLastEdge = adatReceivedTime; - /* check for coming out of underflow */ - if (adatUnderflow && (adatSamps >= (MAX_ADAT_SAMPLES >> 1))) - { - adatUnderflow = 0; - } - } - } - if(adatChannel == 4 || adatChannel == 8) - { - adatCounters.samples += 1; - - if (clkMode == CLOCK_ADAT && clockValid[CLOCK_ADAT]) - { - adatCounters.receivedSamples += 1; - - /* Inspect for if we need to produce an edge */ - if ((adatCounters.receivedSamples >= adatCounters.samplesPerTick)) - { - /* Check edge is about right... ADAT may have changed freq... */ - if (timeafter(adatReceivedTime, (timeLastEdge + LOCAL_CLOCK_INCREMENT - LOCAL_CLOCK_MARGIN))) - { - /* Record edge time */ - timeLastEdge = adatReceivedTime; - - /* Setup for next edge */ - timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; + /* Setup for next edge */ + timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; #if USE_SW_PLL - do_sw_pll_phase_frequency_detector_dig_rx( mclk_time_stamp, - mclks_per_sample, - c_sigma_delta, - adatCounters.receivedSamples, - reset_sw_pll_pfd); + do_sw_pll_phase_frequency_detector_dig_rx( mclk_time_stamp, + mclks_per_sample, + c_sw_pll, + adatCounters.receivedSamples, + reset_sw_pll_pfd); #else - /* Toggle edge */ - i_pll_ref.toggle_timed(1); + /* Toggle edge */ + i_pll_ref.toggle_timed(1); #endif - - /* Reset counters */ - adatCounters.receivedSamples = 0; - } + + /* Reset counters */ + adatCounters.receivedSamples = 0; } } } - if (adatChannel == 8) - adatChannel = 0; } - break; + if (adatChannel == 8) + adatChannel = 0; + } + break; #endif #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) - /* AudioHub requests data */ - case inuint_byref(c_dig_rx, tmp): + /* AudioHub requests data */ + case inuint_byref(c_dig_rx, tmp): #if (XUA_SPDIF_RX_EN) - if(spdifUnderflow) + if(spdifUnderflow) + { + /* S/PDIF underflowing, send out zero samples */ + g_digData[0] = 0; + g_digData[1] = 0; + } + else + { + /* Read out samples from S/PDIF buffer and send... */ + tmp = spdifSamples[spdifRd]; + tmp2 = spdifSamples[spdifRd + 1]; + + spdifRd += 2; + spdifRd &= (MAX_SPDIF_SAMPLES - 1); + + g_digData[0] = tmp; + g_digData[1] = tmp2; + + spdifSamps -= 2; + + /* spdifSamps could go to -1 */ + if(spdifSamps <= 0) { - /* S/PDIF underflowing, send out zero samples */ - g_digData[0] = 0; - g_digData[1] = 0; + /* We're out of S/PDIF samples, mark underflow condition */ + spdifUnderflow = 1; + spdifLeft = 0; } - else + + /* If we are in over flow condition and we have a sensible number of samples + * come out of overflow condition */ + if(spdifOverflow && (spdifSamps < (MAX_SPDIF_SAMPLES>>1))) { - /* Read out samples from S/PDIF buffer and send... */ - tmp = spdifSamples[spdifRd]; - tmp2 = spdifSamples[spdifRd + 1]; - - spdifRd += 2; - spdifRd &= (MAX_SPDIF_SAMPLES - 1); - - g_digData[0] = tmp; - g_digData[1] = tmp2; - - spdifSamps -= 2; - - /* spdifSamps could go to -1 */ - if(spdifSamps <= 0) - { - /* We're out of S/PDIF samples, mark underflow condition */ - spdifUnderflow = 1; - spdifLeft = 0; - } - - /* If we are in over flow condition and we have a sensible number of samples - * come out of overflow condition */ - if(spdifOverflow && (spdifSamps < (MAX_SPDIF_SAMPLES>>1))) - { - spdifOverflow = 0; - } + spdifOverflow = 0; } + } #endif #if (XUA_ADAT_RX_EN) - if (adatUnderflow) + if (adatUnderflow) + { + /* ADAT underflowing, send out zero samples */ + g_digData[2] = 0; + g_digData[3] = 0; + g_digData[4] = 0; + g_digData[5] = 0; + g_digData[6] = 0; + g_digData[7] = 0; + g_digData[8] = 0; + g_digData[9] = 0; + } + else + { + /* read out samples from the ADAT buffer and send */ + /* always return 8 samples */ + /* SMUX II mode */ + if (smux == 2) { - /* ADAT underflowing, send out zero samples */ - g_digData[2] = 0; - g_digData[3] = 0; + /* SMUX2 mode - 2 samples from fifo and 4 zero samples */ + g_digData[2] = adatSamples[adatRd + 0]; + g_digData[3] = adatSamples[adatRd + 1]; + g_digData[4] = 0; g_digData[5] = 0; g_digData[6] = 0; g_digData[7] = 0; g_digData[8] = 0; g_digData[9] = 0; + adatRd = (adatRd + 2) & (MAX_ADAT_SAMPLES - 1); + adatSamps -= 2; + } + else if(smux) + { + /* SMUX mode - 4 samples from fifo and 4 zero samples */ + g_digData[2] = adatSamples[adatRd + 0]; + g_digData[3] = adatSamples[adatRd + 1]; + g_digData[4] = adatSamples[adatRd + 2]; + g_digData[5] = adatSamples[adatRd + 3]; + + g_digData[6] = 0; + g_digData[7] = 0; + g_digData[8] = 0; + g_digData[9] = 0; + adatRd = (adatRd + 4) & (MAX_ADAT_SAMPLES - 1); + adatSamps -= 4; } else { - /* read out samples from the ADAT buffer and send */ - /* always return 8 samples */ - /* SMUX II mode */ - if (smux == 2) - { - /* SMUX2 mode - 2 samples from fifo and 4 zero samples */ - g_digData[2] = adatSamples[adatRd + 0]; - g_digData[3] = adatSamples[adatRd + 1]; + /* no SMUX mode - 8 samples from fifo */ + g_digData[2] = adatSamples[adatRd + 0]; + g_digData[3] = adatSamples[adatRd + 1]; + g_digData[4] = adatSamples[adatRd + 2]; + g_digData[5] = adatSamples[adatRd + 3]; - g_digData[4] = 0; - g_digData[5] = 0; - g_digData[6] = 0; - g_digData[7] = 0; - g_digData[8] = 0; - g_digData[9] = 0; - adatRd = (adatRd + 2) & (MAX_ADAT_SAMPLES - 1); - adatSamps -= 2; - } - else if(smux) - { - /* SMUX mode - 4 samples from fifo and 4 zero samples */ - g_digData[2] = adatSamples[adatRd + 0]; - g_digData[3] = adatSamples[adatRd + 1]; - g_digData[4] = adatSamples[adatRd + 2]; - g_digData[5] = adatSamples[adatRd + 3]; + g_digData[6] = adatSamples[adatRd + 4]; + g_digData[7] = adatSamples[adatRd + 5]; + g_digData[8] = adatSamples[adatRd + 6]; + g_digData[9] = adatSamples[adatRd + 7]; - g_digData[6] = 0; - g_digData[7] = 0; - g_digData[8] = 0; - g_digData[9] = 0; - adatRd = (adatRd + 4) & (MAX_ADAT_SAMPLES - 1); - adatSamps -= 4; - } - else - { - /* no SMUX mode - 8 samples from fifo */ - g_digData[2] = adatSamples[adatRd + 0]; - g_digData[3] = adatSamples[adatRd + 1]; - g_digData[4] = adatSamples[adatRd + 2]; - g_digData[5] = adatSamples[adatRd + 3]; - - g_digData[6] = adatSamples[adatRd + 4]; - g_digData[7] = adatSamples[adatRd + 5]; - g_digData[8] = adatSamples[adatRd + 6]; - g_digData[9] = adatSamples[adatRd + 7]; - - adatRd = (adatRd + 8) & (MAX_ADAT_SAMPLES - 1); - adatSamps -= 8; - } - - /* adatSamps could go to -1 */ - if (adatSamps <= 0) - { - /* we're out of ADAT samples, mark underflow condition */ - adatUnderflow = 1; - } - - /* if we are in overflow condition and have a sensible number of samples - come out of overflow condition */ - if (adatOverflow && adatSamps < (MAX_ADAT_SAMPLES >> 1)) - { - adatOverflow = 0; - } + adatRd = (adatRd + 8) & (MAX_ADAT_SAMPLES - 1); + adatSamps -= 8; } -#endif - outuint(c_dig_rx, 1); - break; -#endif - } /* select */ - } /* while(1) */ - } /* clkgen task scope */ -} + + /* adatSamps could go to -1 */ + if (adatSamps <= 0) + { + /* we're out of ADAT samples, mark underflow condition */ + adatUnderflow = 1; + } + + /* if we are in overflow condition and have a sensible number of samples + come out of overflow condition */ + if (adatOverflow && adatSamps < (MAX_ADAT_SAMPLES >> 1)) + { + adatOverflow = 0; + } + } +#endif + outuint(c_dig_rx, 1); + break; +#endif + } /* select */ + } /* while(1) */ +} /* clkgen task scope */ diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.h b/lib_xua/src/core/clocking/sw_pll_wrapper.h index be808696..315824e6 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.h +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.h @@ -27,29 +27,29 @@ extern "C" /** Task that receives an error term, passes it through a PI controller and periodically * calclulates a sigma delta output value and sends it to the PLL fractional register. * - * \param c_sigma_delta Channel connected to the clocking thread to pass raw error terms. - * \param selected_mclk_rate_ptr Pointer to the mclk rate variable declared in clockgen. + * \param c_sw_pll Channel connected to the clocking thread to pass raw error terms. */ -void SigmaDeltaTask(chanend c_sigma_delta, unsigned * unsafe selected_mclk_rate_ptr); +void sw_pll_task(chanend c_sw_pll); /** Helper function that sends a special restart command. It causes the SDM task * to quit and restart using the new mclk. * - * \param c_sigma_delta Channel connected to the clocking thread to pass raw error terms. + * \param c_sw_pll Channel connected to the clocking thread to pass raw error terms. + * \param mclk_Rate The mclk frequency in Hz. */ -void restart_sigma_delta(chanend c_sigma_delta); +void restart_sigma_delta(chanend c_sw_pll, unsigned mclk_rate); /** Performs a frequency comparsion between the incoming digital Rx stream and the local mclk. * * \param mclk_time_stamp The captured mclk count (using port timer) at the time of sample Rx. * \param mclks_per_sample The nominal number of mclks per audio sample. - * \param c_sigma_delta Channel connected to the sigma delta and controller thread. + * \param c_sw_pll Channel connected to the sigma delta and controller thread. * \param receivedSamples The number of received samples since tha last call to this function. * \param reset_sw_pll_pfd Reference to a flag which will be used to signal reset of this function's state. */ void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp, unsigned mclks_per_sample, - chanend c_sigma_delta, + chanend c_sw_pll, int receivedSamples, int &reset_sw_pll_pfd); diff --git a/lib_xua/src/core/clocking/sw_pll_wrapper.xc b/lib_xua/src/core/clocking/sw_pll_wrapper.xc index 7cb3163d..0513e261 100644 --- a/lib_xua/src/core/clocking/sw_pll_wrapper.xc +++ b/lib_xua/src/core/clocking/sw_pll_wrapper.xc @@ -114,79 +114,82 @@ void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp, } } -void SigmaDeltaTask(chanend c_sigma_delta, unsigned * unsafe selected_mclk_rate_ptr){ +void sw_pll_task(chanend c_sigma_delta){ /* Zero is an invalid number and the SDM will not write the frac reg until the first control value has been received. This avoids issues with channel lockup if two tasks (eg. init and SDM) try to write at the same time. */ - int f_error = 0; - int dco_setting = 0; /* gets set at InitSWPLL */ - unsigned sdm_interval = 0; /* gets set at InitSWPLL */ - sw_pll_state_t sw_pll; - - unsafe + while(1) { + unsigned selected_mclk_rate = inuint(c_sigma_delta); + + int f_error = 0; + int dco_setting = 0; /* gets set at InitSWPLL */ + unsigned sdm_interval = 0; /* gets set at InitSWPLL */ + sw_pll_state_t sw_pll; + /* initialse the SDM and gather SDM initial settings */ - {sdm_interval, dco_setting} = InitSWPLL(sw_pll, (unsigned)*selected_mclk_rate_ptr); - } + {sdm_interval, dco_setting} = InitSWPLL(sw_pll, selected_mclk_rate); - tileref_t this_tile = get_local_tile_id(); + tileref_t this_tile = get_local_tile_id(); - timer tmr; - int32_t time_trigger; - tmr :> time_trigger; - int running = 1; + timer tmr; + int32_t time_trigger; + tmr :> time_trigger; + int running = 1; - outuint(c_sigma_delta, 0); /* Signal back via clockgen to audio to start I2S */ + outuint(c_sigma_delta, 0); /* Signal back via clockgen to audio to start I2S */ - unsigned rx_word = 0; - while(running) - { - /* Poll for new SDM control value */ - select + unsigned rx_word = 0; + while(running) { - case inuint_byref(c_sigma_delta, rx_word): - if(rx_word == DISABLE_SDM) - { - f_error = 0; - running = 0; - } - else - { - f_error = (int32_t)rx_word; - unsafe + /* Poll for new SDM control value */ + select + { + case inuint_byref(c_sigma_delta, rx_word): + if(rx_word == DISABLE_SDM) { - sw_pll_sdm_do_control_from_error(&sw_pll, -f_error); - dco_setting = sw_pll.sdm_state.current_ctrl_val; + f_error = 0; + running = 0; } - } - break; + else + { + f_error = (int32_t)rx_word; + unsafe + { + sw_pll_sdm_do_control_from_error(&sw_pll, -f_error); + dco_setting = sw_pll.sdm_state.current_ctrl_val; + } + } + break; - /* Do nothing & fall-through. Above case polls only once per loop */ - default: - break; - } + /* Do nothing & fall-through. Above case polls only once per loop */ + default: + break; + } - /* Wait until the timer value has been reached - This implements a timing barrier and keeps - the loop rate constant. */ - select - { - case tmr when timerafter(time_trigger) :> int _: - time_trigger += sdm_interval; - break; - } + /* Wait until the timer value has been reached + This implements a timing barrier and keeps + the loop rate constant. */ + select + { + case tmr when timerafter(time_trigger) :> int _: + time_trigger += sdm_interval; + break; + } - unsafe { - sw_pll_do_sigma_delta(&sw_pll.sdm_state, this_tile, dco_setting); - } - } /* if running */ + unsafe { + sw_pll_do_sigma_delta(&sw_pll.sdm_state, this_tile, dco_setting); + } + } /* if running */ + } /* while(1) */ } -void restart_sigma_delta(chanend c_sigma_delta) +void restart_sigma_delta(chanend c_sigma_delta, unsigned selected_mclk_rate) { outuint(c_sigma_delta, DISABLE_SDM); /* Resets SDM */ + outuint(c_sigma_delta, selected_mclk_rate); } #endif /* USE_SW_PLL */ diff --git a/lib_xua/src/core/main.xc b/lib_xua/src/core/main.xc index 053dd63b..7e1f9303 100755 --- a/lib_xua/src/core/main.xc +++ b/lib_xua/src/core/main.xc @@ -314,8 +314,11 @@ void usb_audio_io(chanend ?c_aud_in, #endif #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , client interface pll_ref_if i_pll_ref - , port ?p_for_mclk_count_aud -#endif +#if USE_SW_PLL + , port p_for_mclk_count_aud + , chanend c_sw_pll +#endif /* USE_SW_PLL */ +#endif /* (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) */ ) { #if (MIXER) @@ -405,8 +408,9 @@ void usb_audio_io(chanend ?c_aud_in, c_dig_rx, c_clk_ctl, c_clk_int, + c_mclk_change, p_for_mclk_count_aud, - c_mclk_change); + c_sw_pll); } #endif @@ -483,7 +487,7 @@ int main() #endif #endif -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && !USE_SW_PLL) +#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) ) interface pll_ref_if i_pll_ref; #endif @@ -511,7 +515,7 @@ int main() { USER_MAIN_CORES -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && !USE_SW_PLL) +#if (((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)) on tile[PLL_REF_TILE]: PllRefPinTask(i_pll_ref, p_pll_ref); #endif on tile[XUD_TILE]: @@ -524,10 +528,6 @@ int main() DFUHandler(dfuInterface, null); #endif -#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) - //XUA_SoftPll(tile[0], i_softPll, c_swpll_update); -#endif - /* Core USB task, buffering, USB etc */ { #ifdef XUD_PRIORITY_HIGH @@ -589,7 +589,7 @@ int main() #if (!USE_SW_PLL) , i_pll_ref #else - , c_sw_pll + , c_sw_pll #endif #endif ); @@ -605,8 +605,8 @@ int main() #endif /* XUA_USB_EN */ } -#if (XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !USE_SW_PLL) - // on tile[AUDIO_IO_TILE]: XUA_SoftPll(tile[0], i_softPll, c_swpll_update); +#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) && USE_SW_PLL) + on tile[AUDIO_IO_TILE]: sw_pll_task(c_sw_pll); #endif on tile[AUDIO_IO_TILE]: @@ -625,16 +625,13 @@ int main() , dfuInterface #endif #if (XUA_NUM_PDM_MICS > 0) - #if (PDM_TILE == AUDIO_IO_TILE) - , c_ds_output - #endif - , c_pdm_pcm #endif -#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) +#if ((XUA_SYNCMODE == XUA_SYNCMODE_SYNC && !USE_SW_PLL) || XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) , i_pll_ref #endif -#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) +#if (USE_SW_PLL && (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)) , p_for_mclk_count_audio + , c_sw_pll #endif ); }