Hi,

Just a quick question: I can't seem to find any code examples of using a Mirny/AD5355. I have the coredevice files for these, including the Urukul, but I can quite get the Mirny to operate the way I would expect it to. (the sw.on() function works, but set(freq=###, amplitude=###) function does not). Are there any examples of how to interact with the Mirny available?

Regards,
Luke

Software support for Mirny is quite rough at the moment (associated issue: https://github.com/m-labs/artiq/issues/1421).

Try this (somewhat embarrassing) code as a starting point:

Sample 1:

from artiq.experiment import *


class Test(EnvExperiment):
    def build(self):
        self.setattr_device("core")
        self.setattr_device("mirny0_cpld")
        self.setattr_device("mirny0_ch0")

    @rpc(flags={"async"})
    def p(self, *p):
        print([hex(_) for _ in p])

    @kernel
    def run(self):
        self.core.reset()
        self.core.break_realtime()
        m = self.mirny0_cpld
        m0 = self.mirny0_ch0

        #while True:
        #    m.write_reg(2, 0b1111)
        #    self.p(m.read_reg(2))
        #    delay(10*ms)

        m.init()
        m0.init()
        m0.set_att_mu(255)
        m0.sw.on()

        # https://www.analog.com/media/en/technical-documentation/user-guides/EV-ADF5356SD1Z-UG-1087.pdf
        m0.write(0x0000000d)
        m0.write(0x000015fc)
        m0.write(0x0061200b)
        m0.write(0x00c026ba)
        m0.write(0x2719fcc9)
        m0.write(0x15596568)
        m0.write(0x060000e7)
        if False:
            m0.write(0x35c30846)  # div 64, -4dBm
        else:
            m0.write(0x35030076)  # div 1, 5dBm
        m0.write(0x00800025)
        m0.write(0x32008b84)
        m0.write(0x00000003)
        m0.write(0x00000012)
        m0.write(0x06c00001)
        delay(10*ms)
        m0.write(0x003006b0)

        delay(10*ms)
        assert m0.read_muxout()

Sample 2:

from artiq.experiment import *
from regdesc.devices import adf5356

class TestMirny(EnvExperiment):
    def build(self):
        self.setattr_device("core")
        self.setattr_device("mirny0_ch0")

        self.ch = self.mirny0_ch0
        self.cpld = self.ch.cpld

        self.clk_sel = 0
        self.f_ref = [100, 10, 125, 10][self.clk_sel] * MHz
        
        self.reg = adf5356.Device()
        init_reg(self.reg)

    @kernel
    def run(self):
        self.core.reset()
        self.core.break_realtime()

        m = self.cpld
        m0 = self.ch
        
        m.init()
        m.write_reg(1, 0)
        m0.init()
        m.write_reg(1, (self.clk_sel<<4))
        m0.set_att_mu(0)
        m0.sw.on()

        m0.write(self.reg.r13.storage)
        m0.write(self.reg.r12.storage)
        m0.write(self.reg.r11.storage)
        m0.write(self.reg.r10.storage)
        m0.write(self.reg.r9.storage)
        m0.write(self.reg.r8.storage)
        m0.write(self.reg.r7.storage)
        m0.write(self.reg.r6.storage)
        m0.write(self.reg.r5.storage)
        m0.write(self.reg.r4.storage)
        m0.write(self.reg.r3.storage)
        m0.write(self.reg.r2.storage)
        m0.write(self.reg.r1.storage)
        delay(10*ms)
        m0.write(self.reg.r0.storage)

        delay(10*ms)
        print(m0.read_muxout())
        print_pll(self.f_ref, self.reg)
        delay(100*ms)
        print(m.read_reg(1))
        # delay(4*s)
        # m0.sw.off()

@rpc
def init_reg(reg):
    reg.r13.storage = 0xd
    reg.r12.storage = 0x15fc
    reg.r11.storage = 0x61200b
    reg.r10.storage = 0xc026ba
    reg.r9.storage = 0x2719fcc9
    reg.r8.storage = 0x15596568
    reg.r7.storage = 0x60000e7
    reg.r6.storage = 0x35c30846
    reg.r5.storage = 0x800025
    reg.r4.storage = 0x32008b84
    reg.r3.storage = 0x3
    reg.r2.storage = 0x12
    reg.r1.storage = 0x6c00001
    reg.r0.storage = 0x3006b0
    
    # reg.r4.r_doubler = 1
    # reg.r4.r_divider = 0
    # reg.r0.int_value = 305
    # reg.r1.main_frac_value = 0
    # reg.r2.aux_frac_lsb_value = 0
    # reg.r13.aux_frac_msb_value = 0
    # reg.r2.aux_mod_lsb_value = 1
    # reg.r13.aux_mod_msb_value = 0

@rpc
def print_pll(f_ref, reg):
    from pprint import pprint

    print("f_ref:", f_ref/MHz, "MHz")
    print("f_pfd:", reg.f_pfd(f_ref)/MHz, "MHz")
    print("f_vco:", reg.f_vco(f_ref)/MHz, "MHz")
    print("f_outA:", reg.f_outA(f_ref)/MHz, "MHz")
    pprint(reg.pll_params())
    pprint(reg.r_params())

Sample 3:

from artiq.experiment import *
from artiq.language.units import ns, us

class TestComm(EnvExperiment):

    def build(self):
        self.setattr_device("core")
        self.mirny = self.get_device("mirny0_cpld")

    @kernel
    def init(self):
        self.core.break_realtime()
        self.mirny.init()

        # reg1  = 0b0000  # enable all PLLs  
        # reg1 |= 0 << 4  # Clock source = OSC
        # reg1 |= 0 << 6  # divide-by-one
        # reg1 |= 0 << 7  # disable attenuator reset        
        # reg1 |= 0 << 8  # FSEN_N = 1
        # self.mirny.write_reg(1, reg1)
       
        self.mirny.write_reg(2, 0xF)

        # PLL registers for Fout = 156.25 MHz with 100 MHz reference
        # FVCO = 5 GHz div = 32

        # Regs are listed in the descending order R12..R0
        pll_regs = [
            0x1041C,
            0x61300B,
            0xC01F7A,
            0x15153CC9,
            0x102D0428,
            0x120000E7,
            0x35A140F6,
            0x800025,
            0x32008B84,
            0x3,
            0x12,
            0x1,
            0x200640
        ]

        for pll_idx in range(4):
            for r in pll_regs:
                self.core.break_realtime()
                self.mirny.write_ext(4+pll_idx, 32, r)

    @kernel
    def set_channel_rf_switch(self, channel, value):
        self.core.break_realtime()
        val = self.mirny.read_reg(2)
        self.core.break_realtime()
        val &= ~(1 << channel)
        val |=  ((value & 0x1) << channel)
        self.mirny.write_reg(2, val)

    @kernel
    def test_rf_switch_channel(self, channel):
        self.core.break_realtime()
        self.mirny.write_reg(2, ~(0x1 << channel))
        delay(500*ms)
        self.mirny.write_reg(2, 0xF)

    def test_rf_switch(self):
        print("RF SWITCH TEST")
        print("*"*80)

        for i in range(4):
            input("\tConnect channel {}".format(i))
            self.set_channel_rf_switch(i, 0x0)
            input("\tContinue? [ENTER]")
            self.set_channel_rf_switch(i, 0x1)

    @kernel
    def set_att_channel(self, channel, value):
        self.core.break_realtime()
        self.mirny.set_att_mu(channel, value)

    @kernel
    def test_att_channel(self, channel):
        for a in [0, 1, 2, 3, 4]:
            self.core.break_realtime()
            self.mirny.set_att_mu(channel, a)
            delay(1*s)

    def test_att(self):
        print("ATTENUATION TEST")
        print("*"*80)

        for i in range(4):
            input("\tConnect channel {}".format(i))
            self.test_att_channel(i)
         
    def run(self):
        self.init()
        self.test_rf_switch()
        self.test_att()
5 days later

HI,

To update on what I have been doing to get the Mirny working: I tried your sample codes, but was only able to get Sample 3 to output a frequency from the Mirny. I've written a class and set of functions that takes each of the input variables the Mirny can be set with in the Registers and converts them into a list of ints for each register, which can be send to the Mirny for operating.

I've tested this in theory and I'm happy that the functions I've written correctly write to the registers (I can share this if you like). I also have some additional functionality for setting certain variables that are dictated by the supplied equations (or inequalities) in the ADF5355 manual.

The problem is I don't know what all the variables need to be set to. Currently, I haven't been able to change the Mirny RFout (It currently only outputs at 143MHz). My ideal scenario is the most basic output possible (with the power at its highest +5dBm). Most of the features of the Mirny I can disable, but there are some I'd like a better explanation of, or advice on what to set these variables such that I can change the RFout frequency to my desired values. I've list these settings below, highlighting the values I'm not sure of. Everything else is either disabled or calculated from other variables.

Settings have been set to disabled, unless otherwise stated
R0 : Autocal (enabled), Prescaler (4/5),
R3 : SD Load Reset (Enabled), Phase (0)
R4 : Muxout (???), R Counter (???), Current setting (0.9mA), Reference Mode (Single Ended), Mux Logic (???), PD Polarity (Negative)
R6 : Bleed Polarity (Negative), Negative Bleed (Enabled), Feedback Select (Fundamental), RF Output A (Enabled), RF Output A Power (+5dBm)
R7 : Synchronisation (Falling Edge), Frac-N Cycle Count (1024), Frac-N Precision (5.0ns)
R9 : Timeout (84)
R11 : VCO Band Hold (Normal Operation)
R12 : Phase Resynch Clock Value (1, Normal Operation)

There's also the fCHSP value in the ADF5355 manual (Used to calculated MOD2), set at 200kHz, but I don't know if this is the same for the Mirny.

Thanks in advance,
Luke

    LukeBaker The problem is I don't know what all the variables need to be set to.

    I don't know either, and I have the same difficulties that you have with the ADF5355 datasheet and its application, as well as some of the sample code not working for unknown reasons. The hardware was developed by WUT, and without much funding for the software side of things. The ARTIQ issue I have linked to is still looking for sponsors...