sinara-hw / Urukul

4 channel 1GS/s DDS (AD9910 or AD9912 variant)
14 stars 8 forks source link

Urukul (AD9912) glitches during phase ramping #15

Closed jordens closed 6 years ago

jordens commented 6 years ago

From @kjh-m on October 11, 2018 7:35

Hello,

I'm getting glitches from AD9912 output during a phase ramp experiment. Phase is ramped by small steps at a given intervals, while keeping the frequency set-point constant.

Problem persist for wide range of interval times (10 us - 10 ms) and frequencies (100 kHz to 300 MHz).

Initially I noticed this while doing frequency measurement with a counter. Observing the waveform with an oscilloscope revealed fast glitches occurring at random points of the cycle (see below).

scope_0 scope_2 scope_6

Zooming in: scope_8

It seems that the glitches don't occur at every phase step. Screen capture of the oscilloscope shows glitch interval of 728 us, which is weirdly reproducible. In the measurement below, scope is triggered from glitches, so the waveform itself actually runs freely.

scope_5_arrows

Also, DDS doesn't seem to lose coherence at the glitch, and the waveform continues smoothly.

All electrical connections are terminated to 50 ohms. Urukul is referenced to an external clock, while Kasli is not.

Simplified version of the phase ramping program is shown below.


from artiq.experiment import *

class stepper(EnvExperiment):

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

    @kernel
    def run(self):

        self.core.reset()

        self.urukul0_cpld.init()
        self.urukul0_ch0.init()

        delay(1*ms)

        self.urukul0_ch0.set_att(10.)

        freq = 1*MHz
        freq_word = self.urukul0_ch0.frequency_to_ftw(freq)

        # Step phase by 16 units every 1 ms
        step_time = 1*ms
        phi_step = 16
        phi = 0

        # Start DDS
        self.urukul0_ch0.set_mu(freq_word,phi)
        self.urukul0_ch0.sw.on()

        delay(step_time)

        while True:
            # Increment phase
            phi += phi_step
            # Check if phase wraps around 2*pi, and correct accordingly
        # 2*pi equals 2^14 = 16384
            if phi >= 16384:
                phi -= 16384
            # Set phase word
            self.urukul0_ch0.set_mu(freq_word,phi)
            delay(step_time)

Copied from original issue: sinara-hw/sinara#596

hartytp commented 6 years ago

This reminds me of the glitches we saw when trying to do phase ramps on the AD9910. It was a few years back, so I forget the details, but IIRC:

Anyway, not sure if this is related to your observations, but figured it might be a useful data point..

jordens commented 6 years ago

@kjh-m thanks for the report.

I can't reproduce your exact issue because I don't have a Urukul-AD9912 at hand right now. From your description (but I am not sure because you seem to imply that the code you posted does not correspond to the screenshots, correct me if I am wrong):

Could you try adding a delay (e.g. 1 µs) before the IO_UPDATE pulse (before https://github.com/m-labs/artiq/blob/08074d52754af33781a9683a3392c12099b37c5c/artiq/coredevice/ad9912.py#L151)? Maybe this is just a latency mismatch. And also try lengthening the IO_UPDATE pulse (to e.g. 100 ns).

@hartytp Thanks for the info. Hmm. That would be bad.

With the test program above on a Urukul-AD9910/v1.3 I am seeing something much worse than just short glitches. I am seeing phase jumps that look like data corruption. I'll look at those.

hartytp commented 6 years ago

@hartytp Thanks for the info. Hmm. That would be bad.

Caveats are that I never tried with an AD9912, I didn't try other phase update modes, etc so there may be some way around that issue even for the AD9910. But worth being aware that we had problems with it.

jordens commented 6 years ago

Ok. The AD9910 phase corruption was just user error. I.e. I can't reproduce the glitches @kjh-m reported on Urukul-AD9910/v1.0 or Urukul-AD9910/v1.3. @kjh-m please let me know if the delay or a longer IO_UPDATE pulse fix this.

jordens commented 6 years ago

@hartytp Not that it would necessarily explain what you observed, but when you did that absolute phase control with the AD9910, did the synchronous IO_UPDATE meet s/h w.r.t. SYNC_CLK?

kjh-m commented 6 years ago

Thanks for quick replies!

@jordens ok, it's interesting that you didn't see the problem with AD9910. Adding a delay before io_update and/or lengthening the pulse didn't resolve the problem.

jordens commented 6 years ago

@kjh-m

Two things that weren't clear:

And two things to test:

kjh-m commented 6 years ago

@jordens

Generally speaking I get similar behavior with any frequency or timing settings.

Interestingly, if I switch between any two adjacent (non-wrapping) phase values (e.g. 0x00, 0x01 or 0x50 and 0x50) I don't get any glitching. But switching between 0x0000 and 0x3fff results in significant glitching. So that's probably it. Going over 2*pi does something bad.

I'm bit confused about the phase setting anyway. In ad9912.py, doesn't the phase setting float get scaled to 16 bits? (Here: https://github.com/m-labs/artiq/blob/7d6a1b528d6cc5ad7b01df11ea5b01fd50d40ed0/artiq/coredevice/ad9912.py#L172)

Changing SPIT_DDS_WR to 4 didn't help.

Maybe 728 µs was a coincidence after all..

kjh-m commented 6 years ago

Ok, so the following is stated in the AD9912 datasheet about the phase tuning word:

Allows the user to vary the phase of the DDS output. See the Direct Digital Synthesizer section. Register 0x01AC is the least significant byte of the phase offset word (POW). Note that a momentary phase discontinuity may occur as the phase passes through 45° intervals.

45° corresponds to 0x800. Quick test reveals glitches when switching over the 45° boundaries (but nowhere else):

45° 0x7FF to 0x800 90° 0xFFF to 0x1000 135° 0x17FF to 0x1800 180° 0x1FFF to 0x2000 225° 0x27FF to 0x2800 270° 0x2FFF to 0x3000 315° 0x37FF to 0x3800 360° 0x3FFF to 0x0000

So it might be a feature. I wonder if there's a way around it..

jordens commented 6 years ago

@kjh-m L172 is probably a bug. It's 14 bit LSB aligned.

And oh surprise: "Note that a momentary phase discontinuity may occur as the phase passes through 45° intervals.". That's intrinsic to that DDS.

jordens commented 6 years ago

The workaround that I can see is shifting the frequency for some duration and then shifting back. Has the advantage of more phase resolution and being continuous.

jordens commented 6 years ago

Annoying bug in the AD9912. Closing as "can't-fix".

hartytp commented 6 years ago

@hartytp Not that it would necessarily explain what you observed, but when you did that absolute phase control with the AD9910, did the synchronous IO_UPDATE meet s/h w.r.t. SYNC_CLK?

Yes.

As I said, it was a couple of years back, so I'd have to dig out the (paper) lab books to be sure about what we were doing then.