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 {
|
||||
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);
|
||||
|
|
|
@ -222,119 +222,70 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> {
|
|||
}
|
||||
|
||||
fn sysref_cal_dac(dacno: u8) -> Result<u8, &'static str> {
|
||||
// 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;
|
||||
info!(" ...done");
|
||||
Ok(7)
|
||||
}
|
||||
|
||||
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> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 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");
|
||||
}
|
||||
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 {
|
||||
return Err("Unable to determine SYSREF margins at DAC");
|
||||
info!(" rotation at delay={} is {} delay steps from target (PASS)", scan_delay, distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Put SYSREF at the correct phase and sync DAC
|
||||
hmc7043::sysref_offset_dac(dacno, phase);
|
||||
if !rotation_seen {
|
||||
return Err("no rotation seen when scanning DAC SYSREF delay");
|
||||
}
|
||||
|
||||
info!(" ...done");
|
||||
|
||||
// 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(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue