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)]
|
#[cfg(has_si5324)]
|
||||||
pub mod si5324;
|
pub mod si5324;
|
||||||
|
#[cfg(has_wrpll)]
|
||||||
|
pub mod wrpll;
|
||||||
|
|
||||||
#[cfg(has_hmc830_7043)]
|
#[cfg(has_hmc830_7043)]
|
||||||
pub mod hmc830_7043;
|
pub mod hmc830_7043;
|
||||||
|
|
|
@ -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 core::convert::TryFrom;
|
||||||
use board_misoc::{csr, irq, ident, clock, uart_logger, i2c};
|
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;
|
use board_artiq::drtio_routing;
|
||||||
#[cfg(has_hmc830_7043)]
|
#[cfg(has_hmc830_7043)]
|
||||||
use board_artiq::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
|
const SI5324_SETTINGS: si5324::FrequencySettings
|
||||||
= si5324::FrequencySettings {
|
= si5324::FrequencySettings {
|
||||||
n1_hs : 6,
|
n1_hs : 6,
|
||||||
|
@ -426,7 +430,7 @@ const SI5324_SETTINGS: si5324::FrequencySettings
|
||||||
crystal_ref: true
|
crystal_ref: true
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(rtio_frequency = "125.0")]
|
#[cfg(all(has_si5324, rtio_frequency = "125.0"))]
|
||||||
const SI5324_SETTINGS: si5324::FrequencySettings
|
const SI5324_SETTINGS: si5324::FrequencySettings
|
||||||
= si5324::FrequencySettings {
|
= si5324::FrequencySettings {
|
||||||
n1_hs : 5,
|
n1_hs : 5,
|
||||||
|
@ -448,8 +452,13 @@ pub extern fn main() -> i32 {
|
||||||
info!("software ident {}", csr::CONFIG_IDENTIFIER_STR);
|
info!("software ident {}", csr::CONFIG_IDENTIFIER_STR);
|
||||||
info!("gateware ident {}", ident::read(&mut [0; 64]));
|
info!("gateware ident {}", ident::read(&mut [0; 64]));
|
||||||
|
|
||||||
i2c::init().expect("I2C initialization failed");
|
#[cfg(has_si5324)]
|
||||||
si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324");
|
{
|
||||||
|
i2c::init().expect("I2C initialization failed");
|
||||||
|
si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324");
|
||||||
|
}
|
||||||
|
#[cfg(has_wrpll)]
|
||||||
|
wrpll::init();
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::drtio_transceiver::stable_clkin_write(1);
|
csr::drtio_transceiver::stable_clkin_write(1);
|
||||||
}
|
}
|
||||||
|
@ -490,8 +499,13 @@ pub extern fn main() -> i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("uplink is up, switching to recovered clock");
|
info!("uplink is up, switching to recovered clock");
|
||||||
si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks");
|
#[cfg(has_si5324)]
|
||||||
si5324::siphaser::calibrate_skew().expect("failed to calibrate skew");
|
{
|
||||||
|
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)]
|
#[cfg(has_jdcg)]
|
||||||
{
|
{
|
||||||
|
@ -561,8 +575,11 @@ pub extern fn main() -> i32 {
|
||||||
drtiosat_reset_phy(true);
|
drtiosat_reset_phy(true);
|
||||||
drtiosat_reset(true);
|
drtiosat_reset(true);
|
||||||
drtiosat_tsc_loaded();
|
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");
|
si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks");
|
||||||
|
#[cfg(has_wrpll)]
|
||||||
|
wrpll::select_recovered_clock(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,26 +130,10 @@ class SatelliteBase(MiniSoC):
|
||||||
self.add_csr_group("drtiorep", drtiorep_csr_group)
|
self.add_csr_group("drtiorep", drtiorep_csr_group)
|
||||||
|
|
||||||
self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6)
|
self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6)
|
||||||
self.comb += platform.request("filtered_clk_sel").eq(1)
|
|
||||||
self.submodules.siphaser = SiPhaser7Series(
|
|
||||||
si5324_clkin=platform.request("si5324_clkin"),
|
|
||||||
rx_synchronizer=self.rx_synchronizer,
|
|
||||||
ultrascale=True,
|
|
||||||
rtio_clk_freq=rtio_clk_freq)
|
|
||||||
platform.add_false_path_constraints(
|
|
||||||
self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output)
|
|
||||||
self.csr_devices.append("siphaser")
|
|
||||||
self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n)
|
|
||||||
self.csr_devices.append("si5324_rst_n")
|
|
||||||
i2c = self.platform.request("i2c")
|
|
||||||
self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda])
|
|
||||||
self.csr_devices.append("i2c")
|
|
||||||
self.config["I2C_BUS_COUNT"] = 1
|
|
||||||
self.config["HAS_SI5324"] = None
|
|
||||||
|
|
||||||
if with_wrpll:
|
if with_wrpll:
|
||||||
# TODO: check OE polarity (depends on what was installed on the boards)
|
# TODO: check OE polarity (depends on what was installed on the boards)
|
||||||
self.comb += [
|
self.comb += [
|
||||||
|
platform.request("filtered_clk_sel").eq(0),
|
||||||
platform.request("ddmtd_main_dcxo_oe").eq(1),
|
platform.request("ddmtd_main_dcxo_oe").eq(1),
|
||||||
platform.request("ddmtd_helper_dcxo_oe").eq(1)
|
platform.request("ddmtd_helper_dcxo_oe").eq(1)
|
||||||
]
|
]
|
||||||
|
@ -157,6 +141,23 @@ class SatelliteBase(MiniSoC):
|
||||||
main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"),
|
main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"),
|
||||||
helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"))
|
helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"))
|
||||||
self.csr_devices.append("wrpll")
|
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"),
|
||||||
|
rx_synchronizer=self.rx_synchronizer,
|
||||||
|
ultrascale=True,
|
||||||
|
rtio_clk_freq=rtio_clk_freq)
|
||||||
|
platform.add_false_path_constraints(
|
||||||
|
self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output)
|
||||||
|
self.csr_devices.append("siphaser")
|
||||||
|
self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n)
|
||||||
|
self.csr_devices.append("si5324_rst_n")
|
||||||
|
i2c = self.platform.request("i2c")
|
||||||
|
self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda])
|
||||||
|
self.csr_devices.append("i2c")
|
||||||
|
self.config["I2C_BUS_COUNT"] = 1
|
||||||
|
self.config["HAS_SI5324"] = None
|
||||||
|
|
||||||
rtio_clk_period = 1e9/rtio_clk_freq
|
rtio_clk_period = 1e9/rtio_clk_freq
|
||||||
gth = self.drtio_transceiver.gths[0]
|
gth = self.drtio_transceiver.gths[0]
|
||||||
|
|
Loading…
Reference in New Issue