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 */
|
/* Notify clockgen of new mCLk */
|
||||||
c_mclk_change <: mClk;
|
c_mclk_change <: mClk;
|
||||||
c_mclk_change <: curFreq;
|
c_mclk_change <: curFreq;
|
||||||
c_mclk_change :> int _; /* Acknowledge when clocks all setup */
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ unsigned g_digData[10];
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int receivedSamples;
|
int receivedSamples; /* Uses by clockgen to count number of dig rx samples to ascertain clock specs */
|
||||||
int samples;
|
int samples; /* Raw sample count - rolling int and never reset */
|
||||||
int savedSamples;
|
int savedSamples; /* Used by validSamples() to store state of last raw sample count */
|
||||||
int lastDiff;
|
int lastDiff; /* Used by validSamples() to store state of last sample count diff */
|
||||||
unsigned identicaldiffs;
|
unsigned identicaldiffs; /* Used by validSamples() to store state of number of identical diffs */
|
||||||
int samplesPerTick;
|
int samplesPerTick;
|
||||||
} Counter;
|
} Counter;
|
||||||
|
|
||||||
@@ -107,6 +107,7 @@ static inline void setClockValidity(chanend c_interruptControl, int clkIndex, in
|
|||||||
{
|
{
|
||||||
clockValid[clkIndex] = valid;
|
clockValid[clkIndex] = valid;
|
||||||
outInterrupt(c_interruptControl, clockId[clkIndex]);
|
outInterrupt(c_interruptControl, clockId[clkIndex]);
|
||||||
|
printstr("clockValid=");printintln(valid);
|
||||||
|
|
||||||
#ifdef CLOCK_VALIDITY_CALL
|
#ifdef CLOCK_VALIDITY_CALL
|
||||||
#if (XUA_ADAT_RX_EN)
|
#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.identicaldiffs = 0;
|
||||||
counter.lastDiff = diff;
|
counter.lastDiff = diff;
|
||||||
@@ -203,7 +204,10 @@ static inline int validSamples(Counter &counter, int clockIndex)
|
|||||||
#if USE_SW_PLL
|
#if USE_SW_PLL
|
||||||
/* Pointer to sw_pll struct to allow it to be used in separate SDM thread */
|
/* Pointer to sw_pll struct to allow it to be used in separate SDM thread */
|
||||||
extern sw_pll_state_t * unsafe sw_pll_ptr;
|
extern sw_pll_state_t * unsafe sw_pll_ptr;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
unsigned * unsafe selected_mclk_rate_ptr = NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LEVEL_METER_LEDS
|
#ifdef LEVEL_METER_LEDS
|
||||||
@@ -240,7 +244,7 @@ void clockGen ( streaming chanend ?c_spdif_rx,
|
|||||||
|
|
||||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
timer t_external;
|
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 selected_sample_rate = 0;
|
||||||
unsigned mclks_per_sample = 0;
|
unsigned mclks_per_sample = 0;
|
||||||
unsigned short mclk_time_stamp = 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))
|
#if (USE_SW_PLL && (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN))
|
||||||
chan c_sigma_delta;
|
chan c_sigma_delta;
|
||||||
sw_pll_state_t sw_pll;
|
|
||||||
int reset_sw_pll_pfd = 1;
|
int reset_sw_pll_pfd = 1;
|
||||||
|
unsafe {
|
||||||
/* Initialise before we par off the SDM thread/
|
selected_mclk_rate_ptr = &selected_mclk_rate;
|
||||||
We share the sw_pll struct across threads and this
|
|
||||||
us safe because the threads access different memebers */
|
|
||||||
unsafe
|
|
||||||
{
|
|
||||||
sw_pll_ptr = &sw_pll;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned sdm_interval = InitSWPLL(sw_pll, MCLK_48); // Assume 24.576MHz initial clock
|
|
||||||
|
|
||||||
par
|
par
|
||||||
{
|
{
|
||||||
SigmaDeltaTask(c_sigma_delta, sdm_interval);
|
while(1)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
SigmaDeltaTask(c_sigma_delta, selected_mclk_rate_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
@@ -532,13 +534,12 @@ void clockGen ( streaming chanend ?c_spdif_rx,
|
|||||||
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
#if (XUA_SPDIF_RX_EN || XUA_ADAT_RX_EN)
|
||||||
case c_mclk_change :> selected_mclk_rate:
|
case c_mclk_change :> selected_mclk_rate:
|
||||||
c_mclk_change :> selected_sample_rate;
|
c_mclk_change :> selected_sample_rate;
|
||||||
mclks_per_sample = selected_mclk_rate / selected_sample_rate;
|
printintln(selected_sample_rate);
|
||||||
#if USE_SW_PLL
|
#if USE_SW_PLL
|
||||||
disable_sigma_delta(c_sigma_delta); /* Blocks until SDM is idle */
|
mclks_per_sample = selected_mclk_rate / selected_sample_rate;
|
||||||
InitSWPLL(sw_pll, selected_mclk_rate);
|
restart_sigma_delta(c_sigma_delta);
|
||||||
reset_sw_pll_pfd = 1;
|
reset_sw_pll_pfd = 1;
|
||||||
#endif
|
#endif
|
||||||
c_mclk_change <: 0; /* Acknowledge to hold off starting audio until done */
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -21,23 +21,23 @@ extern "C"
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Special control value to disable SDM. Outside of normal range which is less than 16b.*/
|
/* 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
|
/** 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.
|
* 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 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 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
|
/** Helper function that sends a special restart command. It causes the SDM task
|
||||||
* to help prevemt simultaenous access to the PLL register from two different threads,
|
* 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_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.
|
/** Performs a frequency comparsion between the incoming digital Rx stream and the local mclk.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -9,12 +9,6 @@
|
|||||||
|
|
||||||
#if USE_SW_PLL
|
#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)
|
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
|
/* 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
|
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. */
|
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 f_error = 0;
|
||||||
int dco_setting = SW_PLL_SDM_CTRL_MID_24; // Assume 24.576MHz as initial clock
|
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
|
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();
|
tileref_t this_tile = get_local_tile_id();
|
||||||
@@ -140,10 +135,10 @@ void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval){
|
|||||||
timer tmr;
|
timer tmr;
|
||||||
int32_t time_trigger;
|
int32_t time_trigger;
|
||||||
tmr :> time_trigger;
|
tmr :> time_trigger;
|
||||||
int send_ack_once = 1;
|
int running = 1;
|
||||||
|
|
||||||
unsigned rx_word;
|
unsigned rx_word;
|
||||||
while(1)
|
while(running)
|
||||||
{
|
{
|
||||||
/* Poll for new SDM control value */
|
/* Poll for new SDM control value */
|
||||||
select
|
select
|
||||||
@@ -151,16 +146,17 @@ void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval){
|
|||||||
case inuint_byref(c_sigma_delta, rx_word):
|
case inuint_byref(c_sigma_delta, rx_word):
|
||||||
if(rx_word == DISABLE_SDM)
|
if(rx_word == DISABLE_SDM)
|
||||||
{
|
{
|
||||||
|
printhexln(rx_word);
|
||||||
f_error = 0;
|
f_error = 0;
|
||||||
send_ack_once = 1;
|
running = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
f_error = (int32_t)rx_word;
|
f_error = (int32_t)rx_word;
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
sw_pll_sdm_do_control_from_error(sw_pll_ptr, -f_error);
|
sw_pll_sdm_do_control_from_error(&sw_pll, -f_error);
|
||||||
dco_setting = sw_pll_ptr->sdm_state.current_ctrl_val;
|
dco_setting = sw_pll.sdm_state.current_ctrl_val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -180,29 +176,16 @@ void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval){
|
|||||||
break;
|
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 {
|
unsafe {
|
||||||
sw_pll_do_sigma_delta(&sw_pll_ptr->sdm_state, this_tile, dco_setting);
|
sw_pll_do_sigma_delta(&sw_pll.sdm_state, this_tile, dco_setting);
|
||||||
send_ack_once = 1;
|
|
||||||
}
|
}
|
||||||
else if(send_ack_once)
|
} /* if running */
|
||||||
{
|
|
||||||
/* 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)
|
void restart_sigma_delta(chanend c_sigma_delta)
|
||||||
{
|
{
|
||||||
outuint(c_sigma_delta, DISABLE_SDM); /* Stops SDM */
|
outuint(c_sigma_delta, DISABLE_SDM); /* Resets SDM */
|
||||||
inuint(c_sigma_delta); /* Wait for ACK so we know reg write is complete */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* USE_SW_PLL */
|
#endif /* USE_SW_PLL */
|
||||||
|
|||||||
Reference in New Issue
Block a user