mirror of
https://github.com/m-labs/artiq.git
synced 2025-01-27 10:58:12 +08:00
Sebastien Bourdeauducq
a65721d649
* Fixes one bug where siphaser was one Si5324 output and the rest of the system was clocked by the other. With the Si5324 settings we have, skew between the outputs is not controlled. * Puts the coaxial cable between AMC and RTM into the siphaser loop.
341 lines
11 KiB
Rust
341 lines
11 KiB
Rust
#![feature(lang_items, never_type)]
|
|
#![no_std]
|
|
|
|
#[macro_use]
|
|
extern crate log;
|
|
#[macro_use]
|
|
extern crate board_misoc;
|
|
extern crate board_artiq;
|
|
|
|
use board_misoc::{csr, ident, clock, uart_logger};
|
|
use board_artiq::{i2c, spi, si5324, drtioaux};
|
|
#[cfg(has_serwb_phy_amc)]
|
|
use board_artiq::serwb;
|
|
#[cfg(has_hmc830_7043)]
|
|
use board_artiq::hmc830_7043;
|
|
|
|
fn drtio_reset(reset: bool) {
|
|
unsafe {
|
|
(csr::DRTIO[0].reset_write)(if reset { 1 } else { 0 });
|
|
}
|
|
}
|
|
|
|
fn drtio_reset_phy(reset: bool) {
|
|
unsafe {
|
|
(csr::DRTIO[0].reset_phy_write)(if reset { 1 } else { 0 });
|
|
}
|
|
}
|
|
|
|
fn drtio_tsc_loaded() -> bool {
|
|
unsafe {
|
|
let tsc_loaded = (csr::DRTIO[0].tsc_loaded_read)() == 1;
|
|
if tsc_loaded {
|
|
(csr::DRTIO[0].tsc_loaded_write)(1);
|
|
}
|
|
tsc_loaded
|
|
}
|
|
}
|
|
|
|
fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error<!>> {
|
|
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
|
|
// and u16 otherwise; hence the `as _` conversion.
|
|
match packet {
|
|
drtioaux::Packet::EchoRequest =>
|
|
drtioaux::send_link(0, &drtioaux::Packet::EchoReply),
|
|
drtioaux::Packet::ResetRequest { phy } => {
|
|
if phy {
|
|
drtio_reset_phy(true);
|
|
drtio_reset_phy(false);
|
|
} else {
|
|
drtio_reset(true);
|
|
drtio_reset(false);
|
|
}
|
|
drtioaux::send_link(0, &drtioaux::Packet::ResetAck)
|
|
},
|
|
|
|
drtioaux::Packet::RtioErrorRequest => {
|
|
let errors;
|
|
unsafe {
|
|
errors = (csr::DRTIO[0].rtio_error_read)();
|
|
}
|
|
if errors & 1 != 0 {
|
|
let channel;
|
|
unsafe {
|
|
channel = (csr::DRTIO[0].sequence_error_channel_read)();
|
|
(csr::DRTIO[0].rtio_error_write)(1);
|
|
}
|
|
drtioaux::send_link(0,
|
|
&drtioaux::Packet::RtioErrorSequenceErrorReply { channel })
|
|
} else if errors & 2 != 0 {
|
|
let channel;
|
|
unsafe {
|
|
channel = (csr::DRTIO[0].collision_channel_read)();
|
|
(csr::DRTIO[0].rtio_error_write)(2);
|
|
}
|
|
drtioaux::send_link(0,
|
|
&drtioaux::Packet::RtioErrorCollisionReply { channel })
|
|
} else if errors & 4 != 0 {
|
|
let channel;
|
|
unsafe {
|
|
channel = (csr::DRTIO[0].busy_channel_read)();
|
|
(csr::DRTIO[0].rtio_error_write)(4);
|
|
}
|
|
drtioaux::send_link(0,
|
|
&drtioaux::Packet::RtioErrorBusyReply { channel })
|
|
}
|
|
else {
|
|
drtioaux::send_link(0, &drtioaux::Packet::RtioNoErrorReply)
|
|
}
|
|
}
|
|
|
|
drtioaux::Packet::MonitorRequest { channel, probe } => {
|
|
let value;
|
|
#[cfg(has_rtio_moninj)]
|
|
unsafe {
|
|
csr::rtio_moninj::mon_chan_sel_write(channel as _);
|
|
csr::rtio_moninj::mon_probe_sel_write(probe);
|
|
csr::rtio_moninj::mon_value_update_write(1);
|
|
value = csr::rtio_moninj::mon_value_read();
|
|
}
|
|
#[cfg(not(has_rtio_moninj))]
|
|
{
|
|
value = 0;
|
|
}
|
|
let reply = drtioaux::Packet::MonitorReply { value: value as u32 };
|
|
drtioaux::send_link(0, &reply)
|
|
},
|
|
drtioaux::Packet::InjectionRequest { channel, overrd, value } => {
|
|
#[cfg(has_rtio_moninj)]
|
|
unsafe {
|
|
csr::rtio_moninj::inj_chan_sel_write(channel as _);
|
|
csr::rtio_moninj::inj_override_sel_write(overrd);
|
|
csr::rtio_moninj::inj_value_write(value);
|
|
}
|
|
Ok(())
|
|
},
|
|
drtioaux::Packet::InjectionStatusRequest { channel, overrd } => {
|
|
let value;
|
|
#[cfg(has_rtio_moninj)]
|
|
unsafe {
|
|
csr::rtio_moninj::inj_chan_sel_write(channel as _);
|
|
csr::rtio_moninj::inj_override_sel_write(overrd);
|
|
value = csr::rtio_moninj::inj_value_read();
|
|
}
|
|
#[cfg(not(has_rtio_moninj))]
|
|
{
|
|
value = 0;
|
|
}
|
|
drtioaux::send_link(0, &drtioaux::Packet::InjectionStatusReply { value: value })
|
|
},
|
|
|
|
drtioaux::Packet::I2cStartRequest { busno } => {
|
|
let succeeded = i2c::start(busno).is_ok();
|
|
drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
|
}
|
|
drtioaux::Packet::I2cRestartRequest { busno } => {
|
|
let succeeded = i2c::restart(busno).is_ok();
|
|
drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
|
}
|
|
drtioaux::Packet::I2cStopRequest { busno } => {
|
|
let succeeded = i2c::stop(busno).is_ok();
|
|
drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
|
}
|
|
drtioaux::Packet::I2cWriteRequest { busno, data } => {
|
|
match i2c::write(busno, data) {
|
|
Ok(ack) => drtioaux::send_link(0,
|
|
&drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }),
|
|
Err(_) => drtioaux::send_link(0,
|
|
&drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false })
|
|
}
|
|
}
|
|
drtioaux::Packet::I2cReadRequest { busno, ack } => {
|
|
match i2c::read(busno, ack) {
|
|
Ok(data) => drtioaux::send_link(0,
|
|
&drtioaux::Packet::I2cReadReply { succeeded: true, data: data }),
|
|
Err(_) => drtioaux::send_link(0,
|
|
&drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff })
|
|
}
|
|
}
|
|
|
|
drtioaux::Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => {
|
|
let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok();
|
|
drtioaux::send_link(0,
|
|
&drtioaux::Packet::SpiBasicReply { succeeded: succeeded })
|
|
},
|
|
drtioaux::Packet::SpiWriteRequest { busno, data } => {
|
|
let succeeded = spi::write(busno, data).is_ok();
|
|
drtioaux::send_link(0,
|
|
&drtioaux::Packet::SpiBasicReply { succeeded: succeeded })
|
|
}
|
|
drtioaux::Packet::SpiReadRequest { busno } => {
|
|
match spi::read(busno) {
|
|
Ok(data) => drtioaux::send_link(0,
|
|
&drtioaux::Packet::SpiReadReply { succeeded: true, data: data }),
|
|
Err(_) => drtioaux::send_link(0,
|
|
&drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 })
|
|
}
|
|
}
|
|
|
|
_ => {
|
|
warn!("received unexpected aux packet");
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
|
|
fn process_aux_packets() {
|
|
let result =
|
|
drtioaux::recv_link(0).and_then(|packet| {
|
|
if let Some(packet) = packet {
|
|
process_aux_packet(packet)
|
|
} else {
|
|
Ok(())
|
|
}
|
|
});
|
|
match result {
|
|
Ok(()) => (),
|
|
Err(e) => warn!("aux packet error ({})", e)
|
|
}
|
|
}
|
|
|
|
fn process_errors() {
|
|
let errors;
|
|
unsafe {
|
|
errors = (csr::DRTIO[0].protocol_error_read)();
|
|
}
|
|
if errors & 1 != 0 {
|
|
error!("received packet of an unknown type");
|
|
}
|
|
if errors & 2 != 0 {
|
|
error!("received truncated packet");
|
|
}
|
|
if errors & 4 != 0 {
|
|
let channel;
|
|
let timestamp_event;
|
|
let timestamp_counter;
|
|
unsafe {
|
|
channel = (csr::DRTIO[0].underflow_channel_read)();
|
|
timestamp_event = (csr::DRTIO[0].underflow_timestamp_event_read)() as i64;
|
|
timestamp_counter = (csr::DRTIO[0].underflow_timestamp_counter_read)() as i64;
|
|
}
|
|
error!("write underflow, channel={}, timestamp={}, counter={}, slack={}",
|
|
channel, timestamp_event, timestamp_counter, timestamp_event-timestamp_counter);
|
|
}
|
|
if errors & 8 != 0 {
|
|
error!("write overflow");
|
|
}
|
|
unsafe {
|
|
(csr::DRTIO[0].protocol_error_write)(errors);
|
|
}
|
|
}
|
|
|
|
#[cfg(rtio_frequency = "150.0")]
|
|
const SI5324_SETTINGS: si5324::FrequencySettings
|
|
= si5324::FrequencySettings {
|
|
n1_hs : 6,
|
|
nc1_ls : 6,
|
|
n2_hs : 10,
|
|
n2_ls : 270,
|
|
n31 : 75,
|
|
n32 : 75,
|
|
bwsel : 4,
|
|
crystal_ref: true
|
|
};
|
|
|
|
fn drtio_link_rx_up() -> bool {
|
|
unsafe {
|
|
(csr::DRTIO[0].rx_up_read)() == 1
|
|
}
|
|
}
|
|
|
|
const SIPHASER_PHASE: u16 = 32;
|
|
#[cfg(has_ad9154)]
|
|
const SYSREF_PHASE_FPGA: u16 = 53;
|
|
#[cfg(has_ad9154)]
|
|
const SYSREF_PHASE_DAC: u16 = 64;
|
|
|
|
#[no_mangle]
|
|
pub extern fn main() -> i32 {
|
|
clock::init();
|
|
uart_logger::ConsoleLogger::register();
|
|
|
|
info!("ARTIQ satellite manager starting...");
|
|
info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe")));
|
|
info!("gateware version {}", ident::read(&mut [0; 64]));
|
|
|
|
#[cfg(has_slave_fpga_cfg)]
|
|
board_artiq::slave_fpga::load().expect("cannot load RTM FPGA gateware");
|
|
#[cfg(has_serwb_phy_amc)]
|
|
serwb::wait_init();
|
|
|
|
i2c::init();
|
|
si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324");
|
|
unsafe {
|
|
csr::drtio_transceiver::stable_clkin_write(1);
|
|
}
|
|
|
|
#[cfg(has_hmc830_7043)]
|
|
/* must be the first SPI init because of HMC830 SPI mode selection */
|
|
hmc830_7043::init().expect("cannot initialize HMC830/7043");
|
|
#[cfg(has_ad9154)]
|
|
let mut ad9154_initialized = false;
|
|
#[cfg(has_allaki_atts)]
|
|
board_artiq::hmc542::program_all(8/*=4dB*/);
|
|
|
|
loop {
|
|
while !drtio_link_rx_up() {
|
|
process_errors();
|
|
}
|
|
info!("link is up, switching to recovered clock");
|
|
si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks");
|
|
si5324::siphaser::calibrate_skew(SIPHASER_PHASE).expect("failed to calibrate skew");
|
|
#[cfg(has_ad9154)]
|
|
{
|
|
if !ad9154_initialized {
|
|
board_artiq::ad9154::init(SYSREF_PHASE_FPGA, SYSREF_PHASE_DAC);
|
|
ad9154_initialized = true;
|
|
}
|
|
}
|
|
drtioaux::reset(0);
|
|
drtio_reset(false);
|
|
drtio_reset_phy(false);
|
|
while drtio_link_rx_up() {
|
|
process_errors();
|
|
process_aux_packets();
|
|
#[cfg(has_hmc830_7043)]
|
|
{
|
|
if drtio_tsc_loaded() {
|
|
// Expected alignment: 1 RTIO clock period
|
|
hmc830_7043::hmc7043::sysref_rtio_align(
|
|
SYSREF_PHASE_FPGA,
|
|
hmc830_7043::hmc7043::FPGA_CLK_DIV);
|
|
}
|
|
}
|
|
}
|
|
drtio_reset_phy(true);
|
|
drtio_reset(true);
|
|
drtio_tsc_loaded();
|
|
info!("link is down, switching to local crystal clock");
|
|
si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks");
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) {
|
|
panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern fn abort() {
|
|
println!("aborted");
|
|
loop {}
|
|
}
|
|
|
|
#[no_mangle]
|
|
#[lang = "panic_fmt"]
|
|
pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str,
|
|
line: u32, column: u32) -> ! {
|
|
println!("panic at {}:{}:{}: {}", file, line, column, args);
|
|
loop {}
|
|
}
|