“This tutorial walks through an application that reads/writes data to DDR memory from the Linux userspace on the Zynq-based Arty Z7 FPGA.
Direct memory access, or DMA as it’s referred to, is an important aspect of embedded development as it a method for accessing the embedded system’s main memory (typically DDR) without tying up the CPU, therefore leaving it open for performing other operations during the read/write cycle to memory. DMA simply allows for the processor to kick off a transfer to read from/write to the main system memory, then it generates an interrupt indicating the completion of the transfer. Which leaves the processor free to do other tasks until the interrupt calls its respective service routine.
While the concept of DMA is straightforward enough, trying to get the full picture in one’s mind of how to implement it on an FPGA with embedded processor such as the ARM-core processor in the Xilinx Zynq SoC is no small feat. Then throwing in the extra layer of complexity of how to access it from the userspace of an operating system such as Linux, just makes it even worse.
So for this project, I’ll start by going over the mechanics of getting the hardware setup in Vivado, and base settings in the PetaLinux project setup for the kernel drivers and Linux application in the root filesystem. Then I’ll go over the functionality of how the code in the Linux application is actually accomplishing the task of controlling the AXI DMA in the programmable logic of the FPGA to perform a transfer.
Add DMA to the Hardware Design in Vivado
While the Zynq processing system has native DMA channels built-in, it is only for memory-to-memory transfers, not stream-to-memory or memory-to-stream transfers. Thus for peripherals to be able to use the Zynq’s native DMA channels, they must already have the DMA-capable interface for memory-to-memory transfers.
The differentiation is important because memory-to-memory transfers read/write data between different memory locations whereas a stream-to-memory transfer takes a serialized representation of data and writes it to a designated memory location and a memory-to-stream transfer reads data from a location in memory then converts it to a serialized format.
The AXI DMA IP block allows for any peripheral equipped with an AXI stream interface to access the main memory of the system via stream-to-memory or memory-to-stream transfers. Given that I’ve come across the need to use DMA for stream-to-memory/memory-to-stream transfers more often as an FPGA developer, I’m going to go with the AXI DMA IP for this tutorial.
I’m using the Arty Z7 FPGA development board and I’m starting with the base hardware design for it that I created in Vivado 2020.2 as outlined in one of my previous posts. All of the modifications I will be making will be in the block design of that project.”