zynq-PS、PL交互篇——DMA循环传输数据


之前,我在博客中分享了如何zynq7020采用GitHub的开源linux DMA驱动的移植,并完成了示例程序的测试。但其中主要为单次DMA的传输,即传输完成一次后需要手动再次配置并启动传输,但在一些特定场景下,我们需要连续的DMA传输。比如你要通过天线发射连续的脉冲,或者后续FPGA需要进行实时的处理,这自然是不允许数据流出现间隙的。这就需要采用我们的DMA循环传输的功能。

PL端

需要勾选Enable Scatter Gather Engine。

循环模式需要硬件DMA的SG模式配合
在这里插入图片描述

先暂时不要回环

正常的回环是PS DDR --> DMA --> PL FIFO -->DMA --> PS DDR
如果正常使用该回环,对后续CPU接收数据等等操作的调试要求较高,处理不好可能会引发内核的抱怨还是啥(笔者尚且没有解决)

在这里插入图片描述

因此我们从中打断这个回环,FIFO的输出端写一个程序专门用来接收数据,READY信号始终拉高,接收数据后直接丢弃数据
在这里插入图片描述

添加中断

记得加上concast,要有中断才行,参考Zynq linux加载axi_dma驱动报错 axidma: axidma_dma.c: axidma_request_channels: 651: Unable to get slave chan
在这里插入图片描述

硬件资源已经上传至SCDN

软件源码分析与修改

axidma_video_transfer

实际上,软件源码中给出了video循环传输的功能,如果你是视频、图像传输,理论上可以直接调用这个,按照其注释的功能说明,其可以实现循环传输。但可能需要你把硬件端配置为VDMA,且传输的数据有图像那样子的三维数据。

笔者需要做的是天线信号的循环传输, 用的主要还是DMA。所以决定自己修改源码来适配DMA的循环传输功能。
在这里插入图片描述

应用层源码修改

后续的内容都将以后缀 circle 来表征我们修改的部分,为了不破坏原本的结构,都将原函数复制一个。

library/libaxidma.c

在这里插入图片描述

这里的ioctl的命令也要加上这个后缀,我们后续对让底层文件也支持这个命令

在这里插入图片描述

include/libaxidma.h

在这个文件下也要添加对这个函数的声明,这样子其他函数才能调用这个
在这里插入图片描述

include/axidma_ioctl.h

这个文件下 AXIDMA_NUM_IOCTLS定义了驱动向上提供的IOCTL命令的个数,因为我们多加了一个命令,所以需要增加这个宏定义的值,让他支持更多的IOCTL命令。
在这里插入图片描述

如果不添加支持的IOCTL命令个数,报错如下:“IOCTL command is out of range for device”
在这里插入图片描述

因为我们这个命令是参照着AXI_DMA_READWRITE写的,可以直接把对这个命令的定义放在其下面,编号要顺着最后的写,这里为“11”.
在这里插入图片描述

驱动层源码修改

driver/axidma_chrdev.c

这里面接收前文提到的 library/libaxidma.c 的命令,在其中对ioctl命令的switch case语句下添加对我们新增的命令的支持
(library/libaxidma.c是应用层的程序,其发送的命令会通过内核给到驱动程序)

在这里插入图片描述

driver/axidma_dma.c

(driver/axidma_chrdev.c 主要是判断命令类别,更底层的函数实现封装在 driver/axidma_dma.c 中)
在这里插入图片描述

同样的,也是添加后缀
在这里插入图片描述
备份一份axidma_prep_transfer函数,修改其中一份为axidma_prep_transfer_circle
在这里插入图片描述
这里需要调用另外一个api,dmaengine_prep_dma_cyclic
在这里插入图片描述

内核源码程序中我们可以找到这个API函数
在这里插入图片描述
在这里插入图片描述
上图截图自DMA engine 笔记

接下来,我们了解一下这个API需要的参数

dmaengine_prep_slave_sg

  • struct dma_chan *chan :DMA 通道结构体指针。
  • struct scatterlist *sgl :分散列表结构体指针。
  • unsigned int sg_len :分散列表的长度。
  • enum dma_transfer_direction dir :DMA 传输方向枚举值。
  • unsigned long flags :标志位。

