Hello,

I am currently testing three Urukuls (run with Kasli v.2 and Artiq-6), and I want to ask about their expected performance.

  1. I have already found on the forum that there is a time delay when changing the DDS output parameters (frequency, amplitude) that was estimated to be 1.3 us. Is there any measure to reduce this time?
    ()

  2. There is a delay of > 3us when turning off a DDS output, is it expected?

  3. I observe phase drifts between experiments when I compare output of two channels (both on different Urukuls and on the same one). Phase drifts occur also when I compare channels without red lights on. What could be the reason for that? The DDSs have clocking from Kasli (125 MHz I suppose), and Kasli, in turn, gets an external clock signal at 10 MHz. Below I attach scope prints for comparison. These are two attempts to run the same code.

  4. Partially related to the question above - I keep seeing red lights at the output channels of the DDSs, but not at all of them. The red lights seem to switch on and off in a random manner when running different programs. Some of them are on and others are off when no program is running (all dds are sw.off() properly). Did anyone have similar experience? Could it be related to the issues with PPLs? The device does not overheat (as this could be one of the potential problems).

Below, I attach a relevant part of my code.

    @kernel 
    def run(self):
       self.core.reset()                   #initiate the core module  
       delay(1*ms)
       self.ttl5.output()                 
           
       self.urukul2_cpld.init()      
       delay(1*ms)
       
       self.urukul2_ch1.init() #initialise and configure the DDS channel 
       delay(1*ms)
       
       FREQ_MHZ =20*MHz
       self.urukul2_ch1.set_att(10.0) #set digital step attenuator in SI units
       self.urukul2_ch1.set(FREQ_MHZ,1.0,1.0) #sets freq in MHz, amplitude and phase
       self.urukul2_ch1.sw.on() #turn on the DDS ouput
       delay(2*s) 
       # self.urukul2_ch1.sw.off() #turn off the DDS output
       self.urukul2_ch1.sw.off()
       delay(500*ns)
       self.urukul2_ch1.set(FREQ2_MHZ,1.0,1.0)
       delay(500*ns)
       
       
       with parallel: #turn on the ttl mark at the same moment as DDS changes freq (use ttl as a mark on a scope)  
            self.urukul2_ch1.sw.on()
            self.ttl5.on()
       
       delay(20*ms)
       self.ttl5.off()
       delay(90*s) 
       self.urukul2_ch1.sw.off()
  • rjo replied to this.
    1. On Urukul, the AD9910 are connected via a serial interface to the on-board CPLD. A call to AD9910.set() needs to write a 64-bits register (the requested single tone profile register) and pulse IO_UPDATE. A register operation on AD9910 is always preceded by an instruction byte, so there are actually 72 bits to write (more if not operating in continuous phase mode, see AD9910.set_mu). For writes, the serial clock ticks at 125 MHz/2, so the serial transfer takes roughly 1.15 µs followed by a ca. 60 ns wide IO_UPDATE pulse. Hence the delay you observe. One can go faster, at the price of flexibility (probably not exhaustive):

    A) If you want to switch between discrete, predefined, frequencies (maximum 8), the fastest is probably to use different profiles:

    self.dds.cpld.set_profile(0)
    self.dds.set(5*MHz, profile=0)  # outputs 5 MHz
    
    self.dds.set(30*MHz, profile=1)  # configure profile 1
    self.dds.cpld.set_profile(1)  # actually switch to profile 1, output = 30 MHz

    A change of profile corresponds to a write of the Urukul CPLD configuration register (24 bits) so takes roughly 400 ns. Ad-hoc changes to the Urukul CPLD gateware could expose direct access to (some of) the profile pins (e.g. instead of the switches) to circumvent the CFG register write.

    B) The AD9910 FTW is only 32 bits wide, so this (+ an IO_UPDATE pulse) should be sufficient to just change frequency. Table 5 page 21 of the datasheet indicates that the FTW register (@0x07) is used in RAM mode when the destination is amplitude or phase (or both). So you could misuse the RAM for example like this:

    from artiq.coredevice.ad9910 import RAM_DEST_ASF
    
    data = [self.dds.amplitude_to_asf(1.) << 18]  # full-scale amplitude
    self.dds.set_profile_ram(start=0, end=0)  # RAM profile 0, one value
    self.dds.write_ram(data)
    self.dds.set_cfr1(ram_enable=1, ram_destination=RAM_DEST_ASF)
    self.dds.set_frequency(5*MHz)
    self.dds.cpld.io_update.pulse_mu(8)  # "commit"
    
    # an example frequency change
    self.dds.set_frequency(30*MHz)
    self.dds.cpld.io_update.pulse_mu(8)

    The frequency change is now a (8+32)-bits write and an IO_UPDATE pulse, that is roughly 700 ns.

    1. Isn't this probe capacitance you're seeing? HMC349ALP4CE on/off time is expected around 150 ns.

    2. This is expected and addressed by the SYNC_IN / IO_UPDATE delay tuning routines in AD9910. See #1143, in particular the example codes. You'd need to adapt the examples from point 1. to get absolute phase tracking (delay the IO_UPDATE pulse by dds.sync_data.io_update_delay).

    3. This doesn't seem to be normal. Which board revision are you using? Is this stock CPLD gateware? Can you systematically reproduce the issue with a very minimal piece of code?

    MikoT42

    1. Decide whether you need speed or determinism. For speed see the reply above. The delay is deterministic and sits on top of all the other delays in your experiment (cables, amplifiers, etc etc). It can therefore only ever be compensated manually with respect to a reference plane of your choice.
    2. AC coupling
    3. Read up on DDS and the manual. You are setting the phase offsets in relative mode. The underlying phase accumulator is never cleared by your code.