forked from PAWPAW-Mirror/lib_xua
Move sw_pll init to SD task to remove backpressure on clockgen
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user