1. LED流水灯控制
任务目标
在Zynq-7000系列芯片上,通过ARM Cortex-A9核配置FPGA侧的AXI GPIO IP核,控制4个LED实现流水灯效果。本案例将完成硬件工程搭建(Vivado)、软件工程编写(Vitis)及开发板验证,帮助掌握PS-PL间AXI接口的基本使用流程。
硬件设计(Vivado)
使用Vivado创建Block Design,添加Zynq PS核与AXI GPIO IP,完成PL侧LED引脚约束。
- 创建工程,器件选择xc7z020clg400-1(以Zynq-7020为例)
- 添加Zynq7 Processing System IP,运行Block Automation自动配置(UART、DDR等默认即可)
- 添加AXI GPIO IP,双击配置:
- GPIO Width:4
- 取消勾选All Outputs(默认输出即可)
- 勾选Enable Dual Channel(不需要,保持默认单通道) - 运行Connection Automation,将S_AXI连接到PS的M_AXI_GP0
- 右键点击GPIO引脚,选择Make External,重命名为led_tri_io
- 创建约束文件,添加引脚约束:
set_property PACKAGE_PIN M14 [get_ports {led_tri_io_tri_o[0]}]
set_property PACKAGE_PIN M15 [get_ports {led_tri_io_tri_o[1]}]
set_property PACKAGE_PIN K16 [get_ports {led_tri_io_tri_o[2]}]
set_property PACKAGE_PIN J16 [get_ports {led_tri_io_tri_o[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {led_tri_io_tri_o[*]}]
生成比特流后导出硬件(File → Export Hardware,勾选Include bitstream),启动Vitis。
软件设计(Vitis)
创建Application Project,平台选择导出的硬件。以下是完整C代码:
#include "xgpio.h"
#include "xparameters.h"
#include "sleep.h"
#define GPIO_DEVICE_ID XPAR_AXI_GPIO_0_DEVICE_ID
#define LED_CHANNEL 1
#define LED_BLINK_MS 200
static XGpio gpio;
int main(void)
{
u32 led_pattern = 0x01; // 初始点亮LED0
int status;
// 初始化GPIO
status = XGpio_Initialize(&gpio, GPIO_DEVICE_ID);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
// 设置GPIO方向为输出
XGpio_SetDataDirection(&gpio, LED_CHANNEL, 0x0);
while (1) {
// 输出当前流水灯模式
XGpio_DiscreteWrite(&gpio, LED_CHANNEL, led_pattern);
// 移位实现流水效果:LED0→LED1→LED2→LED3→LED0
led_pattern = (led_pattern << 1);
if (led_pattern > 0x08) {
led_pattern = 0x01; // 循环回到LED0
}
usleep(LED_BLINK_MS * 1000);
}
return 0;
}
运行与验证
运行步骤:
- 将比特流下载到开发板(Program FPGA)
- 在Vitis中右键点击工程,选择Run As → Launch on Hardware
- 观察开发板4个LED状态
通过标准:4个LED按LED0→LED1→LED2→LED3顺序依次点亮,每个LED亮200ms后熄灭并点亮下一个,循环往复。若观察到该流水效果,说明ARM通过AXI接口成功控制FPGA侧GPIO,案例验证通过。
常见问题
- LED不亮:检查约束文件中引脚编号是否与开发板原理图一致,确认比特流已正确下载
- 编译报错:确认Vitis平台选择的是导出的硬件文件(.xsa),而非默认空平台
- 流水速度异常:usleep参数单位为微秒,200ms对应200000,代码中已正确换算