From fdbf1cc2b2cf63bdfaff871f30c02145cbf50b69 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Jan 2019 14:04:43 +0800 Subject: [PATCH] sayma: rework DAC SYSREF margin validation Previous code did not work when delay range was not enough for two rotations. This removes autocalibration, to be done later. Uses hardcoded value for now. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 +- artiq/firmware/libboard_artiq/jesd204sync.rs | 121 ++++++------------- 2 files changed, 39 insertions(+), 86 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index c425d71d5..eb28bafd9 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -158,6 +158,8 @@ mod hmc830 { pub mod hmc7043 { use board_misoc::{csr, clock}; + pub const ANALOG_DELAY_RANGE: u8 = 24; + // Warning: dividers are not synchronized with HMC830 clock input! // Set DAC_CLK_DIV to 1 or 0 for deterministic phase. // (0 bypasses the divider and reduces noise) @@ -390,7 +392,7 @@ pub mod hmc7043 { } } - pub fn sysref_offset_dac(dacno: u8, phase_offset: u8) { + pub fn sysref_delay_dac(dacno: u8, phase_offset: u8) { spi_setup(); if dacno == 0 { write(0x00d5, phase_offset); diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index ffd7cd143..92985d9ce 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -222,119 +222,70 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { } fn sysref_cal_dac(dacno: u8) -> Result { + // TODO info!("calibrating SYSREF phase at DAC-{}...", dacno); - - let mut d = 0; - let dmin; - let dmax; - - hmc7043::sysref_offset_dac(dacno, d); - ad9154::dac_sync(dacno)?; - - loop { - hmc7043::sysref_offset_dac(dacno, d); - let realign_occured = ad9154::dac_sync(dacno)?; - if realign_occured { - dmin = d; - break; - } - - d += 1; - if d > 23 { - return Err("no sync errors found when scanning delay"); - } - } - - d += 5; // get away from jitter - hmc7043::sysref_offset_dac(dacno, d); - ad9154::dac_sync(dacno)?; - - loop { - hmc7043::sysref_offset_dac(dacno, d); - let realign_occured = ad9154::dac_sync(dacno)?; - if realign_occured { - dmax = d; - break; - } - - d += 1; - if d > 23 { - return Err("no sync errors found when scanning delay"); - } - } - - let phase = (dmin+dmax)/2; - info!(" ...done, min={}, max={}, result={}", dmin, dmax, phase); - Ok(phase) + info!(" ...done"); + Ok(7) } -fn sysref_dac_align(dacno: u8, phase: u8) -> Result<(), &'static str> { - let mut margin_minus = None; - let mut margin_plus = None; +fn sysref_dac_align(dacno: u8, delay: u8) -> Result<(), &'static str> { + let tolerance = 5; info!("verifying SYSREF margins at DAC-{}...", dacno); - hmc7043::sysref_offset_dac(dacno, phase); + // avoid spurious rotation at delay=0 + hmc7043::sysref_delay_dac(dacno, 0); ad9154::dac_sync(dacno)?; - for d in 0..24 { - hmc7043::sysref_offset_dac(dacno, phase - d); - let realign_occured = ad9154::dac_sync(dacno)?; - if realign_occured { - margin_minus = Some(d); - break; + + let mut rotation_seen = false; + for scan_delay in 0..hmc7043::ANALOG_DELAY_RANGE { + hmc7043::sysref_delay_dac(dacno, scan_delay); + if ad9154::dac_sync(dacno)? { + rotation_seen = true; + let distance = (scan_delay as i16 - delay as i16).abs(); + if distance < tolerance { + error!(" rotation at delay={} is {} delay steps from target (FAIL)", scan_delay, distance); + return Err("insufficient SYSREF margin at DAC"); + } else { + info!(" rotation at delay={} is {} delay steps from target (PASS)", scan_delay, distance); + } } } - hmc7043::sysref_offset_dac(dacno, phase); - ad9154::dac_sync(dacno)?; - for d in 0..24 { - hmc7043::sysref_offset_dac(dacno, phase + d); - let realign_occured = ad9154::dac_sync(dacno)?; - if realign_occured { - margin_plus = Some(d); - break; - } + if !rotation_seen { + return Err("no rotation seen when scanning DAC SYSREF delay"); } - if margin_minus.is_some() && margin_plus.is_some() { - let margin_minus = margin_minus.unwrap(); - let margin_plus = margin_plus.unwrap(); - info!(" margins: -{} +{}", margin_minus, margin_plus); - if margin_minus < 5 || margin_plus < 5 { - return Err("SYSREF margins at DAC are too small, board needs recalibration"); - } - } else { - return Err("Unable to determine SYSREF margins at DAC"); - } + info!(" ...done"); - // Put SYSREF at the correct phase and sync DAC - hmc7043::sysref_offset_dac(dacno, phase); + // We tested that the value is correct - now use it + hmc7043::sysref_delay_dac(dacno, delay); ad9154::dac_sync(dacno)?; Ok(()) } pub fn sysref_auto_dac_align() -> Result<(), &'static str> { - // We assume that DAC SYSREF traces are length-matched so only one phase + // We assume that DAC SYSREF traces are length-matched so only one delay // value is needed, and we use DAC-0 as calibration reference. - let entry = config::read_str("sysref_7043_phase_dac", |r| r.map(|s| s.parse())); - let phase = match entry { - Ok(Ok(phase)) => { - info!("using DAC SYSREF phase from config: {}", phase); - phase + let entry = config::read_str("sysref_7043_delay_dac", |r| r.map(|s| s.parse())); + let delay = match entry { + Ok(Ok(delay)) => { + info!("using DAC SYSREF delay from config: {}", delay); + delay }, _ => { - let phase = sysref_cal_dac(0)?; - if let Err(e) = config::write_int("sysref_7043_phase_dac", phase as u32) { - error!("failed to update DAC SYSREF phase in config: {}", e); + let delay = sysref_cal_dac(0)?; + if let Err(e) = config::write_int("sysref_7043_delay_dac", delay as u32) { + error!("failed to update DAC SYSREF delay in config: {}", e); } - phase + delay } }; for dacno in 0..csr::AD9154.len() { - sysref_dac_align(dacno as u8, phase)?; + sysref_dac_align(dacno as u8, delay)?; } Ok(()) }