mirror of https://github.com/m-labs/artiq
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
parent
9d0d02a561
commit
c591009220
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue