DMA MM2S Channel Stuck “Running” with Length=0

Hello guys,

I am experiencing an issue with the AXI DMA on a PYNQ/Zynq system.

When I load the bitstream, before sending any data, the DMA immediately enters “running” status.

register_map:

// Channel 1 register map: RegisterMap {
MM2S_DMACR       = Register(RS=1, Reset=0, Keyhole=0, Cyclic_BD_Enable=0, IOC_IrqEn=1, Dly_IrqEn=0, Err_IrqEn=0, IRQThreshold=1, IRQDelay=0)
MM2S_DMASR       = Register(Halted=0, Idle=0, SGIncld=0, DMAIntErr=0, DMASlvErr=0, DMADecErr=0, SGIntErr=0, SGSlvErr=0, SGDecErr=0, IOC_Irq=0, Dly_Irq=0, Err_Irq=0, IRQThresholdSts=0, IRQDelaySts=0)
MM2S_CURDESC     = Register(Current_Descriptor_Pointer=0)
MM2S_CURDESC_MSB = Register(Current_Descriptor_Pointer=0)
MM2S_TAILDESC    = Register(Tail_Descriptor_Pointer=0)
MM2S_TAILDESC_MSB= Register(Tail_Descriptor_Pointer=0)
MM2S_SA          = Register(Source_Address=0)
MM2S_SA_MSB      = Register(Source_Address=0)
MM2S_LENGTH      = Register(Length=0)
SG_CTL           = Register(SG_CACHE=0, SG_USER=0)

S2MM_DMACR       = Register(RS=0, Reset=0, Keyhole=0, Cyclic_BD_Enable=0, IOC_IrqEn=0, Dly_IrqEn=0, Err_IrqEn=0, IRQThreshold=0, IRQDelay=0)
S2MM_DMASR       = Register(Halted=0, Idle=0, SGIncld=0, DMAIntErr=0, DMASlvErr=0, DMADecErr=0, SGIntErr=0, SGSlvErr=0, SGDecErr=0, IOC_Irq=0, Dly_Irq=0, Err_Irq=0, IRQThresholdSts=0, IRQDelaySts=0)
S2MM_CURDESC     = Register(Current_Descriptor_Pointer=0)
S2MM_CURDESC_MSB = Register(Current_Descriptor_Pointer=0)
S2MM_TAILDESC    = Register(Tail_Descriptor_Pointer=0)
S2MM_TAILDESC_MSB= Register(Tail_Descriptor_Pointer=0)
S2MM_DA          = Register(Destination_Address=0)
S2MM_DA_MSB      = Register(Destination_Address=0)
S2MM_LENGTH      = Register(Length=0)
// }

some warnings:

my init code:

import logging,os
import time
import queue
import multiprocessing
import zipfile
import tempfile
import shutil


from pynq import Overlay
from pynq import GPIO
import pynq.lib.dma
from pynq import allocate
from pynq import MMIO
from pynq import PL
from pynq import DefaultHierarchy
import numpy as np

