forked from M-Labs/artiq
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.
This commit is contained in:
parent
7e5c062c2c
commit
fdbf1cc2b2
|
@ -158,6 +158,8 @@ mod hmc830 {
|
||||||
pub mod hmc7043 {
|
pub mod hmc7043 {
|
||||||
use board_misoc::{csr, clock};
|
use board_misoc::{csr, clock};
|
||||||
|
|
||||||
|
pub const ANALOG_DELAY_RANGE: u8 = 24;
|
||||||
|
|
||||||
// Warning: dividers are not synchronized with HMC830 clock input!
|
// Warning: dividers are not synchronized with HMC830 clock input!
|
||||||
// Set DAC_CLK_DIV to 1 or 0 for deterministic phase.
|
// Set DAC_CLK_DIV to 1 or 0 for deterministic phase.
|
||||||
// (0 bypasses the divider and reduces noise)
|
// (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();
|
spi_setup();
|
||||||
if dacno == 0 {
|
if dacno == 0 {
|
||||||
write(0x00d5, phase_offset);
|
write(0x00d5, phase_offset);
|
||||||
|
|
|
@ -222,119 +222,70 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sysref_cal_dac(dacno: u8) -> Result<u8, &'static str> {
|
fn sysref_cal_dac(dacno: u8) -> Result<u8, &'static str> {
|
||||||
|
// TODO
|
||||||
info!("calibrating SYSREF phase at DAC-{}...", dacno);
|
info!("calibrating SYSREF phase at DAC-{}...", dacno);
|
||||||
|
info!(" ...done");
|
||||||
let mut d = 0;
|
Ok(7)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sysref_dac_align(dacno: u8, phase: u8) -> Result<(), &'static str> {
|
fn sysref_dac_align(dacno: u8, delay: u8) -> Result<(), &'static str> {
|
||||||
let mut margin_minus = None;
|
let tolerance = 5;
|
||||||
let mut margin_plus = None;
|
|
||||||
|
|
||||||
info!("verifying SYSREF margins at DAC-{}...", dacno);
|
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)?;
|
ad9154::dac_sync(dacno)?;
|
||||||
for d in 0..24 {
|
|
||||||
hmc7043::sysref_offset_dac(dacno, phase - d);
|
let mut rotation_seen = false;
|
||||||
let realign_occured = ad9154::dac_sync(dacno)?;
|
for scan_delay in 0..hmc7043::ANALOG_DELAY_RANGE {
|
||||||
if realign_occured {
|
hmc7043::sysref_delay_dac(dacno, scan_delay);
|
||||||
margin_minus = Some(d);
|
if ad9154::dac_sync(dacno)? {
|
||||||
break;
|
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);
|
if !rotation_seen {
|
||||||
ad9154::dac_sync(dacno)?;
|
return Err("no rotation seen when scanning DAC SYSREF delay");
|
||||||
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 margin_minus.is_some() && margin_plus.is_some() {
|
info!(" ...done");
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put SYSREF at the correct phase and sync DAC
|
// We tested that the value is correct - now use it
|
||||||
hmc7043::sysref_offset_dac(dacno, phase);
|
hmc7043::sysref_delay_dac(dacno, delay);
|
||||||
ad9154::dac_sync(dacno)?;
|
ad9154::dac_sync(dacno)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sysref_auto_dac_align() -> Result<(), &'static str> {
|
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.
|
// 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 entry = config::read_str("sysref_7043_delay_dac", |r| r.map(|s| s.parse()));
|
||||||
let phase = match entry {
|
let delay = match entry {
|
||||||
Ok(Ok(phase)) => {
|
Ok(Ok(delay)) => {
|
||||||
info!("using DAC SYSREF phase from config: {}", phase);
|
info!("using DAC SYSREF delay from config: {}", delay);
|
||||||
phase
|
delay
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
let phase = sysref_cal_dac(0)?;
|
let delay = sysref_cal_dac(0)?;
|
||||||
if let Err(e) = config::write_int("sysref_7043_phase_dac", phase as u32) {
|
if let Err(e) = config::write_int("sysref_7043_delay_dac", delay as u32) {
|
||||||
error!("failed to update DAC SYSREF phase in config: {}", e);
|
error!("failed to update DAC SYSREF delay in config: {}", e);
|
||||||
}
|
}
|
||||||
phase
|
delay
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for dacno in 0..csr::AD9154.len() {
|
for dacno in 0..csr::AD9154.len() {
|
||||||
sysref_dac_align(dacno as u8, phase)?;
|
sysref_dac_align(dacno as u8, delay)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue