forked from M-Labs/artiq
wrpll: i2c functions, select_recovered_clock placeholder
This commit is contained in:
parent
449d2c4f08
commit
4832bfb08c
@ -26,6 +26,8 @@ pub mod rpc_queue;
|
||||
|
||||
#[cfg(has_si5324)]
|
||||
pub mod si5324;
|
||||
#[cfg(has_wrpll)]
|
||||
pub mod wrpll;
|
||||
|
||||
#[cfg(has_hmc830_7043)]
|
||||
pub mod hmc830_7043;
|
||||
|
190
artiq/firmware/libboard_artiq/wrpll.rs
Normal file
190
artiq/firmware/libboard_artiq/wrpll.rs
Normal file
@ -0,0 +1,190 @@
|
||||
mod i2c {
|
||||
use board_misoc::{csr, clock};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Dcxo {
|
||||
Main,
|
||||
Helper
|
||||
}
|
||||
|
||||
fn half_period() { clock::spin_us(100) }
|
||||
const SDA_MASK: u8 = 2;
|
||||
const SCL_MASK: u8 = 1;
|
||||
|
||||
fn sda_i(dcxo: Dcxo) -> bool {
|
||||
let reg = match dcxo {
|
||||
Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_in_read() },
|
||||
Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_in_read() },
|
||||
};
|
||||
reg & SDA_MASK != 0
|
||||
}
|
||||
|
||||
fn sda_oe(dcxo: Dcxo, oe: bool) {
|
||||
let reg = match dcxo {
|
||||
Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_oe_read() },
|
||||
Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_oe_read() },
|
||||
};
|
||||
let reg = if oe { reg | SDA_MASK } else { reg & !SDA_MASK };
|
||||
match dcxo {
|
||||
Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_oe_write(reg) },
|
||||
Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_oe_write(reg) }
|
||||
}
|
||||
}
|
||||
|
||||
fn sda_o(dcxo: Dcxo, o: bool) {
|
||||
let reg = match dcxo {
|
||||
Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_out_read() },
|
||||
Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_out_read() },
|
||||
};
|
||||
let reg = if o { reg | SDA_MASK } else { reg & !SDA_MASK };
|
||||
match dcxo {
|
||||
Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_out_write(reg) },
|
||||
Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_out_write(reg) }
|
||||
}
|
||||
}
|
||||
|
||||
fn scl_oe(dcxo: Dcxo, oe: bool) {
|
||||
let reg = match dcxo {
|
||||
Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_oe_read() },
|
||||
Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_oe_read() },
|
||||
};
|
||||
let reg = if oe { reg | SCL_MASK } else { reg & !SCL_MASK };
|
||||
match dcxo {
|
||||
Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_oe_write(reg) },
|
||||
Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_oe_write(reg) }
|
||||
}
|
||||
}
|
||||
|
||||
fn scl_o(dcxo: Dcxo, o: bool) {
|
||||
let reg = match dcxo {
|
||||
Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_out_read() },
|
||||
Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_out_read() },
|
||||
};
|
||||
let reg = if o { reg | SCL_MASK } else { reg & !SCL_MASK };
|
||||
match dcxo {
|
||||
Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_out_write(reg) },
|
||||
Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_out_write(reg) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(dcxo: Dcxo) -> Result<(), &'static str> {
|
||||
// Set SCL as output, and high level
|
||||
scl_o(dcxo, true);
|
||||
scl_oe(dcxo, true);
|
||||
// Prepare a zero level on SDA so that sda_oe pulls it down
|
||||
sda_o(dcxo, false);
|
||||
// Release SDA
|
||||
sda_oe(dcxo, false);
|
||||
|
||||
// Check the I2C bus is ready
|
||||
half_period();
|
||||
half_period();
|
||||
if !sda_i(dcxo) {
|
||||
// Try toggling SCL a few times
|
||||
for _bit in 0..8 {
|
||||
scl_o(dcxo, false);
|
||||
half_period();
|
||||
scl_o(dcxo, true);
|
||||
half_period();
|
||||
}
|
||||
}
|
||||
|
||||
if !sda_i(dcxo) {
|
||||
return Err("SDA is stuck low and doesn't get unstuck");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start(dcxo: Dcxo) {
|
||||
// Set SCL high then SDA low
|
||||
scl_o(dcxo, true);
|
||||
half_period();
|
||||
sda_oe(dcxo, true);
|
||||
half_period();
|
||||
}
|
||||
|
||||
pub fn restart(dcxo: Dcxo) {
|
||||
// Set SCL low then SDA high */
|
||||
scl_o(dcxo, false);
|
||||
half_period();
|
||||
sda_oe(dcxo, false);
|
||||
half_period();
|
||||
// Do a regular start
|
||||
start(dcxo);
|
||||
}
|
||||
|
||||
pub fn stop(dcxo: Dcxo) {
|
||||
// First, make sure SCL is low, so that the target releases the SDA line
|
||||
scl_o(dcxo, false);
|
||||
half_period();
|
||||
// Set SCL high then SDA high
|
||||
sda_oe(dcxo, true);
|
||||
scl_o(dcxo, true);
|
||||
half_period();
|
||||
sda_oe(dcxo, false);
|
||||
half_period();
|
||||
}
|
||||
|
||||
pub fn write(dcxo: Dcxo, data: u8) -> bool {
|
||||
// MSB first
|
||||
for bit in (0..8).rev() {
|
||||
// Set SCL low and set our bit on SDA
|
||||
scl_o(dcxo, false);
|
||||
sda_oe(dcxo, data & (1 << bit) == 0);
|
||||
half_period();
|
||||
// Set SCL high ; data is shifted on the rising edge of SCL
|
||||
scl_o(dcxo, true);
|
||||
half_period();
|
||||
}
|
||||
// Check ack
|
||||
// Set SCL low, then release SDA so that the I2C target can respond
|
||||
scl_o(dcxo, false);
|
||||
half_period();
|
||||
sda_oe(dcxo, false);
|
||||
// Set SCL high and check for ack
|
||||
scl_o(dcxo, true);
|
||||
half_period();
|
||||
// returns true if acked (I2C target pulled SDA low)
|
||||
!sda_i(dcxo)
|
||||
}
|
||||
|
||||
pub fn read(dcxo: Dcxo, ack: bool) -> u8 {
|
||||
// Set SCL low first, otherwise setting SDA as input may cause a transition
|
||||
// on SDA with SCL high which will be interpreted as START/STOP condition.
|
||||
scl_o(dcxo, false);
|
||||
half_period(); // make sure SCL has settled low
|
||||
sda_oe(dcxo, false);
|
||||
|
||||
let mut data: u8 = 0;
|
||||
|
||||
// MSB first
|
||||
for bit in (0..8).rev() {
|
||||
scl_o(dcxo, false);
|
||||
half_period();
|
||||
// Set SCL high and shift data
|
||||
scl_o(dcxo, true);
|
||||
half_period();
|
||||
if sda_i(dcxo) { data |= 1 << bit }
|
||||
}
|
||||
// Send ack
|
||||
// Set SCL low and pull SDA low when acking
|
||||
scl_o(dcxo, false);
|
||||
if ack { sda_oe(dcxo, true) }
|
||||
half_period();
|
||||
// then set SCL high
|
||||
scl_o(dcxo, true);
|
||||
half_period();
|
||||
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
info!("initializing...");
|
||||
i2c::init(i2c::Dcxo::Main);
|
||||
i2c::init(i2c::Dcxo::Helper);
|
||||
}
|
||||
|
||||
pub fn select_recovered_clock(rc: bool) {
|
||||
info!("select_recovered_clock: {}", rc);
|
||||
}
|
@ -9,7 +9,11 @@ extern crate board_artiq;
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use board_misoc::{csr, irq, ident, clock, uart_logger, i2c};
|
||||
use board_artiq::{spi, si5324, drtioaux};
|
||||
#[cfg(has_si5324)]
|
||||
use board_artiq::si5324;
|
||||
#[cfg(has_wrpll)]
|
||||
use board_artiq::wrpll;
|
||||
use board_artiq::{spi, drtioaux};
|
||||
use board_artiq::drtio_routing;
|
||||
#[cfg(has_hmc830_7043)]
|
||||
use board_artiq::hmc830_7043;
|
||||
@ -413,7 +417,7 @@ fn hardware_tick(ts: &mut u64) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(rtio_frequency = "150.0")]
|
||||
#[cfg(all(has_si5324, rtio_frequency = "150.0"))]
|
||||
const SI5324_SETTINGS: si5324::FrequencySettings
|
||||
= si5324::FrequencySettings {
|
||||
n1_hs : 6,
|
||||
@ -426,7 +430,7 @@ const SI5324_SETTINGS: si5324::FrequencySettings
|
||||
crystal_ref: true
|
||||
};
|
||||
|
||||
#[cfg(rtio_frequency = "125.0")]
|
||||
#[cfg(all(has_si5324, rtio_frequency = "125.0"))]
|
||||
const SI5324_SETTINGS: si5324::FrequencySettings
|
||||
= si5324::FrequencySettings {
|
||||
n1_hs : 5,
|
||||
@ -448,8 +452,13 @@ pub extern fn main() -> i32 {
|
||||
info!("software ident {}", csr::CONFIG_IDENTIFIER_STR);
|
||||
info!("gateware ident {}", ident::read(&mut [0; 64]));
|
||||
|
||||
#[cfg(has_si5324)]
|
||||
{
|
||||
i2c::init().expect("I2C initialization failed");
|
||||
si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324");
|
||||
}
|
||||
#[cfg(has_wrpll)]
|
||||
wrpll::init();
|
||||
unsafe {
|
||||
csr::drtio_transceiver::stable_clkin_write(1);
|
||||
}
|
||||
@ -490,8 +499,13 @@ pub extern fn main() -> i32 {
|
||||
}
|
||||
|
||||
info!("uplink is up, switching to recovered clock");
|
||||
#[cfg(has_si5324)]
|
||||
{
|
||||
si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks");
|
||||
si5324::siphaser::calibrate_skew().expect("failed to calibrate skew");
|
||||
}
|
||||
#[cfg(has_wrpll)]
|
||||
wrpll::select_recovered_clock(true);
|
||||
|
||||
#[cfg(has_jdcg)]
|
||||
{
|
||||
@ -561,8 +575,11 @@ pub extern fn main() -> i32 {
|
||||
drtiosat_reset_phy(true);
|
||||
drtiosat_reset(true);
|
||||
drtiosat_tsc_loaded();
|
||||
info!("uplink is down, switching to local crystal clock");
|
||||
info!("uplink is down, switching to local oscillator clock");
|
||||
#[cfg(has_si5324)]
|
||||
si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks");
|
||||
#[cfg(has_wrpll)]
|
||||
wrpll::select_recovered_clock(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,6 +130,18 @@ class SatelliteBase(MiniSoC):
|
||||
self.add_csr_group("drtiorep", drtiorep_csr_group)
|
||||
|
||||
self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6)
|
||||
if with_wrpll:
|
||||
# TODO: check OE polarity (depends on what was installed on the boards)
|
||||
self.comb += [
|
||||
platform.request("filtered_clk_sel").eq(0),
|
||||
platform.request("ddmtd_main_dcxo_oe").eq(1),
|
||||
platform.request("ddmtd_helper_dcxo_oe").eq(1)
|
||||
]
|
||||
self.submodules.wrpll = WRPLL(
|
||||
main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"),
|
||||
helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"))
|
||||
self.csr_devices.append("wrpll")
|
||||
else:
|
||||
self.comb += platform.request("filtered_clk_sel").eq(1)
|
||||
self.submodules.siphaser = SiPhaser7Series(
|
||||
si5324_clkin=platform.request("si5324_clkin"),
|
||||
@ -147,17 +159,6 @@ class SatelliteBase(MiniSoC):
|
||||
self.config["I2C_BUS_COUNT"] = 1
|
||||
self.config["HAS_SI5324"] = None
|
||||
|
||||
if with_wrpll:
|
||||
# TODO: check OE polarity (depends on what was installed on the boards)
|
||||
self.comb += [
|
||||
platform.request("ddmtd_main_dcxo_oe").eq(1),
|
||||
platform.request("ddmtd_helper_dcxo_oe").eq(1)
|
||||
]
|
||||
self.submodules.wrpll = WRPLL(
|
||||
main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"),
|
||||
helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"))
|
||||
self.csr_devices.append("wrpll")
|
||||
|
||||
rtio_clk_period = 1e9/rtio_clk_freq
|
||||
gth = self.drtio_transceiver.gths[0]
|
||||
platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2)
|
||||
|
Loading…
Reference in New Issue
Block a user