forked from M-Labs/artiq
1
0
Fork 0

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.
This commit is contained in:
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) Ok(target)
} }
fn sysref_get_sample() -> Result<bool, &'static str> { fn sysref_get_tsc_phase_raw() -> Result<u8, &'static str> {
if sysref_sh_error() { if sysref_sh_error() {
return Err("SYSREF failed S/H timing"); 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) 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() { fn sysref_slip_rtio_cycle() {
for _ in 0..hmc7043::FPGA_CLK_DIV { for _ in 0..hmc7043::FPGA_CLK_DIV {
hmc7043::sysref_slip(); 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> { pub fn sysref_rtio_align() -> Result<(), &'static str> {
info!("aligning SYSREF with RTIO TSC..."); info!("aligning SYSREF with RTIO TSC...");
let mut previous_sample = sysref_get_sample()?;
let mut nslips = 0; let mut nslips = 0;
loop { loop {
sysref_slip_rtio_cycle(); sysref_slip_rtio_cycle();
let sample = sysref_get_sample()?; if sysref_get_tsc_phase()? == 0 {
if sample && !previous_sample {
info!(" ...done"); info!(" ...done");
return Ok(()) return Ok(())
} }
previous_sample = sample;
nslips += 1; nslips += 1;
if nslips > hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV { 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> { pub fn sysref_auto_rtio_align() -> Result<(), &'static str> {
test_ddmtd_stability(true, 4)?; test_ddmtd_stability(true, 4)?;
test_ddmtd_stability(false, 1)?; test_ddmtd_stability(false, 1)?;
@ -299,8 +321,9 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> {
} }
info!(" ...done, delta={}", delta); info!(" ...done, delta={}", delta);
test_sysref_frequency()?;
test_slip_tsc()?;
sysref_rtio_align()?; sysref_rtio_align()?;
test_sysref_period()?;
Ok(()) Ok(())
} }

View File

@ -155,19 +155,15 @@ class DDMTD(Module, AutoCSR):
# This assumes: # This assumes:
# * coarse RTIO frequency = 16*SYSREF frequency
# * fine RTIO frequency (rtiox) = 2*RTIO frequency # * fine RTIO frequency (rtiox) = 2*RTIO frequency
# * JESD and coarse RTIO clocks are the same # * JESD and coarse RTIO clocks are the same
# (only reset may differ). # (only reset may differ).
#
# Look at the 4 LSBs of the coarse RTIO timestamp counter
# to determine SYSREF phase.
class SysrefSampler(Module, AutoCSR): 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 = CSRStatus()
self.sh_error_reset = CSRStorage() 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() self.jref = Signal()
@ -206,6 +202,11 @@ class SysrefSampler(Module, AutoCSR):
MultiReg(sh_error, self.sh_error.status) MultiReg(sh_error, self.sh_error.status)
] ]
sample = Signal() jref_r = Signal()
self.sync.rtio += If(coarse_ts[:4] == 0, sample.eq(self.jref)) sysref_phase_rtio = Signal(sysref_phase_bits)
self.specials += MultiReg(sample, self.sample_result.status) 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)