forked from M-Labs/artiq
sayma: automated DAC SYSREF phase calibration
This commit is contained in:
parent
dbcf2fe9b4
commit
32c95ac034
|
@ -1,6 +1,5 @@
|
||||||
use board_misoc::{csr, clock};
|
use board_misoc::{csr, clock};
|
||||||
use ad9154_reg;
|
use ad9154_reg;
|
||||||
use hmc830_7043::hmc7043;
|
|
||||||
|
|
||||||
fn spi_setup(dacno: u8) {
|
fn spi_setup(dacno: u8) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -688,7 +687,7 @@ fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dac_get_sync_error(dacno: u8) -> u16 {
|
pub fn dac_get_sync_error(dacno: u8) -> u16 {
|
||||||
spi_setup(dacno);
|
spi_setup(dacno);
|
||||||
let sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) |
|
let sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) |
|
||||||
((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8))
|
((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8))
|
||||||
|
@ -696,73 +695,24 @@ fn dac_get_sync_error(dacno: u8) -> u16 {
|
||||||
sync_error
|
sync_error
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dac_sysref_scan(dacno: u8, center_phase: u16) {
|
fn init_dac(dacno: u8) -> Result<(), &'static str> {
|
||||||
let mut margin_minus = None;
|
|
||||||
let mut margin_plus = None;
|
|
||||||
|
|
||||||
info!("AD9154-{} SYSREF scan...", dacno);
|
|
||||||
|
|
||||||
hmc7043::sysref_offset_dac(dacno, center_phase);
|
|
||||||
clock::spin_us(10000);
|
|
||||||
let mut sync_error_last = dac_get_sync_error(dacno);
|
|
||||||
for d in 0..128 {
|
|
||||||
hmc7043::sysref_offset_dac(dacno, center_phase - d);
|
|
||||||
clock::spin_us(10000);
|
|
||||||
let sync_error = dac_get_sync_error(dacno);
|
|
||||||
if sync_error != sync_error_last {
|
|
||||||
info!(" sync error-: {} -> {}", sync_error_last, sync_error);
|
|
||||||
margin_minus = Some(d);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hmc7043::sysref_offset_dac(dacno, center_phase);
|
|
||||||
clock::spin_us(10000);
|
|
||||||
sync_error_last = dac_get_sync_error(dacno);
|
|
||||||
for d in 0..128 {
|
|
||||||
hmc7043::sysref_offset_dac(dacno, center_phase + d);
|
|
||||||
clock::spin_us(10000);
|
|
||||||
let sync_error = dac_get_sync_error(dacno);
|
|
||||||
if sync_error != sync_error_last {
|
|
||||||
info!(" sync error+: {} -> {}", sync_error_last, sync_error);
|
|
||||||
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 < 10 || margin_plus < 10 {
|
|
||||||
error!("SYSREF margins are too small");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error!("Unable to determine SYSREF margins");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_dac(dacno: u8, sysref_phase: u16) -> Result<(), &'static str> {
|
|
||||||
let dacno = dacno as u8;
|
let dacno = dacno as u8;
|
||||||
// Reset the DAC, detect and configure it
|
|
||||||
dac_reset(dacno);
|
dac_reset(dacno);
|
||||||
dac_detect(dacno)?;
|
dac_detect(dacno)?;
|
||||||
dac_cfg_retry(dacno)?;
|
dac_cfg_retry(dacno)?;
|
||||||
// Run the PRBS, STPL and SYSREF scan tests
|
|
||||||
dac_prbs(dacno)?;
|
dac_prbs(dacno)?;
|
||||||
dac_stpl(dacno, 4, 2)?;
|
dac_stpl(dacno, 4, 2)?;
|
||||||
dac_sysref_scan(dacno, sysref_phase);
|
|
||||||
// Set SYSREF phase and reconfigure the DAC
|
|
||||||
hmc7043::sysref_offset_dac(dacno, sysref_phase);
|
|
||||||
dac_cfg_retry(dacno)?;
|
dac_cfg_retry(dacno)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(sysref_phase_dac: u16) {
|
pub fn init() {
|
||||||
for dacno in 0..csr::AD9154.len() {
|
for dacno in 0..csr::AD9154.len() {
|
||||||
// We assume DCLK and SYSREF traces are matched on the PCB
|
match init_dac(dacno as u8) {
|
||||||
// (they are on Sayma) so only one phase is needed.
|
|
||||||
match init_dac(dacno as u8, sysref_phase_dac) {
|
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) => error!("failed to initialize AD9154-{}: {}", dacno, e)
|
Err(e) => error!("failed to initialize AD9154-{}: {}", dacno, e)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use board_misoc::csr;
|
use board_misoc::{csr, clock, config};
|
||||||
use board_misoc::config;
|
|
||||||
|
|
||||||
use hmc830_7043::hmc7043;
|
use hmc830_7043::hmc7043;
|
||||||
|
use ad9154;
|
||||||
|
|
||||||
fn sysref_sample() -> bool {
|
fn sysref_sample() -> bool {
|
||||||
unsafe { csr::sysref_sampler::sample_result_read() == 1 }
|
unsafe { csr::sysref_sampler::sample_result_read() == 1 }
|
||||||
|
@ -142,3 +141,127 @@ pub fn sysref_auto_rtio_align(expected_align: u16) -> Result<(), &'static str> {
|
||||||
};
|
};
|
||||||
sysref_rtio_align(phase_offset, expected_align)
|
sysref_rtio_align(phase_offset, expected_align)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sysref_cal_dac(dacno: u8) -> Result<u16, &'static str> {
|
||||||
|
info!("calibrating SYSREF phase at DAC-{}...", dacno);
|
||||||
|
|
||||||
|
let mut d = 0;
|
||||||
|
let dmin;
|
||||||
|
let dmax;
|
||||||
|
|
||||||
|
hmc7043::sysref_offset_dac(dacno, d);
|
||||||
|
clock::spin_us(10000);
|
||||||
|
let sync_error_last = ad9154::dac_get_sync_error(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 {
|
||||||
|
dmin = d;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
d += 1;
|
||||||
|
if d > 128 {
|
||||||
|
return Err("no sync errors found when scanning delay");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d += 5; // get away from jitter
|
||||||
|
hmc7043::sysref_offset_dac(dacno, d);
|
||||||
|
clock::spin_us(10000);
|
||||||
|
let sync_error_last = ad9154::dac_get_sync_error(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 {
|
||||||
|
dmax = d;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
d += 1;
|
||||||
|
if d > 128 {
|
||||||
|
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: u16) -> Result<(), &'static str> {
|
||||||
|
let mut margin_minus = None;
|
||||||
|
let mut margin_plus = None;
|
||||||
|
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
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 < 10 || margin_plus < 10 {
|
||||||
|
return Err("SYSREF margins at DAC are too small, board needs recalibration");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err("Unable to determine SYSREF margins at DAC");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leave SYSREF at the correct setting
|
||||||
|
hmc7043::sysref_offset_dac(dacno, phase);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sysref_auto_dac_align() -> Result<(), &'static str> {
|
||||||
|
// We assume that DAC SYSREF traces are length-matched so only one phase
|
||||||
|
// value is needed, and we use DAC-0 as calibration reference.
|
||||||
|
|
||||||
|
let entry = config::read_str("sysref_phase_dac", |r| r.map(|s| s.parse()));
|
||||||
|
let phase = match entry {
|
||||||
|
Ok(Ok(phase)) => phase,
|
||||||
|
_ => {
|
||||||
|
let phase = sysref_cal_dac(0)?;
|
||||||
|
if let Err(e) = config::write_int("sysref_phase_dac", phase as u32) {
|
||||||
|
error!("failed to update DAC SYSREF phase in config: {}", e);
|
||||||
|
}
|
||||||
|
phase
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for dacno in 0..csr::AD9154.len() {
|
||||||
|
sysref_dac_align(dacno as u8, phase)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -56,9 +56,6 @@ mod moninj;
|
||||||
#[cfg(has_rtio_analyzer)]
|
#[cfg(has_rtio_analyzer)]
|
||||||
mod analyzer;
|
mod analyzer;
|
||||||
|
|
||||||
#[cfg(has_ad9154)]
|
|
||||||
const SYSREF_PHASE_DAC: u16 = 94;
|
|
||||||
|
|
||||||
fn startup() {
|
fn startup() {
|
||||||
irq::set_mask(0);
|
irq::set_mask(0);
|
||||||
irq::set_ie(true);
|
irq::set_ie(true);
|
||||||
|
@ -114,10 +111,13 @@ fn startup() {
|
||||||
#[cfg(has_ad9154)]
|
#[cfg(has_ad9154)]
|
||||||
{
|
{
|
||||||
board_artiq::ad9154::jesd_unreset();
|
board_artiq::ad9154::jesd_unreset();
|
||||||
|
board_artiq::ad9154::init();
|
||||||
if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align(1) {
|
if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align(1) {
|
||||||
error!("failed to align SYSREF at FPGA: {}", e);
|
error!("failed to align SYSREF at FPGA: {}", e);
|
||||||
}
|
}
|
||||||
board_artiq::ad9154::init(SYSREF_PHASE_DAC);
|
if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() {
|
||||||
|
error!("failed to align SYSREF at DAC: {}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[cfg(has_allaki_atts)]
|
#[cfg(has_allaki_atts)]
|
||||||
board_artiq::hmc542::program_all(8/*=4dB*/);
|
board_artiq::hmc542::program_all(8/*=4dB*/);
|
||||||
|
|
Loading…
Reference in New Issue