2016-03-05 01:12:30 +08:00
|
|
|
from artiq.language.core import kernel, portable, delay_mu
|
2016-03-04 07:00:25 +08:00
|
|
|
from artiq.coredevice import spi
|
|
|
|
|
2016-03-05 01:12:30 +08:00
|
|
|
# Designed from the data sheets and somewhat after the linux kernel
|
|
|
|
# iio driver.
|
2016-03-04 07:00:25 +08:00
|
|
|
|
|
|
|
_AD5360_SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_CS_POLARITY |
|
|
|
|
0*spi.SPI_CLK_POLARITY | 1*spi.SPI_CLK_PHASE |
|
|
|
|
0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX)
|
|
|
|
|
|
|
|
_AD5360_CMD_DATA = 3 << 22
|
|
|
|
_AD5360_CMD_OFFSET = 2 << 22
|
|
|
|
_AD5360_CMD_GAIN = 1 << 22
|
|
|
|
_AD5360_CMD_SPECIAL = 0 << 22
|
|
|
|
|
|
|
|
|
|
|
|
@portable
|
|
|
|
def _AD5360_WRITE_CHANNEL(c):
|
|
|
|
return (c + 8) << 16
|
|
|
|
|
|
|
|
_AD5360_SPECIAL_NOP = 0 << 16
|
|
|
|
_AD5360_SPECIAL_CONTROL = 1 << 16
|
|
|
|
_AD5360_SPECIAL_OFS0 = 2 << 16
|
|
|
|
_AD5360_SPECIAL_OFS1 = 3 << 16
|
2016-03-05 01:12:30 +08:00
|
|
|
_AD5360_SPECIAL_READ = 5 << 16
|
2016-03-04 07:00:25 +08:00
|
|
|
|
|
|
|
|
|
|
|
@portable
|
|
|
|
def _AD5360_READ_CHANNEL(ch):
|
|
|
|
return (ch + 8) << 7
|
|
|
|
|
|
|
|
_AD5360_READ_X1A = 0x000 << 7
|
|
|
|
_AD5360_READ_X1B = 0x040 << 7
|
|
|
|
_AD5360_READ_OFFSET = 0x080 << 7
|
|
|
|
_AD5360_READ_GAIN = 0x0c0 << 7
|
|
|
|
_AD5360_READ_CONTROL = 0x101 << 7
|
|
|
|
_AD5360_READ_OFS0 = 0x102 << 7
|
|
|
|
_AD5360_READ_OFS1 = 0x103 << 7
|
|
|
|
|
|
|
|
|
|
|
|
class AD5360:
|
|
|
|
"""
|
|
|
|
Support for the Analog devices AD53[67][0123]
|
|
|
|
multi-channel Digital to Analog Converters
|
|
|
|
"""
|
|
|
|
|
2016-03-05 01:15:35 +08:00
|
|
|
def __init__(self, dmgr, spi_device, ldac_device=None, chip_select=1):
|
2016-03-04 07:00:25 +08:00
|
|
|
self.core = dmgr.get("core")
|
2016-03-05 01:12:30 +08:00
|
|
|
self.bus = dmgr.get(spi_device)
|
|
|
|
if ldac_device is not None:
|
|
|
|
ldac = dmgr.get(ldac_device)
|
2016-03-04 07:00:25 +08:00
|
|
|
self.ldac = ldac
|
|
|
|
self.chip_select = chip_select
|
|
|
|
|
|
|
|
@kernel
|
|
|
|
def setup_bus(self, write_div=4, read_div=7):
|
|
|
|
# write: 2*8ns >= 10ns = t_6 (clk falling to cs_n rising)
|
|
|
|
# read: 4*8*ns >= 25ns = t_22 (clk falling to miso valid)
|
|
|
|
self.bus.set_config_mu(_AD5360_SPI_CONFIG, write_div, read_div)
|
|
|
|
self.bus.set_xfer(self.chip_select, 24, 0)
|
|
|
|
|
2016-03-05 01:12:30 +08:00
|
|
|
@kernel
|
|
|
|
def write(self, data):
|
|
|
|
self.bus.write(data << 8)
|
|
|
|
delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high
|
|
|
|
|
2016-03-04 07:00:25 +08:00
|
|
|
@kernel
|
|
|
|
def write_offsets(self, value=0x1fff):
|
|
|
|
value &= 0x3fff
|
2016-03-05 01:12:30 +08:00
|
|
|
self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_OFS0 | value)
|
|
|
|
self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_OFS1 | value)
|
2016-03-04 07:00:25 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def write_channel(self, channel=0, value=0, op=_AD5360_CMD_DATA):
|
|
|
|
channel &= 0x3f
|
|
|
|
value &= 0xffff
|
2016-03-05 01:12:30 +08:00
|
|
|
self.write(op | _AD5360_WRITE_CHANNEL(channel) | value)
|
2016-03-04 07:00:25 +08:00
|
|
|
|
|
|
|
@kernel
|
2016-03-05 01:12:30 +08:00
|
|
|
def write_channels(self, values, op=_AD5360_CMD_DATA):
|
2016-03-04 07:00:25 +08:00
|
|
|
for i in range(len(values)):
|
2016-03-05 01:12:30 +08:00
|
|
|
self.write_channel(i, values[i], op)
|
2016-03-04 07:00:25 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def read_channel_sync(self, channel=0, op=_AD5360_READ_X1A):
|
|
|
|
channel &= 0x3f
|
2016-03-05 01:12:30 +08:00
|
|
|
self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_READ | op |
|
|
|
|
_AD5360_READ_CHANNEL(channel))
|
2016-03-04 07:00:25 +08:00
|
|
|
self.bus.set_xfer(self.chip_select, 0, 24)
|
2016-03-05 01:12:30 +08:00
|
|
|
self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_NOP)
|
2016-03-04 07:00:25 +08:00
|
|
|
self.bus.read_async()
|
|
|
|
self.bus.set_xfer(self.chip_select, 24, 0)
|
|
|
|
return self.bus.input_async() & 0xffff
|
|
|
|
|
|
|
|
@kernel
|
|
|
|
def load(self):
|
|
|
|
self.ldac.off()
|
2016-03-05 01:12:30 +08:00
|
|
|
delay_mu(3*self.bus.ref_period_mu)
|
2016-03-04 07:00:25 +08:00
|
|
|
self.ldac.on()
|
2016-03-05 01:14:24 +08:00
|
|
|
|
|
|
|
@kernel
|
|
|
|
def set(self, values, op=_AD5360_CMD_DATA):
|
|
|
|
# write() compensation
|
|
|
|
delay_mu(-len(values)*(self.bus.xfer_period_mu +
|
|
|
|
self.bus.write_period_mu +
|
|
|
|
self.bus.ref_period_mu) -
|
|
|
|
3*self.bus.ref_period_mu) # latency alignment
|
|
|
|
self.write_channels(values, op)
|
|
|
|
delay_mu(3*self.bus.ref_period_mu) # latency alignment
|
|
|
|
self.load()
|
|
|
|
delay_mu(-3*self.bus.ref_period_mu) # load() compensation
|