sayma: report TSC phase of SYSREF (TSC LSBs on SYSREF rising edge) in SYSREF sampler

Better visibility, better diagnostics, allows some changing of SYSREF frequency while keeping the same gateware.
pull/1259/head
Sebastien Bourdeauducq 2019-01-29 23:30:01 +08:00
parent 9d0d02a561
commit c591009220
2 changed files with 62 additions and 38 deletions

View File

@ -198,32 +198,75 @@ fn calibrate_sysref_target(rising_average: i32, falling_average: i32) -> Result<
Ok(target)
}
fn sysref_get_sample() -> Result<bool, &'static str> {
fn sysref_get_tsc_phase_raw() -> Result<u8, &'static str> {
if sysref_sh_error() {
return Err("SYSREF failed S/H timing");
}
let ret = unsafe { csr::sysref_sampler::sample_result_read() } != 0;
let ret = unsafe { csr::sysref_sampler::sysref_phase_read() };
Ok(ret)
}
// Note: the code below assumes RTIO/SYSREF frequency ratio is a power of 2
fn sysref_get_tsc_phase() -> Result<i32, &'static str> {
let mask = (hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV - 1) as u8;
Ok((sysref_get_tsc_phase_raw()? & mask) as i32)
}
pub fn test_sysref_frequency() -> Result<(), &'static str> {
info!("testing SYSREF frequency against raw TSC phase bit toggles...");
let mut all_toggles = 0;
let initial_phase = sysref_get_tsc_phase_raw()?;
for _ in 0..20000 {
clock::spin_us(1);
all_toggles |= sysref_get_tsc_phase_raw()? ^ initial_phase;
}
let ratio = (hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV) as u8;
let expected_toggles = 0xff ^ (ratio - 1);
if all_toggles == expected_toggles {
info!(" ...done (0x{:02x})", all_toggles);
Ok(())
} else {
error!(" ...unexpected toggles: got 0x{:02x}, expected 0x{:02x}",
all_toggles, expected_toggles);
Err("unexpected toggles")
}
}
fn sysref_slip_rtio_cycle() {
for _ in 0..hmc7043::FPGA_CLK_DIV {
hmc7043::sysref_slip();
}
}
pub fn test_slip_tsc() -> Result<(), &'static str> {
info!("testing HMC7043 SYSREF slip against TSC phase...");
let initial_phase = sysref_get_tsc_phase()?;
let modulo = (hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV) as i32;
for i in 0..128 {
sysref_slip_rtio_cycle();
let expected_phase = (initial_phase + i + 1) % modulo;
let phase = sysref_get_tsc_phase()?;
if phase != expected_phase {
error!(" ...unexpected TSC phase: got {}, expected {} ", phase, expected_phase);
return Err("HMC7043 SYSREF slip produced unexpected TSC phase");
}
}
info!(" ...done");
Ok(())
}
pub fn sysref_rtio_align() -> Result<(), &'static str> {
info!("aligning SYSREF with RTIO TSC...");
let mut previous_sample = sysref_get_sample()?;
let mut nslips = 0;
loop {
sysref_slip_rtio_cycle();
let sample = sysref_get_sample()?;
if sample && !previous_sample {
if sysref_get_tsc_phase()? == 0 {
info!(" ...done");
return Ok(())
}
previous_sample = sample;
nslips += 1;
if nslips > hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV {
@ -232,27 +275,6 @@ pub fn sysref_rtio_align() -> Result<(), &'static str> {
}
}
pub fn test_sysref_period() -> Result<(), &'static str> {
info!("testing SYSREF period...");
let half_sysref_period = hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV/2;
for _ in 0..32 {
for _ in 0..half_sysref_period {
if !sysref_get_sample()? {
return Err("unexpected SYSREF value during period test");
}
sysref_slip_rtio_cycle();
}
for _ in 0..half_sysref_period {
if sysref_get_sample()? {
return Err("unexpected SYSREF value during period test");
}
sysref_slip_rtio_cycle();
}
}
info!(" ...done");
Ok(())
}
pub fn sysref_auto_rtio_align() -> Result<(), &'static str> {
test_ddmtd_stability(true, 4)?;
test_ddmtd_stability(false, 1)?;
@ -299,8 +321,9 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> {
}
info!(" ...done, delta={}", delta);
test_sysref_frequency()?;
test_slip_tsc()?;
sysref_rtio_align()?;
test_sysref_period()?;
Ok(())
}

View File

@ -155,19 +155,15 @@ class DDMTD(Module, AutoCSR):
# This assumes:
# * coarse RTIO frequency = 16*SYSREF frequency
# * fine RTIO frequency (rtiox) = 2*RTIO frequency
# * JESD and coarse RTIO clocks are the same
# (only reset may differ).
#
# Look at the 4 LSBs of the coarse RTIO timestamp counter
# to determine SYSREF phase.
class SysrefSampler(Module, AutoCSR):
def __init__(self, sysref_pads, coarse_ts):
def __init__(self, sysref_pads, coarse_ts, sysref_phase_bits=8):
self.sh_error = CSRStatus()
self.sh_error_reset = CSRStorage()
self.sample_result = CSRStatus()
# Note: only the lower log2(RTIO frequency / SYSREF frequency) bits are stable
self.sysref_phase = CSRStatus(8)
self.jref = Signal()
@ -206,6 +202,11 @@ class SysrefSampler(Module, AutoCSR):
MultiReg(sh_error, self.sh_error.status)
]
sample = Signal()
self.sync.rtio += If(coarse_ts[:4] == 0, sample.eq(self.jref))
self.specials += MultiReg(sample, self.sample_result.status)
jref_r = Signal()
sysref_phase_rtio = Signal(sysref_phase_bits)
self.sync.rtio += [
jref_r.eq(self.jref),
If(self.jref & ~jref_r, sysref_phase_rtio.eq(coarse_ts))
]
sysref_phase_rtio.attr.add("no_retiming")
self.specials += MultiReg(sysref_phase_rtio, self.sysref_phase.status)