Commit ce1a593a authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

softpll: experimental support for fractional frequency ratio locking.

Notes:
- no PPS divider phase alignment (yet)
- works on the SPEC's Si570 @ 100 MHz (4/5 freq ratio)
- very untested! consider it a proof of concept.
- requires updated VHDL (see wr-cores with the same branch name)
parent 78ad43bd
......@@ -50,6 +50,8 @@ void mpll_init(struct spll_main_state *s, int id_ref,
#endif
s->enabled = 0;
s->frequency_lock_threshold = 100;
/* Freqency branch lock detection */
s->ld.threshold = 1200;
s->ld.lock_samples = 1000;
......@@ -57,6 +59,7 @@ void mpll_init(struct spll_main_state *s, int id_ref,
s->id_ref = id_ref;
s->id_out = id_out;
s->dac_index = id_out - spll_n_chan_ref;
s->div_ref = s->div_fb = 0;
if( s->gain_sched )
{
......@@ -86,7 +89,7 @@ static inline void mpll_handle_gain_schedule( struct spll_main_state *s )
}
else if ( !s->gain_sched->locked_d && s->ld.locked ) // PLL lock acquired? advance stage
{
spll_debug(DBG_EVENT | DBG_MAIN, DBG_EVT_GAIN_SWITCH, 0);
//spll_debug(DBG_EVENT | DBG_MAIN, DBG_EVT_GAIN_SWITCH, 0);
if ( s->gain_sched->current_stage == s->gain_sched->n_stages - 1 )
{
s->locked = 1;
......@@ -129,13 +132,16 @@ void mpll_start(struct spll_main_state *s)
s->tag_out = -1;
s->tag_ref_d = -1;
s->tag_out_d = -1;
s->tag_out_raw_d = -1;
s->tag_out_interp = -1;
s->tag_out_raw = -1;
s->n_ref = s->n_out = 0;
s->phase_shift_target = 0;
s->phase_shift_current = 0;
s->sample_n = 0;
s->enabled = 1;
s->locked = 0;
s->div_cnt= 0;
if( s->gain_sched )
{
......@@ -154,7 +160,7 @@ void mpll_start(struct spll_main_state *s)
spll_enable_tagger(s->id_ref, 1);
spll_enable_tagger(s->id_out, 1);
spll_debug(DBG_EVENT | DBG_MAIN, DBG_EVT_START, 1);
spll_debug(DBG_EVENT | DBG_MAIN(s->id_out - spll_n_chan_ref), DBG_EVT_START, 1);
}
void mpll_stop(struct spll_main_state *s)
......@@ -163,6 +169,17 @@ void mpll_stop(struct spll_main_state *s)
s->enabled = 0;
}
static inline void update_dtag_dt( int *dtag_dt, int tag, int *tag_d )
{
if( tag == *tag_d )
return;
*dtag_dt = (tag - *tag_d);
if( *dtag_dt < 0 )
*dtag_dt += (1<<TAG_BITS);
*tag_d = tag;
}
int mpll_update(struct spll_main_state *s, int tag, int source)
{
if(!s->enabled)
......@@ -170,13 +187,81 @@ int mpll_update(struct spll_main_state *s, int tag, int source)
int err, y;
int mtag = DBG_MAIN( s->id_out - spll_n_chan_ref );
if (source == s->id_ref)
{
s->tag_ref = tag;
s->n_ref++;
if(s->tag_out_interp >= 0)
{
s->tag_out = s->tag_out_interp;
s->n_out++;
s->tag_out_interp = -1;
}
}
if (source == s->id_out)
s->tag_out = tag;
{
s->tag_out_raw_d = s->tag_out_raw;
s->tag_out_raw = tag;
if (s->div_ref == 0)
{
s->tag_out = tag;
s->n_out++;
}
else
{
int t_raw = s->tag_out_raw;
if (t_raw < s->tag_out_raw_d)
t_raw += (1 << TAG_BITS);
int w0 = s->div_cnt * s->div_fb;
int w1 = (s->div_cnt + 1) * s->div_fb;
//printf("w0 %d/%d w1 %d/%d\n", w0, div_ref, w1, div_ref );
int f0 = w0 % s->div_ref;
int f1 = w1 % s->div_ref;
int c0 = w0 / s->div_ref;
int c1 = w1 / s->div_ref;
int tr = ((s->div_ref - f0) * s->tag_out_raw_d + f0 * t_raw) / s->div_ref;
//printf("Interp[NORM]: %d tprev %d tcur %d c0 %d c1 %d f0 %d f1 %d\n", tr, tag_si_prev, tag_si, c0, c1, f0, f1 );
//spll_debug(mtag | DBG_TAG, tr, 1);
s->tag_out = tr;
s->n_out++;
if (c0 == c1)
{
s->div_cnt++;
int tr2 = ((s->div_ref - f1) * s->tag_out_raw_d + f1 * t_raw) / s->div_ref;
s->tag_out_interp = tr2;
//printf("Interp[SLIP]: %d tprev %d tcur %d c0 %d c1 %d f0 %d f1 %d\n", tr, tag_si_prev, tag_si, c0, c1, f0, f1 );
}
else
{
s->tag_out_interp = -1;
}
s->div_cnt++;
if (s->div_cnt == s->div_ref)
s->div_cnt = 0;
}
}
if (s->tag_ref >= 0) {
update_dtag_dt( &s->dref_dt, s->tag_ref, &s->tag_ref_raw_d );
if(s->tag_ref_d >= 0 && s->tag_ref_d > s->tag_ref)
s->adder_ref += (1 << TAG_BITS);
......@@ -185,6 +270,8 @@ int mpll_update(struct spll_main_state *s, int tag, int source)
if (s->tag_out >= 0) {
update_dtag_dt( &s->dout_dt, s->tag_out, &s->tag_out_raw_d2 );
if(s->tag_out_d >= 0 && s->tag_out_d > s->tag_out)
s->adder_out += (1 << TAG_BITS);
......@@ -192,7 +279,15 @@ int mpll_update(struct spll_main_state *s, int tag, int source)
}
if (s->tag_ref >= 0 && s->tag_out >= 0) {
err = s->adder_ref + s->tag_ref - s->adder_out - s->tag_out;
if( abs(s->dout_dt - s->dref_dt) > s->frequency_lock_threshold )
{
err = s->dref_dt - s->dout_dt;
}
else
{
err = s->adder_ref + s->tag_ref - s->adder_out - s->tag_out;
}
#ifndef WITH_SEQUENCING
......@@ -214,7 +309,7 @@ int mpll_update(struct spll_main_state *s, int tag, int source)
#endif
y = pi_update((spll_pi_t *)&s->pi, err);
if(!s->vco_freeze)
if(!s->vco_freeze )
{
SPLL->DAC_MAIN = SPLL_DAC_MAIN_VALUE_W(y)
| SPLL_DAC_MAIN_DAC_SEL_W(s->dac_index);
......@@ -222,11 +317,12 @@ int mpll_update(struct spll_main_state *s, int tag, int source)
if (s->dac_index == 0)
spll_log_dac(y);
spll_debug(DBG_MAIN | DBG_REF, s->tag_ref + s->adder_ref, 0);
spll_debug(DBG_MAIN | DBG_TAG, s->tag_out + s->adder_out, 0);
spll_debug(DBG_MAIN | DBG_ERR, err, 0);
spll_debug(DBG_MAIN | DBG_SAMPLE_ID, s->sample_n++, 0);
spll_debug(DBG_MAIN | DBG_Y, y, 1);
spll_debug(mtag | DBG_REF, s->dref_dt, 0);
spll_debug(mtag | DBG_TAG, s->dout_dt, 0);
spll_debug(mtag | DBG_ERR, err, 0);
spll_debug(mtag | DBG_SAMPLE_ID, s->sample_n++, 0);
spll_debug(mtag | DBG_Y, y, 1);
s->tag_out = -1;
s->tag_ref = -1;
......@@ -258,7 +354,7 @@ int mpll_update(struct spll_main_state *s, int tag, int source)
ld_update((spll_lock_det_t *)&s->ld, err);
if( s->ld.lock_changed)
spll_debug(DBG_EVENT | DBG_MAIN, DBG_EVT_LOCKED, 1);
spll_debug(DBG_EVENT | mtag, DBG_EVT_LOCKED, 1);
mpll_handle_gain_schedule(s);
......
......@@ -22,10 +22,21 @@ struct spll_main_state {
spll_lock_det_t ld;
spll_gain_schedule_t* gain_sched;
int adder_ref, adder_out, tag_ref, tag_out, tag_ref_d, tag_out_d;
int div_cnt;
int div_fb;
int div_ref;
int div_interp;
int n_ref, n_out;
//uint8_t div_lookup[16];
int tag_out_interp;
int adder_ref, adder_out, tag_ref, tag_out, tag_ref_d, tag_out_d, tag_out_raw_d, tag_out_raw;
int dref_dt, dout_dt, tag_ref_raw_d, tag_out_raw_d2;
int locked; // locked flag
int phase_shift_target;
int phase_shift_current;
int frequency_lock_threshold;
int id_ref, id_out; /* IDs of the reference and the output channel */
int sample_n;
int dac_index;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment