forked from M-Labs/artiq
1
0
Fork 0

ad5360: add documentation and an example

This commit is contained in:
Robert Jördens 2016-03-04 23:36:17 +01:00
parent 18ccac717b
commit f2b4b975a3
2 changed files with 81 additions and 0 deletions

View File

@ -44,6 +44,12 @@ class AD5360:
""" """
Support for the Analog devices AD53[67][0123] Support for the Analog devices AD53[67][0123]
multi-channel Digital to Analog Converters multi-channel Digital to Analog Converters
:param spi_device: Name of the SPI bus this device is on.
:param ldac_device: Name of the TTL device that LDAC is connected to
(optional). Needs to be explicitly initialized to high.
:param chip_select: Value to drive on the chip select lines
during transactions.
""" """
def __init__(self, dmgr, spi_device, ldac_device=None, chip_select=1): def __init__(self, dmgr, spi_device, ldac_device=None, chip_select=1):
@ -55,6 +61,16 @@ class AD5360:
@kernel @kernel
def setup_bus(self, write_div=4, read_div=7): def setup_bus(self, write_div=4, read_div=7):
"""Configure the SPI bus and the SPI transaction parameters
for this device. This method has to be called before any other method
if the bus has been used to access a different device in the meantime.
This method advances the timeline by the duration of two
RTIO-to-Wishbone bus transactions.
:param write_div: Write clock divider.
:param read_div: Read clock divider.
"""
# write: 2*8ns >= 10ns = t_6 (clk falling to cs_n rising) # write: 2*8ns >= 10ns = t_6 (clk falling to cs_n rising)
# read: 4*8*ns >= 25ns = t_22 (clk falling to miso valid) # 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_config_mu(_AD5360_SPI_CONFIG, write_div, read_div)
@ -62,23 +78,56 @@ class AD5360:
@kernel @kernel
def write(self, data): def write(self, data):
"""Write 24 bits of data.
This method advances the timeline by the duration of the SPI transfer
and the required CS high time.
"""
self.bus.write(data << 8) self.bus.write(data << 8)
delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high
@kernel @kernel
def write_offsets(self, value=0x1fff): def write_offsets(self, value=0x1fff):
"""Write the OFS0 and OFS1 offset DACs.
This method advances the timeline by twice the duration of
:meth:`write`.
:param value: Value to set both offset registers to.
"""
value &= 0x3fff value &= 0x3fff
self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_OFS0 | value) self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_OFS0 | value)
self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_OFS1 | value) self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_OFS1 | value)
@kernel @kernel
def write_channel(self, channel=0, value=0, op=_AD5360_CMD_DATA): def write_channel(self, channel=0, value=0, op=_AD5360_CMD_DATA):
"""Write to a channel register.
This method advances the timeline by the duration of :meth:`write`.
:param channel: Channel number to write to.
:param value: 16 bit value to write to the register.
:param op: Operation to perform, one of :const:`_AD5360_CMD_DATA`,
:const:`_AD5360_CMD_OFFSET`, :const:`_AD5360_CMD_GAIN`
(default: :const:`_AD5360_CMD_DATA`).
"""
channel &= 0x3f channel &= 0x3f
value &= 0xffff value &= 0xffff
self.write(op | _AD5360_WRITE_CHANNEL(channel) | value) self.write(op | _AD5360_WRITE_CHANNEL(channel) | value)
@kernel @kernel
def read_channel_sync(self, channel=0, op=_AD5360_READ_X1A): def read_channel_sync(self, channel=0, op=_AD5360_READ_X1A):
"""Read a channel register.
This method advances the timeline by the duration of :meth:`write` plus
three RTIO-to-Wishbone transactions.
:param channel: Channel number to read from.
:param op: Operation to perform, one of :const:`_AD5360_READ_X1A`,
:const:`_AD5360_READ_X1B`, :const:`_AD5360_READ_OFFSET`,
:const:`_AD5360_READ_GAIN` (default: :const:`_AD5360_READ_X1A`).
:return: The 16 bit register value.
"""
channel &= 0x3f channel &= 0x3f
self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_READ | op | self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_READ | op |
_AD5360_READ_CHANNEL(channel)) _AD5360_READ_CHANNEL(channel))
@ -90,6 +139,10 @@ class AD5360:
@kernel @kernel
def load(self): def load(self):
"""Pulse the LDAC line.
This method advances the timeline by two RTIO clock periods (16 ns).
"""
self.ldac.off() self.ldac.off()
# t13 = 10ns ldac pulse width low # t13 = 10ns ldac pulse width low
delay_mu(2*self.bus.ref_period_mu) delay_mu(2*self.bus.ref_period_mu)
@ -97,6 +150,17 @@ class AD5360:
@kernel @kernel
def set(self, values, op=_AD5360_CMD_DATA): def set(self, values, op=_AD5360_CMD_DATA):
"""Write to several channels and pulse LDAC to update the channels.
This method does not advance the timeline. Write events are scheduled
in the past. The DACs will synchronously start changing their output
levels `now`.
:param values: List of 16 bit values to write to the channels.
:param op: Operation to perform, one of :const:`_AD5360_CMD_DATA`,
:const:`_AD5360_CMD_OFFSET`, :const:`_AD5360_CMD_GAIN`
(default: :const:`_AD5360_CMD_DATA`).
"""
# compensate all delays that will be applied # compensate all delays that will be applied
delay_mu(-len(values)*(self.bus.xfer_period_mu + delay_mu(-len(values)*(self.bus.xfer_period_mu +
self.bus.write_period_mu + self.bus.write_period_mu +

View File

@ -0,0 +1,17 @@
from artiq.experiment import *
class AD5360Test(EnvExperiment):
def build(self):
self.setattr_device("core")
self.dac = self.get_device("dac0")
self.setattr_device("led")
@kernel
def run(self):
self.dac.setup_bus(write_div=30, read_div=40)
self.dac.write_offsets()
self.led.on()
delay(400*us)
self.led.off()
self.dac.set([i << 10 for i in range(40)])