Compare commits
4 Commits
0a4c34b1f2
...
7dc57dc24e
Author | SHA1 | Date |
---|---|---|
morgan | 7dc57dc24e | |
morgan | 6a47c2fcf2 | |
morgan | b9251c0b26 | |
morgan | c761958816 |
|
@ -31,7 +31,7 @@ class DDMTDSamplerGTX(Module):
|
|||
|
||||
|
||||
class DDMTDDeglitcherFirstEdge(Module):
|
||||
def __init__(self, input_signal, blind_period=128):
|
||||
def __init__(self, input_signal, blind_period=200):
|
||||
self.detect = Signal()
|
||||
rising = Signal()
|
||||
input_signal_r = Signal()
|
||||
|
@ -70,87 +70,3 @@ class DDMTD(Module):
|
|||
self.h_tag.eq(counter)
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
class Collector(Module):
|
||||
"""
|
||||
A phase and period collector for DDMTD
|
||||
"""
|
||||
|
||||
def __init__(self, N):
|
||||
|
||||
self.gtx_stb = Signal()
|
||||
self.main_stb = Signal()
|
||||
self.tag_gtx = Signal(N)
|
||||
self.tag_main = Signal(N)
|
||||
|
||||
self.out_period_stb = Signal()
|
||||
self.out_beating_period = Signal(N)
|
||||
last_gtx_tag = Signal(N)
|
||||
beating_period_r = Signal(N)
|
||||
|
||||
self.out_phase_stb = Signal()
|
||||
self.out_tag_gtx = Signal(N)
|
||||
self.out_tag_main = Signal(N)
|
||||
tag_gtx_r = Signal(N)
|
||||
tag_main_r = Signal(N)
|
||||
|
||||
# # #
|
||||
|
||||
# Period collector
|
||||
# collect the difference between each gtx tags
|
||||
|
||||
self.submodules.period_colr_fsm = period_colr_fsm = FSM(reset_state="IDLE")
|
||||
|
||||
period_colr_fsm.act("IDLE",
|
||||
NextValue(self.out_period_stb, 0),
|
||||
If(self.gtx_stb,
|
||||
NextValue(beating_period_r, self.tag_gtx - last_gtx_tag),
|
||||
NextValue(last_gtx_tag, self.tag_gtx),
|
||||
NextState("OUTPUT")
|
||||
)
|
||||
)
|
||||
period_colr_fsm.act("OUTPUT",
|
||||
NextValue(self.out_beating_period, beating_period_r),
|
||||
NextValue(self.out_period_stb, 1),
|
||||
NextState("IDLE")
|
||||
)
|
||||
|
||||
|
||||
# Phase collector
|
||||
# collect main and gtx tag
|
||||
|
||||
self.submodules.phase_colr_fsm = phase_colr_fsm = FSM(reset_state="IDLE")
|
||||
|
||||
phase_colr_fsm.act("IDLE",
|
||||
NextValue(self.out_phase_stb, 0),
|
||||
If(self.gtx_stb & self.main_stb,
|
||||
NextValue(tag_gtx_r, self.tag_gtx),
|
||||
NextValue(tag_main_r, self.tag_main),
|
||||
NextState("OUTPUT")
|
||||
).Elif(self.gtx_stb,
|
||||
NextValue(tag_gtx_r, self.tag_gtx),
|
||||
NextState("WAITMAIN")
|
||||
).Elif(self.main_stb,
|
||||
NextValue(tag_main_r, self.tag_main),
|
||||
NextState("WAITGTX")
|
||||
)
|
||||
)
|
||||
phase_colr_fsm.act("WAITGTX",
|
||||
If(self.gtx_stb,
|
||||
NextValue(tag_gtx_r, self.tag_gtx),
|
||||
NextState("OUTPUT")
|
||||
)
|
||||
)
|
||||
phase_colr_fsm.act("WAITMAIN",
|
||||
If(self.main_stb,
|
||||
NextValue(tag_main_r, self.tag_main),
|
||||
NextState("OUTPUT")
|
||||
)
|
||||
)
|
||||
phase_colr_fsm.act("OUTPUT",
|
||||
NextValue(self.out_tag_gtx, tag_gtx_r),
|
||||
NextValue(self.out_tag_main, tag_main_r),
|
||||
NextValue(self.out_phase_stb, 1),
|
||||
NextState("IDLE")
|
||||
)
|
|
@ -107,7 +107,7 @@ class GTPBootstrapClock(Module):
|
|||
|
||||
|
||||
class GenericStandalone(SoCCore):
|
||||
def __init__(self, description, acpki=False, si5324=False):
|
||||
def __init__(self, description, acpki=False, with_wrpll=False):
|
||||
self.acpki = acpki
|
||||
clk_freq = description["rtio_frequency"]
|
||||
|
||||
|
@ -207,7 +207,7 @@ class GenericStandalone(SoCCore):
|
|||
|
||||
|
||||
class GenericMaster(SoCCore):
|
||||
def __init__(self, description, acpki=False, si5324=False):
|
||||
def __init__(self, description, acpki=False, with_wrpll=False):
|
||||
clk_freq = description["rtio_frequency"]
|
||||
|
||||
has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"])
|
||||
|
@ -400,7 +400,7 @@ class GenericMaster(SoCCore):
|
|||
|
||||
|
||||
class GenericSatellite(SoCCore):
|
||||
def __init__(self, description, acpki=False, si5324=False):
|
||||
def __init__(self, description, acpki=False, with_wrpll=False):
|
||||
clk_freq = description["rtio_frequency"]
|
||||
|
||||
self.acpki = acpki
|
||||
|
@ -553,16 +553,7 @@ class GenericSatellite(SoCCore):
|
|||
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
|
||||
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
|
||||
|
||||
if si5324:
|
||||
self.submodules.siphaser = SiPhaser7Series(
|
||||
si5324_clkin=platform.request("cdr_clk"),
|
||||
rx_synchronizer=self.rx_synchronizer,
|
||||
ultrascale=False,
|
||||
rtio_clk_freq=self.gt_drtio.rtio_clk_freq)
|
||||
self.csr_devices.append("siphaser")
|
||||
self.config["HAS_SI5324"] = None
|
||||
self.config["SI5324_SOFT_RESET"] = None
|
||||
else:
|
||||
if with_wrpll:
|
||||
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(
|
||||
|
@ -573,10 +564,19 @@ class GenericSatellite(SoCCore):
|
|||
self.csr_devices.append("helper_dcxo")
|
||||
self.csr_devices.append("wrpll")
|
||||
self.comb += [
|
||||
self.ps7.interrupt[0].eq(self.wrpll.period_ev.irq), # IRQ_ID = 61
|
||||
self.ps7.interrupt[1].eq(self.wrpll.phase_ev.irq) # IRQ_ID = 62
|
||||
self.ps7.interrupt[0].eq(self.wrpll.gtx_tag_ev.irq), # IRQ_ID = 61
|
||||
self.ps7.interrupt[1].eq(self.wrpll.main_tag_ev.irq) # IRQ_ID = 62
|
||||
]
|
||||
self.config["HAS_SI549"] = None
|
||||
else:
|
||||
self.submodules.siphaser = SiPhaser7Series(
|
||||
si5324_clkin=platform.request("cdr_clk"),
|
||||
rx_synchronizer=self.rx_synchronizer,
|
||||
ultrascale=False,
|
||||
rtio_clk_freq=self.gt_drtio.rtio_clk_freq)
|
||||
self.csr_devices.append("siphaser")
|
||||
self.config["HAS_SI5324"] = None
|
||||
self.config["SI5324_SOFT_RESET"] = None
|
||||
|
||||
gtx0 = self.gt_drtio.gtxs[0]
|
||||
platform.add_false_path_constraints(
|
||||
|
@ -606,8 +606,8 @@ def main():
|
|||
help="build gateware into the specified directory")
|
||||
parser.add_argument("--acpki", default=False, action="store_true",
|
||||
help="enable ACPKI")
|
||||
parser.add_argument("--si5324", default=False, action="store_true",
|
||||
help="use si5324 over si549")
|
||||
parser.add_argument("--with-wrpll", default=False, action="store_true",
|
||||
help="enable WRPLL")
|
||||
parser.add_argument("description", metavar="DESCRIPTION",
|
||||
help="JSON system description file")
|
||||
args = parser.parse_args()
|
||||
|
@ -625,7 +625,7 @@ def main():
|
|||
else:
|
||||
raise ValueError("Invalid DRTIO role")
|
||||
|
||||
soc = cls(description, acpki=args.acpki, si5324=args.si5324)
|
||||
soc = cls(description, acpki=args.acpki, with_wrpll=args.with_wrpll)
|
||||
soc.finalize()
|
||||
|
||||
if args.r is not None:
|
||||
|
|
|
@ -3,7 +3,7 @@ from migen.genlib.cdc import MultiReg, AsyncResetSynchronizer, PulseSynchronizer
|
|||
from misoc.interconnect.csr import *
|
||||
from misoc.interconnect.csr_eventmanager import *
|
||||
|
||||
from ddmtd import DDMTDSamplerGTX, DDMTD, Collector
|
||||
from ddmtd import DDMTDSamplerGTX, DDMTD
|
||||
|
||||
|
||||
class FrequencyCounter(Module, AutoCSR):
|
||||
|
@ -49,18 +49,15 @@ class FrequencyCounter(Module, AutoCSR):
|
|||
class WRPLL(Module, AutoCSR):
|
||||
def __init__(self, gtx, main_dcxo_pads, helper_dcxo_pads, COUNTER_BIT=32):
|
||||
|
||||
self.gtx_period = CSRStatus(COUNTER_BIT)
|
||||
self.gtx_tag = CSRStatus(COUNTER_BIT)
|
||||
self.main_tag = CSRStatus(COUNTER_BIT)
|
||||
|
||||
ddmtd_counter = Signal(COUNTER_BIT)
|
||||
|
||||
gtx_period_sys = Signal(COUNTER_BIT)
|
||||
gtx_tag_sys = Signal(COUNTER_BIT)
|
||||
main_tag_sys = Signal(COUNTER_BIT)
|
||||
|
||||
period_colr_stb_sys = Signal()
|
||||
phase_colr_stb_sys = Signal()
|
||||
gtx_tag_stb_sys = Signal()
|
||||
main_tag_stb_sys = Signal()
|
||||
|
||||
# # #
|
||||
|
||||
|
@ -84,57 +81,46 @@ class WRPLL(Module, AutoCSR):
|
|||
|
||||
# DDMTD tags collection
|
||||
|
||||
self.submodules.collector = ClockDomainsRenamer("helper")(Collector(COUNTER_BIT))
|
||||
|
||||
self.comb += [
|
||||
self.collector.gtx_stb.eq(self.ddmtd_gtx.h_tag_update),
|
||||
self.collector.main_stb.eq(self.ddmtd_main.h_tag_update),
|
||||
self.collector.tag_gtx.eq(self.ddmtd_gtx.h_tag),
|
||||
self.collector.tag_main.eq(self.ddmtd_main.h_tag)
|
||||
self.specials += [
|
||||
MultiReg(self.ddmtd_gtx.h_tag, gtx_tag_sys),
|
||||
MultiReg(self.ddmtd_main.h_tag, main_tag_sys)
|
||||
]
|
||||
|
||||
period_colr_stb_ps = PulseSynchronizer("helper", "sys")
|
||||
phase_colr_stb_ps = PulseSynchronizer("helper", "sys")
|
||||
gtx_tag_stb_ps = PulseSynchronizer("helper", "sys")
|
||||
main_tag_stb_ps = PulseSynchronizer("helper", "sys")
|
||||
self.submodules += [
|
||||
period_colr_stb_ps,
|
||||
phase_colr_stb_ps
|
||||
gtx_tag_stb_ps,
|
||||
main_tag_stb_ps
|
||||
]
|
||||
self.sync.helper += [
|
||||
period_colr_stb_ps.i.eq(self.collector.out_period_stb),
|
||||
phase_colr_stb_ps.i.eq(self.collector.out_phase_stb)
|
||||
gtx_tag_stb_ps.i.eq(self.ddmtd_gtx.h_tag_update),
|
||||
main_tag_stb_ps.i.eq(self.ddmtd_main.h_tag_update)
|
||||
]
|
||||
self.sync += [
|
||||
period_colr_stb_sys.eq(period_colr_stb_ps.o),
|
||||
phase_colr_stb_sys.eq(phase_colr_stb_ps.o)
|
||||
]
|
||||
|
||||
self.specials += [
|
||||
MultiReg(self.collector.out_beating_period, gtx_period_sys),
|
||||
MultiReg(self.collector.out_tag_gtx, gtx_tag_sys),
|
||||
MultiReg(self.collector.out_tag_main, main_tag_sys)
|
||||
gtx_tag_stb_sys.eq(gtx_tag_stb_ps.o),
|
||||
main_tag_stb_sys.eq(main_tag_stb_ps.o)
|
||||
]
|
||||
|
||||
self.sync += [
|
||||
If(period_colr_stb_sys,
|
||||
self.gtx_period.status.eq(gtx_period_sys),
|
||||
),
|
||||
If(phase_colr_stb_sys,
|
||||
If(gtx_tag_stb_sys,
|
||||
self.gtx_tag.status.eq(gtx_tag_sys),
|
||||
),
|
||||
If(main_tag_stb_sys,
|
||||
self.main_tag.status.eq(main_tag_sys)
|
||||
)
|
||||
]
|
||||
|
||||
# PL-PS shared peripheral interrupt (SPI)
|
||||
|
||||
self.submodules.period_ev = EventManager()
|
||||
self.period_ev.stb = EventSourcePulse()
|
||||
self.period_ev.finalize()
|
||||
self.submodules.gtx_tag_ev = EventManager()
|
||||
self.gtx_tag_ev.stb = EventSourcePulse()
|
||||
self.gtx_tag_ev.finalize()
|
||||
|
||||
self.submodules.phase_ev = EventManager()
|
||||
self.phase_ev.stb = EventSourcePulse()
|
||||
self.phase_ev.finalize()
|
||||
self.submodules.main_tag_ev = EventManager()
|
||||
self.main_tag_ev.stb = EventSourcePulse()
|
||||
self.main_tag_ev.finalize()
|
||||
|
||||
self.sync += [
|
||||
self.period_ev.stb.trigger.eq(period_colr_stb_sys),
|
||||
self.phase_ev.stb.trigger.eq(phase_colr_stb_sys)
|
||||
self.gtx_tag_ev.stb.trigger.eq(gtx_tag_stb_sys),
|
||||
self.main_tag_ev.stb.trigger.eq(main_tag_stb_sys)
|
||||
]
|
||||
|
|
|
@ -12,11 +12,6 @@ struct Registers {
|
|||
gpiob: u8, // Output Port 1
|
||||
}
|
||||
|
||||
#[cfg(has_si549)]
|
||||
const USE_SI549: u8 = 0xFF;
|
||||
#[cfg(has_si5324)]
|
||||
const USE_SI549: u8 = 0x00;
|
||||
|
||||
//IO expanders pins
|
||||
const IODIR_OUT_SFP_TX_DISABLE: u8 = 0x02;
|
||||
const IODIR_OUT_SFP_LED: u8 = 0x40;
|
||||
|
@ -24,12 +19,15 @@ const IODIR_OUT_SFP_LED: u8 = 0x40;
|
|||
const IODIR_OUT_SFP0_LED: u8 = 0x40;
|
||||
#[cfg(hw_rev = "v1.1")]
|
||||
const IODIR_OUT_SFP0_LED: u8 = 0x80;
|
||||
const IODIR_OUT_CLK_SEL: u8 = 0x80;
|
||||
#[cfg(has_si549)]
|
||||
const IODIR_CLK_SEL: u8 = 0x80; // out
|
||||
#[cfg(has_si5324)]
|
||||
const IODIR_CLK_SEL: u8 = 0x00; // in
|
||||
|
||||
//IO expander port direction
|
||||
const IODIR0: [u8; 2] = [
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP0_LED,
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED & !(IODIR_OUT_CLK_SEL & USE_SI549),
|
||||
0xFF & !IODIR_OUT_SFP_TX_DISABLE & !IODIR_OUT_SFP_LED & !IODIR_CLK_SEL,
|
||||
];
|
||||
|
||||
const IODIR1: [u8; 2] = [
|
||||
|
|
|
@ -12,7 +12,7 @@ const ADDRESS: u8 = 0x67;
|
|||
mod i2c {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum DCXO {
|
||||
Main,
|
||||
#[cfg(has_wrpll)]
|
||||
|
@ -287,6 +287,7 @@ pub fn main_setup(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
|||
|
||||
#[cfg(has_wrpll)]
|
||||
pub mod wrpll {
|
||||
|
||||
use libboard_zynq::gic;
|
||||
|
||||
use super::*;
|
||||
|
@ -296,13 +297,107 @@ pub mod wrpll {
|
|||
const TIMER_WIDTH: u32 = 24;
|
||||
const COUNTER_DIV: u32 = 2;
|
||||
|
||||
const BEATING_PERIOD: i32 = 0x4000;
|
||||
const BEATING_HALFPERIOD: i32 = 0x2000;
|
||||
|
||||
const ADPLL_MAX: i32 = (950.0 / 0.0001164) as i32;
|
||||
|
||||
static mut BASE_ADPLL: i32 = 0;
|
||||
static mut H_INTEGRATOR: i32 = 0;
|
||||
static mut M_INTEGRATOR: i32 = 0;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum IRQ {
|
||||
GTXTag,
|
||||
MainTag,
|
||||
}
|
||||
|
||||
mod tag_collector {
|
||||
use super::IRQ;
|
||||
use crate::pl::csr;
|
||||
|
||||
const BEATING_PERIOD: i32 = 0x4000;
|
||||
const BEATING_HALFPERIOD: i32 = 0x2000;
|
||||
|
||||
// for helper PLL
|
||||
static mut LAST_GTX_TAG: u32 = 0;
|
||||
static mut FIRST_GTX_INTERRUPT: bool = true;
|
||||
static mut PERIOD_DET_READY: bool = false;
|
||||
|
||||
// for main PLL
|
||||
static mut GTX_TAG: u32 = 0;
|
||||
static mut GTX_TAG_READY: bool = false;
|
||||
static mut MAIN_TAG: u32 = 0;
|
||||
static mut MAIN_TAG_READY: bool = false;
|
||||
|
||||
pub fn reset() {
|
||||
clear_period_det_ready();
|
||||
clear_phase_det_ready();
|
||||
unsafe {
|
||||
LAST_GTX_TAG = 0;
|
||||
FIRST_GTX_INTERRUPT = true;
|
||||
GTX_TAG = 0;
|
||||
MAIN_TAG = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_period_det_ready() {
|
||||
unsafe {
|
||||
PERIOD_DET_READY = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_phase_det_ready() {
|
||||
unsafe {
|
||||
GTX_TAG_READY = false;
|
||||
MAIN_TAG_READY = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collect_tags(interrupt: IRQ) {
|
||||
match interrupt {
|
||||
IRQ::GTXTag => unsafe {
|
||||
if !FIRST_GTX_INTERRUPT {
|
||||
LAST_GTX_TAG = GTX_TAG;
|
||||
PERIOD_DET_READY = true;
|
||||
}
|
||||
|
||||
GTX_TAG = csr::wrpll::gtx_tag_read();
|
||||
FIRST_GTX_INTERRUPT = false;
|
||||
GTX_TAG_READY = true;
|
||||
},
|
||||
IRQ::MainTag => unsafe {
|
||||
MAIN_TAG = csr::wrpll::main_tag_read();
|
||||
MAIN_TAG_READY = true;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn period_det_ready() -> bool {
|
||||
unsafe { PERIOD_DET_READY }
|
||||
}
|
||||
|
||||
pub fn phase_det_ready() -> bool {
|
||||
unsafe { GTX_TAG_READY && MAIN_TAG_READY }
|
||||
}
|
||||
|
||||
pub fn get_period_error() -> i32 {
|
||||
// when gtx tag roll over, overflowing_sub prevent the difference to overflow and still get the correct period
|
||||
unsafe { BEATING_PERIOD - (GTX_TAG.overflowing_sub(LAST_GTX_TAG).0) as i32 }
|
||||
}
|
||||
|
||||
pub fn get_phase_error() -> i32 {
|
||||
let mut phase_error: i32;
|
||||
|
||||
unsafe {
|
||||
// unwrap tag difference
|
||||
phase_error = MAIN_TAG.overflowing_sub(GTX_TAG).0.rem_euclid(BEATING_PERIOD as u32) as i32;
|
||||
}
|
||||
|
||||
// mapping tags from [0, 2π] -> [-π, π]
|
||||
if phase_error > BEATING_HALFPERIOD {
|
||||
phase_error -= BEATING_PERIOD
|
||||
}
|
||||
phase_error
|
||||
}
|
||||
}
|
||||
|
||||
pub fn helper_setup(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
||||
unsafe {
|
||||
|
@ -327,9 +422,9 @@ pub mod wrpll {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn wrpll_interrupt_setup(interrupt_controller: &mut gic::InterruptController) {
|
||||
pub fn interrupt_setup(interrupt_controller: &mut gic::InterruptController) {
|
||||
for id in IRQ_ID.iter() {
|
||||
// configure registers on cpu for shared peripheral interrupts (SPI)
|
||||
// setup shared peripheral interrupts (SPI)
|
||||
interrupt_controller.enable(
|
||||
gic::InterruptId(*id),
|
||||
gic::CPUCore::Core0,
|
||||
|
@ -339,11 +434,11 @@ pub mod wrpll {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_wrpll_interrupt(en: bool) {
|
||||
fn set_irq(en: bool) {
|
||||
let val = if en { 1 } else { 0 };
|
||||
unsafe {
|
||||
// enable the gateware event managers
|
||||
csr::wrpll::period_ev_enable_write(en as u8);
|
||||
csr::wrpll::phase_ev_enable_write(en as u8);
|
||||
csr::wrpll::gtx_tag_ev_enable_write(val);
|
||||
csr::wrpll::main_tag_ev_enable_write(val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,39 +488,6 @@ pub mod wrpll {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn get_freq_counts(timer: &mut GlobalTimer) -> (u32, 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 gtx = csr::wrpll::frequency_counter_counter_gtx0_rtio_rx_read();
|
||||
let main = csr::wrpll::frequency_counter_counter_sys_read();
|
||||
let helper = csr::wrpll::frequency_counter_counter_helper_read();
|
||||
|
||||
(gtx, main, helper)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_beating_period_error() -> i32 {
|
||||
unsafe { BEATING_PERIOD - csr::wrpll::gtx_period_read() as i32 }
|
||||
}
|
||||
|
||||
fn get_phase_error() -> i32 {
|
||||
let (tag_main, tag_gtx): (u32, u32);
|
||||
unsafe {
|
||||
tag_main = csr::wrpll::main_tag_read();
|
||||
tag_gtx = csr::wrpll::gtx_tag_read();
|
||||
}
|
||||
// unwrap tag difference
|
||||
let mut phase_error = tag_main.overflowing_sub(tag_gtx).0.rem_euclid(BEATING_PERIOD as u32) as i32;
|
||||
|
||||
// mapping tags from [0, 2π] -> [-π, π]
|
||||
if phase_error > BEATING_HALFPERIOD {
|
||||
phase_error -= BEATING_PERIOD
|
||||
}
|
||||
phase_error
|
||||
}
|
||||
|
||||
fn set_base_adpll(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
||||
let count2adpll =
|
||||
|error: i32| (((error) as f64 * 1e6) / (0.0001164 * (1 << (TIMER_WIDTH - COUNTER_DIV)) as f64)) as i32;
|
||||
|
@ -440,15 +502,54 @@ pub mod wrpll {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn get_freq_counts(timer: &mut GlobalTimer) -> (u32, 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 gtx = csr::wrpll::frequency_counter_counter_gtx0_rtio_rx_read();
|
||||
let main = csr::wrpll::frequency_counter_counter_sys_read();
|
||||
let helper = csr::wrpll::frequency_counter_counter_helper_read();
|
||||
|
||||
(gtx, main, helper)
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_plls() -> Result<(), &'static str> {
|
||||
unsafe { H_INTEGRATOR = 0 }
|
||||
unsafe {
|
||||
H_INTEGRATOR = 0;
|
||||
M_INTEGRATOR = 0;
|
||||
}
|
||||
set_adpll(i2c::DCXO::Main, 0)?;
|
||||
set_adpll(i2c::DCXO::Helper, 0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clear_pending(interrupt: IRQ) {
|
||||
match interrupt {
|
||||
IRQ::GTXTag => unsafe { csr::wrpll::gtx_tag_ev_pending_write(1) },
|
||||
IRQ::MainTag => unsafe { csr::wrpll::main_tag_ev_pending_write(1) },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interrupt_handler(interrupt: IRQ) {
|
||||
tag_collector::collect_tags(interrupt);
|
||||
|
||||
if tag_collector::period_det_ready() {
|
||||
helper_pll().expect("failed to run helper DCXO PLL");
|
||||
tag_collector::clear_period_det_ready();
|
||||
}
|
||||
|
||||
if tag_collector::phase_det_ready() {
|
||||
main_pll().expect("failed to run main DCXO PLL");
|
||||
tag_collector::clear_phase_det_ready();
|
||||
}
|
||||
|
||||
clear_pending(interrupt);
|
||||
}
|
||||
|
||||
pub fn helper_pll() -> Result<(), &'static str> {
|
||||
let period_err = get_beating_period_error();
|
||||
let period_err = tag_collector::get_period_error();
|
||||
|
||||
const H_KP: i32 = 2;
|
||||
const H_KI: f32 = 0.5;
|
||||
|
@ -462,45 +563,43 @@ pub mod wrpll {
|
|||
h_adpll = h_adpll.clamp(-ADPLL_MAX, ADPLL_MAX);
|
||||
set_adpll(i2c::DCXO::Helper, h_adpll)?;
|
||||
|
||||
unsafe {
|
||||
// clear the asserted interrupt
|
||||
csr::wrpll::period_ev_pending_write(1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn main_pll() -> Result<(), &'static str> {
|
||||
let phase_err = get_phase_error();
|
||||
let phase_err = tag_collector::get_phase_error();
|
||||
|
||||
const M_KP: i32 = 12;
|
||||
const M_KI: i32 = 2;
|
||||
|
||||
let mut m_adpll: i32;
|
||||
unsafe {
|
||||
m_adpll = BASE_ADPLL + phase_err * M_KP;
|
||||
M_INTEGRATOR += phase_err * M_KI;
|
||||
m_adpll = BASE_ADPLL + phase_err * M_KP + M_INTEGRATOR;
|
||||
}
|
||||
|
||||
m_adpll = m_adpll.clamp(-ADPLL_MAX, ADPLL_MAX);
|
||||
set_adpll(i2c::DCXO::Main, m_adpll)?;
|
||||
|
||||
unsafe {
|
||||
// clear the asserted interrupt
|
||||
csr::wrpll::phase_ev_pending_write(1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn select_recovered_clock(rc: bool, timer: &mut GlobalTimer) {
|
||||
set_wrpll_interrupt(false);
|
||||
reset_plls().expect("failed to reset main and helper PLL");
|
||||
set_irq(false);
|
||||
|
||||
if rc {
|
||||
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);
|
||||
set_base_adpll(timer).expect("failed to set base adpll");
|
||||
set_wrpll_interrupt(true);
|
||||
|
||||
// clear gateware pending flag
|
||||
clear_pending(IRQ::GTXTag);
|
||||
clear_pending(IRQ::MainTag);
|
||||
set_irq(true);
|
||||
info!("WRPLL interrupt enabled");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,13 +23,13 @@ interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
|
|||
0 => match id.0 {
|
||||
61 => {
|
||||
#[cfg(has_wrpll)]
|
||||
si549::wrpll::helper_pll().expect("failed to run helper DCXO PLL");
|
||||
si549::wrpll::interrupt_handler(si549::wrpll::IRQ::GTXTag);
|
||||
gic.end_interrupt(id);
|
||||
return;
|
||||
}
|
||||
62 => {
|
||||
#[cfg(has_wrpll)]
|
||||
si549::wrpll::main_pll().expect("failed to run main DCXO PLL");
|
||||
si549::wrpll::interrupt_handler(si549::wrpll::IRQ::MainTag);
|
||||
gic.end_interrupt(id);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -807,7 +807,7 @@ pub extern "C" fn main_core0() -> i32 {
|
|||
#[cfg(has_wrpll)]
|
||||
{
|
||||
si549::wrpll::helper_setup(&mut timer).expect("cannot initialize helper Si549");
|
||||
si549::wrpll::wrpll_interrupt_setup(&mut interrupt_controller);
|
||||
si549::wrpll::interrupt_setup(&mut interrupt_controller);
|
||||
}
|
||||
|
||||
#[cfg(has_drtio_routing)]
|
||||
|
|
Loading…
Reference in New Issue