Commit 48f54b88 authored by Grzegorz Daniluk's avatar Grzegorz Daniluk

softpll_ng: imported from wr switch

parent e0228897
This diff is collapsed.
......@@ -3,9 +3,10 @@
White Rabbit Softcore PLL (SoftPLL) - common definitions
Copyright (c) 2010 - 2012 CERN / BE-CO-HT (Tomasz Włostowski)
Licensed under LGPL 2.1.
spll_common.h - common data structures and functions
*/
......@@ -131,7 +132,8 @@ static int lowpass_update(spll_lowpass_t *lp, int x)
lp->y_d = x;
return x;
} else {
lp->y_d = lp->y_d + ((lp->alpha * (x - lp->y_d)) >> 16);
int scaled = (lp->alpha * (x - lp->y_d)) >> 15;
lp->y_d = lp->y_d + (scaled >> 1) + (scaled & 1);
return lp->y_d;
}
}
......@@ -164,5 +166,5 @@ static void spll_enable_tagger(int channel, int enable)
SPLL->RCER &= ~ (1<<channel);
}
TRACE_DEV("%s: ch %d, OCER 0x%x, RCER 0x%x\n", __FUNCTION__, channel, SPLL->OCER, SPLL->RCER);
// TRACE("%s: ch %d, OCER 0x%x, RCER 0x%x\n", __FUNCTION__, channel, SPLL->OCER, SPLL->RCER);
}
/*
White Rabbit Softcore PLL (SoftPLL) - debugging/diagnostic interface
White Rabbit Softcore PLL (SoftPLL) - common definitions
Copyright (c) 2010 - 2012 CERN / BE-CO-HT (Tomasz Włostowski)
Licensed under LGPL 2.1.
spll_debug.h - debugging/diagnostic interface
The so-called debug inteface is a large, interrupt-driven FIFO which passes
various realtime parameters (e.g. error value, tags, DAC drive) to an external
application where they can be analyzed. It's very useful for optimizing PI coefficients
application where they are further analyzed. It's very useful for optimizing PI coefficients
and/or lock thresholds.
The data is organized as a stream of samples, where each sample can store a number of parameters.
......
......@@ -10,7 +10,10 @@ WARNING: These parameters must be in sync with the generics of the HDL instantia
#include <stdio.h>
/* Reference clock frequency, in [Hz] */
#define CLOCK_FREQ 62500000
#define CLOCK_FREQ 125000000
/* Reference clock period, in picoseconds */
#define CLOCK_PERIOD_PICOSECONDS 8000
/* Number of bits in phase tags generated by the DMTDs. Used to sign-extend the tags.
Corresponding VHDL generic: g_tag_bits. */
......@@ -25,10 +28,10 @@ WARNING: These parameters must be in sync with the generics of the HDL instantia
#define PI_FRACBITS 12
/* Max. allowed number of reference channels. Can be used to tweak memory usage. */
#define MAX_CHAN_REF 7
#define MAX_CHAN_REF 1
/* Max. allowed number of output channels */
#define MAX_CHAN_OUT 1
/* Max. allowed number of auxillary channels */
#define MAX_CHAN_AUX 1
/* Max. allowed number of phase trackers */
#define MAX_PTRACKERS 6
......@@ -37,6 +40,9 @@ WARNING: These parameters must be in sync with the generics of the HDL instantia
all the outputs. */
#define DAC_BITS 16
/* Number of samples in a single ptracker averaging bin */
#define PTRACKER_AVERAGE_SAMPLES 512
/* 1.0 / (Speed of the phase shifter) - the higher value, the slower phase shifting.
Used to prevent de-locking PLLs when shifting large offsets. */
#define PHASE_SHIFTER_SPEED 1
#include <timer.h>
#include <hw/pps_gen_regs.h>
/* Number of bits of the BB phase detector error counter. Bit [BB_ERROR_BITS] is the wrap-around bit */
#define BB_ERROR_BITS 16
/* Alignment FSM states */
/* 1st alignment stage, done before starting the ext channel PLL: alignment of the rising edge
of the external clock (10 MHz), with the rising edge of the local reference (62.5/125 MHz)
and the PPS signal. Because of non-integer ratio (6.25 or 12.5), the PLL must know which edges
shall be kept at phase==0. We align to the edge of the 10 MHz clock which comes right after the edge
of the PPS pulse (see drawing below):
PLL reference (62.5 MHz) ____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|
External clock (10 MHz) ^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|___
External PPS ___________|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/
#define REALIGN_STAGE1 1
#define REALIGN_STAGE1_WAIT 2
/* 2nd alignment stage, done after the ext channel PLL has locked. We make sure that the switch's internal PPS signal
is produced exactly on the edge of PLL reference in-phase with 10 MHz clock edge, which has come right after the PPS input
PLL reference (62.5 MHz) ____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|
External clock (10 MHz) ^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|___
External PPS ___________|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Internal PPS __________________________________|^^^^^^^^^|______________________________________________________________________
^ aligned clock edges and PPS
*/
#define REALIGN_STAGE2 3
#define REALIGN_STAGE2_WAIT 4
/* Error state - PPS signal missing or of bad frequency */
#define REALIGN_PPS_INVALID 5
/* Realignment is disabled (i.e. the switch inputs only the reference frequency, but not time) */
#define REALIGN_DISABLED 6
/* Realignment done */
#define REALIGN_DONE 7
//GGDD
PACKED struct PPSG_WB
{
uint32_t CR;
uint32_t CNTR_NSEC;
uint32_t CNTR_UTCLO;
uint32_t CNTR_UTCHI;
uint32_t ADJ_NSEC;
uint32_t ADJ_UTCLO;
uint32_t ADJ_UTCHI;
uint32_t ESCR;
};
//volatile struct temp_ppsg_regs *PPSG = BASE_PPSGEN;
//
struct spll_external_state {
int ref_src;
int sample_n;
int ph_err_offset, ph_err_cur, ph_err_d0, ph_raw_d0;
int realign_clocks;
int realign_state;
int realign_timer;
spll_pi_t pi;
spll_lowpass_t lp_short, lp_long;
spll_lock_det_t ld;
};
static void external_init(struct spll_external_state *s, int ext_ref)
static void external_init( struct spll_external_state *s, int ext_ref, int realign_clocks)
{
s->pi.y_min = 5;
......@@ -30,13 +91,74 @@ static void external_init(struct spll_external_state *s, int ext_ref)
s->ph_err_d0 = 0;
s->ph_raw_d0 = 0;
s->realign_clocks = realign_clocks;
s->realign_state = (realign_clocks ? REALIGN_STAGE1 : REALIGN_DISABLED);
pi_init(&s->pi);
ld_init(&s->ld);
lowpass_init(&s->lp_short, 4000);
lowpass_init(&s->lp_long, 1000);
lowpass_init(&s->lp_long, 300);
}
static inline void realign_fsm( struct spll_external_state *s)
{
uint32_t eccr;
switch(s->realign_state)
{
case REALIGN_STAGE1:
SPLL->ECCR |= SPLL_ECCR_ALIGN_EN;
s->realign_state = REALIGN_STAGE1_WAIT;
s->realign_timer = timer_get_tics();
break;
case REALIGN_STAGE1_WAIT:
if(SPLL->ECCR & SPLL_ECCR_ALIGN_DONE)
s->realign_state = REALIGN_STAGE2;
else if (timer_get_tics() - s->realign_timer > 2*TICS_PER_SECOND)
{
SPLL->ECCR &= ~SPLL_ECCR_ALIGN_EN;
s->realign_state = REALIGN_PPS_INVALID;
}
break;
case REALIGN_STAGE2:
if(s->ld.locked)
{
PPSG->CR = PPSG_CR_CNT_RST | PPSG_CR_CNT_EN;
PPSG->ADJ_UTCLO = 0;
PPSG->ADJ_UTCHI = 0;
PPSG->ADJ_NSEC = 0;
PPSG->ESCR = PPSG_ESCR_SYNC;
s->realign_state = REALIGN_STAGE2_WAIT;
s->realign_timer = timer_get_tics();
}
break;
case REALIGN_STAGE2_WAIT:
if(PPSG->ESCR & PPSG_ESCR_SYNC)
{
PPSG->ESCR = PPSG_ESCR_PPS_VALID | PPSG_ESCR_TM_VALID;
s->realign_state = REALIGN_DONE;
} else if (timer_get_tics() - s->realign_timer > 2*TICS_PER_SECOND)
{
PPSG->ESCR = 0;
s->realign_state = REALIGN_PPS_INVALID;
}
break;
case REALIGN_PPS_INVALID:
case REALIGN_DISABLED:
case REALIGN_DONE:
return ;
}
}
static int external_update(struct spll_external_state *s, int tag, int source)
static int external_update( struct spll_external_state *s, int tag, int source)
{
int err, y, y2, yd, ylt;
......@@ -44,6 +166,8 @@ static int external_update(struct spll_external_state *s, int tag, int source)
{
int wrap = tag & (1<<BB_ERROR_BITS) ? 1 : 0;
realign_fsm(s);
tag &= ((1<<BB_ERROR_BITS) - 1);
......@@ -67,6 +191,12 @@ static int external_update(struct spll_external_state *s, int tag, int source)
y2 = lowpass_update(&s->lp_short, y);
ylt = lowpass_update(&s->lp_long, y);
if(! (SPLL->ECCR & SPLL_ECCR_EXT_REF_PRESENT)) /* no reference? de-lock now */
{
ld_init(&s->ld);
y2 = 32000;
}
SPLL->DAC_MAIN = y2 & 0xffff;
spll_debug(DBG_ERR | DBG_EXT, ylt, 0);
......@@ -80,17 +210,21 @@ static int external_update(struct spll_external_state *s, int tag, int source)
}
static void external_start(struct spll_external_state *s, int align_pps)
static void external_start( struct spll_external_state *s)
{
// mprintf("ExtStartup\n");
SPLL->ECCR = 0;
s->sample_n = 0;
s->realign_state = (s->realign_clocks ? REALIGN_STAGE1 : REALIGN_DISABLED);
SPLL->ECCR = SPLL_ECCR_EXT_EN;
mprintf("ExtStartup\n");
spll_debug(DBG_EVENT | DBG_EXT, DBG_EVT_START, 1);
if(align_pps)
{
SPLL->ECCR |= SPLL_ECCR_ALIGN_EN;
while (! (SPLL->ECCR & SPLL_ECCR_ALIGN_DONE));
}
spll_debug(DBG_EVENT | DBG_EXT, DBG_EVT_START, 1);
}
static inline int external_locked( struct spll_external_state *s)
{
return (s->ld.locked && (s->realign_clocks ? s->realign_state == REALIGN_DONE : 1));
}
......@@ -31,22 +31,12 @@ static void helper_init(struct spll_helper_state *s, int ref_channel)
s->pi.ki = (int)(0.03 * 32.0 * 3.0);
s->pi.anti_windup = 1;
/* Set the bias to the upper end of tuning range. This is to ensure that
the HPLL will always lock on positive frequency offset. */
s->pi.bias = s->pi.y_max;
/* Phase branch lock detection */
s->ld.threshold = 200;
s->ld.lock_samples = 1000;
s->ld.delock_samples = 900;
s->ref_src = ref_channel;
s->p_setpoint = 0;
s->p_adder = 0;
s->sample_n = 0;
s->tag_d0 = -1;
pi_init(&s->pi);
ld_init(&s->ld);
}
static int helper_update(struct spll_helper_state *s, int tag, int source)
......@@ -71,18 +61,12 @@ static int helper_update(struct spll_helper_state *s, int tag, int source)
err = (tag + s->p_adder) - s->p_setpoint;
// if(s->tag_d0 - tag > -100000)
//spll_debug(DBG_ERR | DBG_HELPER, s->tag_d0-tag, 1);
if(HELPER_ERROR_CLAMP)
{
if(err < -HELPER_ERROR_CLAMP) err = -HELPER_ERROR_CLAMP;
if(err > HELPER_ERROR_CLAMP) err = HELPER_ERROR_CLAMP;
}
//GD
//TRACE_DEV("hpll 2err=%d\n", err);
if((tag + s->p_adder) > HELPER_TAG_WRAPAROUND && s->p_setpoint > HELPER_TAG_WRAPAROUND)
{
s->p_adder -= HELPER_TAG_WRAPAROUND;
......@@ -106,8 +90,21 @@ static int helper_update(struct spll_helper_state *s, int tag, int source)
}
static void helper_start(struct spll_helper_state *s)
{
/* Set the bias to the upper end of tuning range. This is to ensure that
the HPLL will always lock on positive frequency offset. */
s->pi.bias = s->pi.y_max;
s->p_setpoint = 0;
s->p_adder = 0;
s->sample_n = 0;
s->tag_d0 = -1;
pi_init(&s->pi);
ld_init(&s->ld);
spll_enable_tagger(s->ref_src, 1);
spll_debug(DBG_EVENT | DBG_HELPER, DBG_EVT_START, 1);
}
......
#define MPLL_TAG_WRAPAROUND 1000000000
#define MPLL_TAG_WRAPAROUND 100000000
#define MATCH_NEXT_TAG 0
#define MATCH_WAIT_REF 1
#define MATCH_WAIT_OUT 2
#undef WITH_SEQUENCING
/* State of the Main PLL */
struct spll_main_state {
......@@ -9,14 +15,18 @@ struct spll_main_state {
spll_lock_det_t ld;
int adder_ref, adder_out, tag_ref, tag_out, tag_ref_d, tag_out_d;
// tag sequencing stuff
uint32_t seq_ref, seq_out;
int match_state;
int match_seq;
int phase_shift_target;
int phase_shift_current;
int id_ref, id_out; /* IDs of the reference and the output channel */
int sample_n;
int shift_div;
};
volatile int lerr = 0, ly=0;
static void mpll_init(struct spll_main_state *s, int id_ref, int id_out)
{
......@@ -32,53 +42,114 @@ static void mpll_init(struct spll_main_state *s, int id_ref, int id_out)
s->ld.threshold = 120;
s->ld.lock_samples = 400;
s->ld.delock_samples = 390;
s->id_ref = id_ref;
s->id_out = id_out;
pi_init(&s->pi);
ld_init(&s->ld);
}
static void mpll_start(struct spll_main_state *s)
{
s->adder_ref = s->adder_out = 0;
s->tag_ref = -1;
s->tag_out = -1;
s->tag_ref_d = -1;
s->tag_out_d = -1;
s->seq_ref = 0;
s->seq_out = 0;
s->match_state = MATCH_NEXT_TAG;
s->phase_shift_target = 0;
s->phase_shift_current = 0;
s->id_ref = id_ref;
s->id_out = id_out;
s->sample_n= 0;
s->shift_div = 0;
pi_init(&s->pi);
ld_init(&s->ld);
}
static 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);
}
static void mpll_stop(struct spll_main_state *s)
{
spll_enable_tagger(s->id_out, 0);
}
static int mpll_update(struct spll_main_state *s, int tag, int source)
{
int err, y, tmp;
#ifdef WITH_SEQUENCING
int new_ref = -1, new_out = -1;
if(source == s->id_ref)
{
new_ref = tag;
s->seq_ref++;
} else if(source == s->id_out) {
new_out = tag;
s->seq_out++;
}
switch(s->match_state)
{
case MATCH_NEXT_TAG:
if(new_ref > 0 && s->seq_out < s->seq_ref)
{
s->tag_ref = new_ref;
s->match_seq = s->seq_ref;
s->match_state = MATCH_WAIT_OUT;
}
if (new_out > 0 && s->seq_out > s->seq_ref)
{
s->tag_out = new_out;
s->match_seq = s->seq_out;
s->match_state = MATCH_WAIT_REF;
}
break;
case MATCH_WAIT_REF:
if(new_ref > 0 && s->seq_ref == s->match_seq)
{
s->match_state = MATCH_NEXT_TAG;
s->tag_ref = new_ref;
}
break;
case MATCH_WAIT_OUT:
if(new_out > 0 && s->seq_out == s->match_seq)
{
s->match_state = MATCH_NEXT_TAG;
s->tag_out = new_out;
}
break;
}
#else
if(source == s->id_ref)
s->tag_ref = tag;
if(source == s->id_out)
s->tag_out = tag;
#endif
if(s->tag_ref >= 0 && s->tag_out >= 0)
{
if(s->tag_ref_d >= 0 && s->tag_ref_d > s->tag_ref)
s->adder_ref += (1<<TAG_BITS);
if(s->tag_out_d >= 0 && s->tag_out_d > s->tag_out)
s->adder_out += (1<<TAG_BITS);
err = s->adder_ref + s->tag_ref - s->adder_out - s->tag_out;
s->tag_ref_d = s->tag_ref;
s->tag_out_d = s->tag_out;
if(s->adder_ref > MPLL_TAG_WRAPAROUND && s->adder_out > MPLL_TAG_WRAPAROUND)
{
s->adder_ref -= MPLL_TAG_WRAPAROUND;
s->adder_out -= MPLL_TAG_WRAPAROUND;
}
err = s->adder_ref + s->tag_ref - s->adder_out - s->tag_out;
#ifndef WITH_SEQUENCING
/* Hack: the PLL is locked, so the tags are close to each other. But when we start phase shifting, after reaching
full clock period, one of the reference tags will flip before the other, causing a suddent 2**HPLL_N jump in the error.
......@@ -93,39 +164,37 @@ static int mpll_update(struct spll_main_state *s, int tag, int source)
}
#endif
y = pi_update(&s->pi, err);
lerr = err;
ly=y;
SPLL->DAC_MAIN = SPLL_DAC_MAIN_VALUE_W(y) | SPLL_DAC_MAIN_DAC_SEL_W(s->id_out);
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);
s->tag_ref_d = s->tag_ref;
s->tag_out_d = s->tag_out;
s->tag_out = -1;
s->tag_ref = -1;
if(s->phase_shift_current < s->phase_shift_target)
if(s->adder_ref > 2*MPLL_TAG_WRAPAROUND && s->adder_out > 2*MPLL_TAG_WRAPAROUND)
{
s->adder_ref -= MPLL_TAG_WRAPAROUND;
s->adder_out -= MPLL_TAG_WRAPAROUND;
}
if(s->ld.locked)
{
if(s->shift_div == PHASE_SHIFTER_SPEED-1)
if(s->phase_shift_current < s->phase_shift_target)
{
s->phase_shift_current++;
s->adder_ref++;
s->shift_div = 0;
} else s->shift_div++;
} else if(s->phase_shift_current > s->phase_shift_target) {
if(s->shift_div == PHASE_SHIFTER_SPEED-1)
{
s->phase_shift_current--;
s->adder_ref--;
s->shift_div = 0;
} else s->shift_div++;
}
}
if(ld_update(&s->ld, err))
return SPLL_LOCKED;
......@@ -136,7 +205,6 @@ static int mpll_update(struct spll_main_state *s, int tag, int source)
static int mpll_set_phase_shift(struct spll_main_state *s, int desired_shift)
{
s->shift_div = 0;
s->phase_shift_target = desired_shift;
}
......
......@@ -27,6 +27,13 @@ static void ptracker_init(struct spll_ptracker_state *s, int id_a, int id_b, int
static void ptracker_start(struct spll_ptracker_state *s)
{
s->tag_a = s->tag_b = -1;
s->ready = 0;
s->acc = 0;
s->avg_count = 0;
s->sample_n= 0;
s->preserve_sign = 0;
spll_enable_tagger(s->id_a, 1);
spll_enable_tagger(s->id_b, 1);
}
......@@ -46,6 +53,8 @@ static int ptracker_update(struct spll_ptracker_state *s, int tag, int source)
{
int delta = (s->tag_a - s->tag_b) & ((1<<HPLL_N) - 1);
s->sample_n++;
if(s->avg_count == 0)
{
......@@ -56,7 +65,7 @@ static int ptracker_update(struct spll_ptracker_state *s, int tag, int source)
else
s->preserve_sign = 0;
s->avg_count++;
s->acc = delta;
} else {
......@@ -78,6 +87,7 @@ static int ptracker_update(struct spll_ptracker_state *s, int tag, int source)
}
}
s->tag_b = s->tag_a = -1;
}
......
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