Hi,

We would like to synchronize the start of our experimental sequence with the phase of the electric power line. We have an analogue module which converts the 230 V AC to a 5 V TTL pulse, which goes into one of the TTL inputs of our first satellite Kasli.

We are able to detect the TTL pulses with the Kasli (rising edge counts increase continuously and level changes) but we are not able to have subsequent output TTL pulses of the Kasli to be in a fixed phase relation to the input pulses.

We tried three different approaches to detect the rising edge (self.manual, self.watch, self.count):

from artiq.experiment import *

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


        self.ttl_line_trigger = self.get_device("ttl16")
        self.ttl_osci_trigger = self.get_device("ttl46")

    @subkernel(destination=1)
    def manual(self):
        prev = -1
        curr = -1

        while prev != curr:
            level = self.ttl_line_trigger.sample_get_nonrt()

            if prev == -1 or curr == -1:
                prev = level
                curr = level
            else:
                prev = curr
                curr = level

            if prev != curr:
                break
        
            delay(10*ns)

    @subkernel(destination=1)
    def watch(self):
        delay(10*ms)
        try:
            while self.ttl_line_trigger.watch_stay_off():
                delay(100*us)
        finally:
            delay(100*us)
            self.ttl_line_trigger.watch_done()

    @subkernel(destination=1)
    def count(self):
        while self.ttl_line_trigger.count(self.ttl_line_trigger.gate_rising(10 * us)) > 0:
            delay(100 * us)

    @kernel    
    def run(self):
        subkernel_preload(self.manual)
        subkernel_preload(self.watch)
        subkernel_preload(self.count)

        self.core.reset()
        delay(10*ms)

        self.ttl_osci_trigger.output()
        self.ttl_line_trigger.input()
        delay(5*us)

        while True:
            #self.manual()
            #self.watch()
            #self.watch()
            self.count()
            #delay(100*ms)
            subkernel_await(self.count)

            delay(200*ms)
            for i in range(6):
                delay(10*ms)
                self.ttl_osci_trigger.pulse(2*ms)

self.count and self.watch give underflow errors when used as sub kernel, which I am not able to workaround with delays.

On the oscilloscope the sequence gives the signal in the video (got an error when trying to upload the video here), where the green signal is the output of the analog electric power line module, red is the output of the output TTL of the artiq, and the oscilloscope triggers on the TTL output of the ARTIQ.

I always get a RTIO underflow when using

class ExternalTrigger(EnvExperiment):
    def build(self):
        self.setattr_device("core")
        self.ttlin = self.get_device("ttl0")
        self.ttlout = self.get_device("ttl4")

    @kernel
    def run(self):
        self.core.reset()
        gate_end_mu = self.ttlin.gate_rising(5*ms)
        timestamp_mu = self.ttlin.timestamp_mu(gate_end_mu)
        at_mu(timestamp_mu + self.core.seconds_to_mu(10*ms))
        self.ttlout.pulse(1*us)

also when adding long delays (~ ms) in-between.

This is probably due to the TTLInput being on a satellite, correct?

There is no way, I can use an TTLInput for this on a satellite but I need to reconfigure the master for TTL input, correct?