diff --git a/artiq/firmware/libboard_artiq/grabber.rs b/artiq/firmware/libboard_artiq/grabber.rs new file mode 100644 index 000000000..a70cb0e28 --- /dev/null +++ b/artiq/firmware/libboard_artiq/grabber.rs @@ -0,0 +1,93 @@ +use board_misoc::csr; + +static mut GRABBER_UP: &'static mut [bool] = &mut [false; 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 +} + +pub fn tick() { + for g in 0..csr::GRABBER.len() { + if unsafe { GRABBER_UP[g] } { + if !clock_pattern_ok(g) || !pll_locked(g) { + set_pll_reset(g, true); + unsafe { GRABBER_UP[g] = false; } + info!("grabber{} is down", g); + } + } else { + if get_pll_reset(g) { + set_pll_reset(g, false); + } else { + if pll_locked(g) { + info!("grabber{} PLL is locked", g); + if clock_align(g) { + info!("grabber{} is up", g); + unsafe { GRABBER_UP[g] = true; } + } else { + set_pll_reset(g, true); + } + } else { + set_pll_reset(g, true); + } + } + } + } +} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index af8c1336a..3402a1d2f 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -40,6 +40,8 @@ mod ad9154_reg; pub mod ad9154; #[cfg(has_allaki_atts)] pub mod hmc542; +#[cfg(has_grabber)] +pub mod grabber; #[cfg(has_drtio)] pub mod drtioaux; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index f0bef4108..eaaa1721d 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -168,6 +168,14 @@ fn setup_si5324_as_synthesizer() board_artiq::si5324::Input::Ckin2).expect("cannot initialize Si5324"); } +#[cfg(has_grabber)] +fn grabber_thread(io: sched::Io) { + loop { + board_artiq::grabber::tick(); + io.sleep(200).unwrap(); + } +} + #[cfg(has_ethmac)] fn startup_ethernet() { let hardware_addr; @@ -237,6 +245,8 @@ fn startup_ethernet() { io.spawn(4096, moninj::thread); #[cfg(has_rtio_analyzer)] io.spawn(4096, analyzer::thread); + #[cfg(has_grabber)] + io.spawn(4096, grabber_thread); let mut net_stats = ethmac::EthernetStatistics::new(); loop { diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index ec43ce29c..8ecff1168 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_35+git9bc084a - - misoc 0.11 py35_14+gitc60ccfb2 + - misoc 0.11 py35_15+git7f63aff5 - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27