在嵌入式系统开发中,FPGA与处理器的协同工作能力是提升系统灵活性的关键。黑金AXU3EG开发板作为一款集成了Zynq UltraScale+ MPSoC的硬件平台,为开发者提供了丰富的PL(可编程逻辑)和PS(处理系统)资源交互的可能性。本文将从一个具体案例出发,详细讲解如何通过EMIO(Extended Multiplexed I/O)实现PL端按键对PS端LED的控制,涵盖从Vivado硬件配置到Vitis软件开发的完整流程。
在开始之前,请确保已安装Vivado 2020.1和Vitis 2020.1开发环境,并准备好黑金AXU3EG开发板的原理图文档。我们将从创建一个新的Vivado工程开始:
完成工程创建后,我们需要配置Zynq UltraScale+ MPSoC处理系统:
tcl复制# 在Vivado Tcl控制台中执行以下命令创建Zynq块设计
create_bd_design "zu3eg_system"
startgroup
create_bd_cell -type ip -vlnv xilinx.com:ip:zynq_ultra_ps_e zynq_ultra_ps_e_0
endgroup
EMIO是Zynq系列芯片中连接PS和PL的重要桥梁,它允许PS端的GPIO通过PL进行扩展。在黑金AXU3EG开发板上,我们需要根据原理图确定按键和LED对应的引脚:
在Vivado中配置EMIO的步骤如下:
完成配置后,右键点击GPIO端口选择"Make External"将其引出,并重命名为"PL_KEY"以便识别。
正确的引脚约束是确保硬件功能正常的关键。创建一个新的XDC约束文件:
xdc复制# 黑金AXU3EG PL端按键约束示例
set_property PACKAGE_PIN W13 [get_ports PL_KEY]
set_property IOSTANDARD LVCMOS33 [get_ports PL_KEY]
生成比特流前的重要检查点:
生成比特流后,通过以下步骤导出硬件平台:
切换到Vitis 2020.1环境,创建一个新的应用工程:
以下是完整的C代码实现,包含详细注释:
c复制#include "xparameters.h" // 器件参数头文件
#include "xgpiops.h" // PS GPIO驱动头文件
#include "xstatus.h" // 状态宏定义
#include <xil_printf.h> // 打印函数
#include "sleep.h" // 延时函数
// 设备ID定义(自动生成于xparameters.h)
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID
// PS端LED引脚定义(根据原理图确认)
#define PS_LED1 40
// PL端按键引脚定义(通过EMIO扩展)
#define PL_KEY 78
XGpioPs PS_Gpio; // GPIO驱动实例
int main(void) {
int Status;
XGpioPs_Config *ConfigPtr;
xil_printf("EMIO Control Demo Start\r\n");
// 1. 初始化GPIO驱动
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
Status = XGpioPs_CfgInitialize(&PS_Gpio, ConfigPtr,
ConfigPtr->BaseAddr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
// 2. 配置引脚方向
// PS LED设置为输出
XGpioPs_SetDirectionPin(&PS_Gpio, PS_LED1, 1);
XGpioPs_SetOutputEnablePin(&PS_Gpio, PS_LED1, 1);
// PL按键设置为输入
XGpioPs_SetDirectionPin(&PS_Gpio, PL_KEY, 0);
// 3. 主控制循环
while (1) {
if (XGpioPs_ReadPin(&PS_Gpio, PL_KEY) == 0) {
usleep(10000); // 10ms消抖
XGpioPs_WritePin(&PS_Gpio, PS_LED1, 1); // LED亮
} else {
usleep(10000);
XGpioPs_WritePin(&PS_Gpio, PS_LED1, 0); // LED灭
}
}
return XST_SUCCESS;
}
代码中的关键点解析:
XGpioPs_LookupConfig函数通过设备ID获取GPIO配置信息XGpioPs_CfgInitialize初始化GPIO驱动,返回状态需检查SetDirectionPin设置引脚方向(1输出,0输入)SetOutputEnablePin使能输出引脚ReadPin/WritePin实现引脚状态读写在实际开发中,可能会遇到以下典型问题及解决方案:
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| 程序运行但LED无反应 | 引脚定义错误 | 核对原理图确认LED和按键引脚号 |
| 按键控制不稳定 | 消抖时间不足 | 增加usleep时间或添加硬件消抖电路 |
| 无法下载比特流 | JTAG连接问题 | 检查开发板供电和JTAG连接线 |
| Vitis工程找不到设备 | 驱动未安装 | 安装正确的USB-JTAG驱动 |
调试建议:
xil_printf输出调试信息基于当前项目,可以考虑以下扩展方向:
多按键控制:增加PL端按键数量,实现不同控制模式
中断模式优化:将轮询改为中断驱动
c复制// 中断初始化示例代码片段
XGpioPs_SetIntrTypePin(&PS_Gpio, PL_KEY, XGPIOPS_IRQ_TYPE_EDGE_FALLING);
XGpioPs_SetCallbackHandler(&PS_Gpio, (void *)&PS_Gpio, KeyInterruptHandler);
XGpioPs_IntrEnablePin(&PS_Gpio, PL_KEY);
PL端逻辑增强:在FPGA中实现更复杂的按键处理逻辑
系统集成:将本功能作为子系统集成到更大项目中
在实际项目中,EMIO的应用不仅限于简单的GPIO扩展。通过合理设计,它可以成为PS和PL之间高效通信的桥梁,实现数据交换、状态同步等复杂功能。掌握EMIO的使用是Zynq系列开发的基础技能之一,为后续更复杂的异构系统设计打下坚实基础。