diff --git a/artiq/coredevice/ad5360.py b/artiq/coredevice/ad5360.py index a72b8909a..b2dbe79c6 100644 --- a/artiq/coredevice/ad5360.py +++ b/artiq/coredevice/ad5360.py @@ -44,6 +44,12 @@ class AD5360: """ Support for the Analog devices AD53[67][0123] 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): @@ -55,6 +61,16 @@ class AD5360: @kernel 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) # read: 4*8*ns >= 25ns = t_22 (clk falling to miso valid) self.bus.set_config_mu(_AD5360_SPI_CONFIG, write_div, read_div) @@ -62,23 +78,56 @@ class AD5360: @kernel 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) delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high @kernel 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 self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_OFS0 | value) self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_OFS1 | value) @kernel 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 value &= 0xffff self.write(op | _AD5360_WRITE_CHANNEL(channel) | value) @kernel 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 self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_READ | op | _AD5360_READ_CHANNEL(channel)) @@ -90,6 +139,10 @@ class AD5360: @kernel def load(self): + """Pulse the LDAC line. + + This method advances the timeline by two RTIO clock periods (16 ns). + """ self.ldac.off() # t13 = 10ns ldac pulse width low delay_mu(2*self.bus.ref_period_mu) @@ -97,6 +150,17 @@ class AD5360: @kernel 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 delay_mu(-len(values)*(self.bus.xfer_period_mu + self.bus.write_period_mu + diff --git a/examples/master/repository/coredevice_examples/simple/ad5360.py b/examples/master/repository/coredevice_examples/simple/ad5360.py new file mode 100644 index 000000000..5dd731c04 --- /dev/null +++ b/examples/master/repository/coredevice_examples/simple/ad5360.py @@ -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)])