xilinx_axidma 驱动移植与使用

前言

需要在ZYNQ平台上使用DMA驱动,裸机的还到好说,Linux下的DMA驱动框架复杂,这对本身不是搞驱动的我难度太大。自己动手丰衣足食,但是试错成本很大,记录下来希望能给后来者帮助。

参考资源

开源项目xilinx_axidma

Petalinux2020.2 开发ZYNQ的AXI DMA - 知乎 (zhihu.com)

Linux环境下在用户空间使用AXI-DMA进行传输

开发环境

vivado2020.1,ubuntu18.04下运行的petalinux

开发板 AXU9EG

FPGA工程:配套工程 dma_loopback

FPGA工程搭建

参见:《ZYNQ MPSoC 开发平台 VITIS 应用教程》第二十一章 DMA 环通测试
设置DMA IP 核的 width of Buffer Length Register 参数应设置23或更大

 

xilinx_axidma 驱动移植与使用_第1张图片
xilinx_axidma 驱动移植与使用_第2张图片

Petalinux系统编译

设备树

pl.dtsi 中系统生成的DMA设备树:

路径:[项目]/components/plnx_workspace/device-tree/device-tree

#### pl.dtsi中生成的设备树

    amba_pl: amba_pl@0 {
        #address-cells = <2>;
        #size-cells = <2>;
        compatible = "simple-bus";
        ranges ;
        axi_dma_0: dma@80000000 {
            #dma-cells = <1>;
            clock-names = "s_axi_lite_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk";
            clocks = <&zynqmp_clk 71>, <&zynqmp_clk 71>, <&zynqmp_clk 71>;
            compatible = "xlnx,axi-dma-7.1", "xlnx,axi-dma-1.00.a";
            interrupt-names = "mm2s_introut", "s2mm_introut";
            interrupt-parent = <&gic>;
            interrupts = <0 89 4 0 90 4>;
            reg = <0x0 0x80000000 0x0 0x10000>;
            xlnx,addrwidth = <0x20>;
            xlnx,sg-length-width = <0xe>;
            dma-channel@80000000 {
                compatible = "xlnx,axi-dma-mm2s-channel";
                dma-channels = <0x1>;
                interrupts = <0 89 4>;
                xlnx,datawidth = <0x20>;
                xlnx,device-id = <0x0>;
            };
            dma-channel@80000030 {
                compatible = "xlnx,axi-dma-s2mm-channel";
                dma-channels = <0x1>;
                interrupts = <0 90 4>;
                xlnx,datawidth = <0x20>;
                xlnx,device-id = <0x0>;
            };
        };
    };

根据生成的DMA在system-user.dtsi做相应修改添加axidma_chrdev设备

路径:[项目]/project-spec/meta-user/recipes-bsp/device-tree/files

/include/ "system-conf.dtsi"
/ {
};

/* SD */
&sdhci1 {
	disable-wp;
	no-1-8-v;
};

/* USB */
&dwc3_0 {
	status = "okay";
	dr_mode = "host";
};

&amba_pl{
	axidma_chrdev: axidma_chrdev@0 {
		compatible = "xlnx,axidma-chrdev";
		dmas = <&axi_dma_1 0 &axi_dma_1 1 &axi_dma_0 2 &axi_dma_0 3>;
		dma-names = "tx_channel", "rx_channel", "tx_channel", "rx_channel";
	};

};

    &amba_pl{
        axidma_chrdev: axidma_chrdev@0 {
            compatible = "xlnx,axidma-chrdev";
            dmas = <&axi_dma_0 0 &axi_dma_0 1 >;
            dma-names = "tx_channel", "rx_channel";
        };
    };

    &axi_dma_0 {
        dma-channel@80000000 {		
        xlnx,device-id = <0x0>;
        };
        dma-channel@80000030 {		
        xlnx,device-id = <0x1>;
        };
    };

注意两点:

1、根据自己的开发板,修改设备树满足Linux运行基本条件,如这里的SD卡和USB;

2、这里的axi_dma_0为DMA外设,地址要和pl.dtsi中的一致。

编译系统

按照上面两个教程操作基本没啥问题,如果采用相同版本的话,默认CMA为256MB,添加了DMA,Kernel的DMA也会使能,这里没有特别注意该地方。

编译驱动.ko

1、使用petalinux构建模块:

petalinux-create -t modules --name xilinx-axidma --enable

2、添加驱动源码

由于版本变更,驱动代码需要进行稍微修改,参考Petalinux2020.2 开发ZYNQ的AXI DMA - 知乎 (zhihu.com)

这里我将petalinux下的搭建的module放到CSDN上了,使用的内核版本是(5.4.0), xilinx-axidma驱动模块petalinux2020

3、编译为独立的模块

在 project-spec/meta-user/conf/petalinuxbsp.conf 中添加以下行

RM_WORK_EXCLUDE += "xilinx-axidma"  

4、编译驱动模块

petalinux-build -c xilinx-axidma

您可在 [项目]/build/tmp/work/zynqmp_generic-xilinx-linux/xilinx-axidma/1.0-r0 中找到编译的驱动模块

测试

对DMA进行了测试,源码里有两个例子,一个是文件传输 axidma_transfer.c,一个用于测试带宽 axidma_benchmark.c,基于Qt搭建的测试工程也放到驱动链接里面了。

wk​​​​​​​xilinx-axidma驱动模块petalinux2020-Linux文档类资源-CSDN文库​​​​​​​

注意:测试时发现一个问题,你需要将传输的大小设置 > 4KB 一定要大于4KB数据才正常,等于4KB也不好使。(也可能是buf的大小需要 >4KB,猜测是不是和PAGESIZE有关,4KB)

这样带来了测试困惑:FPGA工程中DMA回环fifo是4KB大小,和测试有冲突,一种方法是增大fifo的深度,另一种方法是先开启DMA读再开启DMA写。

    rc = axidma_oneway_transfer(axidma_dev, rx_channel, rx_buf, rx_size,false);
    rc = axidma_oneway_transfer(axidma_dev, tx_channel, tx_buf, tx_size,true);

你可能感兴趣的:(FPGA,linux,linux,运维,服务器)