FIQ_issue

This commit is contained in:
morgan 2024-03-04 12:03:53 +08:00
parent f8f6dcef14
commit adaecf87a8
5 changed files with 255 additions and 41 deletions

View File

@ -231,6 +231,7 @@ class GenericMaster(SoCCore):
pads=data_pads, pads=data_pads,
clk_freq=clk_freq) clk_freq=clk_freq)
self.csr_devices.append("gt_drtio") self.csr_devices.append("gt_drtio")
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
self.config["CLOCK_FREQUENCY"] = int(clk_freq) self.config["CLOCK_FREQUENCY"] = int(clk_freq)
txout_buf = Signal() txout_buf = Signal()
@ -259,10 +260,17 @@ class GenericMaster(SoCCore):
if with_wrpll: if with_wrpll:
self.submodules.wrpll_refclk = wrpll.SMAFrequencyMultiplier(platform.request("sma_clkin")) 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.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("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["HAS_SI549"] = None
self.config["WRPLL_REF_CLK"] = "SMA_CLKIN" self.config["WRPLL_REF_CLK"] = "SMA_CLKIN"
else: else:
@ -612,7 +620,7 @@ def main():
help="build gateware into the specified directory") help="build gateware into the specified directory")
parser.add_argument("--acpki", default=False, action="store_true", parser.add_argument("--acpki", default=False, action="store_true",
help="enable ACPKI") 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") help="enable WRPLL")
parser.add_argument("description", metavar="DESCRIPTION", parser.add_argument("description", metavar="DESCRIPTION",
help="JSON system description file") help="JSON system description file")

View File

@ -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.clock_domains.cd_helper = ClockDomain()
self.specials += [ self.specials += [
Instance("IBUFGDS", Instance("IBUFGDS",
@ -131,6 +131,7 @@ class SMAFrequencyMultiplier(Module, AutoCSR):
freq = 125e6 freq = 125e6
period = 1e9/freq # ns period = 1e9/freq # ns
sma_clkin_se = Signal()
mmcm_locked = Signal() mmcm_locked = Signal()
mmcm_fb_clk = Signal() mmcm_fb_clk = Signal()
ref_clk = Signal() ref_clk = Signal()
@ -150,6 +151,9 @@ class SMAFrequencyMultiplier(Module, AutoCSR):
# # # # # #
self.specials += [ 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) # MMCME2 is capable to accept 10Mhz input while PLLE2 only support down to 19Mhz input (DS191)
Instance("MMCME2_ADV", Instance("MMCME2_ADV",
p_BANDWIDTH="LOW", # lower jitter p_BANDWIDTH="LOW", # lower jitter
@ -157,7 +161,7 @@ class SMAFrequencyMultiplier(Module, AutoCSR):
i_RST=self.mmcm_reset.storage, i_RST=self.mmcm_reset.storage,
p_CLKIN1_PERIOD=period, p_CLKIN1_PERIOD=period,
i_CLKIN1=ClockSignal("sys"), i_CLKIN1=sma_clkin_se,
i_CLKINSEL=1, # 1=CLKIN1 0=CLKIN2 i_CLKINSEL=1, # 1=CLKIN1 0=CLKIN2
# VCO @ 1.25Ghz # VCO @ 1.25Ghz
@ -178,7 +182,4 @@ class SMAFrequencyMultiplier(Module, AutoCSR):
), ),
Instance("BUFG", i_I=ref_clk, o_O=self.cd_ref.clk), Instance("BUFG", i_I=ref_clk, o_O=self.cd_ref.clk),
AsyncResetSynchronizer(self.cd_ref, ~self.mmcm_locked.status), 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)
] ]

View File

@ -7,12 +7,14 @@ use crate::pl::csr;
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
const ADDRESS: u8 = 0x67; const ADDRESS: u8 = 0x67;
#[derive(Clone, Copy)]
pub struct DividerConfig { pub struct DividerConfig {
pub hsdiv: u16, pub hsdiv: u16,
pub lsdiv: u8, pub lsdiv: u8,
pub fbdiv: u64, pub fbdiv: u64,
} }
#[derive(Clone, Copy)]
pub struct FrequencySetting { pub struct FrequencySetting {
pub main: DividerConfig, pub main: DividerConfig,
#[cfg(has_wrpll)] #[cfg(has_wrpll)]
@ -272,6 +274,7 @@ pub fn main_setup(timer: &mut GlobalTimer, settings: FrequencySetting) -> Result
#[cfg(has_wrpll)] #[cfg(has_wrpll)]
pub mod wrpll { pub mod wrpll {
use embedded_hal::blocking::delay::DelayMs;
use libcortex_a9::mutex::Mutex; use libcortex_a9::mutex::Mutex;
use super::*; use super::*;
@ -376,6 +379,8 @@ pub mod wrpll {
csr::helper_dcxo::bitbang_enable_write(0); csr::helper_dcxo::bitbang_enable_write(0);
} }
info!("Helper Si549 started"); info!("Helper Si549 started");
timer.delay_ms(5_000);
Ok(()) Ok(())
} }
@ -446,12 +451,15 @@ pub mod wrpll {
Ok(()) Ok(())
} }
fn get_freq_counts(timer: &mut GlobalTimer) -> (u32, u32) { pub fn get_freq_counts(timer: &mut GlobalTimer) -> (u32, u32) {
unsafe { unsafe {
csr::wrpll::frequency_counter_update_en_write(1); csr::wrpll::frequency_counter_update_en_write(1);
timer.delay_us(150_000); // 8ns << TIMER_WIDTH timer.delay_us(150_000); // 8ns << TIMER_WIDTH
csr::wrpll::frequency_counter_update_en_write(0); 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(); let main_count = csr::wrpll::frequency_counter_counter_sys_read();
(ref_count, main_count) (ref_count, main_count)
@ -500,6 +508,21 @@ pub mod wrpll {
} }
fn helper_pll() -> Result<(), &'static str> { 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 period_err = tag_collector::get_period_error();
let mut integrator_lock = H_INTEGRATOR.lock(); let mut integrator_lock = H_INTEGRATOR.lock();
@ -512,7 +535,29 @@ pub mod wrpll {
Ok(()) 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> { 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 phase_err = tag_collector::get_phase_error();
let mut integrator_lock = M_INTEGRATOR.lock(); let mut integrator_lock = M_INTEGRATOR.lock();
@ -522,6 +567,12 @@ pub mod wrpll {
m_adpll = m_adpll.clamp(-ADPLL_MAX, ADPLL_MAX); m_adpll = m_adpll.clamp(-ADPLL_MAX, ADPLL_MAX);
set_adpll(i2c::DCXO::Main, m_adpll)?; set_adpll(i2c::DCXO::Main, m_adpll)?;
unsafe {
if ERR_ARR[COUNTER] == 0 {
FIN_ADPLL = m_adpll;
}
}
Ok(()) Ok(())
} }
@ -532,18 +583,50 @@ pub mod wrpll {
tag_collector::reset(); tag_collector::reset();
reset_plls().expect("failed to reset main and helper PLL"); reset_plls().expect("failed to reset main and helper PLL");
info!("warming up GTX CDR..."); info!("warming up refclk...");
// gtx need a couple seconds for freq counter to read it properly // refclk need a couple seconds for freq counter to read it properly
timer.delay_us(20_000_000); // timer.delay_us(20_000_000);
set_base_adpll(timer).expect("failed to set base adpll"); 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 gateware pending flag
clear_pending(FIQ::RefTag); clear_pending(FIQ::RefTag);
clear_pending(FIQ::MainTag); 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 // use nFIQ to avoid IRQ being disabled by mutex lock and mess up PLL
set_fiq(true); set_fiq(true);
info!("WRPLL interrupt enabled"); 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 { if !locked {
return Err("failed to generate 125Mhz ref clock from SMA CLKIN"); 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(()) 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");
}
} }

View File

@ -5,6 +5,7 @@ use libcortex_a9::{interrupt_handler, regs::MPIDR};
use libregister::RegisterR; use libregister::RegisterR;
interrupt_handler!(FIQ, fiq, __irq_stack0_start, __irq_stack1_start, { interrupt_handler!(FIQ, fiq, __irq_stack0_start, __irq_stack1_start, {
// println!("hello?");
match MPIDR.read().cpu_id() { match MPIDR.read().cpu_id() {
0 => { 0 => {
// nFIQ is driven directly and bypass GIC // nFIQ is driven directly and bypass GIC

View File

@ -6,6 +6,8 @@ use libboard_artiq::pl;
use libboard_artiq::si5324; use libboard_artiq::si5324;
#[cfg(has_si549)] #[cfg(has_si549)]
use libboard_artiq::si549; use libboard_artiq::si549;
#[cfg(has_wrpll)]
use libboard_artiq::si549::wrpll_refclk;
#[cfg(has_si5324)] #[cfg(has_si5324)]
use libboard_zynq::i2c::I2c; use libboard_zynq::i2c::I2c;
use libboard_zynq::timer::GlobalTimer; 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"); si5324::setup(i2c, &si5324_settings, si5324_ref_input, timer).expect("cannot initialize Si5324");
} }
#[cfg(has_si549)] #[cfg(has_wrpll)]
fn setup_si549(timer: &mut GlobalTimer, clk: RtioClock) { fn wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: si549::FrequencySetting) {
let si549_settings = match clk { 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 => { RtioClock::Int_100 => {
info!("using internal 100MHz RTIO clock"); 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 { si549::FrequencySetting {
main: si549::DividerConfig { main: si549::DividerConfig {
hsdiv: 0x06C, hsdiv: 0x06C,
lsdiv: 0, lsdiv: 0,
fbdiv: 0x046C5F49797, fbdiv: 0x046C5F49797,
}, },
} #[cfg(has_wrpll)]
} helper: si549::DividerConfig {
RtioClock::Int_125 => { // 100Mhz*32767/32768
info!("using internal 125MHz RTIO clock"); hsdiv: 0x06C,
si549::FrequencySetting {
main: si549::DividerConfig {
hsdiv: 0x058,
lsdiv: 0, lsdiv: 0,
fbdiv: 0x04815791F25, fbdiv: 0x046C5670BBD,
}, },
} }
} }
_ => { _ => {
// same setting as Int_125, but fallback to default // Everything else use 125Mhz
warn!(
"rtio_clock setting '{:?}' is unsupported. Falling back to default 125MHz RTIO clock.",
clk
);
si549::FrequencySetting { si549::FrequencySetting {
main: si549::DividerConfig { main: si549::DividerConfig {
hsdiv: 0x058, hsdiv: 0x058,
lsdiv: 0, lsdiv: 0,
fbdiv: 0x04815791F25, 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) { 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), _ => setup_si5324(i2c, timer, clk),
} }
} }
#[cfg(has_si549)] #[cfg(has_si549)]
{ {
si549::sma_pll::setup(timer); let si549_settings = get_si549_setting(clk);
setup_si549(timer, 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)] #[cfg(has_drtio)]
@ -328,4 +434,7 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
#[cfg(not(has_drtio))] #[cfg(not(has_drtio))]
init_rtio(timer); init_rtio(timer);
// !! move back to cfg after testing
si549::wrpll::select_recovered_clock(true, timer);
} }