From 05e908a0fd66709bc143587bb843730a1133535d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Jun 2018 15:54:30 +0800 Subject: [PATCH] hmc7043: align SYSREF with RTIO --- artiq/firmware/libboard_artiq/ad9154.rs | 6 ++ artiq/firmware/libboard_artiq/hmc830_7043.rs | 67 +++++++++++++++++++- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 703438a22..e637a4550 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -770,6 +770,12 @@ pub fn init() { // set up clock chips before. jesd_unreset(); + // This needs to take place once before DAC SYSREF scan, as + // the HMC7043 input clock (which defines slip resolution) + // is 2x the DAC clock, so there are two possible phases from + // the divider states. This deterministically selects one. + hmc7043::sysref_rtio_align(); + for dacno in 0..csr::AD9154.len() { match init_dac(dacno as u8) { Ok(_) => (), diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 8fa2e2ebb..9015bd917 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -283,11 +283,12 @@ pub mod hmc7043 { let (enabled, divider, outcfg) = OUTPUT_CONFIG[channel]; if enabled { - // Only clock channels need to be high-performance if channel % 2 == 0 { + // DCLK channel: enable high-performance mode write(channel_base, 0xd1); } else { - write(channel_base, 0x51); + // SYSREF channel: disable hi-perf mode, enable slip + write(channel_base, 0x71); } } else { write(channel_base, 0x10); @@ -336,6 +337,68 @@ pub mod hmc7043 { } } + fn cfg_fpga_sysref(phase: u16) { + let analog_delay = (phase % 17) as u8; + let digital_delay = (phase / 17) as u8; + spi_setup(); + write(0x0111, analog_delay); + write(0x0112, digital_delay); + } + + fn sysref_slip() { + spi_setup(); + write(0x0002, 0x02); + write(0x0002, 0x00); + } + + fn sysref_sample() -> bool { + unsafe { csr::sysref_sampler::sample_result_read() == 1 } + } + + pub fn sysref_rtio_align() { + info!("aligning SYSREF with RTIO..."); + + let phase_offset = 44; + let mut slips0 = 0; + let mut slips1 = 0; + + // meet setup/hold (assuming FPGA timing margins are OK) + cfg_fpga_sysref(phase_offset); + // if we are already in the 1 zone, get out of it + while sysref_sample() { + sysref_slip(); + slips0 += 1; + } + // get to the edge of the 0->1 transition (our final setpoint) + while !sysref_sample() { + sysref_slip(); + slips1 += 1; + } + + info!(" ...done ({}/{} slips), verifying timing margin", slips0, slips1); + + let mut margin = None; + for d in 0..phase_offset { + cfg_fpga_sysref(phase_offset - d); + if !sysref_sample() { + margin = Some(d); + break; + } + } + + // meet setup/hold + cfg_fpga_sysref(phase_offset); + + if margin.is_some() { + let margin = margin.unwrap(); + info!(" margin at FPGA: {}", margin); + if margin < 10 { + error!("SYSREF margin at FPGA is too small"); + } + } else { + error!("unable to determine SYSREF margin at FPGA"); + } + } } pub fn init() -> Result<(), &'static str> {