diff --git a/lib_xua/src/core/audiohub/xua_audiohub.xc b/lib_xua/src/core/audiohub/xua_audiohub.xc index b8c5e472..c6d53cfc 100755 --- a/lib_xua/src/core/audiohub/xua_audiohub.xc +++ b/lib_xua/src/core/audiohub/xua_audiohub.xc @@ -804,6 +804,7 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk, #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) /* Notify clockgen of new mCLk */ c_mclk_change <: mClk; + c_mclk_change <: curFreq; #endif } diff --git a/lib_xua/src/core/clocking/clockgen.xc b/lib_xua/src/core/clocking/clockgen.xc index 27bd85ba..a489c047 100644 --- a/lib_xua/src/core/clocking/clockgen.xc +++ b/lib_xua/src/core/clocking/clockgen.xc @@ -8,6 +8,7 @@ #include "xua_commands.h" #include "xua_clocking.h" +#include // TODO DEV ONLY - DELME #ifdef __XS3A__ #define USE_SW_PLL 1 @@ -231,7 +232,7 @@ static inline int validSamples(Counter &counter, int clockIndex) #endif #if USE_SW_PLL -void InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk) +unsigned InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk) { /* Autogenerated SDM App PLL setup by dco_model.py using 22.5792_1M profile */ /* Input freq: 24000000 @@ -270,7 +271,7 @@ void InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk) const uint32_t app_pll_div_reg[2] = {APP_PLL_DIV_REG_22, APP_PLL_DIV_REG_24}; const uint32_t app_pll_frac_reg[2] = {APP_PLL_FRAC_REG_22, APP_PLL_FRAC_REG_24}; const uint32_t sw_pll_sdm_ctrl_mid[2] = {SW_PLL_SDM_CTRL_MID_22, SW_PLL_SDM_CTRL_MID_24}; - // const uint32_t sw_pll_sdm_rate[2] = {SW_PLL_SDM_RATE_22, SW_PLL_SDM_RATE_24}; + const uint32_t sw_pll_sdm_rate[2] = {SW_PLL_SDM_RATE_22, SW_PLL_SDM_RATE_24}; const int clkIndex = mClk == MCLK_48 ? 1 : 0; @@ -289,38 +290,102 @@ void InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk) printstr("Init sw_pll: "); printuintln(mClk); + + return (XS1_TIMER_HZ / sw_pll_sdm_rate[clkIndex]); } -void do_sw_pll_control(sw_pll_state_t sw_pll, unsigned short mclk_time_stamp, chanend c_sigma_delta) +void do_sw_pll_control( sw_pll_state_t sw_pll, + unsigned short mclk_time_stamp, + unsigned mclks_per_sample, + chanend c_sigma_delta, + int receivedSamples) { + static unsigned short last_mclk_time_stamp = 0; static unsigned count = 0; count++; + + const unsigned expected_mclk_inc = mclks_per_sample * receivedSamples; + const unsigned short expected_mclk_count = (last_mclk_time_stamp + expected_mclk_inc) & 0xffff; + + short f_error = (int)mclk_time_stamp - (int)expected_mclk_count; + + if(count == 30) { - printuintln(mclk_time_stamp); - count = 0; + //calc mclk inc + + outuint(c_sigma_delta, (unsigned) (1000000 + f_error)); + count = 0; } + + last_mclk_time_stamp = mclk_time_stamp; } -void SigmaDeltaTask(chanend c_sigma_delta){ +void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval){ + /* 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 dco_setting = 0; + sw_pll_sdm_state_t sdm_state; + sw_pll_init_sigma_delta(&sdm_state); + + tileref_t this_tile = get_local_tile_id(); + + timer tmr; + int32_t time_trigger; + tmr :> time_trigger; + int send_ack_once = 1; while(1) { - c_sigma_delta :> dco_setting; - printstr("sigma-delta got: "); printintln(dco_setting); - if(dco_setting == 0) + /* Poll for new SDM control value */ + unsigned tmp; + select { - c_sigma_delta <: 0; /* Send ACK */ + case inuint_byref(c_sigma_delta, tmp): + dco_setting = (int32_t)tmp; + printstr("sigma-delta got: "); printintln(dco_setting); + break; + + // Do nothing & fall-through + 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; + } + + /* Do not write to the frac reg until we get out first + control value. This will avoid the writing of the + frac reg from two different threads which may cause + a channel deadlock. */ + if(dco_setting != 0) + { + sw_pll_do_sigma_delta(&sdm_state, this_tile, dco_setting); + send_ack_once = 1; + } + else if(send_ack_once) + { + /* Send ACK once to synchrnoise with clockgen signalling it's OK to reconfig */ + outuint(c_sigma_delta, 0); /* Send ACK to say reg writes have ceased */ + send_ack_once = 0; + } } } void disable_sigma_delta(chanend c_sigma_delta) { - c_sigma_delta <: 0; /* Stops SD */ - c_sigma_delta :> int _; /* Wait for ACK so we know reg write is complete */ + outuint(c_sigma_delta, 0); /* Stops SD */ + inuint(c_sigma_delta); /* Wait for ACK so we know reg write is complete */ } #endif @@ -360,6 +425,8 @@ void clockGen ( streaming chanend ?c_spdif_rx, #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) timer t_external; unsigned selected_mclk_rate = 0; + unsigned selected_sample_rate = 0; + unsigned mclks_per_sample = 0; unsigned short mclk_time_stamp = 0; /* Get MCLK count */ asm volatile(" getts %0, res[%1]" : "=r" (mclk_time_stamp) : "r" (p_for_mclk_count_aud)); @@ -457,11 +524,11 @@ void clockGen ( streaming chanend ?c_spdif_rx, #if USE_SW_PLL chan c_sigma_delta; sw_pll_state_t sw_pll; - InitSWPLL(sw_pll, MCLK_48); + unsigned sdm_interval = InitSWPLL(sw_pll, MCLK_48); par { - SigmaDeltaTask(c_sigma_delta); + SigmaDeltaTask(c_sigma_delta, sdm_interval); #else { #endif @@ -635,10 +702,14 @@ void clockGen ( streaming chanend ?c_spdif_rx, #if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN) case c_mclk_change :> selected_mclk_rate: + c_mclk_change :> selected_sample_rate; + mclks_per_sample = selected_mclk_rate / selected_sample_rate; #if USE_SW_PLL printstr("c_mclk_change: "); printuintln(selected_mclk_rate); - disable_sigma_delta(c_sigma_delta); /* Blocks until SD is idle */ + disable_sigma_delta(c_sigma_delta); /* Blocks until SDM is idle */ InitSWPLL(sw_pll, selected_mclk_rate); + outuint(c_sigma_delta, sw_pll.sdm_state.ctrl_mid_point); /* Send ctrl mid point to enable SDM */ + printstr("swpll int'd\n"); #endif break; #endif @@ -684,12 +755,14 @@ void clockGen ( streaming chanend ?c_spdif_rx, if(spdifSamps > MAX_SPDIF_SAMPLES-1) { spdifOverflow = 1; + printstr("spo+\n"); // DELME } /* Check for coming out of under flow */ if(spdifUnderflow && (spdifSamps >= (MAX_SPDIF_SAMPLES >> 1))) { spdifUnderflow = 0; + printstr("spu-\n"); // DELME } } break; @@ -719,7 +792,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, timeNextEdge = spdifRxTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; #if USE_SW_PLL - do_sw_pll_control(sw_pll, mclk_time_stamp, c_sigma_delta); + do_sw_pll_control(sw_pll, mclk_time_stamp, mclks_per_sample, c_sigma_delta, spdifCounters.receivedSamples); #else /* Toggle edge */ i_pll_ref.toggle_timed(1); @@ -829,7 +902,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; #if USE_SW_PLL - do_sw_pll_control(sw_pll, mclk_time_stamp, c_sigma_delta); + do_sw_pll_control(sw_pll, mclk_time_stamp, mclks_per_sample, c_sigma_delta, adatCounters.receivedSamples); #else /* Toggle edge */ i_pll_ref.toggle_timed(1); @@ -876,6 +949,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, { /* We're out of S/PDIF samples, mark underflow condition */ spdifUnderflow = 1; + printstr("spu-\n"); // DELME spdifLeft = 0; } @@ -884,6 +958,7 @@ void clockGen ( streaming chanend ?c_spdif_rx, if(spdifOverflow && (spdifSamps < (MAX_SPDIF_SAMPLES>>1))) { spdifOverflow = 0; + printstr("spo-\n"); // DELME } } #endif