From 7f0b2ff5943364fb43ecd0d022840a70fa5a2bc2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Aug 2018 17:42:53 +0800 Subject: [PATCH] jesd204sync: work around HMC7043 poor behavior with combined delays The HMC7043 outputs poorly controlled signals when adjusting two delays at once. This commit puts the DAC in one-shot SYSREF mode, and only triggers synchronizations when SYSREF is stable. --- artiq/firmware/libboard_artiq/ad9154.rs | 47 +++++++++----------- artiq/firmware/libboard_artiq/jesd204sync.rs | 41 +++++++---------- 2 files changed, 36 insertions(+), 52 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 978f2a199..a1c384da9 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -370,28 +370,7 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { write(ad9154_reg::LMFC_VAR_0, 0x0a); // receive buffer delay write(ad9154_reg::LMFC_VAR_1, 0x0a); write(ad9154_reg::SYNC_ERRWINDOW, 0); // +- 1/2 DAC clock - write(ad9154_reg::SYNC_CONTROL, - 0x9*ad9154_reg::SYNCMODE | 0*ad9154_reg::SYNCENABLE | - 0*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY | - 1*ad9154_reg::SYNCCLRLAST); - write(ad9154_reg::SYNC_CONTROL, - 0x9*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | - 0*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY | - 1*ad9154_reg::SYNCCLRLAST); - write(ad9154_reg::SYNC_CONTROL, - 0x9*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | - 1*ad9154_reg::SYNCARM | 0*ad9154_reg::SYNCCLRSTKY | - 0*ad9154_reg::SYNCCLRLAST); - clock::spin_us(1000); // ensure at least one sysref edge - if read(ad9154_reg::SYNC_CONTROL) & ad9154_reg::SYNCARM != 0 { - return Err("no sysref edge"); - } - if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_LOCK == 0 { - return Err("no sync lock"); - } - if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_WLIM != 0 { - return Err("sysref phase error"); - } + write(ad9154_reg::XBAR_LN_0_1, 0*ad9154_reg::LOGICAL_LANE0_SRC | 1*ad9154_reg::LOGICAL_LANE1_SRC); write(ad9154_reg::XBAR_LN_2_3, @@ -687,12 +666,26 @@ fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { } } -pub fn dac_get_sync_error(dacno: u8) -> u16 { +pub fn dac_sync(dacno: u8) -> Result { spi_setup(dacno); - let sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) | - ((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8)) - & 0x1ff; - sync_error + + write(ad9154_reg::SYNC_CONTROL, + 0x1*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | + 1*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY); + clock::spin_us(1000); // ensure at least one sysref edge + let sync_status = read(ad9154_reg::SYNC_STATUS); + + if sync_status & ad9154_reg::SYNC_BUSY != 0 { + return Err("sync logic busy"); + } + if sync_status & ad9154_reg::SYNC_LOCK == 0 { + return Err("no sync lock"); + } + if sync_status & ad9154_reg::SYNC_TRIP == 0 { + return Err("no sysref edge"); + } + let realign_occured = sync_status & ad9154_reg::SYNC_ROTATE != 0; + Ok(realign_occured) } fn init_dac(dacno: u8) -> Result<(), &'static str> { diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 81cf72cac..c4cc18810 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -1,4 +1,4 @@ -use board_misoc::{csr, clock, config}; +use board_misoc::{csr, config}; use hmc830_7043::hmc7043; use ad9154; @@ -147,14 +147,12 @@ fn sysref_cal_dac(dacno: u8) -> Result { let dmax; hmc7043::sysref_offset_dac(dacno, d); - clock::spin_us(10000); - let sync_error_last = ad9154::dac_get_sync_error(dacno); + ad9154::dac_sync(dacno)?; loop { hmc7043::sysref_offset_dac(dacno, d); - clock::spin_us(10000); - let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != sync_error_last { + let realign_occured = ad9154::dac_sync(dacno)?; + if realign_occured { dmin = d; break; } @@ -165,16 +163,14 @@ fn sysref_cal_dac(dacno: u8) -> Result { } } - d += 5; // get away from jitter + d += 17; // get away from jitter hmc7043::sysref_offset_dac(dacno, d); - clock::spin_us(10000); - let sync_error_last = ad9154::dac_get_sync_error(dacno); + ad9154::dac_sync(dacno)?; loop { hmc7043::sysref_offset_dac(dacno, d); - clock::spin_us(10000); - let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != sync_error_last { + let realign_occured = ad9154::dac_sync(dacno)?; + if realign_occured { dmax = d; break; } @@ -197,28 +193,22 @@ fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { info!("verifying SYSREF margins at DAC-{}...", dacno); hmc7043::sysref_offset_dac(dacno, phase); - clock::spin_us(10000); - let sync_error_last = ad9154::dac_get_sync_error(dacno); + ad9154::dac_sync(dacno)?; for d in 0..128 { hmc7043::sysref_offset_dac(dacno, phase - d); - clock::spin_us(10000); - let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != sync_error_last { - info!(" sync error-: {} -> {}", sync_error_last, sync_error); + let realign_occured = ad9154::dac_sync(dacno)?; + if realign_occured { margin_minus = Some(d); break; } } hmc7043::sysref_offset_dac(dacno, phase); - clock::spin_us(10000); - let sync_error_last = ad9154::dac_get_sync_error(dacno); + ad9154::dac_sync(dacno)?; for d in 0..128 { hmc7043::sysref_offset_dac(dacno, phase + d); - clock::spin_us(10000); - let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != sync_error_last { - info!(" sync error+: {} -> {}", sync_error_last, sync_error); + let realign_occured = ad9154::dac_sync(dacno)?; + if realign_occured { margin_plus = Some(d); break; } @@ -235,8 +225,9 @@ fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { return Err("Unable to determine SYSREF margins at DAC"); } - // Leave SYSREF at the correct setting + // Put SYSREF at the correct phase and sync DAC hmc7043::sysref_offset_dac(dacno, phase); + ad9154::dac_sync(dacno)?; Ok(()) }