前段时间在我的一篇博客 "zynq-PS篇------petalinux2022.2的DMA实现" 中带大家搭建了DMA回环的PL工程以及PS端的相关配置。
个人认为该驱动还是蛮好用的,但毕竟该驱动是2017年写的,已经有很多年了,存在一些局限性。但自己又不想找新的DMA驱动,据说proxy-DMA这个驱动也蛮好的,且一直在更新,但笔者实在不想再花时间去了解这个。
本篇主要探讨在利用 https://github.com/bperez77/xilinx_axidma驱动时一些可能导致问题的注意事项。
1、 DMA IP只开启s2mm,mm2s其中一个通道时,需要修改驱动
2、 DMA IP的 lite 和 hpm 时钟需要一致
一、单DMA IP开启S2MM,MM2S双通道

当你的需求只是一个简单的DMA回环,且该DMA IP同时承担了s2mm以及mm2s的功能时,设备树和驱动都依照我在前篇博客中讲到的一样设置即可。
此时你可以看到,你的设备树的pl.dtsi文件中 DMA IP 的s2mm、mm2s通道。把两路的xlnx,device-id设置为不同的值
system-user.dtsi对应的设置为
shell
&amba_pl{
axidma_chrdev: axidma_chrdev@0{
compatible = "xlnx,axidma-chrdev";
dmas = <&axi_dma_0 0 &axi_dma_0 1>;
dma-names = "mm2s_dir0_channel", "s2mm_dir1_channel";
}
}
其中,dma-names是dma的名称,你可以随意修改。dmas属性中,mm2s方向要写0,s2mm方向要写1.
二、双DMA IP分别负责S2MM,MM2S

此时你的设备树会有两个DMA IP的信息,且他们子节点中仅有一个通道
此时你的system-user.dtsi也做对应的修改
shell
&amba_pl{
axidma_chrdev: axidma_chrdev@0{
compatible = "xlnx,axidma-chrdev";
dmas = <&axi_dma_0 0 &axi_dma_1 1>; #axi_dma_0负责mm2s,axi_dma_1负责s2mm
dma-names = "mm2s_dir0_channel", "s2mm_dir1_channel";
}
}
此时如果用原本的那套内核,在 insmod axidma.ko 时会报错,出现段错误导致问题
此时两种解决办法,一个是给两个 PL 端的两个 DMA IP都开启两个方向,但这很麻烦,因为PL的编译时间总是比较久的。
另一种方法,你可以修改源码/driver/axidma_of.c里面,将第98-100行注释
用这样子的内核操作后,驱动插入正常
至于为什么出现该问题,以及为什么这样子可以解决,笔者还没有仔细想过。有了解的可以留言或私信讨论。
在单DMA IP承担双通道任务时,不要注释这个,否则有一路通道会找不到
三、lite和fpd的时钟最好一致
假设我现在需要PL端内部的时钟是分置开的(不同时钟源),
在驱动中你可以看到,s_axi_lite_aclk的时钟源是<&zynqmp_clk 71>,而m_axi_mm2s_aclk的时钟源是<&misc_clk_0>。笔者实测下来这样子会报错找不到通道,
最好把他们三个的时钟统一,如果需要时钟转换,就在DMA数据在PL的流中给个FIFO来转时钟阈。(如图中1,3)
这样子即可插入内核成功
反正简单而言,
1、 mm2s方向要写0,s2mm方向要写1
2、 根据你的需要选择是否注释axidma_of.c中的98-100行
3 、尽量保持DMA IP接口与示例工程统一,把修改留在PL内部,而不是PS-PL的接口上
4、 中断记得要接
以上讲解并没有讲述原理,只是简单提一种解决方案,若有对此了解的,欢迎与我联系。