quartiq / phaser

Phaser AWG DSP design
GNU General Public License v3.0
10 stars 5 forks source link

Interpolation filter initialization #5

Closed jordens closed 3 years ago

jordens commented 4 years ago

There is currently about a 3/4 chance that the filters initialize incorrectly and output noise or high-harmonic signals. Likely the HBF even/odd timing.

jordens commented 4 years ago

The the bad initialization resulting in distortion has been fixed in f351d15 lowering the chance of a bad initialization to about 1/4. Less likely to occur if the Phaser bitstream is loaded after Kasli boot. Still not entirely clear how that issue arrises.

sotirova commented 4 years ago

Have not been able to initialise the filters correctly either. Have tried load.tcl multiple times. Checking out f351d15 and loading the new bitstream didn't help either. (For reference, I am talking about a phaser baseband board that I am trying to get to work for the first time.)

jordens commented 4 years ago

Stick with the commits you had. Those were good. Could you disable/force that amplitude/phase check and look at the RF output on a specturm analyzer? I assume you are using the sinara_tester script or the example.py (do disable the dac_sleep at the end) in the repository.

jordens commented 4 years ago

And you used this bitstream?

sotirova commented 4 years ago

Thanks for the comments! I am using the example.py script for testing and have disabled the dac_sleep at the end. I compiled the bitstream myself having checked out 269724a454034cf86b9211482bf57cb89e59a0ba. I have now disabled the oscillator test however I am not seeing any RF output.

jordens commented 4 years ago

Could you try the bitstream I linked? Just load it after kasli has booted. Then run the example.

sotirova commented 4 years ago

Just tried - still unhappy (i.e. giving no RF). Here is what it prints out (it is the same as before):

print:4 print:['0xffffffff'] (16 times) print:['0x40']

jordens commented 4 years ago

Could you post the system description json, the device db and the exact example script?

sotirova commented 4 years ago

Device db:

core_addr = "xx.xxx.x.xxx"
host_addr = "xx.xxx.x.xxx"
addr_sat = 0x010000

device_db = {
    "core": {
        "type": "local",
        "module": "artiq.coredevice.core",
        "class": "Core",
        "arguments": {"host": core_addr, "ref_period": 1e-9}
    },
    "core_log": {
        "type": "controller",
        "host": "xx.xxx.x.xxx",
        "port": 1068,
        "command":
        "aqctl_corelog -p {port} --bind {bind} --no-localhost-bind " + core_addr,
    },
    "core_cache": {
        "type": "local",
        "module": "artiq.coredevice.cache",
        "class": "CoreCache"
    },
    "core_dma": {
        "type": "local",
        "module": "artiq.coredevice.dma",
        "class": "CoreDMA"
    },
    "i2c_switch0": {
        "type": "local",
        "module": "artiq.coredevice.i2c",
        "class": "PCA9548",
        "arguments": {"address": 0xe0}
    },
    "i2c_switch1": {
        "type": "local",
        "module": "artiq.coredevice.i2c",
        "class": "PCA9548",
        "arguments": {"address": 0xe2}
    },
}

device_db["phaser0"] = {
    "type": "local",
    "module": "artiq.coredevice.phaser",
    "class": "Phaser",
    "arguments": {"channel_base": 0}
}

Exact example sctipt (from 269724a with dac_sleep=0 in the end):

from artiq.experiment import *

# This is a volatile test script to exercise and evaluate some functionality of
# Phaser through ARTIQ.

class Phaser(EnvExperiment):
    def build(self):
        self.setattr_device("core")
        self.setattr_device("phaser0")

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

    def run(self):
        self.do()

    @kernel
    def do(self):
        # self.core.reset()
        self.core.break_realtime()
        for i in range(1):
            self.inner()

    @kernel
    def inner(self):
        f = self.phaser0

        f.init(debug=True)

        for ch in range(2):
            f.channel[ch].set_att(0*dB)
            # f.channel[ch].set_duc_frequency_mu(0)
            f.channel[ch].set_duc_frequency(190.598551*MHz)
            f.channel[ch].set_duc_phase(.25)
            f.channel[ch].set_duc_cfg(select=0, clr=0)
            delay(.1*ms)
            for osc in range(5):
                ftw = (osc + 1)*1.875391*MHz
                asf = (osc + 1)*.066
                #if osc != 4:
                #    asf = 0.
                #else:
                #    asf = .9
                #    ftw = 9.5*MHz
                # f.channel[ch].oscillator[osc].set_frequency_mu(0)
                f.channel[ch].oscillator[osc].set_frequency(ftw)
                delay(.1*ms)
                f.channel[ch].oscillator[osc].set_amplitude_phase(asf, phase=.25, clr=0)
                delay(.1*ms)
        f.duc_stb()

        for ch in range(2):
            for addr in range(8):
                r = f.channel[ch].trf_read(addr)
                delay(.1*ms)
                self.p(r)
                self.core.break_realtime()

        alarm = f.dac_read(0x05)
        self.p(alarm)
        self.core.break_realtime()
        f.set_cfg(dac_sleep=0, trf0_ps=1, trf1_ps=1)
        self.core.wait_until_mu(now_mu())

