diff --git a/src/gateware/kasli_soc.py b/src/gateware/kasli_soc.py index bfd2c78..093541a 100755 --- a/src/gateware/kasli_soc.py +++ b/src/gateware/kasli_soc.py @@ -231,6 +231,7 @@ class GenericMaster(SoCCore): pads=data_pads, clk_freq=clk_freq) self.csr_devices.append("gt_drtio") + self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6) self.config["CLOCK_FREQUENCY"] = int(clk_freq) txout_buf = Signal() @@ -259,10 +260,17 @@ class GenericMaster(SoCCore): if with_wrpll: self.submodules.wrpll_refclk = wrpll.SMAFrequencyMultiplier(platform.request("sma_clkin")) - self.csr_devices.append("wrpll_refclk") - self.submodules.main_dcxo = si549.Si549(platform.request("ddmtd_main_dcxo_i2c")) + self.submodules.helper_dcxo = si549.Si549(platform.request("ddmtd_helper_dcxo_i2c")) + self.submodules.wrpll = wrpll.WRPLL( + cd_ref=self.wrpll_refclk.cd_ref, + main_dcxo_pads=platform.request("cdr_clk_clean_fabric"), + helper_dcxo_pads=platform.request("ddmtd_helper_clk")) + self.csr_devices.append("wrpll_refclk") self.csr_devices.append("main_dcxo") + self.csr_devices.append("helper_dcxo") + self.csr_devices.append("wrpll") + self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq) self.config["HAS_SI549"] = None self.config["WRPLL_REF_CLK"] = "SMA_CLKIN" else: @@ -612,7 +620,7 @@ def main(): help="build gateware into the specified directory") parser.add_argument("--acpki", default=False, action="store_true", help="enable ACPKI") - parser.add_argument("--with-wrpll", default=False, action="store_true", + parser.add_argument("--with-wrpll", default=True, action="store_true", help="enable WRPLL") parser.add_argument("description", metavar="DESCRIPTION", help="JSON system description file") diff --git a/src/gateware/wrpll.py b/src/gateware/wrpll.py index 205a1f1..f779bef 100644 --- a/src/gateware/wrpll.py +++ b/src/gateware/wrpll.py @@ -60,7 +60,7 @@ class WRPLL(Module, AutoCSR): # # # - self.helper_reset = CSRStorage(reset=1) + self.helper_reset = CSRStorage() self.clock_domains.cd_helper = ClockDomain() self.specials += [ Instance("IBUFGDS", @@ -131,6 +131,7 @@ class SMAFrequencyMultiplier(Module, AutoCSR): freq = 125e6 period = 1e9/freq # ns + sma_clkin_se = Signal() mmcm_locked = Signal() mmcm_fb_clk = Signal() ref_clk = Signal() @@ -150,6 +151,9 @@ class SMAFrequencyMultiplier(Module, AutoCSR): # # # self.specials += [ + Instance("IBUFDS", + i_I=sma_clkin.p, i_IB=sma_clkin.n, + o_O=sma_clkin_se), # MMCME2 is capable to accept 10Mhz input while PLLE2 only support down to 19Mhz input (DS191) Instance("MMCME2_ADV", p_BANDWIDTH="LOW", # lower jitter @@ -157,7 +161,7 @@ class SMAFrequencyMultiplier(Module, AutoCSR): i_RST=self.mmcm_reset.storage, p_CLKIN1_PERIOD=period, - i_CLKIN1=ClockSignal("sys"), + i_CLKIN1=sma_clkin_se, i_CLKINSEL=1, # 1=CLKIN1 0=CLKIN2 # VCO @ 1.25Ghz @@ -178,7 +182,4 @@ class SMAFrequencyMultiplier(Module, AutoCSR): ), Instance("BUFG", i_I=ref_clk, o_O=self.cd_ref.clk), AsyncResetSynchronizer(self.cd_ref, ~self.mmcm_locked.status), - - # debug output - Instance("OBUFDS", i_I=self.cd_ref.clk, o_O=sma_clkin.p, o_OB=sma_clkin.n) ] diff --git a/src/libboard_artiq/src/si549.rs b/src/libboard_artiq/src/si549.rs index b6fe28e..d6a732c 100644 --- a/src/libboard_artiq/src/si549.rs +++ b/src/libboard_artiq/src/si549.rs @@ -7,12 +7,14 @@ use crate::pl::csr; #[cfg(feature = "target_kasli_soc")] const ADDRESS: u8 = 0x67; +#[derive(Clone, Copy)] pub struct DividerConfig { pub hsdiv: u16, pub lsdiv: u8, pub fbdiv: u64, } +#[derive(Clone, Copy)] pub struct FrequencySetting { pub main: DividerConfig, #[cfg(has_wrpll)] @@ -272,6 +274,7 @@ pub fn main_setup(timer: &mut GlobalTimer, settings: FrequencySetting) -> Result #[cfg(has_wrpll)] pub mod wrpll { + use embedded_hal::blocking::delay::DelayMs; use libcortex_a9::mutex::Mutex; use super::*; @@ -376,6 +379,8 @@ pub mod wrpll { csr::helper_dcxo::bitbang_enable_write(0); } info!("Helper Si549 started"); + + timer.delay_ms(5_000); Ok(()) } @@ -446,12 +451,15 @@ pub mod wrpll { Ok(()) } - fn get_freq_counts(timer: &mut GlobalTimer) -> (u32, u32) { + pub fn get_freq_counts(timer: &mut GlobalTimer) -> (u32, u32) { unsafe { csr::wrpll::frequency_counter_update_en_write(1); timer.delay_us(150_000); // 8ns << TIMER_WIDTH csr::wrpll::frequency_counter_update_en_write(0); - let ref_count = csr::wrpll::frequency_counter_counter_gtx0_rtio_rx_read(); + #[cfg(wrpll_ref_clk = "GTX_CDR")] + let ref_count = csr::wrpll::frequency_counter_counter_rtio_rx0_read(); + #[cfg(wrpll_ref_clk = "SMA_CLKIN")] + let ref_count = csr::wrpll::frequency_counter_counter_ref_read(); let main_count = csr::wrpll::frequency_counter_counter_sys_read(); (ref_count, main_count) @@ -500,6 +508,21 @@ pub mod wrpll { } fn helper_pll() -> Result<(), &'static str> { + // unsafe { + // use libboard_zynq::println; + + // ERR_ARR[COUNTER] = tag_collector::get_period_error(); + + // if COUNTER == SIZE - 1 { + // for i in 0..SIZE { + // println!("{}", ERR_ARR[i]) + // } + // COUNTER = 0; + // let mut timer = GlobalTimer::get(); + // timer.delay_us(20_000_000); + // } + // COUNTER += 1; + // } let period_err = tag_collector::get_period_error(); let mut integrator_lock = H_INTEGRATOR.lock(); @@ -512,7 +535,29 @@ pub mod wrpll { Ok(()) } + const SIZE: usize = 2000; + static mut COUNTER: usize = 0; + static mut ERR_ARR: [i32; SIZE] = [0; SIZE]; + static mut FIN_ADPLL: i32 = 0; + fn main_pll() -> Result<(), &'static str> { + // unsafe { + // use libboard_zynq::println; + + // ERR_ARR[COUNTER] = tag_collector::get_phase_error(); + + // if COUNTER == SIZE - 1 { + // for i in 0..SIZE { + // println!("{}", ERR_ARR[i]) + // } + // println!("{:>3} Zero crossing adpll = {:>5}", SIZE, FIN_ADPLL); + // COUNTER = 0; + // let mut timer = GlobalTimer::get(); + // timer.delay_us(20_000_000); + // } + // COUNTER += 1; + // } + let phase_err = tag_collector::get_phase_error(); let mut integrator_lock = M_INTEGRATOR.lock(); @@ -522,6 +567,12 @@ pub mod wrpll { m_adpll = m_adpll.clamp(-ADPLL_MAX, ADPLL_MAX); set_adpll(i2c::DCXO::Main, m_adpll)?; + unsafe { + if ERR_ARR[COUNTER] == 0 { + FIN_ADPLL = m_adpll; + } + } + Ok(()) } @@ -532,18 +583,50 @@ pub mod wrpll { tag_collector::reset(); reset_plls().expect("failed to reset main and helper PLL"); - info!("warming up GTX CDR..."); - // gtx need a couple seconds for freq counter to read it properly - timer.delay_us(20_000_000); + info!("warming up refclk..."); + // refclk need a couple seconds for freq counter to read it properly + // timer.delay_us(20_000_000); set_base_adpll(timer).expect("failed to set base adpll"); + let ppm = 0.0; + *BASE_ADPLL.lock() += (ppm / 0.0001164) as i32; + timer.delay_us(200); + info!("KP = {}, KI = {}", KP, KI); + info!("adding {}ppm to main & helper base adpll ({})", ppm, *BASE_ADPLL.lock()); + // clear gateware pending flag clear_pending(FIQ::RefTag); clear_pending(FIQ::MainTag); + unsafe { + info!("ref tag = {} ", csr::wrpll::ref_tag_read()); + info!("main tag = {} ", csr::wrpll::main_tag_read()); + } + // use nFIQ to avoid IRQ being disabled by mutex lock and mess up PLL set_fiq(true); info!("WRPLL interrupt enabled"); + + timer.delay_ms(500); + unsafe { + info!("main_tag_ev_enable_read() = {}", csr::wrpll::main_tag_ev_enable_read()); + info!("main_tag_ev_status_read() = {}", csr::wrpll::main_tag_ev_status_read()); + info!("ref_tag_ev_enable_read() = {}", csr::wrpll::ref_tag_ev_enable_read()); + info!("ref_tag_ev_status_read() = {}", csr::wrpll::ref_tag_ev_status_read()); + + // loop { + // if is_pending(FIQ::RefTag) { + // info!("REF tag is pending") + // } + // if is_pending(FIQ::MainTag) { + // info!("Main tag is pending") + // } + + // // info!("ref tag = {} ", csr::wrpll::ref_tag_read()); + // // info!("main tag = {} ", csr::wrpll::main_tag_read()); + // timer.delay_ms(500); + // } + } } } } @@ -671,13 +754,25 @@ pub mod wrpll_refclk { if !locked { return Err("failed to generate 125Mhz ref clock from SMA CLKIN"); } + + // const TIMER_WIDTH: u32 = 24; + // const COUNTER_DIV: u32 = 2; + + // let (ref_count, main_count) = wrpll::get_freq_counts(timer); + + // let f_sys = 125e6; + + // info!( + // "ref counter = {} freq = {}", + // ref_count, + // (ref_count as f64 * f_sys) as f64 / (1 << (TIMER_WIDTH - COUNTER_DIV)) as f64 + // ); + // info!( + // "Main counter = {} freq = {}", + // main_count, + // (main_count as f64 * f_sys) as f64 / (1 << (TIMER_WIDTH - COUNTER_DIV)) as f64 + // ); + Ok(()) } - - pub fn setup(timer: &mut GlobalTimer) { - for addr in 7..12 { - info!("address = {:#x} | val = {:016b}", addr, mmcm::read(timer, addr)); - } - info!("running SMA PLL"); - } } diff --git a/src/runtime/src/rtio_clocking.rs b/src/runtime/src/rtio_clocking.rs index dbbe6fc..9af5044 100644 --- a/src/runtime/src/rtio_clocking.rs +++ b/src/runtime/src/rtio_clocking.rs @@ -6,6 +6,8 @@ use libboard_artiq::pl; use libboard_artiq::si5324; #[cfg(has_si549)] use libboard_artiq::si549; +#[cfg(has_wrpll)] +use libboard_artiq::si549::wrpll_refclk; #[cfg(has_si5324)] use libboard_zynq::i2c::I2c; use libboard_zynq::timer::GlobalTimer; @@ -262,46 +264,137 @@ fn setup_si5324(i2c: &mut I2c, timer: &mut GlobalTimer, clk: RtioClock) { si5324::setup(i2c, &si5324_settings, si5324_ref_input, timer).expect("cannot initialize Si5324"); } -#[cfg(has_si549)] -fn setup_si549(timer: &mut GlobalTimer, clk: RtioClock) { - let si549_settings = match clk { +#[cfg(has_wrpll)] +fn wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: si549::FrequencySetting) { + let mmcm_setting = match clk { + RtioClock::Ext0_Synth0_10to125 => si549::wrpll_refclk::MmcmSetting { + clkout0_reg1: 0x1083, + clkout0_reg2: 0x0080, + clkfbout_reg1: 0x179e, + clkfbout_reg2: 0x4c00, + div_reg: 0x1041, + lock_reg1: 0x00fa, + lock_reg2: 0x7c01, + lock_reg3: 0xffe9, + power_reg: 0x9900, + filt_reg1: 0x0808, + filt_reg2: 0x0800, + }, + RtioClock::Ext0_Synth0_80to125 => si549::wrpll_refclk::MmcmSetting { + clkout0_reg1: 0x1145, + clkout0_reg2: 0x0000, + clkfbout_reg1: 0x11c7, + clkfbout_reg2: 0x5880, + div_reg: 0x1041, + lock_reg1: 0x028a, + lock_reg2: 0x7c01, + lock_reg3: 0xffe9, + power_reg: 0x9900, + filt_reg1: 0x0808, + filt_reg2: 0x9800, + }, + RtioClock::Ext0_Synth0_100to125 => si549::wrpll_refclk::MmcmSetting { + clkout0_reg1: 0x1145, + clkout0_reg2: 0x0000, + clkfbout_reg1: 0x1145, + clkfbout_reg2: 0x4c00, + div_reg: 0x1041, + lock_reg1: 0x0339, + lock_reg2: 0x7c01, + lock_reg3: 0xffe9, + power_reg: 0x9900, + filt_reg1: 0x0808, + filt_reg2: 0x9800, + }, + RtioClock::Ext0_Synth0_125to125 => si549::wrpll_refclk::MmcmSetting { + clkout0_reg1: 0x1145, + clkout0_reg2: 0x0000, + clkfbout_reg1: 0x1145, + clkfbout_reg2: 0x0000, + div_reg: 0x1041, + lock_reg1: 0x03e8, + lock_reg2: 0x7001, + lock_reg3: 0xf3e9, + power_reg: 0x0100, + filt_reg1: 0x0808, + filt_reg2: 0x1100, + }, + _ => unreachable!(), + }; + + si549::main_setup(timer, si549_settings).expect("cannot initialize main Si549"); + si549::wrpll::helper_setup(timer, si549_settings).expect("cannot initialize helper Si549"); + + si549::wrpll_refclk::setup(timer, mmcm_setting).expect("cannot initialize ref clk for wrpll"); + // si549::wrpll::select_recovered_clock(true, timer); +} + +fn get_si549_setting(clk: RtioClock) -> si549::FrequencySetting { + match clk { + RtioClock::Ext0_Synth0_10to125 => { + info!("using 10MHz reference to make 125MHz RTIO clock with WRPLL"); + } + RtioClock::Ext0_Synth0_80to125 => { + info!("using 80MHz reference to make 125MHz RTIO clock with WRPLL"); + } + RtioClock::Ext0_Synth0_100to125 => { + info!("using 100MHz reference to make 125MHz RTIO clock with WRPLL"); + } + RtioClock::Ext0_Synth0_125to125 => { + info!("using 125MHz reference to make 125MHz RTIO clock with WRPLL"); + } + RtioClock::Int_150 => { + info!("using internal 150MHz RTIO clock"); + } RtioClock::Int_100 => { info!("using internal 100MHz RTIO clock"); + } + RtioClock::Int_125 => { + info!("using internal 125MHz RTIO clock"); + } + _ => { + warn!( + "rtio_clock setting '{:?}' is unsupported. Falling back to default internal 125MHz RTIO clock.", + clk + ); + } + }; + + match clk { + RtioClock::Int_100 => { si549::FrequencySetting { main: si549::DividerConfig { hsdiv: 0x06C, lsdiv: 0, fbdiv: 0x046C5F49797, }, - } - } - RtioClock::Int_125 => { - info!("using internal 125MHz RTIO clock"); - si549::FrequencySetting { - main: si549::DividerConfig { - hsdiv: 0x058, + #[cfg(has_wrpll)] + helper: si549::DividerConfig { + // 100Mhz*32767/32768 + hsdiv: 0x06C, lsdiv: 0, - fbdiv: 0x04815791F25, + fbdiv: 0x046C5670BBD, }, } } _ => { - // same setting as Int_125, but fallback to default - warn!( - "rtio_clock setting '{:?}' is unsupported. Falling back to default 125MHz RTIO clock.", - clk - ); + // Everything else use 125Mhz si549::FrequencySetting { main: si549::DividerConfig { hsdiv: 0x058, lsdiv: 0, fbdiv: 0x04815791F25, }, + #[cfg(has_wrpll)] + helper: si549::DividerConfig { + // 125Mhz*32767/32768 + hsdiv: 0x058, + lsdiv: 0, + fbdiv: 0x04814E8F442, + }, } } - }; - - si549::main_setup(timer, si549_settings).expect("cannot initialize main Si549"); + } } pub fn init(timer: &mut GlobalTimer, cfg: &Config) { @@ -317,10 +410,23 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) { _ => setup_si5324(i2c, timer, clk), } } + #[cfg(has_si549)] { - si549::sma_pll::setup(timer); - setup_si549(timer, clk); + let si549_settings = get_si549_setting(clk); + + match clk { + RtioClock::Ext0_Synth0_10to125 + | RtioClock::Ext0_Synth0_80to125 + | RtioClock::Ext0_Synth0_100to125 + | RtioClock::Ext0_Synth0_125to125 => { + wrpll_setup(timer, clk, si549_settings); + } + _ => { + wrpll_setup(timer, RtioClock::Ext0_Synth0_125to125, si549_settings); + // si549::main_setup(timer, si549_settings).expect("cannot initialize main Si549"); + } + } } #[cfg(has_drtio)] @@ -328,4 +434,9 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) { #[cfg(not(has_drtio))] init_rtio(timer); + + // no error here :v hmmm... + // !! sys clock need to switch for freq_counter to work properly + // !! helper reset after sys clock switch :V -> not ddmtd at all + si549::wrpll::select_recovered_clock(true, timer); }