forked from M-Labs/artiq
78 lines
2.4 KiB
Rust
78 lines
2.4 KiB
Rust
use spi;
|
|
use board_misoc::{csr, clock};
|
|
|
|
const DATA_CTRL_REG : u8 = 0x02;
|
|
const IRCML_REG : u8 = 0x05;
|
|
const QRCML_REG : u8 = 0x08;
|
|
const CLKMODE_REG : u8 = 0x14;
|
|
const VERSION_REG : u8 = 0x1F;
|
|
|
|
const RETIMER_CLK_PHASE : u8 = 0b11;
|
|
|
|
fn hard_reset() {
|
|
unsafe {
|
|
// Min Pulse Width: 50ns
|
|
csr::dac_rst::out_write(1);
|
|
clock::spin_us(1);
|
|
csr::dac_rst::out_write(0);
|
|
}
|
|
}
|
|
|
|
fn spi_setup(dac_sel: u8, half_duplex: bool, end: bool) -> Result<(), &'static str> {
|
|
// Clear the cs_polarity and cs config
|
|
spi::set_config(0, 0, 8, 64, 0b1111)?;
|
|
spi::set_config(0, 1 << 3, 8, 64, (7 - dac_sel) << 1)?;
|
|
spi::set_config(0, (half_duplex as u8) << 7 | (end as u8) << 1, 8, 64, 0b0001)?;
|
|
Ok(())
|
|
}
|
|
|
|
fn write(dac_sel: u8, reg: u8, val: u8) -> Result<(), &'static str> {
|
|
spi_setup(dac_sel, false, false)?;
|
|
spi::write(0, (reg as u32) << 24)?;
|
|
spi_setup(dac_sel, false, true)?;
|
|
spi::write(0, (val as u32) << 24)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn read(dac_sel: u8, reg: u8) -> Result<u8, &'static str> {
|
|
spi_setup(dac_sel, false, false)?;
|
|
spi::write(0, ((reg | 1 << 7) as u32) << 24)?;
|
|
spi_setup(dac_sel, true, true)?;
|
|
spi::write(0, 0)?;
|
|
|
|
Ok(spi::read(0)? as u8)
|
|
}
|
|
|
|
pub fn init() -> Result<(), &'static str> {
|
|
hard_reset();
|
|
|
|
for channel in 0..8 {
|
|
let reg = read(channel, VERSION_REG)?;
|
|
if reg != 0x0A {
|
|
debug!("DAC AD9117 Channel {} has incorrect hardware version. VERSION reg: {:02x}", channel, reg);
|
|
return Err("DAC AD9117 hardware version is not equal to 0x0A");
|
|
}
|
|
// Check for the presence of DCLKIO and CLKIN
|
|
let reg = read(channel, CLKMODE_REG)?;
|
|
if reg >> 4 & 1 != 0 {
|
|
debug!("DAC AD9117 Channel {} retiming fails. CLKMODE reg: {:02x}", channel, reg);
|
|
return Err("DAC AD9117 retiming failure");
|
|
}
|
|
|
|
// Force RETIMER-CLK to be Phase 1 as DCLKIO and CLKIN is known to be safe at Phase 1
|
|
// See Issue #2200
|
|
write(channel, CLKMODE_REG, RETIMER_CLK_PHASE << 6 | 1 << 2 | RETIMER_CLK_PHASE)?;
|
|
|
|
// Set the DACs input data format to be twos complement
|
|
// Set IFIRST and IRISING to True
|
|
write(channel, DATA_CTRL_REG, 1 << 7 | 1 << 5 | 1 << 4)?;
|
|
|
|
// Enable internal common mode resistors of both channels
|
|
write(channel, IRCML_REG, 1 << 7)?;
|
|
write(channel, QRCML_REG, 1 << 7)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|