forked from M-Labs/artiq
hmc7043: align SYSREF with RTIO
This commit is contained in:
parent
9741654cad
commit
05e908a0fd
|
@ -770,6 +770,12 @@ pub fn init() {
|
||||||
// set up clock chips before.
|
// set up clock chips before.
|
||||||
jesd_unreset();
|
jesd_unreset();
|
||||||
|
|
||||||
|
// This needs to take place once before DAC SYSREF scan, as
|
||||||
|
// the HMC7043 input clock (which defines slip resolution)
|
||||||
|
// is 2x the DAC clock, so there are two possible phases from
|
||||||
|
// the divider states. This deterministically selects one.
|
||||||
|
hmc7043::sysref_rtio_align();
|
||||||
|
|
||||||
for dacno in 0..csr::AD9154.len() {
|
for dacno in 0..csr::AD9154.len() {
|
||||||
match init_dac(dacno as u8) {
|
match init_dac(dacno as u8) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
|
|
|
@ -283,11 +283,12 @@ pub mod hmc7043 {
|
||||||
let (enabled, divider, outcfg) = OUTPUT_CONFIG[channel];
|
let (enabled, divider, outcfg) = OUTPUT_CONFIG[channel];
|
||||||
|
|
||||||
if enabled {
|
if enabled {
|
||||||
// Only clock channels need to be high-performance
|
|
||||||
if channel % 2 == 0 {
|
if channel % 2 == 0 {
|
||||||
|
// DCLK channel: enable high-performance mode
|
||||||
write(channel_base, 0xd1);
|
write(channel_base, 0xd1);
|
||||||
} else {
|
} else {
|
||||||
write(channel_base, 0x51);
|
// SYSREF channel: disable hi-perf mode, enable slip
|
||||||
|
write(channel_base, 0x71);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
write(channel_base, 0x10);
|
write(channel_base, 0x10);
|
||||||
|
@ -336,6 +337,68 @@ pub mod hmc7043 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cfg_fpga_sysref(phase: u16) {
|
||||||
|
let analog_delay = (phase % 17) as u8;
|
||||||
|
let digital_delay = (phase / 17) as u8;
|
||||||
|
spi_setup();
|
||||||
|
write(0x0111, analog_delay);
|
||||||
|
write(0x0112, digital_delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sysref_slip() {
|
||||||
|
spi_setup();
|
||||||
|
write(0x0002, 0x02);
|
||||||
|
write(0x0002, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sysref_sample() -> bool {
|
||||||
|
unsafe { csr::sysref_sampler::sample_result_read() == 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sysref_rtio_align() {
|
||||||
|
info!("aligning SYSREF with RTIO...");
|
||||||
|
|
||||||
|
let phase_offset = 44;
|
||||||
|
let mut slips0 = 0;
|
||||||
|
let mut slips1 = 0;
|
||||||
|
|
||||||
|
// meet setup/hold (assuming FPGA timing margins are OK)
|
||||||
|
cfg_fpga_sysref(phase_offset);
|
||||||
|
// if we are already in the 1 zone, get out of it
|
||||||
|
while sysref_sample() {
|
||||||
|
sysref_slip();
|
||||||
|
slips0 += 1;
|
||||||
|
}
|
||||||
|
// get to the edge of the 0->1 transition (our final setpoint)
|
||||||
|
while !sysref_sample() {
|
||||||
|
sysref_slip();
|
||||||
|
slips1 += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
info!(" ...done ({}/{} slips), verifying timing margin", slips0, slips1);
|
||||||
|
|
||||||
|
let mut margin = None;
|
||||||
|
for d in 0..phase_offset {
|
||||||
|
cfg_fpga_sysref(phase_offset - d);
|
||||||
|
if !sysref_sample() {
|
||||||
|
margin = Some(d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// meet setup/hold
|
||||||
|
cfg_fpga_sysref(phase_offset);
|
||||||
|
|
||||||
|
if margin.is_some() {
|
||||||
|
let margin = margin.unwrap();
|
||||||
|
info!(" margin at FPGA: {}", margin);
|
||||||
|
if margin < 10 {
|
||||||
|
error!("SYSREF margin at FPGA is too small");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("unable to determine SYSREF margin at FPGA");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() -> Result<(), &'static str> {
|
pub fn init() -> Result<(), &'static str> {
|
||||||
|
|
Loading…
Reference in New Issue