Kasli target:


#!/usr/bin/env python3

import argparse

from migen import *
from migen.build.generic_platform import *
from migen.genlib.io import DifferentialOutput

from misoc.targets.kasli import soc_kasli_args, soc_kasli_argdict
from misoc.integration.builder import builder_args, builder_argdict

from artiq.gateware import rtio
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi2
from artiq.gateware.rtio.phy.edge_counter import SimpleEdgeCounter
from artiq.build_soc import build_artiq_soc

from artiq.gateware.targets.kasli import (MasterBase, SatelliteBase)
from artiq.gateware import eem

class Master(MasterBase):
    """
    DRTIO Master located in the control rack near the trap.
    """
    def __init__(self, *args, **kwargs):
        MasterBase.__init__(self, *args, rtio_clk_freq=125e6, **kwargs)

        platform = self.platform

        # EEM clock fan-out from Si5324, not MMCX
        try:
            self.comb += platform.request("clk_sel").eq(1)
        except ConstraintError:
            pass

        self.rtio_channels = []

        #EEM0, 1: Phaser
        eem.Phaser.add_std(self, 0)

        self.config["HAS_RTIO_LOG"] = None
        self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels)
        self.rtio_channels.append(rtio.LogChannel())

        self.add_rtio(self.rtio_channels)

def main():
    parser = argparse.ArgumentParser(
        description="ARTIQ device binary builder for Phaser testing")
    builder_args(parser)
    soc_kasli_args(parser)
    parser.set_defaults(output_dir="artiq_kasli")
    parser.add_argument("-V", "--variant", default="master")
    args = parser.parse_args()

    variant = args.variant.lower()
    if variant == "master":
        cls = Master
    else:
        raise SystemExit("Invalid variant (-V/--variant)")

    soc = cls(**soc_kasli_argdict(args))
    build_artiq_soc(soc, builder_argdict(args))

if __name__ == "__main__":
    main()

Misoc: a8a33f6 Migen: c50ecde ARTIQ: eecd97c

jordens commented 4 years ago

I don't see anything obvious.

{
    "target": "kasli",
    "hw_rev": "v2.0",
    "variant": "phaser",
    "base": "standalone",
    "core_addr": "10.34.16.100",
    "peripherals": [
        {
            "type": "phaser",
            "ports": [
                0
            ]
        }
    ]
}
sotirova commented 4 years ago

Completely remove or comment that f.set_cfg(dac_sleep=0, trf0_ps=1, trf1_ps=1) line.

Didn't make a difference

Could you try a bitstream with just the standard json description (python -m artiq.gateware.targets.kasli_generic phaser.json): and phaser.json

Just tried this as well, with the line above line still commented and this bitstream but have seen no RF yet

If that doesn't get us anywhere I'll make a Kasli bitstream for you (this is Kasli v1.1, right?)

Yes, this is kasli v1.1

jordens commented 4 years ago

Try these: phaser_kasli_v11_eem1.tar.gz artiq eecd97ce misoc a8a33f65 phaser 92bca29 Vivado 2020.1

I've tested this with Kasli v2.0, Phaser in EEM1, and clk_sel=1 (external SMA, see device_db) and both a Phaser-Upconverter and a Phaser-Baseband.

It's also not impossible that this is a hardware issue. Maybe try https://github.com/elhep/phaser_gw as well.

sotirova commented 3 years ago

With these kasli/phaser bitstreams I have finally managed to get RF out of both phaser boards we have, thank you very much for the help! However, the interpolation filter initialization is still failing. I am using the artiq/misoc/migen/Vivado versions as per your last comment. I have connected Phaser EEM0 to Kasli EEM1 and INT CLK IN of phaser to J3 on Kasli (have adjusted the device_db accordingly).

jordens commented 3 years ago
RHanley1 commented 3 years ago

Hi Robert, I have taken over the testing of phaser from Ana.

