Compare commits
6 Commits
ff68521bfd
...
cbe48f9412
Author | SHA1 | Date |
---|---|---|
|
cbe48f9412 | |
|
a26e4ced44 | |
|
1e4ff8b887 | |
|
56c008fa67 | |
|
8e1b62e126 | |
|
5c5bd8535f |
20
flake.lock
20
flake.lock
|
@ -11,11 +11,11 @@
|
||||||
"src-pythonparser": "src-pythonparser"
|
"src-pythonparser": "src-pythonparser"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1710303235,
|
"lastModified": 1706785107,
|
||||||
"narHash": "sha256-0rIfVoL8RInAQSDVfjpLdMqIYdnVsA8DdMk2+aqvwrM=",
|
"narHash": "sha256-Uj72tqigiOCdewSSBBMg6zUpVKhwjAo1HeLJgvyZ3oc=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "c4323e1179aa0b9c9b4c135f894f267715cf2391",
|
"rev": "3aaa7e04f26a495e8847e47424bfc16d76d82bf8",
|
||||||
"revCount": 8727,
|
"revCount": 8672,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/m-labs/artiq.git"
|
"url": "https://github.com/m-labs/artiq.git"
|
||||||
},
|
},
|
||||||
|
@ -37,11 +37,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1707216368,
|
"lastModified": 1701573753,
|
||||||
"narHash": "sha256-ZXoqzG2QsVsybALLYXs473avXcyKSZNh2kIgcPo60XQ=",
|
"narHash": "sha256-vhEtXjb9AM6/HnsgfVmhJQeqQ9JqysUm7iWNzTIbexs=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "artiq-comtools",
|
"repo": "artiq-comtools",
|
||||||
"rev": "e5d0204490bccc07ef9141b0d7c405ab01cb8273",
|
"rev": "199bdabf4de49cb7ada8a4ac7133008e0f8434b7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -118,11 +118,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1707347730,
|
"lastModified": 1706515015,
|
||||||
"narHash": "sha256-0etC/exQIaqC9vliKhc3eZE2Mm2wgLa0tj93ZF/egvM=",
|
"narHash": "sha256-eFfY5A7wlYy3jD/75lx6IJRueg4noE+jowl0a8lIlVo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "6832d0d99649db3d65a0e15fa51471537b2c56a6",
|
"rev": "f4a8d6d5324c327dcc2d863eb7f3cc06ad630df4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -119,10 +119,9 @@ class GTPBootstrapClock(Module):
|
||||||
|
|
||||||
|
|
||||||
class GenericStandalone(SoCCore):
|
class GenericStandalone(SoCCore):
|
||||||
def __init__(self, description, acpki=False):
|
def __init__(self, description, acpki=False, with_wrpll=False):
|
||||||
self.acpki = acpki
|
self.acpki = acpki
|
||||||
clk_freq = description["rtio_frequency"]
|
clk_freq = description["rtio_frequency"]
|
||||||
with_wrpll = description["enable_wrpll"]
|
|
||||||
|
|
||||||
platform = kasli_soc.Platform()
|
platform = kasli_soc.Platform()
|
||||||
platform.toolchain.bitstream_commands.extend([
|
platform.toolchain.bitstream_commands.extend([
|
||||||
|
@ -223,9 +222,8 @@ class GenericStandalone(SoCCore):
|
||||||
|
|
||||||
|
|
||||||
class GenericMaster(SoCCore):
|
class GenericMaster(SoCCore):
|
||||||
def __init__(self, description, acpki=False):
|
def __init__(self, description, acpki=False, with_wrpll=False):
|
||||||
clk_freq = description["rtio_frequency"]
|
clk_freq = description["rtio_frequency"]
|
||||||
with_wrpll = description["enable_wrpll"]
|
|
||||||
|
|
||||||
has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"])
|
has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"])
|
||||||
self.acpki = acpki
|
self.acpki = acpki
|
||||||
|
@ -429,9 +427,8 @@ class GenericMaster(SoCCore):
|
||||||
|
|
||||||
|
|
||||||
class GenericSatellite(SoCCore):
|
class GenericSatellite(SoCCore):
|
||||||
def __init__(self, description, acpki=False):
|
def __init__(self, description, acpki=False, with_wrpll=False):
|
||||||
clk_freq = description["rtio_frequency"]
|
clk_freq = description["rtio_frequency"]
|
||||||
with_wrpll = description["enable_wrpll"]
|
|
||||||
|
|
||||||
self.acpki = acpki
|
self.acpki = acpki
|
||||||
|
|
||||||
|
@ -589,8 +586,6 @@ class GenericSatellite(SoCCore):
|
||||||
platform=self.platform,
|
platform=self.platform,
|
||||||
cd_ref=self.gt_drtio.cd_rtio_rx0,
|
cd_ref=self.gt_drtio.cd_rtio_rx0,
|
||||||
main_clk_se=self.clk_synth.se)
|
main_clk_se=self.clk_synth.se)
|
||||||
self.submodules.wrpll_skewtester = wrpll.SkewTester(self.rx_synchronizer)
|
|
||||||
self.csr_devices.append("wrpll_skewtester")
|
|
||||||
self.csr_devices.append("wrpll")
|
self.csr_devices.append("wrpll")
|
||||||
self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq)
|
self.comb += self.ps7.core.core0.nfiq.eq(self.wrpll.ev.irq)
|
||||||
self.config["HAS_SI549"] = None
|
self.config["HAS_SI549"] = None
|
||||||
|
@ -633,6 +628,8 @@ 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",
|
||||||
|
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")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
@ -650,7 +647,7 @@ def main():
|
||||||
else:
|
else:
|
||||||
raise ValueError("Invalid DRTIO role")
|
raise ValueError("Invalid DRTIO role")
|
||||||
|
|
||||||
soc = cls(description, acpki=args.acpki)
|
soc = cls(description, acpki=args.acpki, with_wrpll=args.with_wrpll)
|
||||||
soc.finalize()
|
soc.finalize()
|
||||||
|
|
||||||
if args.r is not None:
|
if args.r is not None:
|
||||||
|
|
|
@ -44,28 +44,6 @@ class FrequencyCounter(Module, AutoCSR):
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
class SkewTester(Module, AutoCSR):
|
|
||||||
def __init__(self, rx_synchronizer):
|
|
||||||
self.error = CSR()
|
|
||||||
|
|
||||||
# # #
|
|
||||||
|
|
||||||
# The RX synchronizer is tested for setup/hold violations by feeding it a
|
|
||||||
# toggling pattern and checking that the same toggling pattern comes out.
|
|
||||||
toggle_in = Signal()
|
|
||||||
self.sync.rtio_rx0 += toggle_in.eq(~toggle_in)
|
|
||||||
toggle_out = rx_synchronizer.resync(toggle_in)
|
|
||||||
|
|
||||||
toggle_out_expected = Signal()
|
|
||||||
self.sync += toggle_out_expected.eq(~toggle_out)
|
|
||||||
|
|
||||||
error = Signal()
|
|
||||||
self.sync += [
|
|
||||||
If(toggle_out != toggle_out_expected, error.eq(1)),
|
|
||||||
If(self.error.re, error.eq(0))
|
|
||||||
]
|
|
||||||
self.specials += MultiReg(error, self.error.w)
|
|
||||||
|
|
||||||
|
|
||||||
class WRPLL(Module, AutoCSR):
|
class WRPLL(Module, AutoCSR):
|
||||||
def __init__(self, platform, cd_ref, main_clk_se, COUNTER_BIT=32):
|
def __init__(self, platform, cd_ref, main_clk_se, COUNTER_BIT=32):
|
||||||
|
|
|
@ -10,7 +10,6 @@ name = "libboard_artiq"
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = ["libboard_zynq/target_zc706", "libconfig/target_zc706"]
|
target_zc706 = ["libboard_zynq/target_zc706", "libconfig/target_zc706"]
|
||||||
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libconfig/target_kasli_soc"]
|
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libconfig/target_kasli_soc"]
|
||||||
calibrate_wrpll_skew = []
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
build_zynq = { path = "../libbuild_zynq" }
|
build_zynq = { path = "../libbuild_zynq" }
|
||||||
|
|
|
@ -7,8 +7,6 @@ use crate::pl::csr;
|
||||||
#[cfg(feature = "target_kasli_soc")]
|
#[cfg(feature = "target_kasli_soc")]
|
||||||
const ADDRESS: u8 = 0x67;
|
const ADDRESS: u8 = 0x67;
|
||||||
|
|
||||||
const ADPLL_MAX: i32 = (950.0 / 0.0001164) as i32;
|
|
||||||
|
|
||||||
pub struct DividerConfig {
|
pub struct DividerConfig {
|
||||||
pub hsdiv: u16,
|
pub hsdiv: u16,
|
||||||
pub lsdiv: u8,
|
pub lsdiv: u8,
|
||||||
|
@ -264,6 +262,95 @@ pub fn main_setup(timer: &mut GlobalTimer, settings: &FrequencySetting) -> Resul
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod wrpll {
|
||||||
|
|
||||||
|
use libcortex_a9::mutex::Mutex;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const TIMER_WIDTH: u32 = 24;
|
||||||
|
const COUNTER_DIV: u32 = 2;
|
||||||
|
|
||||||
|
const ADPLL_MAX: i32 = (950.0 / 0.0001164) as i32;
|
||||||
|
|
||||||
|
const KP: i32 = 6;
|
||||||
|
const KI: i32 = 2;
|
||||||
|
|
||||||
|
static BASE_ADPLL: Mutex<i32> = Mutex::new(0);
|
||||||
|
static H_INTEGRATOR: Mutex<i32> = Mutex::new(0);
|
||||||
|
static M_INTEGRATOR: Mutex<i32> = Mutex::new(0);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum ISR {
|
||||||
|
RefTag,
|
||||||
|
MainTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
mod tag_collector {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const BEATING_PERIOD: i32 = 0x8000;
|
||||||
|
const BEATING_HALFPERIOD: i32 = 0x4000;
|
||||||
|
|
||||||
|
static REF_TAG: Mutex<u32> = Mutex::new(0);
|
||||||
|
static REF_TAG_READY: Mutex<bool> = Mutex::new(false);
|
||||||
|
static MAIN_TAG: Mutex<u32> = Mutex::new(0);
|
||||||
|
static MAIN_TAG_READY: Mutex<bool> = Mutex::new(false);
|
||||||
|
|
||||||
|
pub fn reset() {
|
||||||
|
clear_phase_diff_ready();
|
||||||
|
*REF_TAG.lock() = 0;
|
||||||
|
*MAIN_TAG.lock() = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_phase_diff_ready() {
|
||||||
|
*REF_TAG_READY.lock() = false;
|
||||||
|
*MAIN_TAG_READY.lock() = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn collect_tags(interrupt: ISR) {
|
||||||
|
match interrupt {
|
||||||
|
ISR::RefTag => {
|
||||||
|
*REF_TAG.lock() = unsafe { csr::wrpll::ref_tag_read() };
|
||||||
|
*REF_TAG_READY.lock() = true;
|
||||||
|
}
|
||||||
|
ISR::MainTag => {
|
||||||
|
*MAIN_TAG.lock() = unsafe { csr::wrpll::main_tag_read() };
|
||||||
|
*MAIN_TAG_READY.lock() = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn phase_diff_ready() -> bool {
|
||||||
|
*REF_TAG_READY.lock() && *MAIN_TAG_READY.lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_period_error() -> i32 {
|
||||||
|
// n * BEATING_PERIOD - REF_TAG(n) mod BEATING_PERIOD
|
||||||
|
let mut period_error = (*REF_TAG.lock()).overflowing_neg().0.rem_euclid(BEATING_PERIOD as u32) as i32;
|
||||||
|
|
||||||
|
// mapping tags from [0, 2π] -> [-π, π]
|
||||||
|
if period_error > BEATING_HALFPERIOD {
|
||||||
|
period_error -= BEATING_PERIOD
|
||||||
|
}
|
||||||
|
period_error
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_phase_error() -> i32 {
|
||||||
|
// MAIN_TAG(n) - REF_TAG(n) mod BEATING_PERIOD
|
||||||
|
let mut phase_error = (*MAIN_TAG.lock())
|
||||||
|
.overflowing_sub(*REF_TAG.lock())
|
||||||
|
.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, settings: &FrequencySetting) -> Result<(), &'static str> {
|
pub fn helper_setup(timer: &mut GlobalTimer, settings: &FrequencySetting) -> Result<(), &'static str> {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::wrpll::helper_reset_write(1);
|
csr::wrpll::helper_reset_write(1);
|
||||||
|
@ -284,6 +371,14 @@ pub fn helper_setup(timer: &mut GlobalTimer, settings: &FrequencySetting) -> Res
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_isr(en: bool) {
|
||||||
|
let val = if en { 1 } else { 0 };
|
||||||
|
unsafe {
|
||||||
|
csr::wrpll::ref_tag_ev_enable_write(val);
|
||||||
|
csr::wrpll::main_tag_ev_enable_write(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// set adpll using gateware i2c
|
/// set adpll using gateware i2c
|
||||||
/// Note: disable main/helper i2c bitbang before using this function
|
/// Note: disable main/helper i2c bitbang before using this function
|
||||||
fn set_adpll(dcxo: i2c::DCXO, adpll: i32) -> Result<(), &'static str> {
|
fn set_adpll(dcxo: i2c::DCXO, adpll: i32) -> Result<(), &'static str> {
|
||||||
|
@ -329,115 +424,6 @@ fn set_adpll(dcxo: i2c::DCXO, adpll: i32) -> Result<(), &'static str> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_wrpll)]
|
|
||||||
pub mod wrpll {
|
|
||||||
|
|
||||||
use libcortex_a9::mutex::Mutex;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
const BEATING_PERIOD: i32 = 0x8000;
|
|
||||||
const BEATING_HALFPERIOD: i32 = 0x4000;
|
|
||||||
const TIMER_WIDTH: u32 = 24;
|
|
||||||
const COUNTER_DIV: u32 = 2;
|
|
||||||
|
|
||||||
const KP: i32 = 6;
|
|
||||||
const KI: i32 = 2;
|
|
||||||
|
|
||||||
static BASE_ADPLL: Mutex<i32> = Mutex::new(0);
|
|
||||||
static H_INTEGRATOR: Mutex<i32> = Mutex::new(0);
|
|
||||||
static M_INTEGRATOR: Mutex<i32> = Mutex::new(0);
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum ISR {
|
|
||||||
RefTag,
|
|
||||||
MainTag,
|
|
||||||
}
|
|
||||||
|
|
||||||
mod tag_collector {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[cfg(wrpll_ref_clk = "GTX_CDR")]
|
|
||||||
static TAG_OFFSET: Mutex<u32> = Mutex::new(19050);
|
|
||||||
#[cfg(wrpll_ref_clk = "SMA_CLKIN")]
|
|
||||||
static TAG_OFFSET: Mutex<u32> = Mutex::new(0);
|
|
||||||
static REF_TAG: Mutex<u32> = Mutex::new(0);
|
|
||||||
static REF_TAG_READY: Mutex<bool> = Mutex::new(false);
|
|
||||||
static MAIN_TAG: Mutex<u32> = Mutex::new(0);
|
|
||||||
static MAIN_TAG_READY: Mutex<bool> = Mutex::new(false);
|
|
||||||
|
|
||||||
pub fn reset() {
|
|
||||||
clear_phase_diff_ready();
|
|
||||||
*REF_TAG.lock() = 0;
|
|
||||||
*MAIN_TAG.lock() = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear_phase_diff_ready() {
|
|
||||||
*REF_TAG_READY.lock() = false;
|
|
||||||
*MAIN_TAG_READY.lock() = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn collect_tags(interrupt: ISR) {
|
|
||||||
match interrupt {
|
|
||||||
ISR::RefTag => {
|
|
||||||
*REF_TAG.lock() = unsafe { csr::wrpll::ref_tag_read() };
|
|
||||||
*REF_TAG_READY.lock() = true;
|
|
||||||
}
|
|
||||||
ISR::MainTag => {
|
|
||||||
*MAIN_TAG.lock() = unsafe { csr::wrpll::main_tag_read() };
|
|
||||||
*MAIN_TAG_READY.lock() = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn phase_diff_ready() -> bool {
|
|
||||||
*REF_TAG_READY.lock() && *MAIN_TAG_READY.lock()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "calibrate_wrpll_skew")]
|
|
||||||
pub fn set_tag_offset(offset: u32) {
|
|
||||||
*TAG_OFFSET.lock() = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "calibrate_wrpll_skew")]
|
|
||||||
pub fn get_tag_offset() -> u32 {
|
|
||||||
*TAG_OFFSET.lock()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_period_error() -> i32 {
|
|
||||||
// n * BEATING_PERIOD - REF_TAG(n) mod BEATING_PERIOD
|
|
||||||
let mut period_error = (*REF_TAG.lock()).overflowing_neg().0.rem_euclid(BEATING_PERIOD as u32) as i32;
|
|
||||||
|
|
||||||
// mapping tags from [0, 2π] -> [-π, π]
|
|
||||||
if period_error > BEATING_HALFPERIOD {
|
|
||||||
period_error -= BEATING_PERIOD
|
|
||||||
}
|
|
||||||
period_error
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_phase_error() -> i32 {
|
|
||||||
// MAIN_TAG(n) - REF_TAG(n) - TAG_OFFSET mod BEATING_PERIOD
|
|
||||||
let mut phase_error = (*MAIN_TAG.lock())
|
|
||||||
.overflowing_sub(*REF_TAG.lock() + *TAG_OFFSET.lock())
|
|
||||||
.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_isr(en: bool) {
|
|
||||||
let val = if en { 1 } else { 0 };
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll::ref_tag_ev_enable_write(val);
|
|
||||||
csr::wrpll::main_tag_ev_enable_write(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// To get within capture range
|
/// To get within capture range
|
||||||
fn set_base_adpll(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
fn set_base_adpll(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
||||||
let count2adpll =
|
let count2adpll =
|
||||||
|
@ -534,113 +520,6 @@ pub mod wrpll {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(wrpll_ref_clk = "GTX_CDR")]
|
|
||||||
fn test_skew(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
|
||||||
// wait for PLL to stabilize
|
|
||||||
timer.delay_us(20_000);
|
|
||||||
|
|
||||||
info!("testing the skew of SYS CLK...");
|
|
||||||
if has_timing_error(timer) {
|
|
||||||
return Err("the skew cannot satisfy setup/hold time constraint of RX synchronizer");
|
|
||||||
}
|
|
||||||
info!("the skew of SYS CLK met the timing constraint");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(wrpll_ref_clk = "GTX_CDR")]
|
|
||||||
fn has_timing_error(timer: &mut GlobalTimer) -> bool {
|
|
||||||
unsafe {
|
|
||||||
csr::wrpll_skewtester::error_write(1);
|
|
||||||
}
|
|
||||||
timer.delay_us(5_000);
|
|
||||||
unsafe { csr::wrpll_skewtester::error_read() == 1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "calibrate_wrpll_skew")]
|
|
||||||
fn find_edge(target: bool, timer: &mut GlobalTimer) -> Result<u32, &'static str> {
|
|
||||||
const STEP: u32 = 8;
|
|
||||||
const STABLE_THRESHOLD: u32 = 10;
|
|
||||||
|
|
||||||
enum FSM {
|
|
||||||
Init,
|
|
||||||
WaitEdge,
|
|
||||||
GotEdge,
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut state: FSM = FSM::Init;
|
|
||||||
let mut offset: u32 = tag_collector::get_tag_offset();
|
|
||||||
let mut median_edge: u32 = 0;
|
|
||||||
let mut stable_counter: u32 = 0;
|
|
||||||
|
|
||||||
for _ in 0..(BEATING_PERIOD as u32 / STEP) as usize {
|
|
||||||
tag_collector::set_tag_offset(offset);
|
|
||||||
offset += STEP;
|
|
||||||
// wait for PLL to stabilize
|
|
||||||
timer.delay_us(20_000);
|
|
||||||
|
|
||||||
let error = has_timing_error(timer);
|
|
||||||
// A median edge deglitcher
|
|
||||||
match state {
|
|
||||||
FSM::Init => {
|
|
||||||
if error != target {
|
|
||||||
stable_counter += 1;
|
|
||||||
} else {
|
|
||||||
stable_counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if stable_counter >= STABLE_THRESHOLD {
|
|
||||||
state = FSM::WaitEdge;
|
|
||||||
stable_counter = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FSM::WaitEdge => {
|
|
||||||
if error == target {
|
|
||||||
state = FSM::GotEdge;
|
|
||||||
median_edge = offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FSM::GotEdge => {
|
|
||||||
if error != target {
|
|
||||||
median_edge += STEP;
|
|
||||||
stable_counter = 0;
|
|
||||||
} else {
|
|
||||||
stable_counter += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if stable_counter >= STABLE_THRESHOLD {
|
|
||||||
return Ok(median_edge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Err("failed to find timing error edge");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "calibrate_wrpll_skew")]
|
|
||||||
pub fn calibrate_skew(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
|
||||||
info!("calibrating skew to meet timing constraint...");
|
|
||||||
|
|
||||||
// clear calibrated value
|
|
||||||
tag_collector::set_tag_offset(0);
|
|
||||||
let rising = find_edge(true, timer)? as i32;
|
|
||||||
let falling = find_edge(false, timer)? as i32;
|
|
||||||
|
|
||||||
let width = BEATING_PERIOD - (falling - rising);
|
|
||||||
let result = falling + width / 2;
|
|
||||||
tag_collector::set_tag_offset(result as u32);
|
|
||||||
|
|
||||||
info!(
|
|
||||||
"calibration successful, error zone: {} -> {}, width: {} ({}deg), middle of working region: {}",
|
|
||||||
rising,
|
|
||||||
falling,
|
|
||||||
width,
|
|
||||||
360 * width / BEATING_PERIOD,
|
|
||||||
result,
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn select_recovered_clock(rc: bool, timer: &mut GlobalTimer) {
|
pub fn select_recovered_clock(rc: bool, timer: &mut GlobalTimer) {
|
||||||
set_isr(false);
|
set_isr(false);
|
||||||
|
|
||||||
|
@ -660,12 +539,6 @@ pub mod wrpll {
|
||||||
// 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_isr(true);
|
set_isr(true);
|
||||||
info!("WRPLL interrupt enabled");
|
info!("WRPLL interrupt enabled");
|
||||||
|
|
||||||
#[cfg(feature = "calibrate_wrpll_skew")]
|
|
||||||
calibrate_skew(timer).expect("failed to set the correct skew");
|
|
||||||
|
|
||||||
#[cfg(wrpll_ref_clk = "GTX_CDR")]
|
|
||||||
test_skew(timer).expect("skew test failed");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,7 +262,7 @@ 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(all(has_si549, has_wrpll))]
|
#[cfg(has_si549)]
|
||||||
fn wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: &si549::FrequencySetting) {
|
fn wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: &si549::FrequencySetting) {
|
||||||
// register values are directly copied from preconfigured mmcm
|
// register values are directly copied from preconfigured mmcm
|
||||||
let (mmcm_setting, mmcm_bypass) = match clk {
|
let (mmcm_setting, mmcm_bypass) = match clk {
|
||||||
|
@ -337,7 +337,7 @@ fn wrpll_setup(timer: &mut GlobalTimer, clk: RtioClock, si549_settings: &si549::
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
si549::helper_setup(timer, &si549_settings).expect("cannot initialize helper Si549");
|
si549::wrpll::helper_setup(timer, &si549_settings).expect("cannot initialize helper Si549");
|
||||||
si549::wrpll_refclk::setup(timer, mmcm_setting, mmcm_bypass).expect("cannot initialize ref clk for wrpll");
|
si549::wrpll_refclk::setup(timer, mmcm_setting, mmcm_bypass).expect("cannot initialize ref clk for wrpll");
|
||||||
si549::wrpll::select_recovered_clock(true, timer);
|
si549::wrpll::select_recovered_clock(true, timer);
|
||||||
}
|
}
|
||||||
|
@ -432,7 +432,7 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
|
||||||
#[cfg(not(has_drtio))]
|
#[cfg(not(has_drtio))]
|
||||||
init_rtio(timer);
|
init_rtio(timer);
|
||||||
|
|
||||||
#[cfg(all(has_si549, has_wrpll))]
|
#[cfg(has_si549)]
|
||||||
{
|
{
|
||||||
// SYS CLK switch will reset CSRs that are used by WRPLL
|
// SYS CLK switch will reset CSRs that are used by WRPLL
|
||||||
match clk {
|
match clk {
|
||||||
|
|
|
@ -7,7 +7,6 @@ build = "build.rs"
|
||||||
[features]
|
[features]
|
||||||
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706", "libconfig/target_zc706", "libboard_artiq/target_zc706"]
|
target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706", "libconfig/target_zc706", "libboard_artiq/target_zc706"]
|
||||||
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libsupport_zynq/target_kasli_soc", "libconfig/target_kasli_soc", "libboard_artiq/target_kasli_soc"]
|
target_kasli_soc = ["libboard_zynq/target_kasli_soc", "libsupport_zynq/target_kasli_soc", "libconfig/target_kasli_soc", "libboard_artiq/target_kasli_soc"]
|
||||||
calibrate_wrpll_skew = ["libboard_artiq/calibrate_wrpll_skew"]
|
|
||||||
default = ["target_zc706", ]
|
default = ["target_zc706", ]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|
|
@ -932,7 +932,7 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
csr::gt_drtio::txenable_write(0xffffffffu32 as _);
|
csr::gt_drtio::txenable_write(0xffffffffu32 as _);
|
||||||
}
|
}
|
||||||
#[cfg(has_si549)]
|
#[cfg(has_si549)]
|
||||||
si549::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
|
si549::wrpll::helper_setup(&mut timer, &SI549_SETTINGS).expect("cannot initialize helper Si549");
|
||||||
|
|
||||||
#[cfg(has_drtio_routing)]
|
#[cfg(has_drtio_routing)]
|
||||||
let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()];
|
let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()];
|
||||||
|
@ -978,7 +978,7 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
si5324::siphaser::calibrate_skew(&mut timer).expect("failed to calibrate skew");
|
si5324::siphaser::calibrate_skew(&mut timer).expect("failed to calibrate skew");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_wrpll)]
|
#[cfg(has_si549)]
|
||||||
si549::wrpll::select_recovered_clock(true, &mut timer);
|
si549::wrpll::select_recovered_clock(true, &mut timer);
|
||||||
|
|
||||||
// Various managers created here, so when link is dropped, all DMA traces
|
// Various managers created here, so when link is dropped, all DMA traces
|
||||||
|
@ -1078,7 +1078,7 @@ pub extern "C" fn main_core0() -> i32 {
|
||||||
info!("uplink is down, switching to local oscillator clock");
|
info!("uplink is down, switching to local oscillator clock");
|
||||||
#[cfg(has_siphaser)]
|
#[cfg(has_siphaser)]
|
||||||
si5324::siphaser::select_recovered_clock(&mut i2c, false, &mut timer).expect("failed to switch clocks");
|
si5324::siphaser::select_recovered_clock(&mut i2c, false, &mut timer).expect("failed to switch clocks");
|
||||||
#[cfg(has_wrpll)]
|
#[cfg(has_si549)]
|
||||||
si549::wrpll::select_recovered_clock(false, &mut timer);
|
si549::wrpll::select_recovered_clock(false, &mut timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue