在Petalinux 2020.2上移植xilinx_axidma库:一个ZYNQ开发者的避坑与实战记录
在Petalinux 2020.2上移植xilinx_axidma库一个ZYNQ开发者的避坑与实战记录当你在ZYNQ平台上开发高速数据传输应用时AXI DMA无疑是最核心的组件之一。作为一位长期深耕嵌入式Linux开发的工程师我最近在Petalinux 2020.2环境下移植xilinx_axidma开源库的经历可谓是一波三折。本文将分享我从环境准备到最终测试的全过程特别是那些官方文档中不会告诉你的坑和解决方案。1. 环境准备与基础配置在开始移植之前确保你的开发环境已经正确搭建。我使用的是以下工具链组合Vivado 2020.2用于硬件设计和IP核配置Petalinux 2020.2构建嵌入式Linux系统Ubuntu 18.04 LTS作为开发主机系统提示强烈建议使用与官方推荐匹配的版本组合不同版本间的工具链可能存在兼容性问题。1.1 硬件设计要点在Vivado中设计PL部分时AXI DMA的配置有几个关键点需要注意确保为每个DMA通道正确配置了中断设置合适的DMA缓冲区大小我通常从16KB开始测试验证AXI总线宽度与你的需求匹配32位或64位# 示例Vivado Tcl脚本片段 - 创建AXI DMA IP核 create_ip -name axi_dma -vendor xilinx.com -library ip -version 7.1 -module_name axi_dma_0 set_property -dict [list \ CONFIG.c_include_mm2s {1} \ CONFIG.c_include_s2mm {1} \ CONFIG.c_sg_length_width {14} \ ] [get_ips axi_dma_0]1.2 Petalinux工程初始化创建Petalinux工程后首先需要配置内核参数。以下是我验证过的基础配置命令# 创建Petalinux工程 petalinux-create -t project -n axidma_demo --template zynq cd axidma_demo # 导入硬件描述文件 petalinux-config --get-hw-descriptionpath_to_hdf # 配置内核 petalinux-config -c kernel2. 内核配置与DMA设置移植xilinx_axidma库前必须确保Linux内核正确配置了DMA相关选项。以下是必须启用的内核配置项配置项推荐值说明CONFIG_CMAy连续内存分配器支持CONFIG_DMA_CMAyDMA使用的CMA支持CONFIG_XILINX_DMAENGINESyXilinx DMA引擎支持CONFIG_XILINX_AXIDMAyAXI DMA驱动支持CONFIG_DMA_SHARED_BUFFERyDMA共享缓冲区支持2.1 CMA内存配置DMA操作需要连续的物理内存CMA配置尤为关键。通过以下命令配置CMApetalinux-config -c kernel在配置界面中导航至Library routines → Contiguous Memory Allocator → CMA size in Mega Bytes建议设置为至少25MB具体值取决于你的DMA缓冲区需求。3. 源码修改与适配从GitHub获取xilinx_axidma源码后需要对几个关键文件进行修改以适应Petalinux 2020.2的内核版本5.4.x。3.1 主要修改点axidma_chrdev.c中的access_ok参数变化Linux内核5.x版本中access_ok()函数的参数发生了变化。原代码需要从if (!readonly !access_ok(VERIFY_WRITE, arg, size))修改为if (!readonly !access_ok(arg, size))DMA回调函数签名变化在axidma_dma.c中信号处理相关的结构体发生了变化// 原代码 // struct siginfo sig_info; // 修改为 struct kernel_siginfo sig_info;设备树解析逻辑调整在axidma_of.c中需要确保DMA通道节点解析逻辑正确dma_chan_node of_get_next_child(dma_node, NULL); if (channel 1) { if (of_get_child_count(dma_node) 1) { dma_chan_node of_get_next_child(dma_node, dma_chan_node); } }3.2 设备树配置设备树配置是移植成功的关键。在system-user.dtsi中添加以下内容/ { amba_pl: amba_pl { axidma_chrdev: axidma_chrdev0 { compatible xlnx,axidma-chrdev; dmas axi_dma_0 0 axi_dma_1 1; dma-names tx_channel, rx_channel; }; }; }; axi_dma_0 { dma-channel40400000 { xlnx,device-id 0x1; }; }; axi_dma_1 { dma-channel40410030 { xlnx,device-id 0x2; }; };注意确保设备树中的DMA通道ID与硬件设计匹配否则会导致驱动加载失败。4. 编译与测试4.1 驱动模块编译创建Petalinux模块工程并编译petalinux-create -t modules --name xilinx-axidma --enable修改Makefile确保包含所有源文件DRIVER_NAME xilinx-axidma $(DRIVER_NAME)-objs axi_dma.o axidma_chrdev.o axidma_dma.o axidma_of.o obj-m : $(DRIVER_NAME).o MY_CFLAGS -g -DDEBUG ccflags-y ${MY_CFLAGS} SRC : $(shell pwd) all: $(MAKE) -C $(KERNEL_SRC) M$(SRC)4.2 测试应用程序创建测试应用程序并编译petalinux-create -t apps --name xilinx-axidma-test --enable测试程序Makefile示例APP xilinx-axidma-test APP_OBJS axidma_transfer.o util.o libaxidma.o all: build build: $(APP) $(APP): $(APP_OBJS) $(CC) -o $ $(APP_OBJS) $(LDFLAGS) $(LDLIBS) clean: rm -f $(APP) *.o4.3 性能测试加载驱动并运行测试程序insmod /lib/modules/$(uname -r)/extra/xilinx-axidma.ko ./xilinx-axidma-test -t 0 -r 1 -b 16000 -s 16000预期输出类似AXI DMA Benchmark Parameters: Transmit Buffer Size: 0.02 MiB Receive Buffer Size: 0.02 MiB Number of DMA Transfers: 1000 transfers Using transmit channel 0 and receive channel 1. Single transfer test successfully completed! Beginning performance analysis of the DMA engine. DMA Timing Statistics: Elapsed Time: 0.14 s Transmit Throughput: 106.15 MiB/s Receive Throughput: 106.15 MiB/s Total Throughput: 212.31 MiB/s5. 常见问题与解决方案在实际移植过程中我遇到了几个棘手的问题以下是它们的解决方案驱动加载失败未找到设备检查设备树是否正确编译并包含在最终镜像中。使用以下命令验证dtc -I dtb -O dts -o system.dts system.dtb grep axidma system.dtsDMA传输速度不达标可能的原因包括CMA内存不足AXI总线带宽限制中断处理延迟尝试增大CMA内存并优化中断处理。用户空间访问失败确保设备节点权限正确通常为666SELinux或AppArmor没有阻止访问应用程序以root权限运行仅用于测试内核版本兼容性问题如果遇到其他内核API变化可以通过以下方式查找替代方案git grep 函数名 /path/to/linux-source或者使用在线内核代码浏览器如Bootlin。6. 性能优化技巧经过多次测试和调优我总结出以下几点可以显著提升AXI DMA性能的经验使用多通道并行传输如果硬件支持可以配置多个DMA通道并行工作。在我的测试中双通道可以将吞吐量提升近80%。调整DMA缓冲区大小通过实验找到最佳的缓冲区大小。太小的缓冲区会增加上下文切换开销太大则可能导致内存碎片。启用DMA缓存预取在支持的情况下启用DMA引擎的预取功能可以减少延迟。优化中断处理对于高吞吐量场景可以考虑使用轮询模式替代中断驱动模式。// 示例DMA轮询模式设置 struct axidma_device *dev; dev-dma_mode AXIDMA_MODE_POLLING;内存对齐确保DMA缓冲区按照缓存行大小对齐通常是64字节这可以避免缓存一致性问题。// 确保内存对齐的分配方式 void *buf aligned_alloc(64, buffer_size);移植xilinx_axidma库的过程虽然充满挑战但最终实现的零拷贝用户空间DMA访问能力为我们的高速数据采集系统带来了显著的性能提升。特别是在处理视频流和高速AD采样数据时DMA吞吐量从原来的不足50MB/s提升到了200MB/s以上。