From 4f56710e4beb1c767dc10f7ddbdc283742540508 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jul 2018 02:06:37 +0800 Subject: [PATCH] grabber: add parser, report detected frame size in core device log --- artiq/firmware/libboard_artiq/grabber.rs | 26 ++++++-- artiq/gateware/grabber/core.py | 77 ++++++++++++++++++++++++ artiq/gateware/rtio/phy/grabber.py | 5 +- 3 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 artiq/gateware/grabber/core.py diff --git a/artiq/firmware/libboard_artiq/grabber.rs b/artiq/firmware/libboard_artiq/grabber.rs index a70cb0e28..7df41d3cc 100644 --- a/artiq/firmware/libboard_artiq/grabber.rs +++ b/artiq/firmware/libboard_artiq/grabber.rs @@ -1,6 +1,13 @@ use board_misoc::csr; -static mut GRABBER_UP: &'static mut [bool] = &mut [false; csr::GRABBER_LEN]; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum State { + Down, + WaitResolution, + Up +} + +static mut GRABBER_STATE: &'static mut [State] = &mut [State::Down; csr::GRABBER_LEN]; fn get_pll_reset(g: usize) -> bool { unsafe { (csr::GRABBER[g].pll_reset_read)() != 0 } @@ -64,14 +71,25 @@ fn clock_align(g: usize) -> bool { true } +fn get_last_pixels(g: usize) -> (u16, u16) { + unsafe { ((csr::GRABBER[g].last_x_read)(), + (csr::GRABBER[g].last_y_read)()) } +} + pub fn tick() { for g in 0..csr::GRABBER.len() { - if unsafe { GRABBER_UP[g] } { + if unsafe { GRABBER_STATE[g] != State::Down } { if !clock_pattern_ok(g) || !pll_locked(g) { set_pll_reset(g, true); - unsafe { GRABBER_UP[g] = false; } + unsafe { GRABBER_STATE[g] = State::Down; } info!("grabber{} is down", g); } + if unsafe { GRABBER_STATE[g] == State::WaitResolution } { + let (last_x, last_y) = get_last_pixels(g); + info!("grabber{} detected frame size: {}x{}", + g, last_x + 1, last_y + 1); + unsafe { GRABBER_STATE[g] = State::Up; } + } } else { if get_pll_reset(g) { set_pll_reset(g, false); @@ -80,7 +98,7 @@ pub fn tick() { info!("grabber{} PLL is locked", g); if clock_align(g) { info!("grabber{} is up", g); - unsafe { GRABBER_UP[g] = true; } + unsafe { GRABBER_STATE[g] = State::WaitResolution; } } else { set_pll_reset(g, true); } diff --git a/artiq/gateware/grabber/core.py b/artiq/gateware/grabber/core.py new file mode 100644 index 000000000..6385a27ee --- /dev/null +++ b/artiq/gateware/grabber/core.py @@ -0,0 +1,77 @@ +from migen import * +from migen.genlib.cdc import MultiReg +from misoc.interconnect.csr import * + + +bitseq = [ + # 0 1 2 3 4 5 6 + 6, 5, 4, 3, 2, 1, 27, + + # 7 8 9 10 11 12 13 + 26, 0, 13, 12, 11, 10, 9, + + # 14 15 16 17 18 19 20 + 25, 24, 8, 7, 20, 19, 18, + + # 21 22 23 + 17, 23, 22 +] + +assert len(set(bitseq)) == 24 + + +class Parser(Module, AutoCSR): + """Parses 28 bit encoded words and track pixel coordinates.""" + def __init__(self, width=12): + self.cl = cl = Signal(28) + + self.last_x = CSRStatus(width) + self.last_y = CSRStatus(width) + + self.pix = pix = Record([ + ("x", width), + ("y", width), + ("a", 8), + ("b", 8), + ("c", 8), + ("stb", 1), # dval + ("eop", 1), # ~fval (i.e. not together with stb) + ]) + + # # # + + last_x = Signal(width) + last_y = Signal(width) + + lval = Signal() + fval = Signal() + dval = Signal() + self.comb += [ + Cat(dval, fval, lval).eq(cl[14:17]), + pix.stb.eq(dval), + pix.eop.eq(~fval), + Cat(pix.a, pix.b, pix.c).eq(Cat(cl[i] for i in bitseq)) + ] + last_lval = Signal() + last_fval = Signal() + self.sync.cl += [ + last_lval.eq(lval), + last_fval.eq(fval), + pix.x.eq(pix.x + 1), + If(~lval, + pix.x.eq(0), + If(last_lval, last_x.eq(pix.x)), + If(last_fval & last_lval, + pix.y.eq(pix.y + 1) + ) + ), + If(~fval, + If(last_fval, last_y.eq(pix.y)), + pix.y.eq(0) + ) + ] + + self.specials += [ + MultiReg(last_x, self.last_x.status), + MultiReg(last_y, self.last_y.status) + ] diff --git a/artiq/gateware/rtio/phy/grabber.py b/artiq/gateware/rtio/phy/grabber.py index 9d1a151d7..5639cfaae 100644 --- a/artiq/gateware/rtio/phy/grabber.py +++ b/artiq/gateware/rtio/phy/grabber.py @@ -2,6 +2,7 @@ from migen import * from artiq.gateware.rtio import rtlink from artiq.gateware.grabber import deserializer_7series +from artiq.gateware.grabber.core import * class Grabber(Module): @@ -11,6 +12,8 @@ class Grabber(Module): rtlink.IInterface(10)) self.submodules.deserializer = deserializer_7series.Deserializer(pins) + self.submodules.parser = Parser() + self.comb += self.parser.cl.eq(self.deserializer.q) def get_csrs(self): - return self.deserializer.get_csrs() + return self.deserializer.get_csrs() + self.parser.get_csrs()