Using the kasli/phaser bitstreams you sent, and creating a conda environment with the suggested package git hashes above, I have managed to get some RF out of phaser also. However this seems to be volatile when reloading kasli. I have not commented out the DUC/oscillator test in the phaser init function, and this seems to pass without issue. The testing script I have been using is

from artiq.experiment import *

class PhaserRF(EnvExperiment):
    def build(self):
        self.setattr_device("core")
        self.setattr_device("phaser0")

    @kernel
    def run(self):
        f = self.phaser0
        self.core.reset()
        self.core.break_realtime()
        f.init()
        self.core.break_realtime()
        for ch in range(2):
            f.channel[ch].set_att(0*dB)
            f.channel[ch].set_duc_frequency(100*MHz)
            f.channel[ch].set_duc_phase(0.)
            f.channel[ch].set_duc_cfg(select=0, clr=0)
            delay(.1*ms)
            for osc in range(5):
                if osc == 4:
                    asf = 0.2
                else:
                    asf = 0.0
                freq = 0*MHz
                f.channel[ch].oscillator[osc].set_frequency(freq)
                delay(0.1*ms)
                f.channel[ch].oscillator[osc].set_amplitude_phase(asf, phase=0., clr=0)
                delay(0.1*ms)
        print("Done")

Below is an example of what I have seen during testing:

Note Plot
Run artiq_flash start, then the above script image
Run the above script again image
Run the above script with asf=0 for all channnels image
Run artiq_flash start -
Run the above script with asf=0 for all channnels image
Run the above script image
jordens commented 3 years ago

Yes. If you reload/restart/cycle/flash etc Kasli, you'll need to reload the bitstream to Phaser to reinitialize it cleanly and then run your experiment. Fixing this issue here will remove the need to reload the Phaser bitstream but you'll still have to re-initialize Phaser and re-run your experiments.

RHanley1 commented 3 years ago

Is this still the case if one flashes the bitsream rather than just loading it?

jordens commented 3 years ago

The work around is resetting the FPGA on Phaser. That's done either by flashing or loading. Loading is obviously less stressfull on the flash memory and much faster.

hartytp commented 3 years ago

@jordens this is quite annoying to work around. What's the plan/timeline for resolving it?

jordens commented 3 years ago

Unless you are developing on the gateware this should only hit you less than once per system reboot. That seems acceptable for the characterization phase. It'll be resolved as soon as I find some time and I'm happy that your tests and characterization don't uncover major other issues that would require bigger rework.

hartytp commented 3 years ago

@jordens currently we're seeing quit a bit of non-reproducible behaviour. We have also been swapping Kasli bitstreams around (both debugging issues with why our bitstreams weren't working and changing clocking options on Kasli to debug noise issues). Having to get into a dance of restarting Kasli and reloading phaser until things behave as expected is quite a time sink. It also means that if things happen that we don't expect, it's hard to understand if we're doing something silly or if phaser just didn't initialise correctly without going through a few reset cycles.

Annoyingly vivado is playing up and refusing to recognise the hardware on the computer we're using. This is not directly an issue with phaser, but it is annoying that we need to have a programmer hooked up to allow us to do the reloading dance even though we're not changing phaser bit streams. Having the I2C tool working would at least make this process easier at our end (we're using a kasli 1.1 so no 2.0 support needed atm).

hartytp commented 3 years ago

@RHanley1 should comment, but I believe that the specific issue he's seeing is that he's getting spurious output when using 3 tones on phaser. This had previously been working so it's likely that phaser just needs to be reloaded, but vivado is now playing up.

RHanley1 commented 3 years ago

Current situation:

Number of tones Plot
Single tone at 0MHz image
Two tones, +/- 5MHz image
Three tones, 0MHz and +/- 5MHz image
jordens commented 3 years ago

On I2C flashing: as I explained, the code is there, you need to try it. It will be very slow. Don't magically expect to be comfortable. I don't have a Kasli-v1.1 to test it with.

On the Phaser resets, please re-read my explanations. There is no need to do a dance with reloading Kasli to work around this issue. Let's first fix the easy silly issues and then see whether the remaining are blockers.

Vivado can leave a hw_server and a cs_server around if it is unhappy about something. That'll block.

jordens commented 3 years ago

@RHanley1 please stop posting unrelated stuff on this issue.

hartytp commented 3 years ago

@RHanley1 can you open a new issue for that? https://github.com/quartiq/phaser/issues/5#issuecomment-735813634

nkrackow commented 3 years ago

Hey, I implemented some other interpolation filtes in https://github.com/quartiq/phaser/commit/b36e506b08382969e785597de0cc0e6c222b0445 which should fix the instability for now.