当第一次拿到ZYNQ开发板时,面对复杂的异构计算架构和Linux驱动开发流程,很多工程师都会感到无从下手。特别是当需要在PL(可编程逻辑)和PS(处理系统)之间实现高速数据传输时,AXI DMA(直接内存访问)控制器就成了关键组件。本文将手把手带你完成从Vivado工程配置到最终驱动测试的全过程,其中包含多个官方文档未提及的实战技巧。
在开始之前,确保你的Ubuntu 18.04系统已经安装了必要的依赖库。不同于常规嵌入式开发,Petalinux对环境的要求更为严格:
bash复制sudo apt-get install -y gcc g++ make net-tools libncurses5-dev zlib1g-dev \
flex bison libselinux1 xterm autoconf libtool texinfo gawk \
python3-dev python3-pexpect python3-pip python3-git python3-jinja2 \
xz-utils debianutils iputils-ping libssl-dev
关键工具版本匹配是成功的第一步。我们使用的工具链组合是经过验证的稳定版本:
| 工具名称 | 版本号 | 备注 |
|---|---|---|
| Vivado | 2020.2 | 必须包含Vitis组件 |
| Petalinux | 2020.2 | 与Vivado版本严格对应 |
| Ubuntu | 18.04 LTS | 官方推荐的基础系统 |
提示:建议在/home目录下创建专门的工程目录,路径中不要包含中文或空格,避免工具链解析异常。
在Vivado中创建Block Design时,AXI DMA IP核的参数配置直接影响后续驱动开发。以下是经过实战验证的推荐配置:
基本参数设置:
中断连接技巧:
tcl复制# 在Tcl控制台中执行以下命令可批量连接中断
connect_bd_net [get_bd_pins axi_dma_0/mm2s_introut] [get_bd_pins processing_system7_0/IRQ_F2P]
connect_bd_net [get_bd_pins axi_dma_0/s2mm_introut] [get_bd_pins processing_system7_0/IRQ_F2P]
地址分配验证:
生成比特流前,务必检查Address Editor中DMA控制器的寄存器地址是否与后续设备树配置一致。典型值如下:
c复制axi_dma_0: 0x40400000
axi_dma_1: 0x40410000
创建Petalinux工程后,需要特别关注Linux内核的DMA和CMA(连续内存分配器)配置:
bash复制petalinux-config -c kernel
在menuconfig界面中,确保以下选项被启用:
DMA引擎支持:
code复制CONFIG_DMA_ENGINE=y
CONFIG_XILINX_DMAENGINES=y
AXI DMA专用驱动:
code复制CONFIG_XILINX_AXIDMA=y
CMA配置(位于Device Drivers → CMA):
bash复制CONFIG_CMA_SIZE_MBYTES=25 # 根据实际传输数据量调整
实用技巧:将配置保存为自定义名称后,可以在工程目录下的subsystems/linux/configs/kernel/中找到对应文件,方便版本管理。
设备树是连接硬件和驱动的关键桥梁。针对AXI DMA,需要特别注意以下几点:
DMA通道ID映射:
dts复制&axi_dma_0 {
dma-channel@40400000 {
xlnx,device-id = <0x1>; // MM2S通道
};
};
&axi_dma_1 {
dma-channel@40410030 {
xlnx,device-id = <0x2>; // S2MM通道
};
};
DMA缓冲区配置:
在system-user.dtsi中添加CMA区域声明:
dts复制reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
linux,cma {
compatible = "shared-dma-pool";
reusable;
size = <0x1000000>; // 16MB
linux,cma-default;
};
};
调试技巧:
使用dtc工具反编译DTB文件,验证配置是否生效:
bash复制dtc -I dtb -O dts -o system.dts images/linux/system.dtb
grep -n "dma" system.dts
基于开源项目xilinx_axidma进行移植时,需要针对Petalinux 2020.2的内核版本(5.4)做以下关键修改:
内核API适配:
c复制// 修改axidma_chrdev.c中的访问检查函数
static bool axidma_access_ok(const void __user *arg, size_t size, bool readonly)
{
if (!readonly && !access_ok(arg, size)) {
axidma_err("Write check failed for address %p\n", arg);
return false;
} else if (readonly && !access_ok(arg, size)) {
axidma_err("Read check failed for address %p\n", arg);
return false;
}
return true;
}
DMA回调函数更新:
c复制static void axidma_dma_callback(void *data)
{
struct axidma_cb_data *cb_data = data;
struct kernel_siginfo sig_info;
if (cb_data->comp) {
complete(cb_data->comp);
} else if (VALID_NOTIFY_SIGNAL(cb_data->notify_signal)) {
clear_siginfo(&sig_info);
sig_info.si_signo = cb_data->notify_signal;
sig_info.si_code = SI_QUEUE;
sig_info.si_int = cb_data->channel_id;
send_sig_info(cb_data->notify_signal, &sig_info, cb_data->process);
}
}
Makefile优化:
在驱动模块的Makefile中添加调试支持:
makefile复制MY_CFLAGS += -g -DDEBUG
ccflags-y += ${MY_CFLAGS}
完成驱动加载后,可以通过自行编译的测试程序验证DMA功能:
bash复制# 加载驱动
insmod /lib/modules/$(uname -r)/extra/xilinx-axidma.ko
# 运行测试程序
axidmabenchmark -t 0 -r 1 -b 16384 -s 16384 -i 1000
性能优化参数参考:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 缓冲区大小 | 16KB~1MB | 过小会导致频繁中断,过大增加延迟 |
| SG条目数 | 8~16 | 平衡吞吐量和内存占用 |
| 时钟频率 | 100-150MHz | 在PL端约束文件中设置 |
当遇到性能瓶颈时,可以尝试以下方法:
/proc/interrupts确认中断触发频率dmesg | grep dma查看驱动日志问题1:加载驱动时报错"Unknown symbol in module"
解决方法:
bash复制# 重新生成模块依赖关系
depmod -a
# 检查内核配置是否一致
zcat /proc/config.gz | grep DMA
问题2:DMA传输速度远低于预期
排查步骤:
/sys/kernel/debug/dmaengine/下的性能统计问题3:用户空间程序无法mmap DMA缓冲区
解决方案:
/dev/axidma设备权限c复制buffer = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
经过完整的流程实践后,我们发现最耗时的环节往往是设备树调试和性能调优。建议在工程初期就建立完整的版本控制体系,记录每个阶段的配置变更。