Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
S
Software for White Rabbit PTP Core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
31
Issues
31
List
Board
Labels
Milestones
Merge Requests
4
Merge Requests
4
CI / CD
CI / CD
Pipelines
Schedules
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
Software for White Rabbit PTP Core
Commits
f0953590
Commit
f0953590
authored
Jul 17, 2014
by
Tomasz Wlostowski
Committed by
Grzegorz Daniluk
Aug 05, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
softpll: rewritten external channel, we don't use bang-bang phase detector any more
parent
245d3efb
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
496 additions
and
425 deletions
+496
-425
ad9516.c
dev/ad9516.c
+0
-1
softpll_regs.h
softpll/hw/softpll_regs.h
+106
-93
softpll_ng.c
softpll/softpll_ng.c
+87
-90
softpll_ng.h
softpll/softpll_ng.h
+10
-3
spll_common.c
softpll/spll_common.c
+12
-1
spll_common.h
softpll/spll_common.h
+17
-0
spll_external.c
softpll/spll_external.c
+146
-127
spll_external.h
softpll/spll_external.h
+13
-53
spll_helper.c
softpll/spll_helper.c
+12
-1
spll_helper.h
softpll/spll_helper.h
+1
-0
spll_main.c
softpll/spll_main.c
+44
-52
spll_main.h
softpll/spll_main.h
+1
-1
wrc_main.c
wrc_main.c
+1
-1
wrc_ptp_noposix.c
wrc_ptp_noposix.c
+1
-0
wrs_main.c
wrs_main.c
+45
-2
No files found.
dev/ad9516.c
View file @
f0953590
...
...
@@ -153,7 +153,6 @@ int ad9516_set_output_divider(int output, int ratio, int phase_offset)
ad9516_write_reg
(
base
+
1
,
div_ctl
|
(
1
<<
7
)
|
(
phase_offset
&
0xf
));
}
else
{
uint8_t
div_ctl
=
ad9516_read_reg
(
base
+
1
);
TRACE
(
"DivCtl: %x
\n
"
,
div_ctl
);
ad9516_write_reg
(
base
+
1
,
(
div_ctl
&
(
~
(
1
<<
7
)))
|
(
phase_offset
&
0xf
));
/* disable bypass bit */
ad9516_write_reg
(
base
,
(
lcycles
<<
4
)
|
hcycles
);
}
...
...
softpll/hw/softpll_regs.h
View file @
f0953590
This diff is collapsed.
Click to expand it.
softpll/softpll_ng.c
View file @
f0953590
...
...
@@ -75,6 +75,21 @@ struct softpll_state {
struct
spll_ptracker_state
ptrackers
[
MAX_PTRACKERS
];
};
static
const
struct
stringlist_entry
seq_states
[]
=
{
{
SEQ_START_EXT
,
"start-ext"
},
{
SEQ_WAIT_EXT
,
"wait-ext"
},
{
SEQ_START_HELPER
,
"start-helper"
},
{
SEQ_WAIT_HELPER
,
"wait-helper"
},
{
SEQ_START_MAIN
,
"start-main"
},
{
SEQ_WAIT_MAIN
,
"wait-main"
},
{
SEQ_DISABLED
,
"disabled"
},
{
SEQ_READY
,
"ready"
},
{
SEQ_CLEAR_DACS
,
"clear-dacs"
},
{
SEQ_WAIT_CLEAR_DACS
,
"wait-clear-dacs"
},
{
0
,
NULL
}
};
static
volatile
struct
softpll_state
softpll
;
static
volatile
int
ptracker_mask
=
0
;
...
...
@@ -153,8 +168,10 @@ static inline void sequencing_fsm(struct softpll_state *s, int tag_value, int ta
/* State "Wait until we are locked to external 10MHz clock" */
case
SEQ_WAIT_EXT
:
{
if
(
external_locked
(
&
s
->
ext
))
s
->
seq_state
=
SEQ_START_HELPER
;
if
(
external_locked
(
&
s
->
ext
))
{
start_ptrackers
(
s
);
s
->
seq_state
=
SEQ_READY
;
}
break
;
}
...
...
@@ -200,16 +217,13 @@ static inline void sequencing_fsm(struct softpll_state *s, int tag_value, int ta
case
SEQ_READY
:
{
if
(
!
s
->
helper
.
ld
.
locked
)
{
if
(
s
->
mode
==
SPLL_MODE_GRAND_MASTER
&&
!
external_locked
(
&
s
->
ext
))
{
s
->
delock_count
++
;
s
->
seq_state
=
SEQ_CLEAR_DACS
;
}
else
if
(
s
->
mode
==
SPLL_MODE_GRAND_MASTER
&&
!
external_locked
(
&
s
->
ext
))
{
}
else
if
(
!
s
->
helper
.
ld
.
locked
)
{
s
->
delock_count
++
;
s
->
seq_state
=
SEQ_START_EXT
;
}
else
if
(
s
->
mode
==
SPLL_MODE_SLAVE
&&
!
s
->
mpll
.
ld
.
locked
)
{
s
->
seq_state
=
SEQ_CLEAR_DACS
;
}
else
if
(
s
->
mode
==
SPLL_MODE_SLAVE
&&
!
s
->
mpll
.
ld
.
locked
)
{
s
->
delock_count
++
;
s
->
seq_state
=
SEQ_CLEAR_DACS
;
}
...
...
@@ -221,47 +235,22 @@ static inline void sequencing_fsm(struct softpll_state *s, int tag_value, int ta
static
inline
void
update_loops
(
struct
softpll_state
*
s
,
int
tag_value
,
int
tag_source
)
{
if
(
s
->
mode
==
SPLL_MODE_GRAND_MASTER
)
{
switch
(
s
->
seq_state
)
{
case
SEQ_WAIT_EXT
:
case
SEQ_START_HELPER
:
case
SEQ_WAIT_HELPER
:
case
SEQ_START_MAIN
:
case
SEQ_WAIT_MAIN
:
case
SEQ_READY
:
external_update
(
&
s
->
ext
,
tag_value
,
tag_source
);
break
;
}
}
switch
(
s
->
seq_state
)
{
case
SEQ_WAIT_HELPER
:
case
SEQ_START_MAIN
:
case
SEQ_WAIT_MAIN
:
case
SEQ_READY
:
helper_update
(
&
s
->
helper
,
tag_value
,
tag_source
);
break
;
}
if
(
s
->
seq_state
==
SEQ_WAIT_MAIN
)
if
(
s
->
helper
.
ld
.
locked
)
{
mpll_update
(
&
s
->
mpll
,
tag_value
,
tag_source
);
}
if
(
s
->
seq_state
==
SEQ_READY
)
{
if
(
s
->
mode
==
SPLL_MODE_SLAVE
)
{
if
(
s
->
seq_state
==
SEQ_READY
)
{
if
(
s
->
mode
==
SPLL_MODE_SLAVE
)
{
int
i
;
mpll_update
(
&
s
->
mpll
,
tag_value
,
tag_source
);
for
(
i
=
0
;
i
<
spll_n_chan_out
-
1
;
i
++
)
mpll_update
(
&
s
->
aux
[
i
].
pll
.
dmtd
,
tag_value
,
tag_source
);
// fixme: bb hooks here
mpll_update
(
&
s
->
aux
[
i
].
pll
.
dmtd
,
tag_value
,
tag_source
);
}
update_ptrackers
(
s
,
tag_value
,
tag_source
);
}
}
}
void
_irq_entry
()
...
...
@@ -301,7 +290,6 @@ void spll_init(int mode, int slave_ref_channel, int align_pps)
spll_n_chan_ref
=
SPLL_CSR_N_REF_R
(
csr
);
spll_n_chan_out
=
SPLL_CSR_N_OUT_R
(
csr
);
s
->
mode
=
mode
;
s
->
delock_count
=
0
;
...
...
@@ -318,16 +306,6 @@ void spll_init(int mode, int slave_ref_channel, int align_pps)
PPSG
->
ESCR
=
0
;
PPSG
->
CR
=
PPSG_CR_CNT_EN
|
PPSG_CR_CNT_RST
|
PPSG_CR_PWIDTH_W
(
PPS_WIDTH
);
if
(
mode
==
SPLL_MODE_GRAND_MASTER
)
{
if
(
SPLL
->
ECCR
&
SPLL_ECCR_EXT_SUPPORTED
)
external_init
(
&
s
->
ext
,
spll_n_chan_ref
+
spll_n_chan_out
,
align_pps
);
else
{
TRACE_DEV
(
"softpll: attempting to enable GM mode on non-GM hardware.
\n
"
);
return
;
}
}
if
(
mode
==
SPLL_MODE_DISABLED
)
s
->
seq_state
=
SEQ_DISABLED
;
else
...
...
@@ -354,6 +332,17 @@ void spll_init(int mode, int slave_ref_channel, int align_pps)
for
(
i
=
0
;
i
<
spll_n_chan_ref
;
i
++
)
ptracker_init
(
&
s
->
ptrackers
[
i
],
i
,
PTRACKER_AVERAGE_SAMPLES
);
if
(
mode
==
SPLL_MODE_GRAND_MASTER
)
{
if
(
SPLL
->
ECCR
&
SPLL_ECCR_EXT_SUPPORTED
)
{
s
->
ext
.
helper
=
&
s
->
helper
;
s
->
ext
.
main
=
&
s
->
mpll
;
external_init
(
&
s
->
ext
,
spll_n_chan_ref
+
spll_n_chan_out
,
align_pps
);
}
else
{
TRACE_DEV
(
"softpll: attempting to enable GM mode on non-GM hardware.
\n
"
);
return
;
}
}
TRACE_DEV
(
"softpll: mode %s, %d ref channels, %d out channels
\n
"
,
modes
[
mode
],
spll_n_chan_ref
,
spll_n_chan_out
);
...
...
@@ -400,6 +389,11 @@ void spll_stop_channel(int channel)
mpll_stop
(
&
s
->
aux
[
channel
-
1
].
pll
.
dmtd
);
}
int
spll_ext_locked
()
{
return
external_locked
(
(
struct
spll_external_state
*
)
&
softpll
.
ext
);
}
int
spll_check_lock
(
int
channel
)
{
if
(
!
channel
)
...
...
@@ -409,29 +403,6 @@ int spll_check_lock(int channel)
&&
softpll
.
aux
[
channel
-
1
].
pll
.
dmtd
.
ld
.
locked
;
}
#ifdef CONFIG_PPSI
/* use __div64_32 from ppsi library to save libgcc memory */
static
int32_t
from_picos
(
int32_t
ps
)
{
extern
uint32_t
__div64_32
(
uint64_t
*
n
,
uint32_t
base
);
uint64_t
ups
=
ps
;
if
(
ps
>=
0
)
{
ups
*=
1
<<
HPLL_N
;
__div64_32
(
&
ups
,
CLOCK_PERIOD_PICOSECONDS
);
return
ups
;
}
ups
=
-
ps
*
(
1
<<
HPLL_N
);
__div64_32
(
&
ups
,
CLOCK_PERIOD_PICOSECONDS
);
return
-
ups
;
}
#else
/* previous implementation: ptp-noposix has no __div64_32 available */
static
int32_t
from_picos
(
int32_t
ps
)
{
return
(
int32_t
)
((
int64_t
)
ps
*
(
int64_t
)
(
1
<<
HPLL_N
)
/
(
int64_t
)
CLOCK_PERIOD_PICOSECONDS
);
}
#endif
static
int32_t
to_picos
(
int32_t
units
)
{
return
(
int32_t
)
(((
int64_t
)
units
*
...
...
@@ -443,8 +414,7 @@ static void set_phase_shift(int channel, int32_t value_picoseconds)
{
struct
spll_main_state
*
st
=
(
struct
spll_main_state
*
)
(
!
channel
?
&
softpll
.
mpll
:
&
softpll
.
aux
[
channel
-
1
].
pll
.
dmtd
);
int
div
=
(
DIVIDE_DMTD_CLOCKS_BY_2
?
2
:
1
);
mpll_set_phase_shift
(
st
,
from_picos
(
value_picoseconds
)
/
div
);
mpll_set_phase_shift
(
st
,
value_picoseconds
);
softpll
.
mpll_shift_ps
=
value_picoseconds
;
}
...
...
@@ -502,15 +472,12 @@ void spll_get_num_channels(int *n_ref, int *n_out)
void
spll_show_stats
()
{
if
(
softpll
.
mode
>
0
)
TRACE_DEV
(
"softpll: irq_count %d sequencer_state %d mode %d "
"alignment_state %d HL%d EL%d ML%d HY=%d "
"MY=%d EY=%d DelCnt=%d extsc=%d
\n
"
,
irq_count
,
softpll
.
seq_state
,
softpll
.
mode
,
softpll
.
ext
.
realign_state
,
softpll
.
helper
.
ld
.
locked
,
softpll
.
ext
.
ld
.
locked
,
softpll
.
mpll
.
ld
.
locked
,
softpll
.
helper
.
pi
.
y
,
softpll
.
mpll
.
pi
.
y
,
softpll
.
ext
.
pi
.
y
,
softpll
.
delock_count
,
softpll
.
ext
.
sample_n
);
TRACE_DEV
(
"softpll: irqs %d seq %s mode %d "
"alignment_state %d HL%d ML%d HY=%d MY=%d DelCnt=%d
\n
"
,
irq_count
,
stringlist_lookup
(
seq_states
,
softpll
.
seq_state
),
softpll
.
mode
,
softpll
.
ext
.
align_state
,
softpll
.
helper
.
ld
.
locked
,
softpll
.
mpll
.
ld
.
locked
,
softpll
.
helper
.
pi
.
y
,
softpll
.
mpll
.
pi
.
y
,
softpll
.
delock_count
);
}
int
spll_shifter_busy
(
int
channel
)
...
...
@@ -666,3 +633,33 @@ void spll_set_dac(int index, int value)
softpll
.
aux
[
index
-
1
].
pll
.
dmtd
.
pi
.
y
=
value
;
}
}
void
spll_update
()
{
switch
(
softpll
.
mode
)
{
case
SPLL_MODE_GRAND_MASTER
:
external_align_fsm
(
&
softpll
.
ext
);
break
;
}
spll_update_aux_clocks
();
}
int
spll_measure_frequency
(
int
osc
)
{
volatile
uint32_t
*
reg
;
switch
(
osc
)
{
case
SPLL_OSC_REF
:
reg
=
&
SPLL
->
F_REF
;
break
;
case
SPLL_OSC_DMTD
:
reg
=
&
SPLL
->
F_DMTD
;
break
;
case
SPLL_OSC_EXT
:
reg
=
&
SPLL
->
F_EXT
;
break
;
}
timer_delay_ms
(
2000
);
return
(
*
reg
)
&
(
0xfffffff
);
}
softpll/softpll_ng.h
View file @
f0953590
...
...
@@ -39,6 +39,10 @@
#define SPLL_PD_DDMTD 0
#define SPLL_PD_BANGBANG 1
/* Channels for spll_measure_frequency() */
#define SPLL_OSC_REF 0
#define SPLL_OSC_DMTD 1
#define SPLL_OSC_EXT 2
/* Note on channel naming:
- ref_channel means a PHY recovered clock input. There can be one (as in WR core) or more (WR switch).
...
...
@@ -101,9 +105,10 @@ void spll_enable_ptracker(int ref_channel, int enable);
/* Reads tracked phase shift value for given reference channel */
int
spll_read_ptracker
(
int
ref_channel
,
int32_t
*
phase_ps
,
int
*
enabled
);
/* Calls aux clock handling state machine. Must be called regularly (although it is not time-critical)
in the main loop of the program if aux clocks are used in the design. */
int
spll_update_aux_clocks
();
/* Calls non-realtime update state machine. Must be called regularly (although
* it is not time-critical) in the main loop of the program if aux clocks or
* external reference are used in the design. */
void
spll_update
();
/* Returns the status of given aux clock output (SPLL_AUX_) */
int
spll_get_aux_status
(
int
out_channel
);
...
...
@@ -122,5 +127,7 @@ void spll_set_dac(int out_channel, int value);
/* Returns current DAC sample value for output (out_channel) */
int
spll_get_dac
(
int
out_channel
);
int
spll_measure_frequency
(
int
osc
);
#endif // __SOFTPLL_NG_H
softpll/spll_common.c
View file @
f0953590
...
...
@@ -125,6 +125,7 @@ Channels (spll_n_chan_ref ... spll_n_chan_out + spll_n_chan_ref-1) are the outpu
void
spll_enable_tagger
(
int
channel
,
int
enable
)
{
TRACE
(
"EnableTagger %d %d
\n
"
,
channel
,
enable
);
if
(
channel
>=
spll_n_chan_ref
)
{
/* Output channel? */
if
(
enable
)
SPLL
->
OCER
|=
1
<<
(
channel
-
spll_n_chan_ref
);
...
...
@@ -137,7 +138,7 @@ void spll_enable_tagger(int channel, int enable)
SPLL
->
RCER
&=
~
(
1
<<
channel
);
}
//
TRACE("%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
);
}
void
biquad_init
(
spll_biquad_t
*
bq
,
const
int
*
coefs
,
int
shift
)
...
...
@@ -167,3 +168,13 @@ int biquad_update(spll_biquad_t *bq, int x)
return
y
;
}
const
char
*
stringlist_lookup
(
const
struct
stringlist_entry
*
slist
,
int
id
)
{
int
i
;
for
(
i
=
0
;
slist
[
i
].
str
;
i
++
)
{
if
(
slist
[
i
].
id
==
id
)
return
slist
[
i
].
str
;
}
return
"<unknown>"
;
}
softpll/spll_common.h
View file @
f0953590
...
...
@@ -66,6 +66,21 @@ typedef struct {
int
yd
[
2
],
xd
[
2
];
/* I/O delay lines */
}
spll_biquad_t
;
/* long-term-average filter */
typedef
struct
{
int
acc
;
int
n
;
int
window
;
int
pos
;
int
size
;
int
log
[
16
];
}
spll_lta_t
;
struct
stringlist_entry
{
int
id
;
const
char
*
str
;
};
/* initializes the PI controller state. Currently almost a stub. */
void
pi_init
(
spll_pi_t
*
pi
);
...
...
@@ -83,4 +98,6 @@ void spll_enable_tagger(int channel, int enable);
void
biquad_init
(
spll_biquad_t
*
bq
,
const
int
*
coefs
,
int
shift
);
int
biquad_update
(
spll_biquad_t
*
bq
,
int
x
);
const
char
*
stringlist_lookup
(
const
struct
stringlist_entry
*
slist
,
int
id
);
#endif // __SPLL_COMMON_H
softpll/spll_external.c
View file @
f0953590
...
...
@@ -13,152 +13,171 @@
#include "spll_external.h"
#include "spll_debug.h"
#define BB_ERROR_BITS 16
#include "trace.h"
#include "irq.h"
#define ALIGN_STATE_EXT_OFF 0
#define ALIGN_STATE_START 1
#define ALIGN_STATE_INIT_CSYNC 2
#define ALIGN_STATE_WAIT_CSYNC 3
#define ALIGN_STATE_START_ALIGNMENT 7
#define ALIGN_STATE_WAIT_SAMPLE 4
#define ALIGN_STATE_COMPENSATE_DELAY 5
#define ALIGN_STATE_LOCKED 6
#define ALIGN_STATE_START_MAIN 8
#define ALIGN_SAMPLE_PERIOD 100000
#define ALIGN_TARGET 0
#define EXT_PERIOD_NS 100
#define EXT_FREQ_HZ 10000000
#define EXT_PPS_LATENCY_PS 30000 // fixme: make configurable
void
external_init
(
volatile
struct
spll_external_state
*
s
,
int
ext_ref
,
int
realign_clocks
)
{
int
idx
=
spll_n_chan_ref
+
spll_n_chan_out
;
s
->
pi
.
y_min
=
5
;
s
->
pi
.
y_max
=
(
1
<<
DAC_BITS
)
-
5
;
s
->
pi
.
kp
=
(
int
)(
300
);
s
->
pi
.
ki
=
(
int
)(
1
);
s
->
pi
.
anti_windup
=
1
;
s
->
pi
.
bias
=
32768
;
/* Phase branch lock detection */
s
->
ld
.
threshold
=
400
;
s
->
ld
.
lock_samples
=
10000
;
s
->
ld
.
delock_samples
=
9990
;
s
->
ref_src
=
ext_ref
;
s
->
ph_err_cur
=
0
;
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
((
spll_pi_t
*
)
&
s
->
pi
);
ld_init
((
spll_lock_det_t
*
)
&
s
->
ld
);
lowpass_init
((
spll_lowpass_t
*
)
&
s
->
lp_short
,
4000
);
lowpass_init
((
spll_lowpass_t
*
)
&
s
->
lp_long
,
300
);
}
static
inline
void
realign_fsm
(
struct
spll_external_state
*
s
)
{
switch
(
s
->
realign_state
)
{
case
REALIGN_STAGE1
:
SPLL
->
ECCR
|=
SPLL_ECCR_ALIGN_EN
;
helper_init
(
s
->
helper
,
idx
);
mpll_init
(
s
->
main
,
idx
,
spll_n_chan_ref
);
s
->
realign_state
=
REALIGN_STAGE1_WAIT
;
s
->
realign_timer
=
timer_get_tics
()
+
2
*
TICS_PER_SECOND
;
break
;
s
->
align_state
=
ALIGN_STATE_EXT_OFF
;
s
->
enabled
=
0
;
}
case
REALIGN_STAGE1_WAIT
:
void
external_start
(
struct
spll_external_state
*
s
)
{
helper_start
(
s
->
helper
);
if
(
SPLL
->
ECCR
&
SPLL_ECCR_ALIGN_DONE
)
s
->
realign_state
=
REALIGN_STAGE2
;
else
if
(
time_after
(
timer_get_tics
(),
s
->
realign_timer
))
{
SPLL
->
ECCR
&=
~
SPLL_ECCR_ALIGN_EN
;
s
->
realign_state
=
REALIGN_PPS_INVALID
;
}
break
;
SPLL
->
ECCR
=
SPLL_ECCR_EXT_EN
;
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
->
align_state
=
ALIGN_STATE_START
;
s
->
enabled
=
1
;
spll_debug
(
DBG_EVENT
|
DBG_EXT
,
DBG_EVT_START
,
1
);
}
s
->
realign_state
=
REALIGN_STAGE2_WAIT
;
s
->
realign_timer
=
timer_get_tics
()
+
2
*
TICS_PER_SECOND
;
int
external_locked
(
struct
spll_external_state
*
s
)
{
if
(
!
s
->
helper
->
ld
.
locked
||
!
s
->
main
->
ld
.
locked
)
return
0
;
switch
(
s
->
align_state
)
{
case
ALIGN_STATE_EXT_OFF
:
case
ALIGN_STATE_START
:
case
ALIGN_STATE_START_MAIN
:
case
ALIGN_STATE_INIT_CSYNC
:
case
ALIGN_STATE_WAIT_CSYNC
:
return
0
;
default:
return
1
;
}
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
(
time_after
(
timer_get_tics
(),
s
->
realign_timer
))
{
PPSG
->
ESCR
=
0
;
s
->
realign_state
=
REALIGN_PPS_INVALID
;
static
int
align_sample
(
int
channel
,
int
*
v
)
{
int
mask
=
(
1
<<
channel
);
if
(
SPLL
->
AL_CR
&
mask
)
{
SPLL
->
AL_CR
=
mask
;
// ack
int
ci
=
SPLL
->
AL_CIN
;
if
(
ci
>
100
&&
ci
<
(
EXT_FREQ_HZ
-
100
)
)
{
// give some metastability margin, when the counter transitions from EXT_FREQ_HZ-1 to 0
*
v
=
ci
*
EXT_PERIOD_NS
;
return
1
;
}
break
;
case
REALIGN_PPS_INVALID
:
case
REALIGN_DISABLED
:
case
REALIGN_DONE
:
return
;
}
return
0
;
// sample not valid
}
int
external_update
(
struct
spll_external_state
*
s
,
int
tag
,
int
source
)
void
external_align_fsm
(
struct
spll_external_state
*
s
)
{
int
err
,
y
,
y2
,
ylt
;
if
(
source
==
s
->
ref_src
)
{
int
wrap
=
tag
&
(
1
<<
BB_ERROR_BITS
)
?
1
:
0
;
int
v
;
switch
(
s
->
align_state
)
{
realign_fsm
(
s
);
tag
&=
((
1
<<
BB_ERROR_BITS
)
-
1
);
case
ALIGN_STATE_EXT_OFF
:
break
;
// mprintf("err %d\n", tag);
if
(
wrap
)
{
if
(
tag
>
s
->
ph_raw_d0
)
s
->
ph_err_offset
-=
(
1
<<
BB_ERROR_BITS
);
else
if
(
tag
<=
s
->
ph_raw_d0
)
s
->
ph_err_offset
+=
(
1
<<
BB_ERROR_BITS
)
;
case
ALIGN_STATE_START
:
if
(
s
->
helper
->
ld
.
locked
)
{
disable_irq
();
mpll_start
(
s
->
main
);
enable_irq
();
s
->
align_state
=
ALIGN_STATE_START_MAIN
;
}
break
;
s
->
ph_raw_d0
=
tag
;
err
=
(
tag
+
s
->
ph_err_offset
)
-
s
->
ph_err_d0
;
s
->
ph_err_d0
=
(
tag
+
s
->
ph_err_offset
);
y
=
pi_update
(
&
s
->
pi
,
err
);
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
;
case
ALIGN_STATE_START_MAIN
:
SPLL
->
AL_CR
=
2
;
if
(
s
->
helper
->
ld
.
locked
&&
s
->
main
->
ld
.
locked
)
{
PPSG
->
CR
=
PPSG_CR_CNT_EN
|
PPSG_CR_PWIDTH_W
(
10
);
PPSG
->
ADJ_NSEC
=
3
;
PPSG
->
ESCR
=
PPSG_ESCR_SYNC
;
s
->
align_state
=
ALIGN_STATE_INIT_CSYNC
;
TRACE_DEV
(
"EXT: DMTD locked.
\n
"
);
}
break
;
SPLL
->
DAC_MAIN
=
y2
&
0xffff
;
spll_debug
(
DBG_ERR
|
DBG_EXT
,
ylt
,
0
);
spll_debug
(
DBG_SAMPLE_ID
|
DBG_EXT
,
s
->
sample_n
++
,
0
);
spll_debug
(
DBG_Y
|
DBG_EXT
,
y2
,
1
);
case
ALIGN_STATE_INIT_CSYNC
:
if
(
PPSG
->
ESCR
&
PPSG_ESCR_SYNC
)
{
PPSG
->
ESCR
=
PPSG_ESCR_PPS_VALID
;
// enable PPS output (even though it's not aligned yet)
s
->
align_timer
=
timer_get_tics
()
+
2
*
TICS_PER_SECOND
;
s
->
align_state
=
ALIGN_STATE_WAIT_CSYNC
;
}
break
;
if
(
ld_update
(
&
s
->
ld
,
y2
-
ylt
))
return
SPLL_LOCKED
;
case
ALIGN_STATE_WAIT_CSYNC
:
if
(
timer_get_tics
()
>=
s
->
align_timer
)
{
s
->
align_state
=
ALIGN_STATE_START_ALIGNMENT
;
s
->
align_shift
=
0
;
TRACE_DEV
(
"EXT: CSync complete.
\n
"
);
}
return
SPLL_LOCKING
;
}
break
;
void
external_start
(
struct
spll_external_state
*
s
)
{
case
ALIGN_STATE_START_ALIGNMENT
:
if
(
align_sample
(
1
,
&
v
))
{
v
%=
ALIGN_SAMPLE_PERIOD
;
if
(
v
==
0
||
v
>=
ALIGN_SAMPLE_PERIOD
/
2
)
{
s
->
align_target
=
EXT_PERIOD_NS
;
s
->
align_step
=
-
100
;
}
else
if
(
s
>
0
)
{
s
->
align_target
=
0
;
s
->
align_step
=
100
;
}
SPLL
->
ECCR
=
0
;
TRACE_DEV
(
"EXT: Align target %d, step %d.
\n
"
,
s
->
align_target
,
s
->
align_step
);
s
->
align_state
=
ALIGN_STATE_WAIT_SAMPLE
;
}
break
;
s
->
sample_n
=
0
;
s
->
realign_state
=
(
s
->
realign_clocks
?
REALIGN_STAGE1
:
REALIGN_DISABLED
);
case
ALIGN_STATE_WAIT_SAMPLE
:
if
(
!
mpll_shifter_busy
(
s
->
main
)
&&
align_sample
(
1
,
&
v
))
{
v
%=
ALIGN_SAMPLE_PERIOD
;
if
(
v
!=
s
->
align_target
)
{
s
->
align_shift
+=
s
->
align_step
;
mpll_set_phase_shift
(
s
->
main
,
s
->
align_shift
);
}
else
if
(
v
==
s
->
align_target
)
{
s
->
align_shift
+=
EXT_PPS_LATENCY_PS
;
mpll_set_phase_shift
(
s
->
main
,
s
->
align_shift
);
s
->
align_state
=
ALIGN_STATE_COMPENSATE_DELAY
;
}
}
break
;
SPLL
->
ECCR
=
SPLL_ECCR_EXT_EN
;
case
ALIGN_STATE_COMPENSATE_DELAY
:
if
(
!
mpll_shifter_busy
(
s
->
main
))
{
TRACE_DEV
(
"EXT: Align done.
\n
"
);
s
->
align_state
=
ALIGN_STATE_LOCKED
;
}
break
;
spll_debug
(
DBG_EVENT
|
DBG_EXT
,
DBG_EVT_START
,
1
);
}
case
ALIGN_STATE_LOCKED
:
if
(
!
external_locked
(
s
))
{
s
->
align_state
=
ALIGN_STATE_START
;
}
break
;
int
external_locked
(
struct
spll_external_state
*
s
)
{
return
(
s
->
ld
.
locked
&&
(
s
->
realign_clocks
?
s
->
realign_state
==
REALIGN_DONE
:
1
));
default:
break
;
}
}
softpll/spll_external.h
View file @
f0953590
...
...
@@ -14,69 +14,29 @@
#define __SPLL_EXTERNAL_H
#include "spll_common.h"
#include "spll_helper.h"
#include "spll_main.h"
/* 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
struct
spll_external_state
{
struct
spll_helper_state
*
helper
;
struct
spll_main_state
*
main
;
/* Realignment done */
#define REALIGN_DONE 7
int
enabled
;
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
;
int
align_state
;
int
align_timer
;
int
align_target
;
int
align_step
;
int
align_shift
;
};
void
external_init
(
volatile
struct
spll_external_state
*
s
,
int
ext_ref
,
int
realign_clocks
);
int
external_update
(
struct
spll_external_state
*
s
,
int
tag
,
int
source
);
void
external_start
(
struct
spll_external_state
*
s
);
int
external_locked
(
struct
spll_external_state
*
s
);
void
external_align_fsm
(
struct
spll_external_state
*
s
);
#endif // __SPLL_EXTERNAL_H
softpll/spll_helper.c
View file @
f0953590
...
...
@@ -65,7 +65,6 @@ int helper_update(struct spll_helper_state *s, int tag,
err
=
HELPER_ERROR_CLAMP
;
}
// err = biquad_update(&s->precomp, err);
if
((
tag
+
s
->
p_adder
)
>
HELPER_TAG_WRAPAROUND
&&
s
->
p_setpoint
>
HELPER_TAG_WRAPAROUND
)
{
...
...
@@ -108,3 +107,15 @@ void helper_start(struct spll_helper_state *s)
spll_enable_tagger
(
s
->
ref_src
,
1
);
spll_debug
(
DBG_EVENT
|
DBG_HELPER
,
DBG_EVT_START
,
1
);
}
void
helper_switch_reference
(
struct
spll_helper_state
*
s
,
int
new_ref
)
{
#if 0
disable_irq();
s->ref-src = 1;
s->tag_d0 = -1;
s->p-addr = 0;
enable_irq();
spll_enable_tagger(s->ref_src, 1);
#endif
}
softpll/spll_helper.h
View file @
f0953590
...
...
@@ -41,5 +41,6 @@ int helper_update(struct spll_helper_state *s, int tag,
int
source
);
void
helper_start
(
struct
spll_helper_state
*
s
);
void
helper_switch_reference
(
struct
spll_helper_state
*
s
,
int
new_ref
);
#endif // __SPLL_HELPER_H
softpll/spll_main.c
View file @
f0953590
...
...
@@ -27,10 +27,10 @@ void mpll_init(struct spll_main_state *s, int id_ref,
s
->
pi
.
y_min
=
5
;
s
->
pi
.
y_max
=
65530
;
s
->
pi
.
anti_windup
=
1
;
s
->
pi
.
bias
=
65
000
;
s
->
pi
.
bias
=
30
000
;
#if defined(CONFIG_WR_SWITCH)
s
->
pi
.
kp
=
1
5
00
;
// / 2;
s
->
pi
.
ki
=
7
;
// / 2;
s
->
pi
.
kp
=
1
1
00
;
// / 2;
s
->
pi
.
ki
=
30
;
// / 2;
#elif defined(CONFIG_WR_NODE)
s
->
pi
.
kp
=
1100
;
// / 2;
s
->
pi
.
ki
=
30
;
// / 2;
...
...
@@ -47,12 +47,16 @@ void mpll_init(struct spll_main_state *s, int id_ref,
s
->
id_out
=
id_out
;
s
->
dac_index
=
id_out
-
spll_n_chan_ref
;
TRACE
(
"ref %d out %d idx %x"
,
s
->
id_ref
,
s
->
id_out
,
s
->
dac_index
);
pi_init
((
spll_pi_t
*
)
&
s
->
pi
);
ld_init
((
spll_lock_det_t
*
)
&
s
->
ld
);
}
void
mpll_start
(
struct
spll_main_state
*
s
)
{
TRACE
(
"MPLL_Start [dac %d]
\n
"
,
s
->
dac_index
);
s
->
adder_ref
=
s
->
adder_out
=
0
;
s
->
tag_ref
=
-
1
;
s
->
tag_out
=
-
1
;
...
...
@@ -83,63 +87,28 @@ int mpll_update(struct spll_main_state *s, int tag, int source)
{
int
err
,
y
;
#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
)
{
if
(
s
->
tag_ref_d
>=
0
&&
s
->
tag_ref_d
>
s
->
tag_ref
)
s
->
adder_ref
+=
(
1
<<
TAG_BITS
);
if
(
s
->
tag_ref
>=
0
&&
s
->
tag_out
>=
0
)
{
s
->
tag_ref_d
=
s
->
tag_ref
;
}
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
)
if
(
s
->
tag_out
>=
0
)
{
if
(
s
->
tag_out_d
>=
0
&&
s
->
tag_out_d
>
s
->
tag_out
)
s
->
adder_out
+=
(
1
<<
TAG_BITS
);
s
->
tag_ref_d
=
s
->
tag_ref
;
s
->
tag_out_d
=
s
->
tag_out
;
}
if
(
s
->
tag_ref
>=
0
&&
s
->
tag_out
>=
0
)
{
err
=
s
->
adder_ref
+
s
->
tag_ref
-
s
->
adder_out
-
s
->
tag_out
;
#ifndef WITH_SEQUENCING
...
...
@@ -192,16 +161,39 @@ int mpll_update(struct spll_main_state *s, int tag, int source)
}
if
(
ld_update
((
spll_lock_det_t
*
)
&
s
->
ld
,
err
))
return
SPLL_LOCKED
;
}
return
SPLL_LOCKING
;
}
#ifdef CONFIG_PPSI
/* use __div64_32 from ppsi library to save libgcc memory */
static
int32_t
from_picos
(
int32_t
ps
)
{
extern
uint32_t
__div64_32
(
uint64_t
*
n
,
uint32_t
base
);
uint64_t
ups
=
ps
;
if
(
ps
>=
0
)
{
ups
*=
1
<<
HPLL_N
;
__div64_32
(
&
ups
,
CLOCK_PERIOD_PICOSECONDS
);
return
ups
;
}
ups
=
-
ps
*
(
1
<<
HPLL_N
);
__div64_32
(
&
ups
,
CLOCK_PERIOD_PICOSECONDS
);
return
-
ups
;
}
#else
/* previous implementation: ptp-noposix has no __div64_32 available */
static
int32_t
from_picos
(
int32_t
ps
)
{
return
(
int32_t
)
((
int64_t
)
ps
*
(
int64_t
)
(
1
<<
HPLL_N
)
/
(
int64_t
)
CLOCK_PERIOD_PICOSECONDS
);
}
#endif
int
mpll_set_phase_shift
(
struct
spll_main_state
*
s
,
int
desired_shift
)
int
desired_shift
_ps
)
{
s
->
phase_shift_target
=
desired_shift
;
int
div
=
(
DIVIDE_DMTD_CLOCKS_BY_2
?
2
:
1
);
s
->
phase_shift_target
=
from_picos
(
desired_shift_ps
)
/
div
;
return
0
;
}
...
...
softpll/spll_main.h
View file @
f0953590
...
...
@@ -47,7 +47,7 @@ void mpll_start(struct spll_main_state *s);
int
mpll_update
(
struct
spll_main_state
*
s
,
int
tag
,
int
source
);
int
mpll_set_phase_shift
(
struct
spll_main_state
*
s
,
int
desired_shift
);
int
desired_shift
_ps
);
int
mpll_shifter_busy
(
struct
spll_main_state
*
s
);
...
...
wrc_main.c
View file @
f0953590
...
...
@@ -269,7 +269,7 @@ int main(void)
ui_update
();
wrc_ptp_update
();
spll_update
_aux_clocks
();
spll_update
();
check_stack
();
}
}
wrc_ptp_noposix.c
View file @
f0953590
...
...
@@ -126,6 +126,7 @@ int wrc_ptp_set_mode(int mode)
shw_pps_gen_enable_output
(
0
);
while
(
!
spll_check_lock
(
0
)
&&
lock_timeout
)
{
spll_update
();
timer_delay_ms
(
1000
);
mprintf
(
"."
);
if
(
time_after
(
timer_get_tics
(),
start_tics
+
lock_timeout
))
{
...
...
wrs_main.c
View file @
f0953590
...
...
@@ -8,13 +8,56 @@
const
char
*
build_revision
;
const
char
*
build_date
;
static
int
calc_apr
(
int
meas_min
,
int
meas_max
,
int
f_center
)
{
// apr_min is in PPM
int64_t
delta_low
=
meas_min
-
f_center
;
int64_t
delta_hi
=
meas_max
-
f_center
;
if
(
delta_low
>=
0
)
return
-
1
;
if
(
delta_hi
<=
0
)
return
-
1
;
int
ppm_lo
=
-
(
int64_t
)
delta_low
*
1000000LL
/
f_center
;
int
ppm_hi
=
(
int64_t
)
delta_hi
*
1000000LL
/
f_center
;
return
ppm_lo
<
ppm_hi
?
ppm_lo
:
ppm_hi
;
}
extern
void
disable_irq
();
static
void
check_vco_frequencies
()
{
disable_irq
();
int
f_min
,
f_max
;
TRACE
(
"SoftPLL VCO Frequency/APR test:
\n
"
);
spll_set_dac
(
-
1
,
0
);
f_min
=
spll_measure_frequency
(
SPLL_OSC_DMTD
);
spll_set_dac
(
-
1
,
65535
);
f_max
=
spll_measure_frequency
(
SPLL_OSC_DMTD
);
TRACE
(
"DMTD VCO: Low=%d Hz Hi=%d Hz, APR = %d ppm.
\n
"
,
f_min
,
f_max
,
calc_apr
(
f_min
,
f_max
,
62500000
));
spll_set_dac
(
0
,
0
);
f_min
=
spll_measure_frequency
(
SPLL_OSC_REF
);
spll_set_dac
(
0
,
65535
);
f_max
=
spll_measure_frequency
(
SPLL_OSC_REF
);
TRACE
(
"REF VCO: Low=%d Hz Hi=%d Hz, APR = %d ppm.
\n
"
,
f_min
,
f_max
,
calc_apr
(
f_min
,
f_max
,
62500000
));
f_min
=
spll_measure_frequency
(
SPLL_OSC_EXT
);
TRACE
(
"EXT clock: Freq=%d Hz
\n
"
,
f_min
);
}
int
main
(
void
)
{
uint32_t
start_tics
=
timer_get_tics
();
uart_init_hw
();
TRACE
(
"WR Switch Real Time Subsystem (c) CERN 2011 - 201
3
\n
"
);
TRACE
(
"WR Switch Real Time Subsystem (c) CERN 2011 - 201
4
\n
"
);
TRACE
(
"Revision: %s, built %s.
\n
"
,
build_revision
,
build_date
);
TRACE
(
"--"
);
...
...
@@ -28,12 +71,12 @@ int main(void)
if
(
time_after
(
tics
,
start_tics
+
TICS_PER_SECOND
/
5
))
{
// TRACE("tick!\n");
spll_show_stats
();
start_tics
=
tics
;
}
rts_update
();
rtipc_action
();
spll_update
();
}
return
0
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment