2
0
mirror of https://github.com/m-labs/artiq.git synced 2024-12-18 16:06:30 +08:00

libbsp: add ad9154 and ad9516 init code (untested)

This commit is contained in:
Sebastien Bourdeauducq 2016-12-31 14:48:09 +01:00
parent 62596a733d
commit 6c1fc2987a
2 changed files with 551 additions and 0 deletions

View File

@ -0,0 +1,454 @@
use std::result;
use bsp::board::csr;
use ad9154_reg::reg;
fn spi_setup() {
unsafe {
csr::converter_spi::offline_write(1);
csr::converter_spi::cs_polarity_write(0);
csr::converter_spi::clk_polarity_write(0);
csr::converter_spi::clk_phase_write(0);
csr::converter_spi::lsb_first_write(0);
csr::converter_spi::half_duplex_write(0);
csr::converter_spi::clk_div_write_write(16);
csr::converter_spi::clk_div_read_write(16);
csr::converter_spi::xfer_len_write_write(24);
csr::converter_spi::xfer_len_read_write(0);
csr::converter_spi::cs_write(csr::CONFIG_CONVERTER_SPI_DAC_CS);
csr::converter_spi::offline_write(0);
}
}
fn write(addr: u16, data: u8) {
unsafe {
csr::converter_spi::data_write_write(
((addr as u32) << 16) | ((data as u32) << 8));
while csr::converter_spi::pending_read() != 0 {}
while csr::converter_spi::active_read() != 0 {}
}
}
fn read(addr: u16) -> u8 {
unsafe {
write((1 << 15) | addr, 0);
csr::converter_spi::data_read_read() as u8
}
}
fn jesd_enable(en: bool) {
unsafe {
csr::ad9154::jesd_control_enable_write(if en {1} else {0})
}
}
fn jesd_ready() {
unsafe {
csr::ad9154::jesd_control_ready_read() != 0
}
}
fn jesd_prbs(en: bool) {
unsafe {
csr::ad9154::jesd_control_prbs_config_write(if en {1} else {0})
}
}
fn jesd_stpl(en: bool) {
unsafe {
csr::ad9154::jesd_control_stpl_enable_write(if en {1} else {0})
}
}
fn jesd_jsync() {
unsafe {
csr::ad9154::jesd_jsync_read() != 0
}
}
// ad9154 mode 2
// external clk=300MHz
// pclock=150MHz
// deviceclock_fpga=150MHz
// deviceclock_dac=300MHz
struct JESDSettings {
did: u8,
bid: u8,
l: u8, // lanes
m: u8, // converters
n: u8, // bits/converter
np: u8, // bits/sample
f: u8, // octets/(lane and frame)
s: u8, // samples/(converter and frame)
k: u8, // frames/multiframe
cs: u8, // control bits/sample
subclassv: u8,
jesdv: u8
}
fn jesd_checksum(settings: &JESDSettings) -> u8 {
let mut r: u8 = 0;
for field in [
settings.did,
settings.bid,
settings.l - 1,
settings.f - 1,
settings.k - 1,
settings.m - 1,
settings.n - 1,
settings.cs,
settings.np - 1,
settings.subclassv,
settings.s - 1,
settings.jesdv,
].iter() {
r = r.overflowing_add(*field).0;
}
r
}
const JESD_SETTINGS: JESDSettings = JESDSettings {
did: 0x5a,
bid: 0x5,
l: 4,
m: 4,
n: 16,
np: 16,
f: 2,
s: 1,
k: 16,
cs: 1,
subclassv: 1,
jesdv: 1
};
fn dac_setup() -> Result<(), &'static str> {
// reset
write(ad9154_reg::SPI_INTFCONFA,
1*ad9154_reg::SOFTRESET_M | 1*ad9154_reg::SOFTRESET |
0*ad9154_reg::LSBFIRST_M | 0*ad9154_reg::LSBFIRST |
0*ad9154_reg::ADDRINC_M | 0*ad9154_reg::ADDRINC |
1*ad9154_reg::SDOACTIVE_M | 1*ad9154_reg::SDOACTIVE);
busywait_us(100);
write(ad9154_reg::SPI_INTFCONFA,
0*ad9154_reg::SOFTRESET_M | 0*ad9154_reg::SOFTRESET |
0*ad9154_reg::LSBFIRST_M | 0*ad9154_reg::LSBFIRST |
0*ad9154_reg::ADDRINC_M | 0*ad9154_reg::ADDRINC |
1*ad9154_reg::SDOACTIVE_M | 1*ad9154_reg::SDOACTIVE);
busywait_us(100);
if read(ad9154_reg::PRODIDH) as u16 << 8 |
read(ad9154_reg::PRODIDL) as u16 != 0x9154 {
return Err("AD9154 not found")
}
write(ad9154_reg::PWRCNTRL0,
0*ad9154_reg::PD_DAC0 | 0*ad9154_reg::PD_DAC1 |
0*ad9154_reg::PD_DAC2 | 0*ad9154_reg::PD_DAC3 |
0*ad9154_reg::PD_BG);
busywait_us(100);
write(ad9154_reg::TXENMASK1, 0*ad9154_reg::DACA_MASK |
0*ad9154_reg::DACB_MASK); // TX not controlled by TXEN pins
write(ad9154_reg::CLKCFG0,
0*ad9154_reg::REF_CLKDIV_EN | 1*ad9154_reg::RF_SYNC_EN |
1*ad9154_reg::DUTY_EN | 0*ad9154_reg::PD_CLK_REC |
0*ad9154_reg::PD_SERDES_PCLK | 0*ad9154_reg::PD_CLK_DIG |
0*ad9154_reg::PD_CLK23 | 0*ad9154_reg::PD_CLK01);
write(ad9154_reg::DACPLLCNTRL,
0*ad9154_reg::ENABLE_DACPLL | 0*ad9154_reg::RECAL_DACPLL);
write(ad9154_reg::SYSREF_ACTRL0, // jesd204b subclass 1
0*ad9154_reg::HYS_CNTRL1 | 0*ad9154_reg::SYSREF_RISE |
0*ad9154_reg::HYS_ON | 0*ad9154_reg::PD_SYSREF_BUFFER);
write(ad9154_reg::DEVICE_CONFIG_REG_0, 0x8b); // magic
write(ad9154_reg::DEVICE_CONFIG_REG_1, 0x01); // magic
write(ad9154_reg::DEVICE_CONFIG_REG_2, 0x01); // magic
write(ad9154_reg::SPI_PAGEINDX, 0x3); // A and B dual
write(ad9154_reg::INTERP_MODE, 0); // 1x
write(ad9154_reg::MIX_MODE, 0);
write(ad9154_reg::DATA_FORMAT, 0*ad9154_reg::BINARY_FORMAT); // s16
write(ad9154_reg::DATAPATH_CTRL,
0*ad9154_reg::I_TO_Q | 0*ad9154_reg::SEL_SIDEBAND |
0*ad9154_reg::MODULATION_TYPE | 0*ad9154_reg::PHASE_ADJ_ENABLE |
1*ad9154_reg::DIG_GAIN_ENABLE | 0*ad9154_reg::INVSINC_ENABLE);
write(ad9154_reg::IDAC_DIG_GAIN0, 0x00);
write(ad9154_reg::IDAC_DIG_GAIN1, 0x8);
write(ad9154_reg::QDAC_DIG_GAIN0, 0x00);
write(ad9154_reg::QDAC_DIG_GAIN1, 0x8);
write(ad9154_reg::DC_OFFSET_CTRL, 0);
write(ad9154_reg::IPATH_DC_OFFSET_1PART0, 0x00);
write(ad9154_reg::IPATH_DC_OFFSET_1PART1, 0x00);
write(ad9154_reg::IPATH_DC_OFFSET_2PART, 0x00);
write(ad9154_reg::QPATH_DC_OFFSET_1PART0, 0x00);
write(ad9154_reg::QPATH_DC_OFFSET_1PART1, 0x00);
write(ad9154_reg::QPATH_DC_OFFSET_2PART, 0x00);
write(ad9154_reg::PHASE_ADJ0, 0);
write(ad9154_reg::PHASE_ADJ1, 0);
write(ad9154_reg::GROUP_DLY, 0x8*ad9154_reg::COARSE_GROUP_DELAY |
0x8*ad9154_reg::GROUP_DELAY_RESERVED);
write(ad9154_reg::GROUPDELAY_COMP_BYP,
1*ad9154_reg::GROUPCOMP_BYPQ |
1*ad9154_reg::GROUPCOMP_BYPI);
write(ad9154_reg::GROUPDELAY_COMP_I, 0);
write(ad9154_reg::GROUPDELAY_COMP_Q, 0);
write(ad9154_reg::PDP_AVG_TIME, 0*ad9154_reg::PDP_ENABLE);
write(ad9154_reg::MASTER_PD, 0);
write(ad9154_reg::PHY_PD, 0x0f); // power down lanes 0-3
write(ad9154_reg::GENERIC_PD,
0*ad9154_reg::PD_SYNCOUT0B |
1*ad9154_reg::PD_SYNCOUT1B);
write(ad9154_reg::GENERAL_JRX_CTRL_0,
0x0*ad9154_reg::LINK_EN | 0*ad9154_reg::LINK_PAGE |
0*ad9154_reg::LINK_MODE | 0*ad9154_reg::CHECKSUM_MODE);
write(ad9154_reg::ILS_DID, JESD_SETTINGS.did);
write(ad9154_reg::ILS_BID, JESD_SETTINGS.bid);
write(ad9154_reg::ILS_LID0, 0x00); // lane id
write(ad9154_reg::ILS_SCR_L,
(JESD_SETTINGS.l - 1)*ad9154_reg::L_1 |
1*ad9154_reg::SCR);
write(ad9154_reg::ILS_F, JESD_SETTINGS.f - 1);
write(ad9154_reg::ILS_K, JESD_SETTINGS.k - 1);
write(ad9154_reg::ILS_M, JESD_SETTINGS.m - 1);
write(ad9154_reg::ILS_CS_N,
(JESD_SETTINGS.n - 1)*ad9154_reg::N_1 |
0*ad9154_reg::CS);
write(ad9154_reg::ILS_NP,
(JESD_SETTINGS.np - 1)*ad9154_reg::NP_1 |
JESD_SETTINGS.subclassv*ad9154_reg::SUBCLASSV);
write(ad9154_reg::ILS_S,
(JESD_SETTINGS.s - 1)*ad9154_reg::S_1 |
JESD_SETTINGS.jesdv*ad9154_reg::JESDV);
write(ad9154_reg::ILS_HD_CF,
0*ad9154_reg::HD | 0*ad9154_reg::CF);
write(ad9154_reg::ILS_CHECKSUM, jesd_checksum(JESD_SETTINGS));
write(ad9154_reg::LANEDESKEW, 0x0f);
for i in 0..8 {
write(ad9154_reg::BADDISPARITY, 0*ad9154_reg::RST_IRQ_DIS |
0*ad9154_reg::DISABLE_ERR_CNTR_DIS |
1*ad9154_reg::RST_ERR_CNTR_DIS | i*ad9154_reg::LANE_ADDR_DIS);
write(ad9154_reg::BADDISPARITY, 0*ad9154_reg::RST_IRQ_DIS |
0*ad9154_reg::DISABLE_ERR_CNTR_DIS |
0*ad9154_reg::RST_ERR_CNTR_DIS | i*ad9154_reg::LANE_ADDR_DIS);
write(ad9154_reg::NIT_W, 0*ad9154_reg::RST_IRQ_NIT |
0*ad9154_reg::DISABLE_ERR_CNTR_NIT |
1*ad9154_reg::RST_ERR_CNTR_NIT | i*ad9154_reg::LANE_ADDR_NIT);
write(ad9154_reg::NIT_W, 0*ad9154_reg::RST_IRQ_NIT |
0*ad9154_reg::DISABLE_ERR_CNTR_NIT |
0*ad9154_reg::RST_ERR_CNTR_NIT | i*ad9154_reg::LANE_ADDR_NIT);
write(ad9154_reg::UNEXPECTEDCONTROL_W, 0*ad9154_reg::RST_IRQ_UCC |
0*ad9154_reg::DISABLE_ERR_CNTR_UCC |
1*ad9154_reg::RST_ERR_CNTR_UCC | i*ad9154_reg::LANE_ADDR_UCC);
write(ad9154_reg::BADDISPARITY, 0*ad9154_reg::RST_IRQ_UCC |
0*ad9154_reg::DISABLE_ERR_CNTR_UCC |
0*ad9154_reg::RST_ERR_CNTR_UCC | i*ad9154_reg::LANE_ADDR_UCC);
}
write(ad9154_reg::CTRLREG1, JESD_SETTINGS.f);
write(ad9154_reg::CTRLREG2, 0*ad9154_reg::ILAS_MODE |
0*ad9154_reg::THRESHOLD_MASK_EN);
write(ad9154_reg::KVAL, 1); // *4*K multiframes during ILAS
write(ad9154_reg::LANEENABLE, 0x0f); // CGS _after_ this
write(ad9154_reg::TERM_BLK1_CTRLREG0, 1);
write(ad9154_reg::TERM_BLK2_CTRLREG0, 1);
write(ad9154_reg::SERDES_SPI_REG, 1);
write(ad9154_reg::CDR_OPERATING_MODE_REG_0,
0*ad9154_reg::CDR_OVERSAMP | 0x2*ad9154_reg::CDR_RESERVED |
1*ad9154_reg::ENHALFRATE);
write(ad9154_reg::CDR_RESET, 0);
write(ad9154_reg::CDR_RESET, 1);
write(ad9154_reg::REF_CLK_DIVIDER_LDO,
0x0*ad9154_reg::SPI_CDR_OVERSAMP |
1*ad9154_reg::SPI_LDO_BYPASS_FILT |
0*ad9154_reg::SPI_LDO_REF_SEL);
write(ad9154_reg::LDO_FILTER_1, 0x62); // magic
write(ad9154_reg::LDO_FILTER_2, 0xc9); // magic
write(ad9154_reg::LDO_FILTER_3, 0x0e); // magic
write(ad9154_reg::CP_CURRENT_SPI,
0x12*ad9154_reg::SPI_CP_CURRENT |
0*ad9154_reg::SPI_SERDES_LOGEN_POWER_MODE);
write(ad9154_reg::VCO_LDO, 0x7b); // magic
write(ad9154_reg::PLL_RD_REG,
0*ad9154_reg::SPI_SERDES_LOGEN_PD_CORE |
0*ad9154_reg::SPI_SERDES_LDO_PD | 0*ad9154_reg::SPI_SYN_PD |
0*ad9154_reg::SPI_VCO_PD_ALC | 0*ad9154_reg::SPI_VCO_PD_PTAT |
0*ad9154_reg::SPI_VCO_PD);
write(ad9154_reg::ALC_VARACTOR,
0x9*ad9154_reg::SPI_VCO_VARACTOR |
0x8*ad9154_reg::SPI_INIT_ALC_VALUE);
write(ad9154_reg::VCO_OUTPUT,
0xc*ad9154_reg::SPI_VCO_OUTPUT_LEVEL |
0x4*ad9154_reg::SPI_VCO_OUTPUT_RESERVED);
write(ad9154_reg::CP_CONFIG,
0*ad9154_reg::SPI_CP_TEST |
1*ad9154_reg::SPI_CP_CAL_EN |
0*ad9154_reg::SPI_CP_FORCE_CALBITS |
0*ad9154_reg::SPI_CP_OFFSET_OFF |
1*ad9154_reg::SPI_CP_ENABLE_MACHINE |
0*ad9154_reg::SPI_CP_DITHER_MODE |
0*ad9154_reg::SPI_CP_HALF_VCO_CAL_CLK);
write(ad9154_reg::VCO_BIAS_1,
0x3*ad9154_reg::SPI_VCO_BIAS_REF |
0x3*ad9154_reg::SPI_VCO_BIAS_TCF);
write(ad9154_reg::VCO_BIAS_2,
0x1*ad9154_reg::SPI_PRESCALE_BIAS |
1*ad9154_reg::SPI_LAST_ALC_EN |
0x1*ad9154_reg::SPI_PRESCALE_BYPASS_R |
0*ad9154_reg::SPI_VCO_COMP_BYPASS_BIASR |
0*ad9154_reg::SPI_VCO_BYPASS_DAC_R);
write(ad9154_reg::VCO_PD_OVERRIDES,
0*ad9154_reg::SPI_VCO_PD_OVERRIDE_VCO_BUF |
1*ad9154_reg::SPI_VCO_PD_OVERRIDE_CAL_TCF |
0*ad9154_reg::SPI_VCO_PD_OVERRIDE_VAR_REF_TCF |
0*ad9154_reg::SPI_VCO_PD_OVERRIDE_VAR_REF);
write(ad9154_reg::VCO_CAL,
0x2*ad9154_reg::SPI_FB_CLOCK_ADV |
0x3*ad9154_reg::SPI_VCO_CAL_COUNT |
0*ad9154_reg::SPI_VCO_CAL_ALC_WAIT |
1*ad9154_reg::SPI_VCO_CAL_EN);
write(ad9154_reg::CP_LEVEL_DETECT,
0x2*ad9154_reg::SPI_CP_LEVEL_THRESHOLD_HIGH |
0x5*ad9154_reg::SPI_CP_LEVEL_THRESHOLD_LOW |
0*ad9154_reg::SPI_CP_LEVEL_DET_PD);
write(ad9154_reg::VCO_VARACTOR_CTRL_0,
0xe*ad9154_reg::SPI_VCO_VARACTOR_OFFSET |
0x7*ad9154_reg::SPI_VCO_VARACTOR_REF_TCF);
write(ad9154_reg::VCO_VARACTOR_CTRL_1,
0x6*ad9154_reg::SPI_VCO_VARACTOR_REF);
// ensure link is txing
//write(ad9154_reg::SERDESPLL_ENABLE_CNTRL,
// 1*ad9154_reg::ENABLE_SERDESPLL | 1*ad9154_reg::RECAL_SERDESPLL)
write(ad9154_reg::SERDESPLL_ENABLE_CNTRL,
1*ad9154_reg::ENABLE_SERDESPLL | 0*ad9154_reg::RECAL_SERDESPLL);
while read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB == 0 {}
write(ad9154_reg::EQ_BIAS_REG, 0x22*ad9154_reg::EQ_BIAS_RESERVED |
1*ad9154_reg::EQ_POWER_MODE);
write(ad9154_reg::GENERAL_JRX_CTRL_1, 1); // subclass 1
write(ad9154_reg::LMFC_DELAY_0, 0);
write(ad9154_reg::LMFC_DELAY_1, 0);
write(ad9154_reg::LMFC_VAR_0, 0x0a); // receive buffer delay
write(ad9154_reg::LMFC_VAR_1, 0x0a);
write(ad9154_reg::SYNC_ERRWINDOW, 0); // +- 1/2 DAC clock
write(ad9154_reg::SYNC_CONTROL,
0x9*ad9154_reg::SYNCMODE | 0*ad9154_reg::SYNCENABLE |
0*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY |
1*ad9154_reg::SYNCCLRLAST);
write(ad9154_reg::SYNC_CONTROL,
0x9*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE |
0*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY |
1*ad9154_reg::SYNCCLRLAST);
write(ad9154_reg::SYNC_CONTROL,
0x9*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE |
1*ad9154_reg::SYNCARM | 0*ad9154_reg::SYNCCLRSTKY |
0*ad9154_reg::SYNCCLRLAST);
busywait_us(1000); // ensure at least one sysref edge
if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_LOCK == 0:
return Err("no sync lock")
write(ad9154_reg::XBAR_LN_0_1,
7*ad9154_reg::LOGICAL_LANE0_SRC | 6*ad9154_reg::LOGICAL_LANE1_SRC);
write(ad9154_reg::XBAR_LN_2_3,
5*ad9154_reg::LOGICAL_LANE2_SRC | 4*ad9154_reg::LOGICAL_LANE3_SRC);
write(ad9154_reg::XBAR_LN_4_5,
0*ad9154_reg::LOGICAL_LANE4_SRC | 0*ad9154_reg::LOGICAL_LANE5_SRC);
write(ad9154_reg::XBAR_LN_6_7,
0*ad9154_reg::LOGICAL_LANE6_SRC | 0*ad9154_reg::LOGICAL_LANE7_SRC);
write(ad9154_reg::JESD_BIT_INVERSE_CTRL, 0x00);
write(ad9154_reg::GENERAL_JRX_CTRL_0,
0x1*ad9154_reg::LINK_EN | 0*ad9154_reg::LINK_PAGE |
0*ad9154_reg::LINK_MODE | 0*ad9154_reg::CHECKSUM_MODE);
Ok(())
}
fn monitor() {
write(ad9154_reg::IRQ_STATUS0, 0x00);
write(ad9154_reg::IRQ_STATUS1, 0x00);
write(ad9154_reg::IRQ_STATUS2, 0x00);
write(ad9154_reg::IRQ_STATUS3, 0x00);
write(ad9154_reg::IRQEN_STATUSMODE0,
ad9154_reg::IRQEN_SMODE_LANEFIFOERR |
ad9154_reg::IRQEN_SMODE_SERPLLLOCK |
ad9154_reg::IRQEN_SMODE_SERPLLLOST |
ad9154_reg::IRQEN_SMODE_DACPLLLOCK |
ad9154_reg::IRQEN_SMODE_DACPLLLOST);
write(ad9154_reg::IRQEN_STATUSMODE1,
ad9154_reg::IRQEN_SMODE_PRBS0 |
ad9154_reg::IRQEN_SMODE_PRBS1 |
ad9154_reg::IRQEN_SMODE_PRBS2 |
ad9154_reg::IRQEN_SMODE_PRBS3);
write(ad9154_reg::IRQEN_STATUSMODE2,
ad9154_reg::IRQEN_SMODE_SYNC_TRIP0 |
ad9154_reg::IRQEN_SMODE_SYNC_WLIM0 |
ad9154_reg::IRQEN_SMODE_SYNC_ROTATE0 |
ad9154_reg::IRQEN_SMODE_SYNC_LOCK0 |
ad9154_reg::IRQEN_SMODE_NCO_ALIGN0 |
ad9154_reg::IRQEN_SMODE_BLNKDONE0 |
ad9154_reg::IRQEN_SMODE_PDPERR0);
write(ad9154_reg::IRQEN_STATUSMODE3,
ad9154_reg::IRQEN_SMODE_SYNC_TRIP1 |
ad9154_reg::IRQEN_SMODE_SYNC_WLIM1 |
ad9154_reg::IRQEN_SMODE_SYNC_ROTATE1 |
ad9154_reg::IRQEN_SMODE_SYNC_LOCK1 |
ad9154_reg::IRQEN_SMODE_NCO_ALIGN1 |
ad9154_reg::IRQEN_SMODE_BLNKDONE1 |
ad9154_reg::IRQEN_SMODE_PDPERR1);
write(ad9154_reg::IRQ_STATUS0, 0x00);
write(ad9154_reg::IRQ_STATUS1, 0x00);
write(ad9154_reg::IRQ_STATUS2, 0x00);
write(ad9154_reg::IRQ_STATUS3, 0x00);
}
fn cfg() -> Result<(), &'static str> {
jesd_enable(false);
jesd_prbs(false);
jesd_stpl(false);
busywait_us(10000);
jesd_enable(true);
dac_setup();
jesd_enable(false);
busywait_us(10000);
jesd_enable(true);
monitor();
while !jesd_ready() {}
busywait_us(10000);
if read(ad9154_reg::CODEGRPSYNCFLG) != 0x0f {
return Err("bad CODEGRPSYNCFLG")
}
if !jesd_jsync() {
return Err("bad SYNC")
}
if read(ad9154_reg::FRAMESYNCFLG) != 0x0f {
return Err("bad FRAMESYNCFLG")
}
if read(ad9154_reg::GOODCHKSUMFLG) != 0x0f {
return Err("bad GOODCHECKSUMFLG")
}
if read(ad9154_reg::INITLANESYNCFLG) != 0x0f {
return Err("bad INITLANESYNCFLG")
}
Ok(())
}
pub fn init() -> Result<(), &'static str> {
spi_setup();
for i in 0..99 {
let outcome = cfg();
if outcome.is_ok() {
return outcome
}
}
cfg()
}

