本帖最后由 是木科技 于 2019-12-1 17:00 编辑

    显卡实验肯定是要用到DMA的,这边就和大家一起学习一下,zynq的DMA使用。
    思路是这样,也是米尔科技demo的思路,首先PS通过AXI-lite配置DMA的工作模式,然后,PS将数据写入DDR,再然后,PS控制DMA读出之前写入的数据,将数据流写入FIFO(读完后DMA会向PS发送中断),再然后,PS控制DMA将FIFO的数据流再通过AXI总线写回DDR(写完后DMA会向PS发送中断),PS判断写入的数据和读出的数据是否一致,完成实验。

02.png
    在讨论Zynq DMA的设计细节之前,让我们先要解释几个DMA控制器的原则:
典型的DMA控制器可以工作在以下三种模式:
1.突发模式-以一个连续的操作方式来传输一个完整的数据包,在许多应用中,DMA的突发模式传输会拒绝处理器的总线访问,对于不同的系统而言,这有利有弊(可以是件好事,也可能是一件非常糟糕的事情。)
2. 周期挪用模式-跟处理器一起交替完成单独的DMA字节或者字传输的总线访问,这种模式可以防止处理器无法访问总线。
3.透明模式-效率最高的传输模式,只有在处理器在执行任务而不需要访问外部系统总线的时候,DMA才能传输数据。
    DMA控制器支持scatter/gather操作,这是一个非常有用的特性,这个特性允许多个数据源的数据传输到同一个目的地址,或者同一个源地址的数据传输到不同的目的地址(也可以称为“buffers”)
    Zyng SoC是基于ARM内核的处理系统,它有一个DMA控制器,该DMA控制器连接在Zynq的AXI4中央互连架构上,通过AXI总线来传输数据,它在系统 存储器和Zynq的可编程逻辑单元(PL)之间完成64位的AXI总线传输。如下图所示,Zynq DMA有8个通道,可以同时执行8个DMA传输操作。
06.jpg
    DMA控制器具有以下的特点:
* 8个独立的通道,4个可用于PL—PS间数据管理,每个通道有1024Byte的MFIFO;
* 使用CPU_2x 时钟搬运数据,CPU_2x = (CPU frq/6)*2;
* 执行自定义内存区域内的DMA指令运行DMA;
* AHB控制寄存器支持安全和非安全模式;
* 每个通道内置4字Cache;
*可以访问SoC的以下映射物理地址:DDR、OCM、PL、Linear QSPI Read、SMC和M_AXI_GP设备,访问设备的互联结构如下图所示:


07.jpg
    之前跳过搭建工程环节,我们来看看这次需要添加哪些IP,如下图
03.jpg
    有点模糊,我一个个截图出来,这样可以放大了看清楚,包含了zynq内核,DMA模块,中断,FIFO,内部链等,如下图:
04.jpg
     接下来生成顶层文件,启动SDK,把demo代码copy进去,最后编译,生成镜像文件,通过SD卡烧录到办卡里面,先把硬件连接好:
08.jpg
   看下实现的函数,如果输入输出数据一致就会打印:Successfully ran AXI DMA SG Polling Example
static int CheckDmaResult(XAxiDma * AxiDmaInstPtr)
  • {
  •         XAxiDma_BdRing *TxRingPtr;
  •         XAxiDma_BdRing *RxRingPtr;
  •         XAxiDma_Bd *BdPtr;
  •         int ProcessedBdCount;
  •         int FreeBdCount;
  •         int Status;
  •         TxRingPtr = XAxiDma_GetTxRing(AxiDmaInstPtr);
  •         RxRingPtr = XAxiDma_GetRxRing(AxiDmaInstPtr);
  •         /* Wait until the one BD TX transaction is done */
  •         while ((ProcessedBdCount = XAxiDma_BdRingFromHw(TxRingPtr,
  •                                                        XAXIDMA_ALL_BDS,
  •                                                        &BdPtr)) == 0) {
  •         }
  •         /* Free all processed TX BDs for future transmission */
  •         Status = XAxiDma_BdRingFree(TxRingPtr, ProcessedBdCount, BdPtr);
  •         if (Status != XST_SUCCESS) {
  •                 xil_printf("Failed to free %d tx BDs %d\r\n",
  •                     ProcessedBdCount, Status);
  •                 return XST_FAILURE;
  •         }
  •         /* Wait until the data has been received by the Rx channel */
  •         while ((ProcessedBdCount = XAxiDma_BdRingFromHw(RxRingPtr,
  •                                                        XAXIDMA_ALL_BDS,
  •                                                        &BdPtr)) == 0) {
  •         }
  •         /* Check received data */
  •         if (CheckData() != XST_SUCCESS) {
  •                 return XST_FAILURE;
  •         }
  •         /* Free all processed RX BDs for future transmission */
  •         Status = XAxiDma_BdRingFree(RxRingPtr, ProcessedBdCount, BdPtr);
  •         if (Status != XST_SUCCESS) {
  •                 xil_printf("Failed to free %d rx BDs %d\r\n",
  •                     ProcessedBdCount, Status);
  •                 return XST_FAILURE;
  •         }
  •         /* Return processed BDs to RX channel so we are ready to receive new
  •          * packets:
  •          *    - Allocate all free RX BDs
  •          *    - Pass the BDs to RX channel
  •          */
  •         FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr);
  •         Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr);
  •         if (Status != XST_SUCCESS) {
  •                 xil_printf("bd alloc failed\r\n");
  •                 return XST_FAILURE;
  •         }
  •         Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr);
  •         if (Status != XST_SUCCESS) {
  •                 xil_printf("Submit %d rx BDs failed %d\r\n", FreeBdCount, Status);
  •                 return XST_FAILURE;
  •         }
  •         return XST_SUCCESS;
  • }
  • 复制代码
        实现最终验证如图:
    05.png
    附上源代码哟: DMA.part01.rar (10 MB, 下载次数: 1)