Compare commits
6 Commits
aa4bb8bae8
...
14fa038118
Author | SHA1 | Date |
---|---|---|
morgan | 14fa038118 | |
morgan | b81323af30 | |
morgan | 291777f764 | |
morgan | a1d80fb93b | |
morgan | 7827c7b803 | |
morgan | e4d8d44c7c |
|
@ -26,7 +26,7 @@ class DDMTDSampler(Module):
|
||||||
|
|
||||||
|
|
||||||
class DDMTDDeglitcherFirstEdge(Module):
|
class DDMTDDeglitcherFirstEdge(Module):
|
||||||
def __init__(self, input_signal, blind_period=300):
|
def __init__(self, input_signal, blind_period=400):
|
||||||
self.detect = Signal()
|
self.detect = Signal()
|
||||||
rising = Signal()
|
rising = Signal()
|
||||||
input_signal_r = Signal()
|
input_signal_r = Signal()
|
||||||
|
|
|
@ -7,7 +7,7 @@ from ddmtd import DDMTDSampler, DDMTD
|
||||||
from si549 import Si549
|
from si549 import Si549
|
||||||
|
|
||||||
class FrequencyCounter(Module, AutoCSR):
|
class FrequencyCounter(Module, AutoCSR):
|
||||||
def __init__(self, domains, counter_width=24, freq_div=2):
|
def __init__(self, domains, counter_width=24):
|
||||||
self.update = CSR()
|
self.update = CSR()
|
||||||
self.busy = CSRStatus()
|
self.busy = CSRStatus()
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ class FrequencyCounter(Module, AutoCSR):
|
||||||
self.submodules += fsm
|
self.submodules += fsm
|
||||||
|
|
||||||
fsm.act("IDLE",
|
fsm.act("IDLE",
|
||||||
If(self.update.re,
|
|
||||||
counter_reset.eq(1),
|
counter_reset.eq(1),
|
||||||
|
If(self.update.re,
|
||||||
NextValue(timer, 2**counter_width - 1),
|
NextValue(timer, 2**counter_width - 1),
|
||||||
NextState("COUNTING")
|
NextState("COUNTING")
|
||||||
)
|
)
|
||||||
|
@ -42,37 +42,29 @@ class FrequencyCounter(Module, AutoCSR):
|
||||||
counter_csr = CSRStatus(counter_width, name=name)
|
counter_csr = CSRStatus(counter_width, name=name)
|
||||||
setattr(self, name, counter_csr)
|
setattr(self, name, counter_csr)
|
||||||
|
|
||||||
counter = Signal(max=freq_div)
|
divider = Signal(2)
|
||||||
result = Signal(counter_width)
|
divided = Signal()
|
||||||
|
divided_sys = Signal()
|
||||||
|
divided_sys_r = Signal()
|
||||||
|
divided_tick = Signal()
|
||||||
|
counter = Signal(counter_width)
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
reset_ps = PulseSynchronizer("sys", domain)
|
|
||||||
stb_ps = PulseSynchronizer("sys", domain)
|
|
||||||
self.submodules +=[
|
|
||||||
reset_ps,
|
|
||||||
stb_ps
|
|
||||||
]
|
|
||||||
self.sync +=[
|
|
||||||
reset_ps.i.eq(counter_reset),
|
|
||||||
stb_ps.i.eq(counter_stb)
|
|
||||||
]
|
|
||||||
|
|
||||||
sync_domain = getattr(self.sync, domain)
|
sync_domain = getattr(self.sync, domain)
|
||||||
sync_domain +=[
|
sync_domain +=[
|
||||||
If(counter != 0,
|
divider.eq(divider + 1),
|
||||||
counter.eq(counter - 1)
|
divided.eq(divider[-1])
|
||||||
).Else(
|
|
||||||
result.eq(result + 1),
|
|
||||||
counter.eq(freq_div - 1)
|
|
||||||
),
|
|
||||||
If(reset_ps.o,
|
|
||||||
counter.eq(0),
|
|
||||||
result.eq(0)
|
|
||||||
),
|
|
||||||
If(stb_ps.o, counter_csr.status.eq(result))
|
|
||||||
]
|
]
|
||||||
|
self.specials += MultiReg(divided, divided_sys)
|
||||||
|
self.sync += divided_sys_r.eq(divided_sys)
|
||||||
|
self.comb += divided_tick.eq(divided_sys & ~divided_sys_r)
|
||||||
|
|
||||||
|
self.sync += [
|
||||||
|
If(counter_stb, counter_csr.status.eq(counter)),
|
||||||
|
If(divided_tick, counter.eq(counter + 1)),
|
||||||
|
If(counter_reset, counter.eq(0))
|
||||||
|
]
|
||||||
|
|
||||||
class SkewTester(Module, AutoCSR):
|
class SkewTester(Module, AutoCSR):
|
||||||
def __init__(self, rx_synchronizer):
|
def __init__(self, rx_synchronizer):
|
||||||
|
|
|
@ -333,14 +333,18 @@ pub mod wrpll {
|
||||||
const BEATING_PERIOD: i32 = 0x8000;
|
const BEATING_PERIOD: i32 = 0x8000;
|
||||||
const BEATING_HALFPERIOD: i32 = 0x4000;
|
const BEATING_HALFPERIOD: i32 = 0x4000;
|
||||||
const COUNTER_WIDTH: u32 = 24;
|
const COUNTER_WIDTH: u32 = 24;
|
||||||
const FREQ_DIV: u32 = 2;
|
const DIV_WIDTH: u32 = 2;
|
||||||
|
|
||||||
const KP: i32 = 6;
|
const KP: i32 = 6;
|
||||||
const KI: i32 = 2;
|
const KI: i32 = 2;
|
||||||
|
// 4 ppm capture range
|
||||||
|
const ADPLL_LIM: i32 = (4.0 / 0.0001164) as i32;
|
||||||
|
|
||||||
static mut BASE_ADPLL: i32 = 0;
|
static mut BASE_ADPLL: i32 = 0;
|
||||||
static mut H_INTEGRATOR: i32 = 0;
|
static mut H_LAST_ADPLL: i32 = 0;
|
||||||
static mut M_INTEGRATOR: i32 = 0;
|
static mut LAST_PERIOD_ERR: i32 = 0;
|
||||||
|
static mut M_LAST_ADPLL: i32 = 0;
|
||||||
|
static mut LAST_PHASE_ERR: i32 = 0;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum ISR {
|
pub enum ISR {
|
||||||
|
@ -439,10 +443,9 @@ pub mod wrpll {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// To get within capture range
|
|
||||||
fn set_base_adpll() -> Result<(), &'static str> {
|
fn set_base_adpll() -> Result<(), &'static str> {
|
||||||
let count2adpll =
|
let count2adpll =
|
||||||
|error: i32| ((error as f64 * FREQ_DIV as f64 * 1e6) / (0.0001164 * (1 << COUNTER_WIDTH) as f64)) as i32;
|
|error: i32| ((error as f64 * 1e6) / (0.0001164 * (1 << (COUNTER_WIDTH - DIV_WIDTH)) as f64)) as i32;
|
||||||
|
|
||||||
let (ref_count, main_count) = get_freq_counts();
|
let (ref_count, main_count) = get_freq_counts();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -469,8 +472,10 @@ pub mod wrpll {
|
||||||
|
|
||||||
fn reset_plls(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
fn reset_plls(timer: &mut GlobalTimer) -> Result<(), &'static str> {
|
||||||
unsafe {
|
unsafe {
|
||||||
H_INTEGRATOR = 0;
|
H_LAST_ADPLL = 0;
|
||||||
M_INTEGRATOR = 0;
|
LAST_PERIOD_ERR = 0;
|
||||||
|
M_LAST_ADPLL = 0;
|
||||||
|
LAST_PHASE_ERR = 0;
|
||||||
}
|
}
|
||||||
set_adpll(i2c::DCXO::Main, 0)?;
|
set_adpll(i2c::DCXO::Main, 0)?;
|
||||||
set_adpll(i2c::DCXO::Helper, 0)?;
|
set_adpll(i2c::DCXO::Helper, 0)?;
|
||||||
|
@ -497,7 +502,6 @@ pub mod wrpll {
|
||||||
if is_pending(ISR::RefTag) {
|
if is_pending(ISR::RefTag) {
|
||||||
tag_collector::collect_tags(ISR::RefTag);
|
tag_collector::collect_tags(ISR::RefTag);
|
||||||
clear_pending(ISR::RefTag);
|
clear_pending(ISR::RefTag);
|
||||||
|
|
||||||
helper_pll().expect("failed to run helper DCXO PLL");
|
helper_pll().expect("failed to run helper DCXO PLL");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,22 +518,25 @@ pub mod wrpll {
|
||||||
|
|
||||||
fn helper_pll() -> Result<(), &'static str> {
|
fn helper_pll() -> Result<(), &'static str> {
|
||||||
let period_err = tag_collector::get_period_error();
|
let period_err = tag_collector::get_period_error();
|
||||||
|
unsafe {
|
||||||
let h_adpll = unsafe {
|
// Based on https://hackmd.io/IACbwcOTSt6Adj3_F9bKuw?view#Integral-wind-up-and-output-limiting
|
||||||
H_INTEGRATOR += period_err * KI;
|
let adpll = (H_LAST_ADPLL + (KP + KI) * period_err - KP * LAST_PERIOD_ERR).clamp(-ADPLL_LIM, ADPLL_LIM);
|
||||||
(BASE_ADPLL + period_err * KP + H_INTEGRATOR).clamp(-ADPLL_MAX, ADPLL_MAX)
|
set_adpll(i2c::DCXO::Helper, BASE_ADPLL + adpll)?;
|
||||||
|
H_LAST_ADPLL = adpll;
|
||||||
|
LAST_PERIOD_ERR = period_err;
|
||||||
};
|
};
|
||||||
set_adpll(i2c::DCXO::Helper, h_adpll)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main_pll() -> Result<(), &'static str> {
|
fn main_pll() -> Result<(), &'static str> {
|
||||||
let phase_err = tag_collector::get_phase_error();
|
let phase_err = tag_collector::get_phase_error();
|
||||||
let m_adpll = unsafe {
|
unsafe {
|
||||||
M_INTEGRATOR += phase_err * KI;
|
// Based on https://hackmd.io/IACbwcOTSt6Adj3_F9bKuw?view#Integral-wind-up-and-output-limiting
|
||||||
(BASE_ADPLL + phase_err * KP + M_INTEGRATOR).clamp(-ADPLL_MAX, ADPLL_MAX)
|
let adpll = (M_LAST_ADPLL + (KP + KI) * phase_err - KP * LAST_PHASE_ERR).clamp(-ADPLL_LIM, ADPLL_LIM);
|
||||||
|
set_adpll(i2c::DCXO::Main, BASE_ADPLL + adpll)?;
|
||||||
|
M_LAST_ADPLL = adpll;
|
||||||
|
LAST_PHASE_ERR = phase_err;
|
||||||
};
|
};
|
||||||
set_adpll(i2c::DCXO::Main, m_adpll)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -646,6 +653,8 @@ pub mod wrpll {
|
||||||
if rc {
|
if rc {
|
||||||
tag_collector::reset();
|
tag_collector::reset();
|
||||||
reset_plls(timer).expect("failed to reset main and helper PLL");
|
reset_plls(timer).expect("failed to reset main and helper PLL");
|
||||||
|
|
||||||
|
// get within capture range
|
||||||
set_base_adpll().expect("failed to set base adpll");
|
set_base_adpll().expect("failed to set base adpll");
|
||||||
|
|
||||||
// clear gateware pending flag
|
// clear gateware pending flag
|
||||||
|
|
Loading…
Reference in New Issue