Recently I encountered a weird problem that random RTIO underflow occurs in dds.init() function. I finally figured out that it is due to the function ad9910.set(). The sample code below will sometimes cause a slack of around -18μs in dds.init() if I submit this experiment many times. And adding delay before dds.init() doesn't help. Is there any way to solve this?

from artiq.experiment import *

class TestDDS(EnvExperiment):
    def build(self):
        self.setattr_device("core")
        self.setattr_device("urukul0_ch0")
        self.setattr_device("urukul0_cpld")

    @kernel
    def run(self):
        self.core.reset()
        self.urukul0_cpld.init()
        delay(10 * ms)
        self.urukul0_ch0.init()
        delay(10 * ms)
        self.urukul0_ch0.sw.on()
        delay(10 * ms)
        self.urukul0_ch0.set(1 * MHz)

The delay might need to be added inside the init() function. Clone the ARTIQ repos and use PYTHONPATH so it uses your local driver, then make some modifications to init() and let us know how it goes.

    sb10q I add 30us delay before the for loop in the init() function of class AD9910, and RTIO underflow doesn't occur anymore.😃

    if blind:
        delay(100 * ms)
    else:
        delay(30 * us) # add 30us delay here
        # Wait for PLL lock, up to 100 ms
        for i in range(100):
            sta = self.cpld.sta_read()
            lock = urukul_sta_pll_lock(sta)
            delay(1 * ms)
            if lock & (1 << self.chip_select - 4):
                break
            if i >= 100 - 1:
                raise ValueError("PLL lock timeout")
      4 days later

      qllopg RTIO underflow in dds.init() occurs again😔. This time the error log says ksupport/rtio.rs, line 69 with a slack of -15μs. After I changed the 30us delay to self.core.break_realtime(), it apparently doesn't occur anymore.

        qllopg It occurs again. And the RTIO underflow occurs in the io update function. Now I move break_realtime() before the io update in order to solve this problem. Bellow is the current code.

                self.write32(_AD9910_REG_CFR3, cfr3 | 0x400)  # PFD reset
                self.cpld.io_update.pulse(1 * us)
                if self.pll_en:
                    self.write32(_AD9910_REG_CFR3, cfr3)
                    self.core.break_realtime() # added here
                    self.cpld.io_update.pulse(1 * us)
                    if blind:
                        delay(100 * ms)
                    else:
                        # Wait for PLL lock, up to 100 ms
                        for i in range(100):
                            sta = self.cpld.sta_read()
                            lock = urukul_sta_pll_lock(sta)
                            delay(1 * ms)
                            if lock & (1 << self.chip_select - 4):
                                break
                            if i >= 100 - 1:
                                raise ValueError("PLL lock timeout")