mirror of https://github.com/m-labs/artiq.git
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.
This commit is contained in:
parent
f32f0126e2
commit
7f0b2ff594
|
@ -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_0, 0x0a); // receive buffer delay
|
||||||
write(ad9154_reg::LMFC_VAR_1, 0x0a);
|
write(ad9154_reg::LMFC_VAR_1, 0x0a);
|
||||||
write(ad9154_reg::SYNC_ERRWINDOW, 0); // +- 1/2 DAC clock
|
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,
|
write(ad9154_reg::XBAR_LN_0_1,
|
||||||
0*ad9154_reg::LOGICAL_LANE0_SRC | 1*ad9154_reg::LOGICAL_LANE1_SRC);
|
0*ad9154_reg::LOGICAL_LANE0_SRC | 1*ad9154_reg::LOGICAL_LANE1_SRC);
|
||||||
write(ad9154_reg::XBAR_LN_2_3,
|
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<bool, &'static str> {
|
||||||
spi_setup(dacno);
|
spi_setup(dacno);
|
||||||
let sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) |
|
|
||||||
((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8))
|
write(ad9154_reg::SYNC_CONTROL,
|
||||||
& 0x1ff;
|
0x1*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE |
|
||||||
sync_error
|
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> {
|
fn init_dac(dacno: u8) -> Result<(), &'static str> {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use board_misoc::{csr, clock, config};
|
use board_misoc::{csr, config};
|
||||||
|
|
||||||
use hmc830_7043::hmc7043;
|
use hmc830_7043::hmc7043;
|
||||||
use ad9154;
|
use ad9154;
|
||||||
|
@ -147,14 +147,12 @@ fn sysref_cal_dac(dacno: u8) -> Result<u16, &'static str> {
|
||||||
let dmax;
|
let dmax;
|
||||||
|
|
||||||
hmc7043::sysref_offset_dac(dacno, d);
|
hmc7043::sysref_offset_dac(dacno, d);
|
||||||
clock::spin_us(10000);
|
ad9154::dac_sync(dacno)?;
|
||||||
let sync_error_last = ad9154::dac_get_sync_error(dacno);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
hmc7043::sysref_offset_dac(dacno, d);
|
hmc7043::sysref_offset_dac(dacno, d);
|
||||||
clock::spin_us(10000);
|
let realign_occured = ad9154::dac_sync(dacno)?;
|
||||||
let sync_error = ad9154::dac_get_sync_error(dacno);
|
if realign_occured {
|
||||||
if sync_error != sync_error_last {
|
|
||||||
dmin = d;
|
dmin = d;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -165,16 +163,14 @@ fn sysref_cal_dac(dacno: u8) -> Result<u16, &'static str> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d += 5; // get away from jitter
|
d += 17; // get away from jitter
|
||||||
hmc7043::sysref_offset_dac(dacno, d);
|
hmc7043::sysref_offset_dac(dacno, d);
|
||||||
clock::spin_us(10000);
|
ad9154::dac_sync(dacno)?;
|
||||||
let sync_error_last = ad9154::dac_get_sync_error(dacno);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
hmc7043::sysref_offset_dac(dacno, d);
|
hmc7043::sysref_offset_dac(dacno, d);
|
||||||
clock::spin_us(10000);
|
let realign_occured = ad9154::dac_sync(dacno)?;
|
||||||
let sync_error = ad9154::dac_get_sync_error(dacno);
|
if realign_occured {
|
||||||
if sync_error != sync_error_last {
|
|
||||||
dmax = d;
|
dmax = d;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -197,28 +193,22 @@ fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> {
|
||||||
info!("verifying SYSREF margins at DAC-{}...", dacno);
|
info!("verifying SYSREF margins at DAC-{}...", dacno);
|
||||||
|
|
||||||
hmc7043::sysref_offset_dac(dacno, phase);
|
hmc7043::sysref_offset_dac(dacno, phase);
|
||||||
clock::spin_us(10000);
|
ad9154::dac_sync(dacno)?;
|
||||||
let sync_error_last = ad9154::dac_get_sync_error(dacno);
|
|
||||||
for d in 0..128 {
|
for d in 0..128 {
|
||||||
hmc7043::sysref_offset_dac(dacno, phase - d);
|
hmc7043::sysref_offset_dac(dacno, phase - d);
|
||||||
clock::spin_us(10000);
|
let realign_occured = ad9154::dac_sync(dacno)?;
|
||||||
let sync_error = ad9154::dac_get_sync_error(dacno);
|
if realign_occured {
|
||||||
if sync_error != sync_error_last {
|
|
||||||
info!(" sync error-: {} -> {}", sync_error_last, sync_error);
|
|
||||||
margin_minus = Some(d);
|
margin_minus = Some(d);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hmc7043::sysref_offset_dac(dacno, phase);
|
hmc7043::sysref_offset_dac(dacno, phase);
|
||||||
clock::spin_us(10000);
|
ad9154::dac_sync(dacno)?;
|
||||||
let sync_error_last = ad9154::dac_get_sync_error(dacno);
|
|
||||||
for d in 0..128 {
|
for d in 0..128 {
|
||||||
hmc7043::sysref_offset_dac(dacno, phase + d);
|
hmc7043::sysref_offset_dac(dacno, phase + d);
|
||||||
clock::spin_us(10000);
|
let realign_occured = ad9154::dac_sync(dacno)?;
|
||||||
let sync_error = ad9154::dac_get_sync_error(dacno);
|
if realign_occured {
|
||||||
if sync_error != sync_error_last {
|
|
||||||
info!(" sync error+: {} -> {}", sync_error_last, sync_error);
|
|
||||||
margin_plus = Some(d);
|
margin_plus = Some(d);
|
||||||
break;
|
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");
|
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);
|
hmc7043::sysref_offset_dac(dacno, phase);
|
||||||
|
ad9154::dac_sync(dacno)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue