mirror of https://github.com/m-labs/artiq.git
Merge branch 'master' of github.com:m-labs/artiq
This commit is contained in:
commit
354a62f5d0
|
@ -0,0 +1,95 @@
|
||||||
|
from artiq.language.core import kernel, portable, delay
|
||||||
|
from artiq.language.units import ns
|
||||||
|
from artiq.coredevice import spi
|
||||||
|
|
||||||
|
|
||||||
|
_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
|
||||||
|
_AD5360_SPECIAL_READ = 3 << 16
|
||||||
|
|
||||||
|
|
||||||
|
@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
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, dmgr, spi_bus, ldac=None, chip_select=0):
|
||||||
|
self.core = dmgr.get("core")
|
||||||
|
self.bus = dmgr.get(spi_bus)
|
||||||
|
if ldac is not None:
|
||||||
|
ldac = dmgr.get(ldac)
|
||||||
|
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)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def write_offsets(self, value=0x1fff):
|
||||||
|
value &= 0x3fff
|
||||||
|
self.bus.write((_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_OFS0 | value
|
||||||
|
) << 8)
|
||||||
|
self.bus.write((_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_OFS1 | value
|
||||||
|
) << 8)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def write_channel(self, channel=0, value=0, op=_AD5360_CMD_DATA):
|
||||||
|
channel &= 0x3f
|
||||||
|
value &= 0xffff
|
||||||
|
self.bus.write((op | _AD5360_WRITE_CHANNEL(channel) | value) << 8)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def write_channels(self, values, first=0, op=_AD5360_CMD_DATA):
|
||||||
|
for i in range(len(values)):
|
||||||
|
self.write_channel(i + first, values[i], op)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def read_channel_sync(self, channel=0, op=_AD5360_READ_X1A):
|
||||||
|
channel &= 0x3f
|
||||||
|
self.bus.write((_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_READ | op |
|
||||||
|
_AD5360_READ_CHANNEL(channel)) << 8)
|
||||||
|
self.bus.set_xfer(self.chip_select, 0, 24)
|
||||||
|
self.bus.write((_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_NOP) << 8)
|
||||||
|
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()
|
||||||
|
delay(24*ns)
|
||||||
|
self.ldac.on()
|
|
@ -1,71 +0,0 @@
|
||||||
from artiq.language.core import (kernel, portable, delay, delay_mu, int)
|
|
||||||
from artiq.language.units import ns
|
|
||||||
from artiq.coredevice import spi
|
|
||||||
|
|
||||||
|
|
||||||
_AD53xx_SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_CS_POLARITY |
|
|
||||||
0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE |
|
|
||||||
0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX)
|
|
||||||
|
|
||||||
_AD53xx_MODE_WRITE_X1 = 3 << 22
|
|
||||||
_AD53xx_MODE_WRITE_C = 2 << 22
|
|
||||||
_AD53xx_MODE_WRITE_M = 1 << 22
|
|
||||||
_AD53xx_MODE_SPECIAL = 0 << 22
|
|
||||||
|
|
||||||
_AD53xx_GROUP = portable(lambda g: ((g + 1) << 19))
|
|
||||||
_AD53xx_GROUP_ALL = 0 << 19
|
|
||||||
_AD53xx_GROUP_01234 = 6 << 19
|
|
||||||
_AD53xx_GROUP_1234 = 7 << 19
|
|
||||||
_AD53xx_CHANNEL_ALL = 0 << 16
|
|
||||||
_AD53xx_CHANNEL = portable(lambda g: g << 16)
|
|
||||||
|
|
||||||
_AD53xx_SPECIAL_NOP = 0 << 16
|
|
||||||
_AD53xx_SPECIAL_CONTROL = 1 << 16
|
|
||||||
_AD53xx_SPECIAL_OFS0 = 2 << 16
|
|
||||||
_AD53xx_SPECIAL_OFS1 = 3 << 16
|
|
||||||
_AD53xx_SPECIAL_AB_SELECT = portable(lambda i: (i + 6) << 16)
|
|
||||||
_AD53xx_SPECIAL_AB_SELECT_ALL = 11 << 16
|
|
||||||
|
|
||||||
_AD53xx_READ_X1A = portable(lambda ch: (0x00 | (ch + 8)) << 7)
|
|
||||||
_AD53xx_READ_X1B = portable(lambda ch: (0x40 | (ch + 8)) << 7)
|
|
||||||
_AD53xx_READ_C = portable(lambda ch: (0x80 | (ch + 8)) << 7)
|
|
||||||
_AD53xx_READ_M = portable(lambda ch: (0xc0 | (ch + 8)) << 7)
|
|
||||||
_AD53xx_READ_CONTROL = 0x101 << 7
|
|
||||||
_AD53xx_READ_OFS0 = 0x102 << 7
|
|
||||||
_AD53xx_READ_OFS1 = 0x103 << 7
|
|
||||||
_AD53xx_READ_AB_SELECT = portable(lambda i: (0x100 + (i + 6)) << 7)
|
|
||||||
|
|
||||||
|
|
||||||
class AD53xx:
|
|
||||||
def __init__(self, dmgr, spi_bus, ldac=None,
|
|
||||||
chip_select=0, write_div=4, read_div=6):
|
|
||||||
self.core = dmgr.get("core")
|
|
||||||
self.bus = dmgr.get(spi_bus)
|
|
||||||
if ldac is not None:
|
|
||||||
ldac = dmgr.get(ldac)
|
|
||||||
self.ldac = ldac
|
|
||||||
self.chip_select = chip_select
|
|
||||||
self.write_div = write_div
|
|
||||||
self.read_div = read_div
|
|
||||||
|
|
||||||
@kernel
|
|
||||||
def bus_setup(self):
|
|
||||||
self.bus.set_config_mu(_AD53xx_SPI_CONFIG, self.write_div,
|
|
||||||
self.read_div)
|
|
||||||
self.bus.set_xfer(self.chip_select, 24, 0)
|
|
||||||
|
|
||||||
@kernel
|
|
||||||
def _channel_address(self, channel=0):
|
|
||||||
return int((channel + 8) << 16)
|
|
||||||
|
|
||||||
@kernel
|
|
||||||
def write_x1(self, channel=0, value=0):
|
|
||||||
ch = self._channel_address(channel)
|
|
||||||
self.bus.write(_AD53xx_MODE_WRITE_X1 | ch | value)
|
|
||||||
delay_mu(int(self.bus.xfer_period_mu + self.bus.write_period_mu))
|
|
||||||
|
|
||||||
@kernel
|
|
||||||
def load(self):
|
|
||||||
self.ldac.off()
|
|
||||||
delay(20*ns)
|
|
||||||
self.ldac.on()
|
|
|
@ -198,11 +198,11 @@ class SPIMaster:
|
||||||
the previous transfer's read data is available in the
|
the previous transfer's read data is available in the
|
||||||
``data`` register.
|
``data`` register.
|
||||||
|
|
||||||
This method advances the timeline by the duration of the
|
This method advances the timeline by the duration of the SPI transfer.
|
||||||
RTIO-to-Wishbone bus transaction (three RTIO clock cycles).
|
If a transfer is to be chained, the timeline needs to be rewound.
|
||||||
"""
|
"""
|
||||||
rtio_output(now_mu(), self.channel, SPI_DATA_ADDR, data)
|
rtio_output(now_mu(), self.channel, SPI_DATA_ADDR, data)
|
||||||
delay_mu(3*self.ref_period_mu)
|
delay_mu(self.xfer_period_mu + self.write_period_mu)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def read_async(self):
|
def read_async(self):
|
||||||
|
|
|
@ -238,7 +238,7 @@ class TTLClockGen:
|
||||||
|
|
||||||
# in RTIO cycles
|
# in RTIO cycles
|
||||||
self.previous_timestamp = int(0, width=64)
|
self.previous_timestamp = int(0, width=64)
|
||||||
self.acc_width = 24
|
self.acc_width = int(24, width=64)
|
||||||
|
|
||||||
@portable
|
@portable
|
||||||
def frequency_to_ftw(self, frequency):
|
def frequency_to_ftw(self, frequency):
|
||||||
|
|
|
@ -264,7 +264,7 @@ class NIST_CLOCK(_NIST_Ions):
|
||||||
rtio_channels.append(rtio.Channel.from_phy(
|
rtio_channels.append(rtio.Channel.from_phy(
|
||||||
phy, ofifo_depth=4, ififo_depth=4))
|
phy, ofifo_depth=4, ififo_depth=4))
|
||||||
|
|
||||||
for i in range(1): # spi1 and spi2 collide in pinout with ttl
|
for i in range(3):
|
||||||
phy = spi.SPIMaster(self.platform.request("spi", i))
|
phy = spi.SPIMaster(self.platform.request("spi", i))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(
|
rtio_channels.append(rtio.Channel.from_phy(
|
||||||
|
|
|
@ -30,6 +30,11 @@ These drivers are for the core device and the peripherals closely integrated int
|
||||||
.. automodule:: artiq.coredevice.spi
|
.. automodule:: artiq.coredevice.spi
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
:mod:`artiq.coredevice.ad5360` module
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: artiq.coredevice.ad5360
|
||||||
|
:members:
|
||||||
|
|
||||||
:mod:`artiq.coredevice.exceptions` module
|
:mod:`artiq.coredevice.exceptions` module
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue