Add grabber module to release-7 #271

Merged
sb10q merged 1 commits from esavkin/artiq-zynq:264-grabber-backport into release-7 2023-10-19 14:24:03 +08:00
5 changed files with 195 additions and 4 deletions

View File

@ -77,7 +77,7 @@ class RTIOCRG(Module, AutoCSR):
MultiReg(pll_locked, self.pll_locked.status) MultiReg(pll_locked, self.pll_locked.status)
] ]
eem_iostandard_dict = { eem_iostandard_dict = {
0: "LVDS_25", 0: "LVDS_25",
1: "LVDS_25", 1: "LVDS_25",
@ -114,6 +114,7 @@ class SMAClkinForward(Module):
class GenericStandalone(SoCCore): class GenericStandalone(SoCCore):
def __init__(self, description, acpki=False): def __init__(self, description, acpki=False):
self.acpki = acpki self.acpki = acpki
sys_clk_freq = 125e6
platform = kasli_soc.Platform() platform = kasli_soc.Platform()
platform.toolchain.bitstream_commands.extend([ platform.toolchain.bitstream_commands.extend([
@ -142,6 +143,7 @@ class GenericStandalone(SoCCore):
self.ps7.cd_sys.clk, self.ps7.cd_sys.clk,
self.rtio_crg.cd_rtio.clk) self.rtio_crg.cd_rtio.clk)
fix_serdes_timing_path(platform) fix_serdes_timing_path(platform)
self.config["CLOCK_FREQUENCY"] = int(sys_clk_freq)
Outdated
Review

Looks incorrect. On softcore platforms this is set by MiSoC which does not know anything about RTIO, so this has to be the system clock frequency.

Looks incorrect. On softcore platforms this is set by MiSoC which does not know anything about RTIO, so this has to be the system clock frequency.

Is that that is defined by such line in GenericMaster?

sys_clk_freq = 125e6
Is that that is defined by such line in GenericMaster? ``` sys_clk_freq = 125e6 ```
Outdated
Review

I'm just talking about the value of self.config["CLOCK_FREQUENCY"] here.

I'm just talking about the value of ``self.config["CLOCK_FREQUENCY"]`` here.

I'm just talking about the value of self.config["CLOCK_FREQUENCY"] here.

Yes, I mean so this has to be the system clock frequency refers to sys_clk_freq = 125e6 ? Or it is another variable generated somewhere else?

> I'm just talking about the value of ``self.config["CLOCK_FREQUENCY"]`` here. Yes, I mean `so this has to be the system clock frequency` refers to `sys_clk_freq = 125e6` ? Or it is another variable generated somewhere else?

sys_clk_freq is the one that should be used, as grabber clock is based off the system clock domain (deserializer_7series.py#L22) , and as RTIO clock (theoretically) can be of a different frequency.

And yes it's defined right there. Migen-axi doesn't redefine the sys clock.

``sys_clk_freq`` is the one that should be used, as grabber clock is based off the system clock domain ([deserializer_7series.py#L22](https://github.com/m-labs/artiq/blob/release-7/artiq/gateware/grabber/deserializer_7series.py#L22)) , and as RTIO clock (theoretically) can be of a different frequency. And yes it's defined right there. Migen-axi doesn't redefine the sys clock.
self.rtio_channels = [] self.rtio_channels = []
has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"]) has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"])
@ -226,6 +228,7 @@ class GenericMaster(SoCCore):
pads=data_pads, pads=data_pads,
sys_clk_freq=sys_clk_freq) sys_clk_freq=sys_clk_freq)
self.csr_devices.append("drtio_transceiver") self.csr_devices.append("drtio_transceiver")
self.config["CLOCK_FREQUENCY"] = int(sys_clk_freq)
self.crg = self.ps7 # HACK for eem_7series to find the clock self.crg = self.ps7 # HACK for eem_7series to find the clock
self.submodules.rtio_crg = RTIOClockMultiplier(rtio_clk_freq) self.submodules.rtio_crg = RTIOClockMultiplier(rtio_clk_freq)
@ -330,7 +333,7 @@ class GenericMaster(SoCCore):
class GenericSatellite(SoCCore): class GenericSatellite(SoCCore):
def __init__(self, description, acpki=False): def __init__(self, description, acpki=False):
sys_clk_freq = 125e6 sys_clk_freq = 125e6
rtio_clk_freq = description["rtio_frequency"] rtio_clk_freq = description["rtio_frequency"]
self.acpki = acpki self.acpki = acpki
@ -353,7 +356,7 @@ class GenericSatellite(SoCCore):
self.submodules.rtio_crg = RTIOClockMultiplier(rtio_clk_freq) self.submodules.rtio_crg = RTIOClockMultiplier(rtio_clk_freq)
self.csr_devices.append("rtio_crg") self.csr_devices.append("rtio_crg")
fix_serdes_timing_path(platform) fix_serdes_timing_path(platform)
data_pads = [platform.request("sfp", i) for i in range(4)] data_pads = [platform.request("sfp", i) for i in range(4)]
self.submodules.drtio_transceiver = gtx_7series.GTX( self.submodules.drtio_transceiver = gtx_7series.GTX(
@ -458,6 +461,7 @@ class GenericSatellite(SoCCore):
rtio_clk_period = 1e9/rtio_clk_freq rtio_clk_period = 1e9/rtio_clk_freq
self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6)
self.config["CLOCK_FREQUENCY"] = int(sys_clk_freq)
self.submodules.siphaser = SiPhaser7Series( self.submodules.siphaser = SiPhaser7Series(
si5324_clkin=platform.request("cdr_clk"), si5324_clkin=platform.request("cdr_clk"),
@ -485,7 +489,7 @@ class GenericSatellite(SoCCore):
self.config["HAS_GRABBER"] = None self.config["HAS_GRABBER"] = None
self.add_csr_group("grabber", self.grabber_csr_group) self.add_csr_group("grabber", self.grabber_csr_group)
# no RTIO CRG here # no RTIO CRG here
self.submodules.virtual_leds = virtual_leds.VirtualLeds() self.submodules.virtual_leds = virtual_leds.VirtualLeds()
self.csr_devices.append("virtual_leds") self.csr_devices.append("virtual_leds")

View File

@ -0,0 +1,163 @@
use log::info;
use crate::pl::csr;
#[derive(PartialEq, Clone, Copy)]
enum State {
Reset,
ExitReset,
Lock,
Align,
Watch,
}
#[derive(Clone, Copy)]
struct Info {
state: State,
frame_size: (u16, u16),
}
static mut INFO: [Info; csr::GRABBER_LEN] = [Info {
state: State::Reset,
frame_size: (0, 0),
}; csr::GRABBER_LEN];
fn get_pll_reset(g: usize) -> bool {
unsafe { (csr::GRABBER[g].pll_reset_read)() != 0 }
}
fn set_pll_reset(g: usize, reset: bool) {
let val = if reset { 1 } else { 0 };
unsafe { (csr::GRABBER[g].pll_reset_write)(val) }
}
fn pll_locked(g: usize) -> bool {
unsafe { (csr::GRABBER[g].pll_locked_read)() != 0 }
}
fn clock_pattern_ok(g: usize) -> bool {
unsafe { (csr::GRABBER[g].clk_sampled_read)() == 0b1100011 }
}
fn clock_pattern_ok_filter(g: usize) -> bool {
for _ in 0..128 {
if !clock_pattern_ok(g) {
return false;
}
}
true
}
fn phase_shift(g: usize, direction: u8) {
unsafe {
(csr::GRABBER[g].phase_shift_write)(direction);
while (csr::GRABBER[g].phase_shift_done_read)() == 0 {}
}
}
fn clock_align(g: usize) -> bool {
while clock_pattern_ok_filter(g) {
phase_shift(g, 1);
}
phase_shift(g, 1);
let mut count = 0;
while !clock_pattern_ok_filter(g) {
phase_shift(g, 1);
count += 1;
if count > 1024 {
return false;
}
}
let mut window = 1;
phase_shift(g, 1);
while clock_pattern_ok_filter(g) {
phase_shift(g, 1);
window += 1;
}
for _ in 0..window / 2 {
phase_shift(g, 0);
}
true
}
fn get_last_pixels(g: usize) -> (u16, u16) {
unsafe { ((csr::GRABBER[g].last_x_read)(), (csr::GRABBER[g].last_y_read)()) }
}
fn get_video_clock(g: usize) -> u32 {
let freq_count = unsafe { (csr::GRABBER[g].freq_count_read)() } as u32;
2 * freq_count * (csr::CONFIG_CLOCK_FREQUENCY / 1000) / (511 * 1000)
}
pub fn tick() {
for g in 0..csr::GRABBER.len() {
let next = match unsafe { INFO[g].state } {
State::Reset => {
set_pll_reset(g, true);
unsafe {
INFO[g].frame_size = (0, 0);
}
State::ExitReset
}
State::ExitReset => {
if get_pll_reset(g) {
set_pll_reset(g, false);
State::Lock
} else {
State::ExitReset
}
}
State::Lock => {
if pll_locked(g) {
info!("grabber{} locked: {}MHz", g, get_video_clock(g));
State::Align
} else {
State::Lock
}
}
State::Align => {
if pll_locked(g) {
if clock_align(g) {
info!("grabber{} alignment success", g);
State::Watch
} else {
info!("grabber{} alignment failure", g);
State::Reset
}
} else {
info!("grabber{} lock lost", g);
State::Reset
}
}
State::Watch => {
if pll_locked(g) {
if clock_pattern_ok(g) {
let last_xy = get_last_pixels(g);
if last_xy != unsafe { INFO[g].frame_size } {
// x capture is on ~LVAL which is after
// the last increment on DVAL
// y capture is on ~FVAL which coincides with the
// last increment on ~LVAL
info!("grabber{} frame size: {}x{}", g, last_xy.0, last_xy.1 + 1);
unsafe { INFO[g].frame_size = last_xy }
}
State::Watch
} else {
info!("grabber{} alignment lost", g);
State::Reset
}
} else {
info!("grabber{} lock lost", g);
State::Reset
}
}
};
unsafe {
INFO[g].state = next;
}
}
}

View File

@ -29,6 +29,8 @@ pub mod drtioaux_async;
pub mod mem; pub mod mem;
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
pub mod io_expander; pub mod io_expander;
#[cfg(has_grabber)]
pub mod grabber;
use core::{cmp, str}; use core::{cmp, str};
use libboard_zynq::slcr; use libboard_zynq::slcr;

View File

@ -110,6 +110,21 @@ async fn io_expanders_service(
.expect("I2C I/O expander #1 service failed"); .expect("I2C I/O expander #1 service failed");
} }
} }
#[cfg(has_grabber)]
mod grabber {
use libasync::delay;
use libboard_artiq::grabber;
use libboard_zynq::time::Milliseconds;
use crate::GlobalTimer;
pub async fn grabber_thread(timer: GlobalTimer) {
let mut countdown = timer.countdown();
loop {
grabber::tick();
delay(&mut countdown, Milliseconds(200)).await;
}
}
}
static mut LOG_BUFFER: [u8; 1<<17] = [0; 1<<17]; static mut LOG_BUFFER: [u8; 1<<17] = [0; 1<<17];
#[no_mangle] #[no_mangle]
@ -168,6 +183,9 @@ pub fn main_core0() {
task::spawn(report_async_rtio_errors()); task::spawn(report_async_rtio_errors());
#[cfg(has_grabber)]
task::spawn(grabber::grabber_thread(timer));
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
task::spawn(io_expanders_service( task::spawn(io_expanders_service(
RefCell::new(i2c_bus), RefCell::new(i2c_bus),

View File

@ -20,6 +20,8 @@ extern crate alloc;
use libboard_zynq::{i2c::I2c, timer::GlobalTimer, time::Milliseconds, print, println, mpcore, gic, stdio}; use libboard_zynq::{i2c::I2c, timer::GlobalTimer, time::Milliseconds, print, println, mpcore, gic, stdio};
use libsupport_zynq::ram; use libsupport_zynq::ram;
#[cfg(has_grabber)]
use libboard_artiq::grabber;
#[cfg(has_si5324)] #[cfg(has_si5324)]
use libboard_artiq::si5324; use libboard_artiq::si5324;
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
@ -417,6 +419,8 @@ fn hardware_tick(ts: &mut u64, timer: &mut GlobalTimer) {
if now > ts_ms { if now > ts_ms {
ts_ms = now + Milliseconds(200); ts_ms = now + Milliseconds(200);
*ts = ts_ms.0; *ts = ts_ms.0;
#[cfg(has_grabber)]
grabber::tick();
} }
} }