dmaengine_prep_dma_cyclic

  • struct dma_chan *chan :DMA 通道结构体指针。
  • dma_addr_t buf_addr :缓冲区地址。
  • size_t buf_len :缓冲区长度。
  • size_t period_len :周期长度。每隔多久(单位为byte)调用一次回调函数。需要注意的是,buf_len应该是period_len的整数倍。
  • enum dma_transfer_direction dir :DMA 传输方向枚举值。
  • unsigned long flags :标志位。

在这里插入图片描述

根据参数定义对源码进行修改,
在这里插入图片描述

       // 计算缓冲区地址,这里简单假设从第一个scatterlist元素获取
       dma_addr_t buf_addr = sg_dma_address(&sg_list[0]);
       // 假设缓冲区长度为所有scatterlist元素长度之和,这里简单示意
       size_t buf_len = 0;
       size_t period_len = 0;
       int i = 0;
       for (i = 0; i < sg_len; i++) {
           buf_len += sg_dma_len(&sg_list[i]);
       }
       // 假设周期长度为缓冲区长度,实际需根据业务确定
       size_t period_len = buf_len;
       dma_txnd = dmaengine_prep_dma_cyclic(chan, buf_addr, buf_len, period_len, dma_dir, dma_flags);

中断的修改(如果有必要)
在这里插入图片描述

driver/axidma.h

与应用层的操作一样,我们添加了一个函数,需要在头文件中添加其声明
在这里插入图片描述
在这里插入图片描述

应用层APP

改为调用该函数
在这里插入图片描述
修改Makefile文件
在这里插入图片描述

实验现象

单次传输,开源代码写的完全没有间隙,牛
在这里插入图片描述
我们修改的循环传输(存在间隙)
在这里插入图片描述
在这里插入图片描述
要实现真正的数据连续,还需要适当降低FIFO输出端的时钟信号,以此消除间隙。
在这里插入图片描述

其他注意事项

PL的数据位宽,尽量不要有带宽合成
拉低时钟信号用cloking wizard配置,不要用PS端IP那个PL clock直接输出(笔者测试出来这个时钟好像不能用)
在这里插入图片描述

很好的参考文章
Linux 4.14内核———— scatterlist介绍
Linux驱动如何实现DMA传输

### Zynq DMA Configuration and Usage #### Overview of Direct Memory Access (DMA) Direct Memory Access allows data transfer between memory and peripherals without CPU intervention, improving system efficiency by freeing up the processor for other tasks[^1]. In Zynq devices, AXI DMA is used extensively due to its high performance and flexibility. #### Hardware Design Setup in Vivado To configure AXI DMA within a Zynq project using Vivado: - Create an IP Integrator block design. - Add `AXI_DMA` from the catalog into the design canvas. - Connect necessary interfaces such as S_AXI_LITE for register access, M_AXIS_MM2S for memory-mapped transfers, and S_AXIS_S2MM for stream-to-memory mapped operations. For example, connecting these components can be done via drag-and-drop or TCL scripting. The following snippet shows part of this process programmatically: ```tcl set_property -dict [list CONFIG.c_include_sg {0}] [get_ips axi_dma_0] connect_bd_intf_net [get_bd_intf_pins axi_dma_0/S_AXI_LITE] [get_bd_intf_pins processing_system7_0/M_AXI_GP0] ``` This script configures properties like scatter-gather mode off (`c_include_sg`) and connects the lite interface to the PS7 general-purpose master port. #### Software Application Development with Xilinx SDK After setting up the hardware platform, proceed to develop applications that interact with the DMA engine through drivers provided by the Xilinx SDK. A typical workflow involves initializing the device driver, configuring channel parameters, starting transactions, and handling completion events. An illustrative C function demonstrating initialization might look like below: ```c int init_axi_dma(XAxiDma *InstancePtr){ int Status; /* Initialize the DMA */ Status = XAxiDma_CfgInitialize(InstancePtr, LookupConfig(BASEADDR), BASEADDR); if (Status != XST_SUCCESS) { return XST_FAILURE; } return XST_SUCCESS; } ``` Here, `XAxiDma_CfgInitialize()` sets up the specified instance based on predefined configurations stored at `BASEADDR`. #### Testing on Target Boards Testing typically occurs after deployment onto target boards like MicroZed or ZedBoard where actual performance metrics are gathered under real-world conditions. Precompiled binaries available online facilitate rapid prototyping phases during development cycles.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值