class Xaar1003:
    def __init__(self,config):
        
        self.printer=config.get_printer()        
        self.reactor=self.printer.get_reactor()
        self.gcode=self.printer.lookup_object('gcode')
        self.virtual_sdcard=self.printer.lookup_object("virtual_sdcard")
        #----------overlay--------------------
        PL.reset()
        self.ol = Overlay("/home/xilinx/zynq.bit")
        self.ch1 = self.ol.channel1.axi_dma_0
        self.ch2 = self.ol.channel2.axi_dma_0
        self.ch3 = self.ol.channel3.axi_dma_0
        self.ch4 = self.ol.channel4.axi_dma_0
        self.ch5 = self.ol.channel5.axi_dma_0
        self.ch6 = self.ol.channel6.axi_dma_0
        self.ch7 = self.ol.channel7.axi_dma_0
        self.ch1_buff=allocate(shape=(5*1024*1024,), dtype=np.uint8)
        self.ch2_buff=allocate(shape=(5*1024*1024,), dtype=np.uint8)
        self.ch3_buff=allocate(shape=(5*1024*1024,), dtype=np.uint8)
        self.ch4_buff=allocate(shape=(5*1024*1024,), dtype=np.uint8)
        self.ch5_buff=allocate(shape=(5*1024*1024,), dtype=np.uint8)
        self.ch6_buff=allocate(shape=(5*1024*1024,), dtype=np.uint8)
        self.ch7_buff=allocate(shape=(5*1024*1024,), dtype=np.uint8)
        self.channels = [self.ch1, self.ch2, self.ch3, self.ch4, self.ch5, self.ch6, self.ch7]
        self.ch_buffs = [self.ch1_buff, self.ch2_buff, self.ch3_buff, self.ch4_buff, self.ch5_buff, self.ch6_buff, self.ch7_buff]
        self.head_en = GPIO(GPIO.get_gpio_pin(0), 'out')
        self.head_dir = GPIO(GPIO.get_gpio_pin(1), 'out')
        self.head_jet = GPIO(GPIO.get_gpio_pin(2), 'out')
        self.jet_delay_time = MMIO(0x40000000, 0x1000)

Where might I have configured something incorrectly?

Hi @bonkbonk,

I wrote an extensive debug blog about DMA issues. Please, check it out

Is your IP handling AXI4-Stream signals correctly?

Hi @marioruiz,

I’ve already read your article and learned a lot from it. However, I’m currently encountering a somewhat strange issue: after I initialize the send channel using PYNQ, its status is not idle. That doesn’t seem normal, right?

here my test code:

    def cmd_TEST3(self,gcmd):
        if(self.channels[0].sendchannel.idle):
            self.gcode.respond_info("Channel 1 is idle.")
        if(self.channels[0].sendchannel.running):
            self.gcode.respond_info("Channel 1 is running.")
        if(self.channels[0].sendchannel.error):
            self.gcode.respond_info("Channel 1 is in error state.")
        self.gcode.respond_info("----------------------")
        config_bytes = [i for i in range(256)] 
        config_array = np.array(config_bytes, dtype=np.uint8)
        dma_buffer = allocate(shape=config_array.shape, dtype=np.uint8)
        np.copyto(dma_buffer, config_array)
        self.channels[0].sendchannel.transfer(dma_buffer)
        if(self.channels[0].sendchannel.idle):
            self.gcode.respond_info("Channel 1 is idle.")
        if(self.channels[0].sendchannel.running):
            self.gcode.respond_info("Channel 1 is running.")
        if(self.channels[0].sendchannel.error):
            self.gcode.respond_info("Channel 1 is in error state.")
        self.gcode.respond_info("----------------------")
        self.channels[0].sendchannel.wait()
        del dma_buffer
        if(self.channels[0].sendchannel.idle):
            self.gcode.respond_info("Channel 1 is idle.")
        if(self.channels[0].sendchannel.running):
            self.gcode.respond_info("Channel 1 is running.")
        if(self.channels[0].sendchannel.error):
            self.gcode.respond_info("Channel 1 is in error state.")

        
        self.gcode.respond_info("TEST3 complete ")

result:

$ TEST3
// Channel 1 is running.
// ----------------------
// Channel 1 is idle.
// Channel 1 is running.
// ----------------------
// Channel 1 is idle.
// Channel 1 is running.

// TEST3 complete

In my custom IP stream data to LVDS, I use tready pulses to read data from the AXI Stream FIFO and convert it into a serial output. After reset, tready stays low until I explicitly request data.

I’m not sure whether this is related to the issue where the DMA is not in the idle state after reset. Could it be that the DMA automatically sends an empty packet after reset? I haven’t come across any documentation suggesting that.

Hi @bonkbonk,

How is this an issue for you? Are you seeing transactions happening before you start the transfer?