diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 285ec8816..22d490583 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -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) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index a5da146ed..931b6551e 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -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)) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 8532ab8b6..6648205c6 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -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))) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 6def86ae8..d099c8ff3 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -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: