Fix PLL lock time 2s -> ~150ms

This commit is contained in:
Ed
2024-01-05 14:39:47 +00:00
parent 7f8f07b4b6
commit 56d728f349

View File

@@ -236,6 +236,8 @@ unsafe
sw_pll_state_t * unsafe sw_pll_ptr = NULL; sw_pll_state_t * unsafe sw_pll_ptr = NULL;
} }
#define DISABLE_SDM 0x1000000 /* Control value to disable SDM. Outside of normal range.*/
unsigned 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 */ /* Autogenerated SDM App PLL setup by dco_model.py using 22.5792_1M profile */
@@ -292,6 +294,8 @@ unsigned InitSWPLL(sw_pll_state_t &sw_pll, unsigned mClk)
sw_pll_sdm_ctrl_mid[clkIndex], sw_pll_sdm_ctrl_mid[clkIndex],
3000 /* PPM_RANGE (FOR PFD) Don't care for this API*/ ); 3000 /* PPM_RANGE (FOR PFD) Don't care for this API*/ );
/* Reset SDM too */
sw_pll_init_sigma_delta(&sw_pll.sdm_state);
printstr("Init sw_pll: "); printuintln(mClk); printstr("Init sw_pll: "); printuintln(mClk);
@@ -302,7 +306,8 @@ void do_sw_pll_phase_frequency_detector( sw_pll_state_t sw_pll,
unsigned short mclk_time_stamp, unsigned short mclk_time_stamp,
unsigned mclks_per_sample, unsigned mclks_per_sample,
chanend c_sigma_delta, chanend c_sigma_delta,
int receivedSamples) int receivedSamples,
int &reset_sw_pll_pfd)
{ {
const unsigned control_loop_rate_divider = 6; /* 300Hz * 2 edges / 6 -> 100Hz loop rate */ const unsigned control_loop_rate_divider = 6; /* 300Hz * 2 edges / 6 -> 100Hz loop rate */
static unsigned control_loop_counter = 0; static unsigned control_loop_counter = 0;
@@ -325,9 +330,16 @@ void do_sw_pll_phase_frequency_detector( sw_pll_state_t sw_pll,
/* The difference is the raw error in terms of mclk counts */ /* The difference is the raw error in terms of mclk counts */
short f_error = (int)actual_mclk_inc - (int)expected_mclk_inc; short f_error = (int)actual_mclk_inc - (int)expected_mclk_inc;
if(reset_sw_pll_pfd)
{
f_error = 0; /* Skip first measurement as it will likely be very out */
reset_sw_pll_pfd = 0;
}
printintln(f_error);
/* send PFD output to the sigma delta thread */ /* send PFD output to the sigma delta thread */
outuint(c_sigma_delta, (unsigned) (1000000 + f_error)); outuint(c_sigma_delta, (int) f_error);
last_mclk_time_stamp = mclk_time_stamp; last_mclk_time_stamp = mclk_time_stamp;
control_loop_counter = 0; control_loop_counter = 0;
@@ -344,7 +356,7 @@ void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval){
while(sw_pll_ptr == NULL); while(sw_pll_ptr == NULL);
int f_error = 0; int f_error = 0;
int dco_setting = SW_PLL_SDM_CTRL_MID_24; // TODO FIX ME int dco_setting = SW_PLL_SDM_CTRL_MID_24; // TODO Assume 24.576MHz?
unsafe unsafe
{ {
sw_pll_init_sigma_delta(&sw_pll_ptr->sdm_state); sw_pll_init_sigma_delta(&sw_pll_ptr->sdm_state);
@@ -364,12 +376,20 @@ void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval){
select select
{ {
case inuint_byref(c_sigma_delta, tmp): case inuint_byref(c_sigma_delta, tmp):
if(tmp == DISABLE_SDM)
{
f_error = 0;
send_ack_once = 1;
}
else
{
f_error = (int32_t)tmp; f_error = (int32_t)tmp;
unsafe unsafe
{ {
sw_pll_sdm_do_control_from_error(sw_pll_ptr, -f_error + 1000000); sw_pll_sdm_do_control_from_error(sw_pll_ptr, -f_error);
dco_setting = sw_pll_ptr->sdm_state.current_ctrl_val; dco_setting = sw_pll_ptr->sdm_state.current_ctrl_val;
} }
}
break; break;
// Do nothing & fall-through // Do nothing & fall-through
@@ -391,7 +411,7 @@ void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval){
control value. This will avoid the writing of the control value. This will avoid the writing of the
frac reg from two different threads which may cause frac reg from two different threads which may cause
a channel deadlock. */ a channel deadlock. */
if(f_error != 0) if(tmp != 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_ptr->sdm_state, this_tile, dco_setting);
send_ack_once = 1; send_ack_once = 1;
@@ -408,7 +428,7 @@ void SigmaDeltaTask(chanend c_sigma_delta, unsigned sdm_interval){
void disable_sigma_delta(chanend c_sigma_delta) void disable_sigma_delta(chanend c_sigma_delta)
{ {
outuint(c_sigma_delta, 0); /* Stops SD */ outuint(c_sigma_delta, DISABLE_SDM); /* Stops SDM */
inuint(c_sigma_delta); /* Wait for ACK so we know reg write is complete */ inuint(c_sigma_delta); /* Wait for ACK so we know reg write is complete */
} }
@@ -548,6 +568,7 @@ void clockGen ( streaming chanend ?c_spdif_rx,
#if USE_SW_PLL #if USE_SW_PLL
chan c_sigma_delta; chan c_sigma_delta;
sw_pll_state_t sw_pll; sw_pll_state_t sw_pll;
int reset_sw_pll_pfd = 1;
/* Initialise before we par off the SDM thread/ /* Initialise before we par off the SDM thread/
We share the sw_pll struct across threads and this We share the sw_pll struct across threads and this
@@ -741,7 +762,7 @@ void clockGen ( streaming chanend ?c_spdif_rx,
printstr("c_mclk_change: "); printuintln(selected_mclk_rate); printstr("c_mclk_change: "); printuintln(selected_mclk_rate);
disable_sigma_delta(c_sigma_delta); /* Blocks until SDM is idle */ disable_sigma_delta(c_sigma_delta); /* Blocks until SDM is idle */
InitSWPLL(sw_pll, selected_mclk_rate); InitSWPLL(sw_pll, selected_mclk_rate);
outuint(c_sigma_delta, sw_pll.sdm_state.ctrl_mid_point); /* Send ctrl mid point to re-enable SDM and set to nominal mclk */ reset_sw_pll_pfd = 1;
printstr("swpll int'd\n"); printstr("swpll int'd\n");
#endif #endif
break; break;
@@ -825,7 +846,7 @@ void clockGen ( streaming chanend ?c_spdif_rx,
timeNextEdge = spdifRxTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; timeNextEdge = spdifRxTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
#if USE_SW_PLL #if USE_SW_PLL
do_sw_pll_phase_frequency_detector(sw_pll, mclk_time_stamp, mclks_per_sample, c_sigma_delta, spdifCounters.receivedSamples); do_sw_pll_phase_frequency_detector(sw_pll, mclk_time_stamp, mclks_per_sample, c_sigma_delta, spdifCounters.receivedSamples, reset_sw_pll_pfd);
#else #else
/* Toggle edge */ /* Toggle edge */
i_pll_ref.toggle_timed(1); i_pll_ref.toggle_timed(1);
@@ -935,7 +956,7 @@ void clockGen ( streaming chanend ?c_spdif_rx,
timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN; timeNextEdge = adatReceivedTime + LOCAL_CLOCK_INCREMENT + LOCAL_CLOCK_MARGIN;
#if USE_SW_PLL #if USE_SW_PLL
do_sw_pll_phase_frequency_detector(sw_pll, mclk_time_stamp, mclks_per_sample, c_sigma_delta, adatCounters.receivedSamples); do_sw_pll_phase_frequency_detector(sw_pll, mclk_time_stamp, mclks_per_sample, c_sigma_delta, adatCounters.receivedSamples, reset_sw_pll_pfd);
#else #else
/* Toggle edge */ /* Toggle edge */
i_pll_ref.toggle_timed(1); i_pll_ref.toggle_timed(1);
@@ -982,7 +1003,7 @@ void clockGen ( streaming chanend ?c_spdif_rx,
{ {
/* We're out of S/PDIF samples, mark underflow condition */ /* We're out of S/PDIF samples, mark underflow condition */
spdifUnderflow = 1; spdifUnderflow = 1;
printstr("spu-\n"); // DELME printstr("spu+\n"); // DELME
spdifLeft = 0; spdifLeft = 0;
} }