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:
Sebastien Bourdeauducq 2019-01-27 14:04:43 +08:00
parent 7e5c062c2c
commit fdbf1cc2b2
2 changed files with 39 additions and 86 deletions

View File

@ -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);

View File

@ -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 realign_occured = ad9154::dac_sync(dacno)?;
if realign_occured {
margin_minus = Some(d);
break;
}
}
hmc7043::sysref_offset_dac(dacno, phase); let mut rotation_seen = false;
ad9154::dac_sync(dacno)?; for scan_delay in 0..hmc7043::ANALOG_DELAY_RANGE {
for d in 0..24 { hmc7043::sysref_delay_dac(dacno, scan_delay);
hmc7043::sysref_offset_dac(dacno, phase + d); if ad9154::dac_sync(dacno)? {
let realign_occured = ad9154::dac_sync(dacno)?; rotation_seen = true;
if realign_occured { let distance = (scan_delay as i16 - delay as i16).abs();
margin_plus = Some(d); if distance < tolerance {
break; error!(" rotation at delay={} is {} delay steps from target (FAIL)", scan_delay, distance);
} return Err("insufficient SYSREF margin at DAC");
}
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 { } 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 if !rotation_seen {
hmc7043::sysref_offset_dac(dacno, phase); 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)?; 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(())
} }