Si5324 Rust driver brought on par with og artiq #132

Merged
sb10q merged 5 commits from si5324_improvements into master 2021-08-04 09:12:38 +08:00
1 changed files with 72 additions and 0 deletions
Showing only changes of commit f70ce89ee6 - Show all commits

View File

@ -271,3 +271,75 @@ pub fn select_input(i2c: &mut I2c, input: Input, timer: GlobalTimer) -> Result<(
monitor_lock(i2c, timer)?; monitor_lock(i2c, timer)?;
Ok(()) Ok(())
} }
#[cfg(has_siphaser)]
pub mod siphaser {
use super::*;
use pl::csr;
pub fn select_recovered_clock(i2c: &mut I2c, rc: bool, timer: GlobalTimer) -> Result<()> {
write(i2c, 3, (read(3)? & 0xdf) | (1 << 5))?; // DHOLD=1
unsafe {
csr::siphaser::switch_clocks_write(if rc { 1 } else { 0 });
}
write(i2c, 3, (read(3)? & 0xdf) | (0 << 5))?; // DHOLD=0
monitor_lock(timer)?;
Ok(())
}
fn phase_shift(direction: u8, timer: GlobalTimer) {
unsafe {
csr::siphaser::phase_shift_write(direction);
while csr::siphaser::phase_shift_done_read() == 0 {}
}
// wait for the Si5324 loop to stabilize
timer.delay_us(500);
}
fn has_error(timer: GlobalTimer) -> bool {
unsafe {
csr::siphaser::error_write(1);
}
timer.delay_us(5_000);
unsafe {
csr::siphaser::error_read() != 0
}
}
fn find_edge(target: bool, timer: GlobalTimer) -> Result<u32> {
let mut nshifts = 0;
let mut previous = has_error(timer);
loop {
phase_shift(1, timer);
nshifts += 1;
let current = has_error(timer);
if previous != target && current == target {
return Ok(nshifts);
}
if nshifts > 5000 {
return Err("failed to find timing error edge");
}
previous = current;
}
}
pub fn calibrate_skew(timer: GlobalTimer) -> Result<()> {
let jitter_margin = 32;
let lead = find_edge(false, timer)?;
for _ in 0..jitter_margin {
phase_shift(1, timer);
}
let width = find_edge(true, timer)? + jitter_margin;
// width is 360 degrees (one full rotation of the phase between s/h limits) minus jitter
info!("calibration successful, lead: {}, width: {} ({}deg)", lead, width, width*360/(56*8));
// Apply reverse phase shift for half the width to get into the
// middle of the working region.
for _ in 0..width/2 {
phase_shift(0, timer);
}
Ok(())
}
}