Thanks both for the info! Good to know on the timing. I think we could work around that, and it’s the 128-event max that’s the real issue. I’ve attached a full experiment below to help with reproduction, where the first DMA sequence plays and the second hangs and does not output anything.
spaqin I had thought about sub kernels, but I’ve found that at least on the Kasli I really needed the DMA to push the events at the < 100 ns rate we need, and I didn’t think a sub kernel would fix that. I’ll give it a shot today though and see how quickly a sub kernel running on the phaser is able to update the amplitude.
from artiq.experiment import *
import numpy as np
class PhaserDDMADemo(EnvExperiment):
"""Phaser DDMA demo"""
def build(self):
self.setattr_device("core")
self.setattr_device("core_dma")
self.setattr_device("phaser_drtio_mtdds0_fpga")
self.setattr_device("phaser_drtio_mtdds0_channel0")
self.setattr_device("trigger")
def prepare(self):
self.phaser_fpga = self.phaser_drtio_mtdds0_fpga
self.phaser_ch = self.phaser_drtio_mtdds0_channel0
n = 128
duration_mu = self.core.seconds_to_mu(10*ms)
self.dt_mu = max(8, duration_mu // n)
# Build a sin^2 envelope in amplitude.
x = np.linspace(0.0, np.pi, n)
amps = 0.9 * np.sin(x) ** 2
self.asf_values_128 = np.asarray([self.phaser_ch.ddss[0].amplitude_to_asf(float(a)) for a in amps], dtype=np.int32)
n = 129
duration_mu = self.core.seconds_to_mu(1*ms)
self.dt_mu = max(8, duration_mu // n)
# Build a sin^2 envelope in linear amplitude.
x = np.linspace(0.0, np.pi, n)
amps = 0.9 * np.sin(x) ** 2
self.asf_values_129 = np.asarray([self.phaser_ch.ddss[0].amplitude_to_asf(float(a)) for a in amps], dtype=np.int32)
@kernel
def run(self):
self.core.reset()
self.core.break_realtime()
self.phaser_fpga.init()
self.core.break_realtime()
self.phaser_ch.init()
self.core.break_realtime()
self.phaser_ch.attenuator.set_att(0.0)
delay(1*us)
self.phaser_ch.servo.enable_iir(False)
delay(1*us)
self.phaser_ch.select_dac_source(1)
delay(1*us)
self.phaser_ch.ddss[0].enable_phase_accumulator(True)
delay(1*us)
self.phaser_ch.ddss[0].set_frequency(1*MHz)
delay(1*us)
self.phaser_ch.ddss[0].set_amplitude(0.0)
delay(1*us)
self.core.break_realtime()
# Record 128 sample DDMA
self.record_sequence_ddma("128", self.asf_values_128, self.dt_mu)
# Record 129 sample DDMA
self.record_sequence_ddma("129", self.asf_values_129, self.dt_mu)
self.core.break_realtime()
delay(50*ms)
# Playback (runs OK)
self.trigger.pulse(1*us)
self.playback_ddma("128")
self.core.break_realtime()
# Playback (hangs)
delay(10*ms)
self.playback_ddma("129")
@kernel
def play_sequence_mu(self,
asf_values,
dt_mu):
n = len(asf_values)
for i in range(n):
self.phaser_ch.ddss[0].set_amplitude_mu(asf_values[i])
delay_mu(dt_mu)
@kernel
def record_sequence_ddma(self,
dma_name,
asf_values,
dt_mu):
self.core.break_realtime()
with self.core_dma.record(dma_name, enable_ddma=True):
self.play_sequence_mu(asf_values, dt_mu)
self.core.break_realtime()
@kernel
def playback_ddma(self, dma_name):
self.core.break_realtime()
handle = self.core_dma.get_handle(dma_name)
self.core.break_realtime()
self.core_dma.playback_handle(handle)
delay(1*us)