From 24c3a2fd0af872ef6bff4d452e40082eebe7fa0f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Oct 2023 14:40:53 +0800 Subject: [PATCH] shuttler: port to NAC3 --- artiq/coredevice/shuttler.py | 177 ++++++++++-------- .../kasli_shuttler/repository/shuttler.py | 153 ++++++++------- artiq/examples/nac3devices/nac3devices.json | 6 +- artiq/examples/nac3devices/nac3devices.py | 5 + 4 files changed, 191 insertions(+), 150 deletions(-) diff --git a/artiq/coredevice/shuttler.py b/artiq/coredevice/shuttler.py index c6761e0ba..9da784fe7 100644 --- a/artiq/coredevice/shuttler.py +++ b/artiq/coredevice/shuttler.py @@ -1,20 +1,21 @@ -import numpy +from numpy import int32, int64 -from artiq.language.core import * -from artiq.language.types import * +from artiq.language.core import nac3, Kernel, KernelInvariant, kernel, portable, Option, none from artiq.coredevice.rtio import rtio_output, rtio_input_data -from artiq.coredevice import spi2 as spi +from artiq.coredevice.core import Core +from artiq.coredevice.spi2 import * from artiq.language.units import us @portable -def shuttler_volt_to_mu(volt): +def shuttler_volt_to_mu(volt: float) -> int32: """Return the equivalent DAC code. Valid input range is from -10 to 10 - LSB. """ - return round((1 << 16) * (volt / 20.0)) & 0xffff + return round(float(1 << 16) * (volt / 20.0)) & 0xffff +@nac3 class Config: """Shuttler configuration registers interface. @@ -30,10 +31,13 @@ class Config: :param channel: RTIO channel number of this interface. :param core_device: Core device name. """ - kernel_invariants = { - "core", "channel", "target_base", "target_read", - "target_gain", "target_offset", "target_clr" - } + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + target_base: KernelInvariant[int32] + target_read: KernelInvariant[int32] + target_gain: KernelInvariant[int32] + target_offset: KernelInvariant[int32] + target_clr: KernelInvariant[int32] def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) @@ -45,7 +49,7 @@ class Config: self.target_clr = 1 * (1 << 5) @kernel - def set_clr(self, clr): + def set_clr(self, clr: int32): """Set/Unset waveform phase clear bits. Each bit corresponds to a Shuttler waveform generator core. Setting a @@ -59,7 +63,7 @@ class Config: rtio_output(self.target_base | self.target_clr, clr) @kernel - def set_gain(self, channel, gain): + def set_gain(self, channel: int32, gain: int32): """Set the 16-bits pre-DAC gain register of a Shuttler Core channel. The `gain` parameter represents the decimal portion of the gain @@ -72,7 +76,7 @@ class Config: rtio_output(self.target_base | self.target_gain | channel, gain) @kernel - def get_gain(self, channel): + def get_gain(self, channel: int32) -> int32: """Return the pre-DAC gain value of a Shuttler Core channel. :param channel: The Shuttler Core channel. @@ -83,7 +87,7 @@ class Config: return rtio_input_data(self.channel) @kernel - def set_offset(self, channel, offset): + def set_offset(self, channel: int32, offset: int32): """Set the 16-bits pre-DAC offset register of a Shuttler Core channel. .. seealso:: @@ -95,7 +99,7 @@ class Config: rtio_output(self.target_base | self.target_offset | channel, offset) @kernel - def get_offset(self, channel): + def get_offset(self, channel: int32) -> int32: """Return the pre-DAC offset value of a Shuttler Core channel. :param channel: The Shuttler Core channel. @@ -106,6 +110,7 @@ class Config: return rtio_input_data(self.channel) +@nac3 class Volt: """Shuttler Core cubic DC-bias spline. @@ -127,7 +132,9 @@ class Volt: :param channel: RTIO channel number of this DC-bias spline interface. :param core_device: Core device name. """ - kernel_invariants = {"core", "channel", "target_o"} + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + target_o: KernelInvariant[int32] def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) @@ -135,7 +142,7 @@ class Volt: self.target_o = channel << 8 @kernel - def set_waveform(self, a0: TInt32, a1: TInt32, a2: TInt64, a3: TInt64): + def set_waveform(self, a0: int32, a1: int32, a2: int64, a3: int64): """Set the DC-bias spline waveform. Given `a(t)` as defined in :class:`Volt`, the coefficients should be @@ -168,12 +175,12 @@ class Volt: a0, a1, a1 >> 16, - a2 & 0xFFFF, - (a2 >> 16) & 0xFFFF, - (a2 >> 32) & 0xFFFF, - a3 & 0xFFFF, - (a3 >> 16) & 0xFFFF, - (a3 >> 32) & 0xFFFF, + int32(a2 & int64(0xFFFF)), + int32((a2 >> int64(16)) & int64(0xFFFF)), + int32((a2 >> int64(32)) & int64(0xFFFF)), + int32(a3 & int64(0xFFFF)), + int32((a3 >> int64(16)) & int64(0xFFFF)), + int32((a3 >> int64(32)) & int64(0xFFFF)), ] for i in range(len(coef_words)): @@ -181,6 +188,7 @@ class Volt: delay_mu(int64(self.core.ref_multiplier)) +@nac3 class Dds: """Shuttler Core DDS spline. @@ -206,7 +214,9 @@ class Dds: :param channel: RTIO channel number of this DC-bias spline interface. :param core_device: Core device name. """ - kernel_invariants = {"core", "channel", "target_o"} + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + target_o: KernelInvariant[int32] def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) @@ -214,8 +224,8 @@ class Dds: self.target_o = channel << 8 @kernel - def set_waveform(self, b0: TInt32, b1: TInt32, b2: TInt64, b3: TInt64, - c0: TInt32, c1: TInt32, c2: TInt32): + def set_waveform(self, b0: int32, b1: int32, b2: int64, b3: int64, + c0: int32, c1: int32, c2: int32): """Set the DDS spline waveform. Given `b(t)` and `c(t)` as defined in :class:`Dds`, the coefficients @@ -258,12 +268,12 @@ class Dds: b0, b1, b1 >> 16, - b2 & 0xFFFF, - (b2 >> 16) & 0xFFFF, - (b2 >> 32) & 0xFFFF, - b3 & 0xFFFF, - (b3 >> 16) & 0xFFFF, - (b3 >> 32) & 0xFFFF, + int32(b2 & int64(0xFFFF)), + int32((b2 >> int64(16)) & int64(0xFFFF)), + int32((b2 >> int64(32)) & int64(0xFFFF)), + int32(b3 & int64(0xFFFF)), + int32((b3 >> int64(16)) & int64(0xFFFF)), + int32((b3 >> int64(32)) & int64(0xFFFF)), c0, c1, c1 >> 16, @@ -276,13 +286,16 @@ class Dds: delay_mu(int64(self.core.ref_multiplier)) +@nac3 class Trigger: """Shuttler Core spline coefficients update trigger. :param channel: RTIO channel number of the trigger interface. :param core_device: Core device name. """ - kernel_invariants = {"core", "channel", "target_o"} + core: KernelInvariant[Core] + channel: KernelInvariant[int32] + target_o: KernelInvariant[int32] def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) @@ -290,7 +303,7 @@ class Trigger: self.target_o = channel << 8 @kernel - def trigger(self, trig_out): + def trigger(self, trig_out: int32): """Triggers coefficient update of (a) Shuttler Core channel(s). Each bit corresponds to a Shuttler waveform generator core. Setting @@ -304,15 +317,15 @@ class Trigger: rtio_output(self.target_o, trig_out) -RELAY_SPI_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | - 0*spi.SPI_INPUT | 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) +RELAY_SPI_CONFIG = (0*SPI_OFFLINE | 1*SPI_END | + 0*SPI_INPUT | 0*SPI_CS_POLARITY | + 0*SPI_CLK_POLARITY | 0*SPI_CLK_PHASE | + 0*SPI_LSB_FIRST | 0*SPI_HALF_DUPLEX) -ADC_SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | - 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | - 1*spi.SPI_CLK_POLARITY | 1*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) +ADC_SPI_CONFIG = (0*SPI_OFFLINE | 0*SPI_END | + 0*SPI_INPUT | 0*SPI_CS_POLARITY | + 1*SPI_CLK_POLARITY | 1*SPI_CLK_PHASE | + 0*SPI_LSB_FIRST | 0*SPI_HALF_DUPLEX) # SPI clock write and read dividers # CS should assert at least 9.5 ns after clk pulse @@ -335,6 +348,7 @@ _AD4115_REG_CH0 = 0x10 _AD4115_REG_SETUPCON0 = 0x20 +@nac3 class Relay: """Shuttler AFE relay switches. @@ -349,7 +363,8 @@ class Relay: :param spi_device: SPI bus device name. :param core_device: Core device name. """ - kernel_invariant = {"core", "bus"} + core: KernelInvariant[Core] + bus: KernelInvariant[SPIMaster] def __init__(self, dmgr, spi_device, core_device="core"): self.core = dmgr.get(core_device) @@ -366,7 +381,7 @@ class Relay: RELAY_SPI_CONFIG, 16, SPIT_RELAY_WR, CS_RELAY | CS_LED) @kernel - def enable(self, en: TInt32): + def enable(self, en: int32): """Enable/Disable relay switches of corresponding channels. Each bit corresponds to the relay switch of a channel. Asserting a bit @@ -379,20 +394,22 @@ class Relay: self.bus.write(en << 16) +@nac3 class ADC: """Shuttler AFE ADC (AD4115) driver. :param spi_device: SPI bus device name. :param core_device: Core device name. """ - kernel_invariant = {"core", "bus"} + core: KernelInvariant[Core] + bus: KernelInvariant[SPIMaster] def __init__(self, dmgr, spi_device, core_device="core"): self.core = dmgr.get(core_device) self.bus = dmgr.get(spi_device) @kernel - def read_id(self) -> TInt32: + def read_id(self) -> int32: """Read the product ID of the ADC. The expected return value is 0x38DX, the 4 LSbs are don't cares. @@ -414,86 +431,86 @@ class ADC: after the transfer appears to interrupt the start-up sequence. """ self.bus.set_config_mu(ADC_SPI_CONFIG, 32, SPIT_ADC_WR, CS_ADC) - self.bus.write(0xffffffff) - self.bus.write(0xffffffff) + self.bus.write(-1) + self.bus.write(-1) self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END, 32, SPIT_ADC_WR, CS_ADC) - self.bus.write(0xffffffff) + ADC_SPI_CONFIG | SPI_END, 32, SPIT_ADC_WR, CS_ADC) + self.bus.write(-1) @kernel - def read8(self, addr: TInt32) -> TInt32: + def read8(self, addr: int32) -> int32: """Read from 8 bit register. :param addr: Register address. :return: Read-back register content. """ self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, + ADC_SPI_CONFIG | SPI_END | SPI_INPUT, 16, SPIT_ADC_RD, CS_ADC) self.bus.write((addr | 0x40) << 24) return self.bus.read() & 0xff @kernel - def read16(self, addr: TInt32) -> TInt32: + def read16(self, addr: int32) -> int32: """Read from 16 bit register. :param addr: Register address. :return: Read-back register content. """ self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, + ADC_SPI_CONFIG | SPI_END | SPI_INPUT, 24, SPIT_ADC_RD, CS_ADC) self.bus.write((addr | 0x40) << 24) return self.bus.read() & 0xffff @kernel - def read24(self, addr: TInt32) -> TInt32: + def read24(self, addr: int32) -> int32: """Read from 24 bit register. :param addr: Register address. :return: Read-back register content. """ self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, + ADC_SPI_CONFIG | SPI_END | SPI_INPUT, 32, SPIT_ADC_RD, CS_ADC) self.bus.write((addr | 0x40) << 24) return self.bus.read() & 0xffffff @kernel - def write8(self, addr: TInt32, data: TInt32): + def write8(self, addr: int32, data: int32): """Write to 8 bit register. :param addr: Register address. :param data: Data to be written. """ self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END, 16, SPIT_ADC_WR, CS_ADC) + ADC_SPI_CONFIG | SPI_END, 16, SPIT_ADC_WR, CS_ADC) self.bus.write(addr << 24 | (data & 0xff) << 16) @kernel - def write16(self, addr: TInt32, data: TInt32): + def write16(self, addr: int32, data: int32): """Write to 16 bit register. :param addr: Register address. :param data: Data to be written. """ self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END, 24, SPIT_ADC_WR, CS_ADC) + ADC_SPI_CONFIG | SPI_END, 24, SPIT_ADC_WR, CS_ADC) self.bus.write(addr << 24 | (data & 0xffff) << 8) @kernel - def write24(self, addr: TInt32, data: TInt32): + def write24(self, addr: int32, data: int32): """Write to 24 bit register. :param addr: Register address. :param data: Data to be written. """ self.bus.set_config_mu( - ADC_SPI_CONFIG | spi.SPI_END, 32, SPIT_ADC_WR, CS_ADC) + ADC_SPI_CONFIG | SPI_END, 32, SPIT_ADC_WR, CS_ADC) self.bus.write(addr << 24 | (data & 0xffffff)) @kernel - def read_ch(self, channel: TInt32) -> TFloat: + def read_ch(self, channel: int32) -> float: """Sample a Shuttler channel on the AFE. It performs a single conversion using profile 0 and setup 0, on the @@ -507,9 +524,9 @@ class ADC: self.write16(_AD4115_REG_SETUPCON0, 0x1300) self.single_conversion() - delay(100*us) + self.core.delay(100.*us) adc_code = self.read24(_AD4115_REG_DATA) - return ((adc_code / (1 << 23)) - 1) * 2.5 / 0.1 + return ((float(adc_code) / float(1 << 23)) - 1.) * 2.5 / 0.1 @kernel def single_conversion(self): @@ -560,10 +577,10 @@ class ADC: self.reset() # Although the datasheet claims 500 us reset wait time, only waiting # for ~500 us can result in DOUT pin stuck in high - delay(2500*us) + self.core.delay(2500.*us) @kernel - def calibrate(self, volts, trigger, config, samples=[-5.0, 0.0, 5.0]): + def calibrate(self, volts: list[Volt], trigger: Trigger, config: Config, samples: Option[list[float]] = none): """Calibrate the Shuttler waveform generator using the ADC on the AFE. It finds the average slope rate and average offset by samples, and @@ -588,33 +605,35 @@ class ADC: :param samples: A list of sample voltages for calibration. There must be at least 2 samples to perform slope rate calculation. """ - assert len(volts) == 16 - assert len(samples) > 1 + samples_l = samples.unwrap() if samples.is_some() else [-5.0, 0.0, 5.0] - measurements = [0.0] * len(samples) + assert len(volts) == 16 + assert len(samples_l) > 1 + + measurements = [0.0 for _ in range(len(samples_l))] for ch in range(16): # Find the average slope rate and offset - for i in range(len(samples)): + for i in range(len(samples_l)): self.core.break_realtime() volts[ch].set_waveform( - shuttler_volt_to_mu(samples[i]), 0, 0, 0) + shuttler_volt_to_mu(samples_l[i]), 0, int64(0), int64(0)) trigger.trigger(1 << ch) measurements[i] = self.read_ch(ch) # Find the average output slope slope_sum = 0.0 - for i in range(len(samples) - 1): - slope_sum += (measurements[i+1] - measurements[i])/(samples[i+1] - samples[i]) - slope_avg = slope_sum / (len(samples) - 1) + for i in range(len(samples_l) - 1): + slope_sum += (measurements[i+1] - measurements[i])/(samples_l[i+1] - samples_l[i]) + slope_avg = slope_sum / float(len(samples_l) - 1) - gain_code = int32(1 / slope_avg * (2 ** 16)) & 0xffff + gain_code = int32(1. / slope_avg * float(2 ** 16)) & 0xffff # Scale the measurements by 1/slope, find average offset offset_sum = 0.0 - for i in range(len(samples)): - offset_sum += (measurements[i] / slope_avg) - samples[i] - offset_avg = offset_sum / len(samples) + for i in range(len(samples_l)): + offset_sum += (measurements[i] / slope_avg) - samples_l[i] + offset_avg = offset_sum / float(len(samples_l)) offset_code = shuttler_volt_to_mu(-offset_avg) diff --git a/artiq/examples/kasli_shuttler/repository/shuttler.py b/artiq/examples/kasli_shuttler/repository/shuttler.py index 22a3a776e..9a0b4e517 100644 --- a/artiq/examples/kasli_shuttler/repository/shuttler.py +++ b/artiq/examples/kasli_shuttler/repository/shuttler.py @@ -1,61 +1,82 @@ -from artiq.experiment import * -from artiq.coredevice.shuttler import shuttler_volt_to_mu +from numpy import int32, int64 -DAC_Fs_MHZ = 125 +from artiq.experiment import * +from artiq.coredevice.core import Core +from artiq.coredevice.ttl import TTLOut +from artiq.coredevice.shuttler import ( + shuttler_volt_to_mu, + Config as ShuttlerConfig, + Trigger as ShuttlerTrigger, + Volt as ShuttlerDCBias, + Dds as ShuttlerDDS, + Relay as ShuttlerRelay, + ADC as ShuttlerADC) + + +DAC_Fs_MHZ = 125. CORDIC_GAIN = 1.64676 @portable -def shuttler_phase_offset(offset_degree): - return round(offset_degree / 360 * (2 ** 16)) +def shuttler_phase_offset(offset_degree: float) -> int32: + return round(offset_degree / 360. * float(2 ** 16)) @portable -def shuttler_freq_mu(freq_mhz): +def shuttler_freq_mu(freq_mhz: float) -> int32: return round(float(2) ** 32 / DAC_Fs_MHZ * freq_mhz) @portable -def shuttler_chirp_rate_mu(freq_mhz_per_us): +def shuttler_chirp_rate_mu(freq_mhz_per_us: float) -> int32: return round(float(2) ** 32 * freq_mhz_per_us / (DAC_Fs_MHZ ** 2)) @portable -def shuttler_freq_sweep(start_f_MHz, end_f_MHz, time_us): - return shuttler_chirp_rate_mu((end_f_MHz - start_f_MHz)/(time_us)) +def shuttler_freq_sweep(start_f_MHz: float, end_f_MHz: float, time_us: float) -> int32: + return shuttler_chirp_rate_mu((end_f_MHz - start_f_MHz)/time_us) @portable -def shuttler_volt_amp_mu(volt): +def shuttler_volt_amp_mu(volt: float) -> int32: return shuttler_volt_to_mu(volt) @portable -def shuttler_volt_damp_mu(volt_per_us): - return round(float(2) ** 32 * (volt_per_us / 20) / DAC_Fs_MHZ) +def shuttler_volt_damp_mu(volt_per_us: float) -> int32: + return round(float(2) ** 32 * (volt_per_us / 20.) / DAC_Fs_MHZ) @portable -def shuttler_volt_ddamp_mu(volt_per_us_square): - return round(float(2) ** 48 * (volt_per_us_square / 20) * 2 / (DAC_Fs_MHZ ** 2)) +def shuttler_volt_ddamp_mu(volt_per_us_square: float) -> int64: + return round64(float(2) ** 48 * (volt_per_us_square / 20.) * 2. / (DAC_Fs_MHZ ** 2)) @portable -def shuttler_volt_dddamp_mu(volt_per_us_cube): - return round(float(2) ** 48 * (volt_per_us_cube / 20) * 6 / (DAC_Fs_MHZ ** 3)) +def shuttler_volt_dddamp_mu(volt_per_us_cube: float) -> int64: + return round64(float(2) ** 48 * (volt_per_us_cube / 20.) * 6. / (DAC_Fs_MHZ ** 3)) @portable -def shuttler_dds_amp_mu(volt): +def shuttler_dds_amp_mu(volt: float) -> int32: return shuttler_volt_amp_mu(volt / CORDIC_GAIN) @portable -def shuttler_dds_damp_mu(volt_per_us): +def shuttler_dds_damp_mu(volt_per_us: float) -> int32: return shuttler_volt_damp_mu(volt_per_us / CORDIC_GAIN) @portable -def shuttler_dds_ddamp_mu(volt_per_us_square): +def shuttler_dds_ddamp_mu(volt_per_us_square: float) -> int64: return shuttler_volt_ddamp_mu(volt_per_us_square / CORDIC_GAIN) @portable -def shuttler_dds_dddamp_mu(volt_per_us_cube): +def shuttler_dds_dddamp_mu(volt_per_us_cube: float) -> int64: return shuttler_volt_dddamp_mu(volt_per_us_cube / CORDIC_GAIN) +@nac3 class Shuttler(EnvExperiment): + core: KernelInvariant[Core] + shuttler0_leds: KernelInvariant[list[TTLOut]] + shuttler0_config: KernelInvariant[ShuttlerConfig] + shuttler0_trigger: KernelInvariant[ShuttlerTrigger] + shuttler0_volt: KernelInvariant[list[ShuttlerDCBias]] + shuttler0_dds: KernelInvariant[list[ShuttlerDDS]] + shuttler0_relay: KernelInvariant[ShuttlerRelay] + shuttler0_adc: KernelInvariant[ShuttlerADC] + def build(self): self.setattr_device("core") - self.setattr_device("core_dma") self.setattr_device("scheduler") self.shuttler0_leds = [ self.get_device("shuttler0_led{}".format(i)) for i in range(2) ] self.setattr_device("shuttler0_config") @@ -64,12 +85,6 @@ class Shuttler(EnvExperiment): self.shuttler0_dds = [ self.get_device("shuttler0_dds{}".format(i)) for i in range(16) ] self.setattr_device("shuttler0_relay") self.setattr_device("shuttler0_adc") - - - @kernel - def record(self): - with self.core_dma.record("example_waveform"): - self.example_waveform() @kernel def init(self): @@ -84,35 +99,33 @@ class Shuttler(EnvExperiment): self.core.break_realtime() self.init() - self.record() - example_waveform_handle = self.core_dma.get_handle("example_waveform") - - print("Example Waveforms are on OUT0 and OUT1") + print_rpc("Example Waveforms are on OUT0 and OUT1") self.core.break_realtime() - while not(self.scheduler.check_termination()): - delay(1*s) - self.core_dma.playback_handle(example_waveform_handle) + #while not(self.scheduler.check_termination()): + while True: + self.core.delay(1.*s) + self.example_waveform() @kernel def shuttler_reset(self): for i in range(16): self.shuttler_channel_reset(i) # To avoid RTIO Underflow - delay(50*us) + self.core.delay(50.*us) @kernel - def shuttler_channel_reset(self, ch): + def shuttler_channel_reset(self, ch: int32): self.shuttler0_volt[ch].set_waveform( a0=0, a1=0, - a2=0, - a3=0, + a2=int64(0), + a3=int64(0), ) self.shuttler0_dds[ch].set_waveform( b0=0, b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=0, c1=0, c2=0, @@ -163,13 +176,13 @@ class Shuttler(EnvExperiment): ## Step 2 ## start_f_MHz = 0.01 end_f_MHz = 0.05 - duration_us = 500 + duration_us = 500. # OUT0 and OUT1 have their frequency and phase aligned at 500us self.shuttler0_dds[0].set_waveform( b0=shuttler_dds_amp_mu(1.0), b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=0, c1=shuttler_freq_mu(start_f_MHz), c2=shuttler_freq_sweep(start_f_MHz, end_f_MHz, duration_us), @@ -177,22 +190,22 @@ class Shuttler(EnvExperiment): self.shuttler0_dds[1].set_waveform( b0=shuttler_dds_amp_mu(1.0), b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=0, c1=shuttler_freq_mu(end_f_MHz), c2=0, ) self.shuttler0_trigger.trigger(0b11) - delay(500*us) + self.core.delay(500.*us) ## Step 3 ## # OUT0 and OUT1 has 180 degree phase difference self.shuttler0_dds[0].set_waveform( b0=shuttler_dds_amp_mu(1.0), b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=shuttler_phase_offset(180.0), c1=shuttler_freq_mu(end_f_MHz), c2=0, @@ -200,7 +213,7 @@ class Shuttler(EnvExperiment): # Phase and Output Setting of OUT1 is retained # if the channel is not triggered or config is not cleared self.shuttler0_trigger.trigger(0b1) - delay(500*us) + self.core.delay(500.*us) ## Step 4 ## # b(0) = 0, b(250) = 8.545, b(500) = 0 @@ -208,7 +221,7 @@ class Shuttler(EnvExperiment): b0=0, b1=shuttler_dds_damp_mu(0.06835937), b2=shuttler_dds_ddamp_mu(-0.0001367187), - b3=0, + b3=int64(0), c0=0, c1=shuttler_freq_mu(end_f_MHz), c2=0, @@ -217,26 +230,26 @@ class Shuttler(EnvExperiment): b0=0, b1=shuttler_dds_damp_mu(0.06835937), b2=shuttler_dds_ddamp_mu(-0.0001367187), - b3=0, + b3=int64(0), c0=0, c1=0, c2=0, ) self.shuttler0_trigger.trigger(0b11) - delay(500*us) + self.core.delay(500.*us) ## Step 5 ## self.shuttler0_volt[0].set_waveform( a0=shuttler_volt_amp_mu(-5.0), a1=int32(shuttler_volt_damp_mu(0.01)), - a2=0, - a3=0, + a2=int64(0), + a3=int64(0), ) self.shuttler0_dds[0].set_waveform( b0=shuttler_dds_amp_mu(1.0), b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=0, c1=shuttler_freq_mu(end_f_MHz), c2=0, @@ -244,59 +257,59 @@ class Shuttler(EnvExperiment): self.shuttler0_volt[1].set_waveform( a0=shuttler_volt_amp_mu(-5.0), a1=int32(shuttler_volt_damp_mu(0.01)), - a2=0, - a3=0, + a2=int64(0), + a3=int64(0), ) self.shuttler0_dds[1].set_waveform( b0=0, b1=0, - b2=0, - b3=0, + b2=int64(0), + b3=int64(0), c0=0, c1=0, c2=0, ) self.shuttler0_trigger.trigger(0b11) - delay(1000*us) + self.core.delay(1000.*us) ## Step 6 ## self.shuttler0_volt[0].set_waveform( a0=shuttler_volt_amp_mu(-2.5), a1=int32(shuttler_volt_damp_mu(0.01)), - a2=0, - a3=0, + a2=int64(0), + a3=int64(0), ) self.shuttler0_dds[0].set_waveform( b0=0, b1=shuttler_dds_damp_mu(0.06835937), b2=shuttler_dds_ddamp_mu(-0.0001367187), - b3=0, + b3=int64(0), c0=0, c1=shuttler_freq_mu(start_f_MHz), c2=shuttler_freq_sweep(start_f_MHz, end_f_MHz, duration_us), ) self.shuttler0_trigger.trigger(0b1) self.shuttler_channel_reset(1) - delay(500*us) + self.core.delay(500.*us) ## Step 7 ## self.shuttler0_volt[0].set_waveform( a0=shuttler_volt_amp_mu(2.5), a1=int32(shuttler_volt_damp_mu(-0.01)), - a2=0, - a3=0, + a2=int64(0), + a3=int64(0), ) self.shuttler0_dds[0].set_waveform( b0=0, b1=shuttler_dds_damp_mu(-0.06835937), b2=shuttler_dds_ddamp_mu(0.0001367187), - b3=0, + b3=int64(0), c0=shuttler_phase_offset(180.0), c1=shuttler_freq_mu(end_f_MHz), c2=shuttler_freq_sweep(end_f_MHz, start_f_MHz, duration_us), ) self.shuttler0_trigger.trigger(0b1) - delay(500*us) + self.core.delay(500.*us) ## Step 8 ## self.shuttler0_relay.enable(0) @@ -308,7 +321,7 @@ class Shuttler(EnvExperiment): for i in range(2): for j in range(3): self.shuttler0_leds[i].pulse(.1*s) - delay(.1*s) + self.core.delay(.1*s) @kernel def relay_init(self): diff --git a/artiq/examples/nac3devices/nac3devices.json b/artiq/examples/nac3devices/nac3devices.json index 7fda9ca78..d9b148ddb 100644 --- a/artiq/examples/nac3devices/nac3devices.json +++ b/artiq/examples/nac3devices/nac3devices.json @@ -3,7 +3,7 @@ "min_artiq_version": "9.0", "variant": "nac3devices", "hw_rev": "v2.0", - "base": "standalone", + "drtio_role": "master", "core_addr": "192.168.1.70", "peripherals": [ { @@ -51,6 +51,10 @@ { "type": "phaser", "ports": [10] + }, + { + "type": "shuttler", + "ports": [11] } ] } diff --git a/artiq/examples/nac3devices/nac3devices.py b/artiq/examples/nac3devices/nac3devices.py index 1f2d54cc7..76d3969cf 100644 --- a/artiq/examples/nac3devices/nac3devices.py +++ b/artiq/examples/nac3devices/nac3devices.py @@ -14,6 +14,7 @@ from artiq.coredevice.edge_counter import EdgeCounter from artiq.coredevice.grabber import Grabber from artiq.coredevice.fastino import Fastino from artiq.coredevice.phaser import Phaser +from artiq.coredevice.shuttler import Volt as ShuttlerDCBias, Dds as ShuttlerDDS @nac3 @@ -34,6 +35,8 @@ class NAC3Devices(EnvExperiment): grabber0: KernelInvariant[Grabber] fastino0: KernelInvariant[Fastino] phaser0: KernelInvariant[Phaser] + shuttler0_volt0: KernelInvariant[ShuttlerDCBias] + shuttler0_dds0: KernelInvariant[ShuttlerDDS] def build(self): self.setattr_device("core") @@ -52,6 +55,8 @@ class NAC3Devices(EnvExperiment): self.setattr_device("grabber0") self.setattr_device("fastino0") self.setattr_device("phaser0") + self.setattr_device("shuttler0_volt0") + self.setattr_device("shuttler0_dds0") @kernel def run(self):