View File

@ -0,0 +1,97 @@
use std::result;
use bsp::board::csr;
use ad9516_reg::reg;
fn spi_setup() {
unsafe {
csr::converter_spi::offline_write(1);
csr::converter_spi::cs_polarity_write(0);
csr::converter_spi::clk_polarity_write(0);
csr::converter_spi::clk_phase_write(0);
csr::converter_spi::lsb_first_write(0);
csr::converter_spi::half_duplex_write(0);
csr::converter_spi::clk_div_write_write(16);
csr::converter_spi::clk_div_read_write(16);
csr::converter_spi::xfer_len_write_write(24);
csr::converter_spi::xfer_len_read_write(0);
csr::converter_spi::cs_write(csr::CONFIG_CONVERTER_SPI_CLK_CS);
csr::converter_spi::offline_write(0);
}
}
fn write(addr: u16, data: u8) {
unsafe {
csr::converter_spi::data_write_write(
((addr as u32) << 16) | ((data as u32) << 8));
while csr::converter_spi::pending_read() != 0 {}
while csr::converter_spi::active_read() != 0 {}
}
}
fn read(addr: u16) -> u8 {
unsafe {
write((1 << 15) | addr, 0);
csr::converter_spi::data_read_read() as u8
}
}
pub fn init() -> Result<(), &'static str> {
spi_setup();
write(ad9156_reg::SERIAL_PORT_CONFIGURATION,
ad9156_reg::SOFT_RESET | ad9156_reg::SOFT_RESET_MIRRORED |
ad9156_reg::LONG_INSTRUCTION | ad9156_reg::LONG_INSTRUCTION_MIRRORED |
ad9156_reg::SDO_ACTIVE | ad9156_reg::SDO_ACTIVE_MIRRORED);
write(ad9156_reg::SERIAL_PORT_CONFIGURATION,
ad9156_reg::LONG_INSTRUCTION | ad9156_reg::LONG_INSTRUCTION_MIRRORED |
ad9156_reg::SDO_ACTIVE | ad9156_reg::SDO_ACTIVE_MIRRORED);
if read(ad9156_reg::PART_ID) != 0x41 {
return Err("AD9516 not found")
}
// use clk input, dclk=clk/2
write(ad9156_reg::PFD_AND_CHARGE_PUMP, 1*ad9156_reg::PLL_POWER_DOWN |
0*ad9156_reg::CHARGE_PUMP_MODE);
write(ad9156_reg::VCO_DIVIDER, 0);
write(ad9156_reg::INPUT_CLKS, 0*ad9156_reg::SELECT_VCO_OR_CLK |
0*ad9156_reg::BYPASS_VCO_DIVIDER);
write(ad9156_reg::OUT0, 2*ad9156_reg::OUT0_POWER_DOWN);
write(ad9156_reg::OUT2, 2*ad9156_reg::OUT2_POWER_DOWN);
write(ad9156_reg::OUT3, 2*ad9156_reg::OUT3_POWER_DOWN);
write(ad9156_reg::OUT4, 2*ad9156_reg::OUT4_POWER_DOWN);
write(ad9156_reg::OUT5, 2*ad9156_reg::OUT5_POWER_DOWN);
write(ad9156_reg::OUT8, 1*ad9156_reg::OUT8_POWER_DOWN);
// DAC deviceclk, clk/1
write(ad9156_reg::DIVIDER_0_2, ad9156_reg::DIVIDER_0_DIRECT_TO_OUTPUT)
write(ad9156_reg::OUT1, 0*ad9156_reg::OUT1_POWER_DOWN |
2*ad9156_reg::OUT1_LVPECLDIFFERENTIAL_VOLTAGE);
// FPGA deviceclk, dclk/1
write(ad9156_reg::DIVIDER_4_3, 0*ad9156_reg::DIVIDER_4_NOSYNC |
1*ad9156_reg::DIVIDER_4_BYPASS_1 | 1*ad9156_reg::DIVIDER_4_BYPASS_2);
write(ad9156_reg::DIVIDER_4_4, 0*ad9156_reg::DIVIDER_4_DCCOFF);
write(ad9156_reg::OUT9, 1*ad9156_reg::OUT9_LVDS_OUTPUT_CURRENT |
2*ad9156_reg::OUT9_LVDS_CMOS_OUTPUT_POLARITY |
0*ad9156_reg::OUT9_SELECT_LVDS_CMOS);
// sysref f_data*S/(K*F), dclk/16
write(ad9156_reg::DIVIDER_3_0, (16/2-1)*ad9156_reg::DIVIDER_3_HIGH_CYCLES_1 |
(16/2-1)*ad9156_reg::DIVIDER_3_LOW_CYCLES_1);
write(ad9156_reg::DIVIDER_3_1, 0*ad9156_reg::DIVIDER_3_PHASE_OFFSET_1 |
0*ad9156_reg::DIVIDER_3_PHASE_OFFSET_2);
write(ad9156_reg::DIVIDER_3_3, 0*ad9156_reg::DIVIDER_3_NOSYNC |
0*ad9156_reg::DIVIDER_3_BYPASS_1 | 1*ad9156_reg::DIVIDER_3_BYPASS_2);
write(ad9156_reg::DIVIDER_3_4, 0*ad9156_reg::DIVIDER_3_DCCOFF);
write(ad9156_reg::OUT6, 1*ad9156_reg::OUT6_LVDS_OUTPUT_CURRENT |
2*ad9156_reg::OUT6_LVDS_CMOS_OUTPUT_POLARITY |
0*ad9156_reg::OUT6_SELECT_LVDS_CMOS);
write(ad9156_reg::OUT7, 1*ad9156_reg::OUT7_LVDS_OUTPUT_CURRENT |
2*ad9156_reg::OUT7_LVDS_CMOS_OUTPUT_POLARITY |
0*ad9156_reg::OUT7_SELECT_LVDS_CMOS);
write(ad9156_reg::UPDATE_ALL_REGISTERS, 1);
Ok(())
}