From 54f95c933561535238db19cda9b912de1d7695cc Mon Sep 17 00:00:00 2001 From: mwojcik Date: Mon, 2 Aug 2021 09:52:33 +0200 Subject: [PATCH 1/5] uncommented parts, replaced clock with timer --- src/runtime/src/main.rs | 2 +- src/runtime/src/si5324.rs | 35 ++++++++++++++++++----------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index 5f4d43e..55cee61 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -201,7 +201,7 @@ pub fn main_core0() { i2c::init(); #[cfg(feature = "target_kasli_soc")] si5324::setup(unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() }, - &SI5324_SETTINGS, si5324::Input::Ckin2).expect("cannot initialize Si5324"); + &SI5324_SETTINGS, si5324::Input::Ckin2, timer).expect("cannot initialize Si5324"); let cfg = match Config::new() { Ok(cfg) => cfg, diff --git a/src/runtime/src/si5324.rs b/src/runtime/src/si5324.rs index c2d90a2..3e20ec4 100644 --- a/src/runtime/src/si5324.rs +++ b/src/runtime/src/si5324.rs @@ -1,6 +1,7 @@ use core::result; use log::info; -use libboard_zynq::i2c::I2c; +use libboard_zynq::{i2c::I2c, timer::GlobalTimer, time::Milliseconds}; +use embedded_hal::blocking::delay::DelayUs; type Result = result::Result; @@ -134,9 +135,9 @@ fn ident(i2c: &mut I2c) -> Result { Ok(((read(i2c, 134)? as u16) << 8) | (read(i2c, 135)? as u16)) } -fn soft_reset(i2c: &mut I2c) -> Result<()> { - //TODO write_no_ack_value(i2c, 136, read(136)? | 0x80)?; - //TODO clock::spin_us(10_000); +fn soft_reset(i2c: &mut I2c, timer: GlobalTimer) -> Result<()> { + write_no_ack_value(i2c, 136, read(i2c, 136)? | 0x80)?; + timer.delay_us(10_000); Ok(()) } @@ -155,20 +156,20 @@ fn locked(i2c: &mut I2c) -> Result { Ok((read(i2c, 130)? & 0x01) == 0) // LOL_INT=0 } -fn monitor_lock(i2c: &mut I2c) -> Result<()> { +fn monitor_lock(i2c: &mut I2c, timer: GlobalTimer) -> Result<()> { info!("waiting for Si5324 lock..."); - // TODO let t = clock::get_ms(); + let timeout = timer.get_time() + Milliseconds(20_000); while !locked(i2c)? { // Yes, lock can be really slow. - /*if clock::get_ms() > t + 20000 { + if timer.get_time() > timeout { return Err("Si5324 lock timeout"); - }*/ + } } info!(" ...locked"); Ok(()) } -fn init(i2c: &mut I2c) -> Result<()> { +fn init(i2c: &mut I2c, timer: GlobalTimer) -> Result<()> { #[cfg(feature = "target_kasli_soc")] { i2c.pca9548_select(0x70, 0)?; @@ -179,16 +180,16 @@ fn init(i2c: &mut I2c) -> Result<()> { return Err("Si5324 does not have expected product number"); } - soft_reset(i2c)?; + soft_reset(i2c, timer)?; Ok(()) } -pub fn bypass(i2c: &mut I2c, input: Input) -> Result<()> { +pub fn bypass(i2c: &mut I2c, input: Input, timer: GlobalTimer) -> Result<()> { let cksel_reg = match input { Input::Ckin1 => 0b00, Input::Ckin2 => 0b01, }; - init(i2c)?; + init(i2c, timer)?; rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0 rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?; // CKSEL_REG rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00 @@ -197,14 +198,14 @@ pub fn bypass(i2c: &mut I2c, input: Input) -> Result<()> { Ok(()) } -pub fn setup(i2c: &mut I2c, settings: &FrequencySettings, input: Input) -> Result<()> { +pub fn setup(i2c: &mut I2c, settings: &FrequencySettings, input: Input, timer: GlobalTimer) -> Result<()> { let s = map_frequency_settings(settings)?; let cksel_reg = match input { Input::Ckin1 => 0b00, Input::Ckin2 => 0b01, }; - init(i2c)?; + init(i2c, timer)?; if settings.crystal_ref { rmw(i2c, 0, |v| v | 0x40)?; // FREE_RUN=1 } @@ -239,11 +240,11 @@ pub fn setup(i2c: &mut I2c, settings: &FrequencySettings, input: Input) -> Resul return Err("Si5324 misses clock input signal"); } - monitor_lock(i2c)?; + monitor_lock(i2c, timer)?; Ok(()) } -pub fn select_input(i2c: &mut I2c, input: Input) -> Result<()> { +pub fn select_input(i2c: &mut I2c, input: Input, timer: GlobalTimer) -> Result<()> { let cksel_reg = match input { Input::Ckin1 => 0b00, Input::Ckin2 => 0b01, @@ -252,6 +253,6 @@ pub fn select_input(i2c: &mut I2c, input: Input) -> Result<()> { if !has_ckin(i2c, input)? { return Err("Si5324 misses clock input signal"); } - monitor_lock(i2c)?; + monitor_lock(i2c, timer)?; Ok(()) } -- 2.42.0 From af693fc3a9ccb0a9d19dc2578b16c9a52b5cd13e Mon Sep 17 00:00:00 2001 From: mwojcik Date: Mon, 2 Aug 2021 12:12:58 +0200 Subject: [PATCH 2/5] si5324: added hard reset support for zc706 --- src/gateware/kasli_soc.py | 3 +++ src/gateware/zc706.py | 5 +++++ src/runtime/src/main.rs | 6 +++--- src/runtime/src/si5324.rs | 15 +++++++++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/gateware/kasli_soc.py b/src/gateware/kasli_soc.py index 3e26cb4..5226501 100755 --- a/src/gateware/kasli_soc.py +++ b/src/gateware/kasli_soc.py @@ -108,6 +108,9 @@ class GenericStandalone(SoCCore): platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]") platform.add_platform_command("set_input_jitter clk_fpga_0 0.24") + self.rustc_cfg["HAS_SI5324"] = None + self.rustc_cfg["SI5324_SOFT_RESET"] = None + self.crg = self.ps7 # HACK for eem_7series to find the clock self.submodules.rtio_crg = RTIOCRG(self.platform) self.csr_devices.append("rtio_crg") diff --git a/src/gateware/zc706.py b/src/gateware/zc706.py index 766cab5..f5005b9 100755 --- a/src/gateware/zc706.py +++ b/src/gateware/zc706.py @@ -11,6 +11,7 @@ from migen_axi.integration.soc_core import SoCCore from migen_axi.platforms import zc706 from misoc.interconnect.csr import * from misoc.integration import cpu_interface +from misoc.cores import gpio from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2 @@ -81,6 +82,10 @@ class ZC706(SoCCore): platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]") platform.add_platform_command("set_input_jitter clk_fpga_0 0.24") + self.config["HAS_SI5324"] = None + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) + self.csr_devices.append("si5324_rst_n") + self.submodules.rtio_crg = RTIOCRG(self.platform, self.ps7.cd_sys.clk) self.csr_devices.append("rtio_crg") self.rustc_cfg["has_rtio_crg_clock_sel"] = None diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index 55cee61..f59d2b9 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -45,7 +45,7 @@ mod mgmt; mod analyzer; mod irq; mod i2c; -#[cfg(feature = "target_kasli_soc")] +#[cfg(has_si5324)] mod si5324; fn init_gateware() { @@ -162,7 +162,7 @@ async fn report_async_rtio_errors() { } } -#[cfg(feature = "target_kasli_soc")] +#[cfg(has_si5324)] // 125MHz output, from crystal, 7 Hz const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings { @@ -199,7 +199,7 @@ pub fn main_core0() { info!("detected gateware: {}", identifier_read(&mut [0; 64])); i2c::init(); - #[cfg(feature = "target_kasli_soc")] + #[cfg(has_si5324)] si5324::setup(unsafe { (&mut i2c::I2C_BUS).as_mut().unwrap() }, &SI5324_SETTINGS, si5324::Input::Ckin2, timer).expect("cannot initialize Si5324"); diff --git a/src/runtime/src/si5324.rs b/src/runtime/src/si5324.rs index 3e20ec4..48ce207 100644 --- a/src/runtime/src/si5324.rs +++ b/src/runtime/src/si5324.rs @@ -2,11 +2,21 @@ use core::result; use log::info; use libboard_zynq::{i2c::I2c, timer::GlobalTimer, time::Milliseconds}; use embedded_hal::blocking::delay::DelayUs; +#[cfg(not(si5324_soft_reset))] +use pl::csr; type Result = result::Result; const ADDRESS: u8 = 0x68; +#[cfg(not(si5324_soft_reset))] +fn hard_reset(timer: GlobalTimer) { + unsafe { csr::si5324_rst_n::out_write(0); } + timer.delay_us(1_000); + unsafe { csr::si5324_rst_n::out_write(1); } + timer.delay_us(10_000); +} + // NOTE: the logical parameters DO NOT MAP to physical values written // into registers. They have to be mapped; see the datasheet. // DSPLLsim reports the logical parameters in the design summary, not @@ -135,6 +145,7 @@ fn ident(i2c: &mut I2c) -> Result { Ok(((read(i2c, 134)? as u16) << 8) | (read(i2c, 135)? as u16)) } +#[cfg(si5324_soft_reset)] fn soft_reset(i2c: &mut I2c, timer: GlobalTimer) -> Result<()> { write_no_ack_value(i2c, 136, read(i2c, 136)? | 0x80)?; timer.delay_us(10_000); @@ -170,6 +181,9 @@ fn monitor_lock(i2c: &mut I2c, timer: GlobalTimer) -> Result<()> { } fn init(i2c: &mut I2c, timer: GlobalTimer) -> Result<()> { + #[cfg(not(si5324_soft_reset))] + hard_reset(timer); + #[cfg(feature = "target_kasli_soc")] { i2c.pca9548_select(0x70, 0)?; @@ -180,6 +194,7 @@ fn init(i2c: &mut I2c, timer: GlobalTimer) -> Result<()> { return Err("Si5324 does not have expected product number"); } + #[cfg(si5324_soft_reset)] soft_reset(i2c, timer)?; Ok(()) } -- 2.42.0 From f70ce89ee6a271233b554e6f3cf3edaad55465b6 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Mon, 2 Aug 2021 15:05:27 +0200 Subject: [PATCH 3/5] si5324: added siphaser --- src/runtime/src/si5324.rs | 72 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/runtime/src/si5324.rs b/src/runtime/src/si5324.rs index 48ce207..dbd301d 100644 --- a/src/runtime/src/si5324.rs +++ b/src/runtime/src/si5324.rs @@ -271,3 +271,75 @@ pub fn select_input(i2c: &mut I2c, input: Input, timer: GlobalTimer) -> Result<( monitor_lock(i2c, timer)?; 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 { + 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(()) + } +} -- 2.42.0 From e3e51b5ab127bb2fa5b05839a7365bf55edaf450 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Mon, 2 Aug 2021 15:06:29 +0200 Subject: [PATCH 4/5] zc706 gateware: fix rust_cfg lacking has_si5324 --- src/gateware/zc706.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gateware/zc706.py b/src/gateware/zc706.py index f5005b9..071fa94 100755 --- a/src/gateware/zc706.py +++ b/src/gateware/zc706.py @@ -82,7 +82,7 @@ class ZC706(SoCCore): platform.add_platform_command("create_clock -name clk_fpga_0 -period 8 [get_pins \"PS7/FCLKCLK[0]\"]") platform.add_platform_command("set_input_jitter clk_fpga_0 0.24") - self.config["HAS_SI5324"] = None + self.rustc_cfg["HAS_SI5324"] = None self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) self.csr_devices.append("si5324_rst_n") -- 2.42.0 From 66b2063ae00cf8a3e726e4a5fc4bd51d23ef735b Mon Sep 17 00:00:00 2001 From: mwojcik Date: Tue, 3 Aug 2021 06:00:45 +0200 Subject: [PATCH 5/5] removed siphaser code, will be merged with drtio --- src/runtime/src/si5324.rs | 74 +-------------------------------------- 1 file changed, 1 insertion(+), 73 deletions(-) diff --git a/src/runtime/src/si5324.rs b/src/runtime/src/si5324.rs index dbd301d..f981c00 100644 --- a/src/runtime/src/si5324.rs +++ b/src/runtime/src/si5324.rs @@ -270,76 +270,4 @@ pub fn select_input(i2c: &mut I2c, input: Input, timer: GlobalTimer) -> Result<( } monitor_lock(i2c, timer)?; 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 { - 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(()) - } -} +} \ No newline at end of file -- 2.42.0