I'm trying to fire a TTL based off of a very long pulse sequence. The method I believe to be fastest is to:
1) Chunk the long message into smaller blocks
2) Load the first block into memory using the core DMA
3) Loop through the blocks by parallelizing: (i) play back the stored block and (ii) record the next block
My issue is that I am getting an RTIOUnderFlow error whenever I try to play back the sequence of events stored in memory. The error occurs at the first playback. See code below for an example:

class DMAPulses(EnvExperiment):
    def build(self):
        self.setattr_device("core")
        self.setattr_device("core_dma")
        self.setattr_device("ttl5") # connected to a laser
        self.setattr_device("ttl7") # gating pulse for PMT
        self.setattr_device("ttl0_counter") # returns from PMT

    def prepare(self):
        # Create PRBS signal
        msg = np.random.rand(5000, 1)
        self.msg = [int(np.round_(x)) for x in msg]

    def run(self):
        # define the first block to be loaded
        self.load_block = self.msg[0:1000]
        self.record_kernel("block 0", self.load_block) # record the first waveform

        for i in range(5):
            p_handle = "block " + str(i)
            c_handle = "block " + str(i+1)
            if i < 4:
                self.load_block = self.msg[(i+1) * 1000 : (i+2) * 1000]
                self.run_kernel(p_handle, c_handle, False)
           else:
                self.run_kernel(p_handle, c_handle, True)

    @kernel
    def run_kernel(self, p_handle, c_handle, end):
        self.core.break_realtime()
        with parallel:
            if not end:
                self.record_kernel(c_handle, self.load_block)

            with sequential:
                prev_handle = self.core_dma.get_handle(p_handle)
                self.core_dma.playback_handle(prev_handle) # UNDERFLOW OCCURS HERE UPON FIRST ITERATION
                count = self.ttl0_counter.fetch_count()

    @kernel
    def record_kernel(self, handle, block):
         with self.core_dma.record(handle):
            for val in block:
                with parallel:
                    self.ttl7.pulse(1*us)
                    self.ttl0_counter.gate_rising(1*us)
                    if val == 1: # fire the laser for a "1", don't fire for a "0"
                        self.ttl5.pulse(1*us)
         print("recorded " + handle)

Any ideas on how to handle this?
EDIT: Not sure why the build() method is formatting like that, but the rest should be legible.

    Nefelibata EDIT: Not sure why the build() method is formatting like that, but the rest should be legible.

    It was formatted like that because the correct syntax for multiline code blocks is a triple tick on a single line, and you had used one tick.

    Thanks for the correction! Any insight as to the underflow error? Does my approach make sense?

    8 days later

    Just want to push this once more - is there a way for me to play back a trace from the DMA while recording a trace (of a different name) simultaneously? After looking a bit further at the documentation for DMA playback it seems that this might not be possible because now() is reset to 0 at the beginning of record() and then restored to the value it had at the beginning of the call, by which time playback should have started in parallel. Am I understanding this right? For example, would the code below work?

    @kernel
    def run_kernel(self, old, new): # old and new are strings for trace names in the DMA
        self.core.break_realtime()
        with parallel:
           with self.core_dma.record(new):
                with parallel:
                    self.ttl7.pulse(1*us)
                    self.ttl0_counter.gate_rising(1*us)
           self.playback_handle(self.core_dma.get_handle(old))

    To my understanding, the self.core_dma.record() call will reset now() to zero and shunt the RTIO timeline into a buffer. However, this cannot happen in parallel with the playback which starts at whatever now() was before the DMA recording, resulting in RTIOUnderflow. Am I correct in my understanding? How do I achieve what I am trying to do?

    DMA playback is blocking so you cannot do something in the background (at least without changing firmware code etc.).