urukul: document ad9912, and cpld, fix api

pull/922/head
Robert Jördens 2018-02-14 09:45:17 +01:00
parent ede98679fc
commit 2adba3ed33
4 changed files with 109 additions and 17 deletions

View File

@ -149,7 +149,7 @@ class AD9910:
raise ValueError("PLL failed to lock")
@kernel
def set_mu(self, ftw, pow=0, asf=0x3fff):
def set_mu(self, ftw=int32(0), pow=int32(0), asf=int32(0x3fff)):
"""Set profile 0 data in machine units.
After the SPI transfer, the shared IO update pin is pulsed to
@ -195,9 +195,11 @@ class AD9910:
self.amplitude_to_asf(amplitude))
@kernel
def set_att_mu(self, att):
def set_att_mu(self, att=int32(0)):
"""Set digital step attenuator in machine units.
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att_mu`
:param att: Attenuation setting, 8 bit digital.
"""
self.cpld.set_att_mu(self.chip_select - 4, att)
@ -206,6 +208,8 @@ class AD9910:
def set_att(self, att):
"""Set digital step attenuator in SI units.
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att`
:param att: Attenuation in dB.
"""
self.cpld.set_att(self.chip_select - 4, att)

View File

@ -7,11 +7,19 @@ from numpy import int32, int64
class AD9912:
"""
Support for the AD9912 DDS on Urukul
AD9912 DDS channel on Urukul
:param chip_select: Chip select configuration.
This class supports a single DDS channel and exposes the DDS,
the digital step attenuator, and the RF switch.
:param chip_select: Chip select configuration. On Urukul this is an
encoded chip select and not "one-hot".
:param cpld_device: Name of the Urukul CPLD this device is on.
:param sw_device: Name of the RF switch device.
:param sw_device: Name of the RF switch device. The RF switch is a
TTLOut channel available as the :attr:`sw` attribute of this instance.
:param pll_n: DDS PLL multiplier. The DDS sample clock is
f_ref*pll_n where f_ref is the reference frequency (set in the parent
Urukul CPLD instance).
"""
kernel_invariants = {"chip_select", "cpld", "core", "bus", "sw",
"ftw_per_hz", "sysclk", "pll_n"}
@ -27,10 +35,17 @@ class AD9912:
self.sw = dmgr.get(sw_device)
self.pll_n = pll_n
self.sysclk = self.cpld.refclk*pll_n
assert self.sysclk < 1e9
self.ftw_per_hz = 1/self.sysclk*(int64(1) << 48)
@kernel
def write(self, addr, data, length=1):
def write(self, addr=int32(0), data=int32(0), length=int32(1)):
"""Variable length write to a register. Up to 32 bits.
:param addr: Register address
:param data: Data to be written: int32
:param length: Length in bytes (1-4)
"""
assert length > 0
assert length <= 4
self.bus.set_xfer(self.chip_select, 16, 0)
@ -41,7 +56,12 @@ class AD9912:
delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu)
@kernel
def read(self, addr, length=1):
def read(self, addr=int32(0), length=int32(1)):
"""Variable length read from a register. Up to 32 bits.
:param addr: Register address
:param length: Length in bytes (1-4)
"""
assert length > 0
assert length <= 4
self.bus.set_xfer(self.chip_select, 16, 0)
@ -57,8 +77,11 @@ class AD9912:
@kernel
def init(self):
"""Initialize and configure the DDS."""
t = now_mu()
# SPI mode
self.write(AD9912_SER_CONF, 0x99)
# Verify chip ID and presence
prodid = self.read(AD9912_PRODIDH, length=2)
if (prodid != 0x1982) and (prodid != 0x1902):
raise ValueError("Urukul AD9912 product id mismatch")
@ -69,19 +92,39 @@ class AD9912:
delay(10*us)
self.write(AD9912_PLLCFG, 0b00000101) # 375 µA, high range
at_mu(t)
delay(100*us)
delay(100*us) # constant duration of 100 µs
@kernel
def set_att_mu(self, att):
"""Set digital step attenuator in machine units.
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att_mu`
:param att: Attenuation setting, 8 bit digital.
"""
self.cpld.set_att_mu(self.chip_select - 4, att)
@kernel
def set_att(self, att):
"""Set digital step attenuator in SI units.
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att`
:param att: Attenuation in dB.
"""
self.cpld.set_att(self.chip_select - 4, att)
@kernel
def set_mu(self, ftw=int64(0), pow=int32(0)):
# do a streaming transfer of FTW and POW
"""Set profile 0 data in machine units.
After the SPI transfer, the shared IO update pin is pulsed to
activate the data.
:param ftw: Frequency tuning word: 32 bit unsigned.
:param pow: Phase tuning word: 16 bit unsigned.
"""
# streaming transfer of FTW and POW
self.bus.set_xfer(self.chip_select, 16, 0)
self.bus.write((AD9912_POW1 << 16) | (3 << 29))
delay_mu(-self.bus.xfer_period_mu)
@ -107,5 +150,12 @@ class AD9912:
@kernel
def set(self, frequency, phase=0.0):
"""Set profile 0 data in SI units.
.. seealso:: :meth:`set_mu`
:param ftw: Frequency in Hz
:param pow: Phase tuning word in turns
"""
self.set_mu(self.frequency_to_ftw(frequency),
self.turns_to_pow(phase))

View File

@ -87,6 +87,15 @@ CS_DDS_CH3 = 7
class CPLD:
"""Urukul CPLD SPI router and configuration interface.
:param spi_device: SPI bus device name
:param io_update_device: IO update RTIO TTLOut channel name
:param dds_reset_device: DDS reset RTIO TTLOut channel name
:param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator)
frequency in Hz
:param core_device: Core device name
"""
def __init__(self, dmgr, spi_device, io_update_device,
dds_reset_device=None,
refclk=100e6, core_device="core"):
@ -103,12 +112,17 @@ class CPLD:
self.att_reg = int32(0)
@kernel
def cfg_write(self, cfg_reg):
def cfg_write(self, data=int32(0)):
"""Write to the configuration register.
:param data: 24 bit data to be written. Will be stored at
:attr:`cfg_reg`.
"""
self.bus.set_config_mu(_SPI_CONFIG, _SPIT_CFG_WR, _SPIT_CFG_RD)
self.bus.set_xfer(CS_CFG, 24, 0)
self.bus.write(cfg_reg << 8)
self.bus.write(data << 8)
self.bus.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD)
self.cfg_reg = cfg_reg
self.cfg_reg = data
@kernel
def sta_read(self):
@ -150,11 +164,12 @@ class CPLD:
self.cfg_write(c)
@kernel
def set_att_mu(self, channel, att):
"""
Parameters:
att (int): 0-255, 255 minimum attenuation,
0 maximum attenuation (31.5 dB)
def set_att_mu(self, channel=int32(0), att=int32(0)):
"""Set digital step attenuator in machine units.
:param channel: Attenuator channel (0-3).
:param att: Digital attenuation setting:
255 minimum attenuation, 0 maximum attenuation (31.5 dB)
"""
a = self.att_reg & ~(0xff << (channel * 8))
a |= att << (channel * 8)
@ -165,4 +180,9 @@ class CPLD:
@kernel
def set_att(self, channel, att):
"""Set digital step attenuator in SI units.
:param channel: Attenuator channel (0-3).
:param att: Attenuation in dB.
"""
self.set_att_mu(channel, 255 - int32(round(att*8)))

View File

@ -68,3 +68,21 @@ These drivers are for the core device and the peripherals closely integrated int
.. automodule:: artiq.coredevice.sawg
:members:
:mod:`artiq.coredevice.urukul` module
-------------------------------------
.. automodule:: artiq.coredevice.urukul
:members:
:mod:`artiq.coredevice.ad9912` module
-------------------------------------
.. automodule:: artiq.coredevice.ad9912
:members:
:mod:`artiq.coredevice.ad9910` module
-------------------------------------
.. automodule:: artiq.coredevice.ad9910
:members: