Move sw_pll init to SD task to remove backpressure on clockgen

This commit is contained in:
Ed
2024-01-12 15:38:03 +00:00
parent 529aea28dc
commit d81b510102
4 changed files with 48 additions and 65 deletions

View File

@@ -805,7 +805,6 @@ void XUA_AudioHub(chanend ?c_aud, clock ?clk_audio_mclk, clock ?clk_audio_bclk,
/* Notify clockgen of new mCLk */
c_mclk_change <: mClk;
c_mclk_change <: curFreq;
c_mclk_change :> int _; /* Acknowledge when clocks all setup */
#endif
}

View File

@@ -26,11 +26,11 @@ unsigned g_digData[10];
typedef struct
{
int receivedSamples;
int samples;
int savedSamples;
int lastDiff;
unsigned identicaldiffs;
int receivedSamples; /* Uses by clockgen to count number of dig rx samples to ascertain clock specs */
int samples; /* Raw sample count - rolling int and never reset */
int savedSamples; /* Used by validSamples() to store state of last raw sample count */
int lastDiff; /* Used by validSamples() to store state of last sample count diff */
unsigned identicaldiffs; /* Used by validSamples() to store state of number of identical diffs */
int samplesPerTick;
} Counter;
@@ -107,6 +107,7 @@ static inline void setClockValidity(chanend c_interruptControl, int clkIndex, in
{
clockValid[clkIndex] = valid;
outInterrupt(c_interruptControl, clockId[clkIndex]);
printstr("clockValid=");printintln(valid);
#ifdef CLOCK_VALIDITY_CALL
#if (XUA_ADAT_RX_EN)
@@ -191,7 +192,7 @@ static inline int validSamples(Counter &counter, int clockIndex)
}
}
}
else
else /* No valid frequency found - reset state */
{
counter.identicaldiffs = 0;
counter.lastDiff = diff;
@@ -203,7 +204,10 @@ static inline int validSamples(Counter &counter, int clockIndex)
#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;
}
#endif
#ifdef LEVEL_METER_LEDS
@@ -240,7 +244,7 @@ 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_mclk_rate = MCLK_48; // Assume 24.576MHz initial clock
unsigned selected_sample_rate = 0;
unsigned mclks_per_sample = 0;
unsigned short mclk_time_stamp = 0;
@@ -342,22 +346,20 @@ void clockGen ( streaming chanend ?c_spdif_rx,
#if (USE_SW_PLL && (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN))
chan c_sigma_delta;
sw_pll_state_t sw_pll;
int reset_sw_pll_pfd = 1;
/* Initialise before we par off the SDM thread/
We share the sw_pll struct across threads and this
us safe because the threads access different memebers */
unsafe
{
sw_pll_ptr = &sw_pll;
unsafe {
selected_mclk_rate_ptr = &selected_mclk_rate;
}
unsigned sdm_interval = InitSWPLL(sw_pll, MCLK_48); // Assume 24.576MHz initial clock
par
{
SigmaDeltaTask(c_sigma_delta, sdm_interval);
while(1)
{
unsafe
{
SigmaDeltaTask(c_sigma_delta, selected_mclk_rate_ptr);
}
}
#else
{
#endif
@@ -532,13 +534,12 @@ 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;
printintln(selected_sample_rate);
#if USE_SW_PLL
disable_sigma_delta(c_sigma_delta); /* Blocks until SDM is idle */
InitSWPLL(sw_pll, selected_mclk_rate);
mclks_per_sample = selected_mclk_rate / selected_sample_rate;
restart_sigma_delta(c_sigma_delta);
reset_sw_pll_pfd = 1;
#endif
c_mclk_change <: 0; /* Acknowledge to hold off starting audio until done */
break;
#endif

View File

@@ -21,23 +21,23 @@ extern "C"
}
/* Special control value to disable SDM. Outside of normal range which is less than 16b.*/
#define DISABLE_SDM 0x1000000
#define DISABLE_SDM 0x10000000
/** 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 sdm_interval Unisgned value containing the sigma delta period in timer ticks.
* \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.
*/
void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval);
void SigmaDeltaTask(chanend c_sigma_delta, unsigned * unsafe selected_mclk_rate_ptr);
/** Helper function that sends a special disable command and waits for ACK. This is used
* to help prevemt simultaenous access to the PLL register from two different threads,
*
/** 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.
*/
void disable_sigma_delta(chanend c_sigma_delta);
void restart_sigma_delta(chanend c_sigma_delta);
/** Performs a frequency comparsion between the incoming digital Rx stream and the local mclk.
*

View File

@@ -9,12 +9,6 @@
#if USE_SW_PLL
/* Pointer to sw_pll struct to allow it to be used in separate SDM thread */
unsafe
{
sw_pll_state_t * unsafe sw_pll_ptr = NULL;
}
unsigned InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk)
{
@@ -120,19 +114,20 @@ void do_sw_pll_phase_frequency_detector_dig_rx( unsigned short mclk_time_stamp,
}
}
void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval){
void SigmaDeltaTask(chanend c_sigma_delta, unsigned * unsafe selected_mclk_rate_ptr){
/* 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. */
/* To be extra safe, spin on sw_pll_ptr until it has been initialised by clockgen */
while(sw_pll_ptr == NULL);
int f_error = 0;
int dco_setting = SW_PLL_SDM_CTRL_MID_24; // Assume 24.576MHz as initial clock
unsigned sdm_interval = 0;
sw_pll_state_t sw_pll;
unsafe
{
sw_pll_init_sigma_delta(&sw_pll_ptr->sdm_state);
printf("SigmaDeltaTask: %u\n", *selected_mclk_rate_ptr);
sdm_interval = InitSWPLL(sw_pll, (unsigned)*selected_mclk_rate_ptr);
}
tileref_t this_tile = get_local_tile_id();
@@ -140,10 +135,10 @@ void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval){
timer tmr;
int32_t time_trigger;
tmr :> time_trigger;
int send_ack_once = 1;
int running = 1;
unsigned rx_word;
while(1)
while(running)
{
/* Poll for new SDM control value */
select
@@ -151,16 +146,17 @@ void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval){
case inuint_byref(c_sigma_delta, rx_word):
if(rx_word == DISABLE_SDM)
{
printhexln(rx_word);
f_error = 0;
send_ack_once = 1;
running = 0;
}
else
{
f_error = (int32_t)rx_word;
unsafe
{
sw_pll_sdm_do_control_from_error(sw_pll_ptr, -f_error);
dco_setting = sw_pll_ptr->sdm_state.current_ctrl_val;
sw_pll_sdm_do_control_from_error(&sw_pll, -f_error);
dco_setting = sw_pll.sdm_state.current_ctrl_val;
}
}
break;
@@ -180,29 +176,16 @@ void SigmaDeltaTask(chanend c_sigma_delta, unsigned 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(rx_word != DISABLE_SDM)
unsafe {
sw_pll_do_sigma_delta(&sw_pll_ptr->sdm_state, this_tile, dco_setting);
send_ack_once = 1;
sw_pll_do_sigma_delta(&sw_pll.sdm_state, this_tile, dco_setting);
}
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;
}
}
} /* if running */
}
void disable_sigma_delta(chanend c_sigma_delta)
void restart_sigma_delta(chanend c_sigma_delta)
{
outuint(c_sigma_delta, DISABLE_SDM); /* Stops SDM */
inuint(c_sigma_delta); /* Wait for ACK so we know reg write is complete */
outuint(c_sigma_delta, DISABLE_SDM); /* Resets SDM */
}
#endif /* USE_SW_PLL */