Commit 33cd8408 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

softpll: enable PPS output after locking to external 10 MHz reference

parent 708b2d4a
...@@ -6,12 +6,12 @@ ...@@ -6,12 +6,12 @@
/* Alignment FSM states */ /* Alignment FSM states */
/* 1st alignment stage, done before starting the ext channel PLL: alignment of the rising edge /* 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) 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 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 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): of the PPS pulse (see drawing below):
PLL reference (62.5 MHz) ____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____| PLL reference (62.5 MHz) ____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|
External clock (10 MHz) ^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|___ External clock (10 MHz) ^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|___
External PPS ___________|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ External PPS ___________|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...@@ -20,15 +20,14 @@ External PPS ___________|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...@@ -20,15 +20,14 @@ External PPS ___________|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#define REALIGN_STAGE1_WAIT 2 #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 /* 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 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) ____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____| PLL reference (62.5 MHz) ____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|^^^^|____|
External clock (10 MHz) ^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|___ External clock (10 MHz) ^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|________________________|^^^^^^^^^^^^^^^^^^^^^^^^^|___
External PPS ___________|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ External PPS ___________|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Internal PPS __________________________________|^^^^^^^^^|______________________________________________________________________ Internal PPS __________________________________|^^^^^^^^^|______________________________________________________________________
^ aligned clock edges and PPS
^ aligned clock edges and PPS
*/ */
#define REALIGN_STAGE2 3 #define REALIGN_STAGE2 3
...@@ -51,22 +50,22 @@ struct spll_external_state { ...@@ -51,22 +50,22 @@ struct spll_external_state {
int realign_clocks; int realign_clocks;
int realign_state; int realign_state;
int realign_timer; int realign_timer;
spll_pi_t pi; spll_pi_t pi;
spll_lowpass_t lp_short, lp_long; spll_lowpass_t lp_short, lp_long;
spll_lock_det_t ld; spll_lock_det_t ld;
}; };
static void external_init( struct spll_external_state *s, int ext_ref, int realign_clocks) static void external_init( struct spll_external_state *s, int ext_ref, int realign_clocks)
{ {
s->pi.y_min = 5; s->pi.y_min = 5;
s->pi.y_max = (1 << DAC_BITS) - 5; s->pi.y_max = (1 << DAC_BITS) - 5;
s->pi.kp = (int)(300); s->pi.kp = (int)(300);
s->pi.ki = (int)(1); s->pi.ki = (int)(1);
s->pi.anti_windup = 1; s->pi.anti_windup = 1;
s->pi.bias = 32768; s->pi.bias = 32768;
/* Phase branch lock detection */ /* Phase branch lock detection */
s->ld.threshold = 250; s->ld.threshold = 250;
s->ld.lock_samples = 10000; s->ld.lock_samples = 10000;
...@@ -75,10 +74,10 @@ static void external_init( struct spll_external_state *s, int ext_ref, int reali ...@@ -75,10 +74,10 @@ static void external_init( struct spll_external_state *s, int ext_ref, int reali
s->ph_err_cur = 0; s->ph_err_cur = 0;
s->ph_err_d0 = 0; s->ph_err_d0 = 0;
s->ph_raw_d0 = 0; s->ph_raw_d0 = 0;
s->realign_clocks = realign_clocks; s->realign_clocks = realign_clocks;
s->realign_state = (realign_clocks ? REALIGN_STAGE1 : REALIGN_DISABLED); s->realign_state = (realign_clocks ? REALIGN_STAGE1 : REALIGN_DISABLED);
pi_init(&s->pi); pi_init(&s->pi);
ld_init(&s->ld); ld_init(&s->ld);
lowpass_init(&s->lp_short, 4000); lowpass_init(&s->lp_short, 4000);
...@@ -89,16 +88,16 @@ static inline void realign_fsm( struct spll_external_state *s) ...@@ -89,16 +88,16 @@ static inline void realign_fsm( struct spll_external_state *s)
{ {
uint32_t eccr; uint32_t eccr;
switch(s->realign_state) switch(s->realign_state)
{ {
case REALIGN_STAGE1: case REALIGN_STAGE1:
SPLL->ECCR |= SPLL_ECCR_ALIGN_EN; SPLL->ECCR |= SPLL_ECCR_ALIGN_EN;
s->realign_state = REALIGN_STAGE1_WAIT; s->realign_state = REALIGN_STAGE1_WAIT;
s->realign_timer = timer_get_tics(); s->realign_timer = timer_get_tics();
break; break;
case REALIGN_STAGE1_WAIT: case REALIGN_STAGE1_WAIT:
if(SPLL->ECCR & SPLL_ECCR_ALIGN_DONE) if(SPLL->ECCR & SPLL_ECCR_ALIGN_DONE)
...@@ -109,7 +108,7 @@ static inline void realign_fsm( struct spll_external_state *s) ...@@ -109,7 +108,7 @@ static inline void realign_fsm( struct spll_external_state *s)
s->realign_state = REALIGN_PPS_INVALID; s->realign_state = REALIGN_PPS_INVALID;
} }
break; break;
case REALIGN_STAGE2: case REALIGN_STAGE2:
if(s->ld.locked) if(s->ld.locked)
{ {
...@@ -118,16 +117,16 @@ static inline void realign_fsm( struct spll_external_state *s) ...@@ -118,16 +117,16 @@ static inline void realign_fsm( struct spll_external_state *s)
PPSG->ADJ_UTCHI = 0; PPSG->ADJ_UTCHI = 0;
PPSG->ADJ_NSEC = 0; PPSG->ADJ_NSEC = 0;
PPSG->ESCR = PPSG_ESCR_SYNC; PPSG->ESCR = PPSG_ESCR_SYNC;
s->realign_state = REALIGN_STAGE2_WAIT; s->realign_state = REALIGN_STAGE2_WAIT;
s->realign_timer = timer_get_tics(); s->realign_timer = timer_get_tics();
} }
break; break;
case REALIGN_STAGE2_WAIT: case REALIGN_STAGE2_WAIT:
if(PPSG->ESCR & PPSG_ESCR_SYNC) if(PPSG->ESCR & PPSG_ESCR_SYNC)
{ {
PPSG->ESCR = PPSG_ESCR_PPS_VALID; /* enable PPS output */ PPSG->ESCR = PPSG_ESCR_PPS_VALID | PPSG_ESCR_TM_VALID;
s->realign_state = REALIGN_DONE; s->realign_state = REALIGN_DONE;
} else if (timer_get_tics() - s->realign_timer > 2*TICS_PER_SECOND) } else if (timer_get_tics() - s->realign_timer > 2*TICS_PER_SECOND)
{ {
...@@ -135,11 +134,11 @@ static inline void realign_fsm( struct spll_external_state *s) ...@@ -135,11 +134,11 @@ static inline void realign_fsm( struct spll_external_state *s)
s->realign_state = REALIGN_PPS_INVALID; s->realign_state = REALIGN_PPS_INVALID;
} }
break; break;
case REALIGN_PPS_INVALID: case REALIGN_PPS_INVALID:
case REALIGN_DISABLED: case REALIGN_DISABLED:
case REALIGN_DONE: case REALIGN_DONE:
return ; return ;
} }
} }
...@@ -152,7 +151,7 @@ static int external_update( struct spll_external_state *s, int tag, int source) ...@@ -152,7 +151,7 @@ static int external_update( struct spll_external_state *s, int tag, int source)
int wrap = tag & (1<<BB_ERROR_BITS) ? 1 : 0; int wrap = tag & (1<<BB_ERROR_BITS) ? 1 : 0;
realign_fsm(s); realign_fsm(s);
tag &= ((1<<BB_ERROR_BITS) - 1); tag &= ((1<<BB_ERROR_BITS) - 1);
...@@ -160,16 +159,16 @@ static int external_update( struct spll_external_state *s, int tag, int source) ...@@ -160,16 +159,16 @@ static int external_update( struct spll_external_state *s, int tag, int source)
// mprintf("err %d\n", tag); // mprintf("err %d\n", tag);
if(wrap) if(wrap)
{ {
if(tag > s->ph_raw_d0) if(tag > s->ph_raw_d0)
s->ph_err_offset -= (1<<BB_ERROR_BITS); s->ph_err_offset -= (1<<BB_ERROR_BITS);
else if(tag <= s->ph_raw_d0) else if(tag <= s->ph_raw_d0)
s->ph_err_offset += (1<<BB_ERROR_BITS); s->ph_err_offset += (1<<BB_ERROR_BITS);
} }
s->ph_raw_d0 = tag; s->ph_raw_d0 = tag;
err = (tag + s->ph_err_offset) - s->ph_err_d0; err = (tag + s->ph_err_offset) - s->ph_err_d0;
s->ph_err_d0 = (tag + s->ph_err_offset); s->ph_err_d0 = (tag + s->ph_err_offset);
y = pi_update(&s->pi, err); y = pi_update(&s->pi, err);
...@@ -203,13 +202,13 @@ static void external_start( struct spll_external_state *s) ...@@ -203,13 +202,13 @@ static void external_start( struct spll_external_state *s)
s->sample_n = 0; s->sample_n = 0;
s->realign_state = (s->realign_clocks ? REALIGN_STAGE1 : REALIGN_DISABLED); s->realign_state = (s->realign_clocks ? REALIGN_STAGE1 : REALIGN_DISABLED);
SPLL->ECCR = SPLL_ECCR_EXT_EN; SPLL->ECCR = SPLL_ECCR_EXT_EN;
spll_debug(DBG_EVENT | DBG_EXT, DBG_EVT_START, 1); spll_debug(DBG_EVENT | DBG_EXT, DBG_EVT_START, 1);
} }
static inline int external_locked( struct spll_external_state *s) static inline int external_locked( struct spll_external_state *s)
{ {
return (s->ld.locked && (s->realign_clocks ? s->realign_state == REALIGN_DONE : 1)); return (s->ld.locked && (s->realign_clocks ? s->realign_state == REALIGN_DONE : 1));
} }
\ No newline at end of file
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