Based on my research work requirement. I need DMA to generate continuously repeated arrays. which means, I have one array to send from DMA to outside. But I need it repeated output(no time gap). So I search and found the DMA has Cyclic DMA Mode. I just want to make sure, if the PYNQ could use Cyclic DMA Mode now? Thank you!
This isn’t supported directly. i.e. the PYNQ APIs for the DMA class don’t support this.
However, you can use PYNQ to read/write the DMA control registers, so I think you should be able to set the cyclic bit “manually” or modify the PYNQ API.
Have a look at this tutorial for the DMA, and in particular look at part 2 (linked from part 1) and the register map:
You need a few changes. You need to enable Scatter Gather, you need to connect to the SG ports. You need to make sure your memory buffer(s) are contiguous - i.e. use PYNQ allocate() to create them.
This is the start function. You can see it is a simple MMIO write to the control register https://github.com/Xilinx/PYNQ/blob/master/pynq/lib/dma.py#L323
Note that this is for the _SGDMAChannel
It either writes 0x1001 or 0x1 depending on if you want interrupt enabled.
You would either need to manually do an MMIO write() to the control register and include the cyclic bit (bit 4, so you would write 0x1011 or 0x11), or you could modify the start() method.
Thank you! Appreciate your answer. I will try it based on your answer.
Maybe I am new to PYNQ system. So has few unprofessional problems.
- The tutorial said PYNQ system doesn’t support Scatter Gather now. But the dma.py program has SGDMAChannel class which is for Scatter Gather mode.
- In SGDMAChannel class, it doesn’t configure BDs(which is first, which is last, if I need to define it using allocate?), it has the same input parameter with simple DMA, is that correct?
- You need to make sure your memory buffer(s) are contiguous. What is meant for contiguous? and how to make sure it?
- As the DMA tutorial said the cyclic DMA is based on Scatter Gather mode. So I just need to modify the SGDMAChannel class in PYNQ following your suggestion, right? But now，I don’t know how to use SGDMAChannel class, do you have an example?
This is a little complicated. PYNQ doesn’t support scatter-gather functionality - i.e. where you have multiple (fragmented?) memory buffers.
The DMA has a limit of 8MB per transfer. There was an enhancement to allow transfers larger than 8MB. This is what you see in the SGDMAChannel class, and you need to enable the Scatter Gather engine in the DMA, and you still need to use contiguous memory buffers.
2. Yes, for reasons in 1.
3. Contiguous means in contiguous in physical memory. The Linux OS in the PYNQ image uses virtual memory. When the OS allocates memory, it will be virtually contiguous but the physical memory may be fragmented. This isn’t a problem for a software application, the OS will manage the memory.
A fragmented memory buffer is bad for a Zynq PL design (e.g the DMA) which accesses the physical memory directly. The logic (PL resources) to do this and the software to set this up is much more complicated than contiguous memory.
4. You can use the pynq
allocate() class to allocate contiguous memory for use by IP in the PL.
Thank you for detailed feedback. These days, I have tried your answer. But still face a little problem. The following is my setup step based on your answer.
Firstly, I modified the Vivado layout, enable the SG mode and connect it.
Then use the Pynq to read the DMA. I could see it has changed to SGDMAChannel.
I could see the BD definition. The last descriptor has pointer back to the first BD physical address
Number 0 BD physical address: 1000214528
Then I modify the API start() to set the cyclic enable=1, I could see the cyclic mode open.
Then, run the python program, I could see there is output through GPIO, but only one-time, It is not the cyclic.
So I want to know, if I have missed some parts when setting cyclic model? Thank you!
Could you help me with this problem, when you have time? Thank you very much! This problem has confused me for a long time.
Sorry, I missed your reply.
EDIT: I’m looking at the image of the block diagram. How do you have the AXI stream output connected? (It is hard to see in the image.) Are you managing the AXI Stream VALID/READY signals?
Can you try readback the control register and the status registers from the register_map to check if the DMA is running/idle/error etc. and if the cyclic bit is set correctly?
Info to do that here:
Thank you for the reply.
1. I upload the clear image. It works well in simple DMA mode.
- About the register status, Plase see the below picture.
It looks like only only TDATA on M_AXIS_MM2S is connected and you are not managing the AXI stream handshake. You may see the first data on TDATA, but it should not change to the next value.
There should be an input READY signal to the M_AXIS_MM2S. Can you try tied this to ‘1’?
I have connected constant IP and tied the READY pin to ‘1’.
It still sends out the data one time(the whole 8M PRBS data), Not cyclic and repeatedly.
By the way, Do you need me to attach the Python source code and Vivado code, I could upload them in Google driver.
The register status: