文章目录
-
- 前言
-
- 1.创建Vivado工程
-
- 1.创建XC7Z020CLG400-2项目
- 2.PS端硬件设置
-
- [AXI GPIO信号线连接以及端口连接](#AXI GPIO信号线连接以及端口连接)
- EMIO端口引出
- 3.编写PL端verilog模块
- 4.生成bit流文件以及xsa文件
- 2.Vitis软件设计
-
- [1.在 Vitis 中创建应用工程](#1.在 Vitis 中创建应用工程)
- 2.编写代码
- 3.下载验证
- 总结
前言
无,仅作记录,不具有参考价值。
1.创建Vivado工程
1.创建XC7Z020CLG400-2项目
略。
2.PS端硬件设置














AXI GPIO信号线连接以及端口连接




双击PL_CLK端口:







EMIO端口引出






3.编写PL端verilog模块
创建sys_top.v,key_debounce.v,led_drive,led_flash_drive.v,并编写对应的代码,如下:
sys_top.v:
c
module sys_top(
input [1:0] key,
output [2:0] led,
inout [14:0]DDR_addr,
inout [2:0]DDR_ba,
inout DDR_cas_n,
inout DDR_ck_n,
inout DDR_ck_p,
inout DDR_cke,
inout DDR_cs_n,
inout [3:0]DDR_dm,
inout [31:0]DDR_dq,
inout [3:0]DDR_dqs_n,
inout [3:0]DDR_dqs_p,
inout DDR_odt,
inout DDR_ras_n,
inout DDR_reset_n,
inout DDR_we_n,
inout FIXED_IO_ddr_vrn,
inout FIXED_IO_ddr_vrp,
inout [53:0]FIXED_IO_mio,
inout FIXED_IO_ps_clk,
inout FIXED_IO_ps_porb,
inout FIXED_IO_ps_srstb
);
wire PL_CLK;
wire PL_RST_N;
wire [1:0] AXI_GPIO_I_PL_tri_i;
wire [1:0] AXI_GPIO_O_PL_tri_o;
wire [1:0] EMIO_I;
wire [1:0] EMIO_O;
system_wrapper u_system_wrapper(
.AXI_GPIO_I_PL_tri_i (AXI_GPIO_I_PL_tri_i ),
.AXI_GPIO_O_PL_tri_o (AXI_GPIO_O_PL_tri_o ),
.DDR_addr (DDR_addr ),
.DDR_ba (DDR_ba ),
.DDR_cas_n (DDR_cas_n ),
.DDR_ck_n (DDR_ck_n ),
.DDR_ck_p (DDR_ck_p ),
.DDR_cke (DDR_cke ),
.DDR_cs_n (DDR_cs_n ),
.DDR_dm (DDR_dm ),
.DDR_dq (DDR_dq ),
.DDR_dqs_n (DDR_dqs_n ),
.DDR_dqs_p (DDR_dqs_p ),
.DDR_odt (DDR_odt ),
.DDR_ras_n (DDR_ras_n ),
.DDR_reset_n (DDR_reset_n ),
.DDR_we_n (DDR_we_n ),
.EMIO_I (EMIO_I ),
.EMIO_O (EMIO_O ),
.FIXED_IO_ddr_vrn (FIXED_IO_ddr_vrn ),
.FIXED_IO_ddr_vrp (FIXED_IO_ddr_vrp ),
.FIXED_IO_mio (FIXED_IO_mio ),
.FIXED_IO_ps_clk (FIXED_IO_ps_clk ),
.FIXED_IO_ps_porb (FIXED_IO_ps_porb ),
.FIXED_IO_ps_srstb (FIXED_IO_ps_srstb ),
.PL_CLK (PL_CLK ),
.PL_RST_N (PL_RST_N )
);
key_debounce u_key0_debounce(
.sys_clk (PL_CLK ),
.sys_rst_n (PL_RST_N ),
.key (key[0] ),
.key_filter (AXI_GPIO_I_PL_tri_i[0])
);
key_debounce u_key1_debounce(
.sys_clk (PL_CLK ),
.sys_rst_n (PL_RST_N ),
.key (key[1] ),
.key_filter (AXI_GPIO_I_PL_tri_i[1])
);
led_flash_drive u_led_flash_drive(
.sys_clk (PL_CLK ),
.sys_rst_n (PL_RST_N ),
.trig_500ms (EMIO_I[0] )
);
led_drive u_led0_drive(
.sys_clk (PL_CLK ),
.sys_rst_n (PL_RST_N ),
.gpio_output (AXI_GPIO_O_PL_tri_o[0]),
.led (led[0] )
);
led_drive u_led1_drive(
.sys_clk (PL_CLK ),
.sys_rst_n (PL_RST_N ),
.gpio_output (AXI_GPIO_O_PL_tri_o[1]),
.led (led[1] )
);
led_drive u_led2_drive(
.sys_clk (PL_CLK ),
.sys_rst_n (PL_RST_N ),
.gpio_output (EMIO_O[1]),
.led (led[2] )
);
endmodule
key_debounce.v:
c
module key_debounce(
input sys_clk,
input sys_rst_n,
input key,
output reg key_filter
);
parameter T = 20; //ms
parameter CNT_MAX = 20'd50_000 * T;
reg key_d0;
reg key_d1;
reg [19:0] cnt;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
key_d0 <= 1;
key_d1 <= 1;
end
else begin
key_d0 <= key;
key_d1 <= key_d0;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 20'd0;
else if(key_d0 != key_d1)
cnt <= CNT_MAX;
else if(cnt > 0)
cnt <= cnt - 1;
else
cnt <= 0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
key_filter <= 1;
else if(cnt == 20'd1)
key_filter <= key_d1;
else
key_filter <= key_filter;
end
endmodule
led_drive.v:
c
module led_drive(
input sys_clk,
input sys_rst_n,
input gpio_output,
output led
);
assign led = gpio_output;
endmodule
led_flash_drive.v:
c
module led_flash_drive(
input sys_clk,
input sys_rst_n,
output trig_500ms
);
reg [24:0] cnt_500ms;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt_500ms <= 0;
else if(cnt_500ms < 25_000_000 - 1)
cnt_500ms <= cnt_500ms + 1;
else
cnt_500ms <= 0;
end
assign trig_500ms = (cnt_500ms == 25_000_000 - 1) ? 1 : 0;
endmodule
模块结构如下:


4.生成bit流文件以及xsa文件
添加并编写pin.xdc:
c
#----------------------PL_KEY---------------------------
set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports {key[0]}]
set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {key[1]}]
#----------------------PL_LED---------------------------
set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports {led[0]}]
set_property -dict {PACKAGE_PIN L15 IOSTANDARD LVCMOS33} [get_ports {led[1]}]
set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports {led[2]}]

bit流生成之后:

导出xsa文件之后:
打开vitis并创建应用工程以及main.c文件。
2.Vitis软件设计
1.在 Vitis 中创建应用工程
略。
2.编写代码
在创建main.c之后编写以下代码:
c
#include <stdio.h>
#include "xparameters.h"
#include "xgpiops.h"
#include "xgpio.h"
#include "sleep.h"
#include "xscugic.h"
#include "xil_exception.h"
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID //中断控制器器件ID
#define AXI_GPIO_DEVICE_ID XPAR_GPIO_0_DEVICE_ID //AXI GPIO的器件ID
#define INTC_GPIO_INTERRUPT_ID XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR //AXI GPIO的中断ID号
#define AXI_GPIO_CHANNEL1 0x1 //AXI GPIO的通道1
#define AXI_GPIO_CHANNEL2 0x2 //AXI GPIO的通道2
#define GPIO_DEVICE_ID XPAR_XGPIOPS_0_DEVICE_ID //GPIO器件ID
#define GPIO_INTERRUPT_ID XPAR_XGPIOPS_0_INTR //GPIO的中断ID号
#define EMIO_PL_FLASH_DRIVE 54 //EMIO0引脚编号
#define EMIO_PL_LED2 55 //EMIO1引脚编号
void SetupInterruptSystem_AxiGpio(XScuGic *GicInstancePtr, XGpio *Axi_Gpio, u16 Axi_GpioIntrId);
void IntrHandler_AxiGpio(void *CallBackRef);
void SetupInterruptSystem_Gpio(XScuGic *GicInstancePtr, XGpioPs *Gpio, u16 GpioIntrId);
void IntrHandler_Gpio(void *CallBackRef);
XScuGic Intc; //GIC器件驱动实例
XGpio Axi_Gpio; //AXI GPIO器件的驱动实例
XGpioPs Gpio; //GPIO驱动实例
u32 axi_gpio_channel1_val_last;
u32 axi_gpio_channel1_val_new;
u8 led0_val = 0;
u8 led1_val = 0;
u8 led2_val = 0;
int main(void)
{
//AXI GPIO初始化
XGpio_Initialize(&Axi_Gpio, AXI_GPIO_DEVICE_ID);
//设置AXI GPIO按键为输入
//AXI GPIO中断配置
SetupInterruptSystem_AxiGpio(&Intc, &Axi_Gpio, INTC_GPIO_INTERRUPT_ID);
axi_gpio_channel1_val_last = XGpio_DiscreteRead(&Axi_Gpio, AXI_GPIO_CHANNEL1);
axi_gpio_channel1_val_new = XGpio_DiscreteRead(&Axi_Gpio, AXI_GPIO_CHANNEL1);
//对GPIO驱动进行初始化
XGpioPs_Config *ConfigPtr;
//根据器件ID来去查找器件的配置信息
ConfigPtr = XGpioPs_LookupConfig(GPIO_DEVICE_ID);
//对GPIO的驱动进行初始化
XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);
//设置引脚的方向 0:输入 1:输出
XGpioPs_SetDirectionPin(&Gpio, EMIO_PL_LED2, 1);
XGpioPs_SetDirectionPin(&Gpio, EMIO_PL_FLASH_DRIVE, 0);
//设置输出使能 1:使能输出 0:不使能输出
XGpioPs_SetOutputEnablePin(&Gpio, EMIO_PL_LED2, 1);
//GPIO中断配置
SetupInterruptSystem_Gpio(&Intc, &Gpio, GPIO_INTERRUPT_ID);
printf("AXI GPIO Interrupt test!\n");
while(1)
{
XGpio_DiscreteWrite(&Axi_Gpio, AXI_GPIO_CHANNEL2, (led0_val << 0) | (led1_val << 1));
XGpioPs_WritePin(&Gpio, EMIO_PL_LED2, led2_val);
}
return 0;
}
void SetupInterruptSystem_AxiGpio(XScuGic *GicInstancePtr, XGpio *Axi_Gpio, u16 Axi_GpioIntrId)
{
XScuGic_Config *IntcConfig; //GIC配置信息的驱动实例
//根据中断控制器的器件ID来查找配置信息
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
//根据查找到的配置信息初始化中断控制器
XScuGic_CfgInitialize(GicInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress);
//关联AXI GPIO中断处理程序
XScuGic_Connect(GicInstancePtr, Axi_GpioIntrId, (Xil_ExceptionHandler)IntrHandler_AxiGpio, (void *)Axi_Gpio);
//设置AXI GPIO的中断优先级和中断触发类型
XScuGic_SetPriorityTriggerType(GicInstancePtr, INTC_GPIO_INTERRUPT_ID, 160, 0x1);
//使能AXI GPIO通道1的中断
XGpio_InterruptEnable(Axi_Gpio, AXI_GPIO_CHANNEL1);
//关闭AXI GPIO通道2的中断,防止误触
XGpio_InterruptDisable(Axi_Gpio, AXI_GPIO_CHANNEL2);
//使能AXI GPIO全局中断
XGpio_InterruptGlobalEnable(Axi_Gpio);
//使能GIC的AXI GPIO中断
XScuGic_Enable(GicInstancePtr, Axi_GpioIntrId);
//异常初始化
Xil_ExceptionInit();
//注册中断请求异常的处理程序
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
GicInstancePtr);
//使能异常处理
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
}
void IntrHandler_AxiGpio(void *CallBackRef)
{
XGpio *Axi_Gpio = (XGpio *)CallBackRef;
if(XGpio_InterruptGetStatus(Axi_Gpio) & XGPIO_IR_CH1_MASK)
{
printf("AXI GPIO CHANNEL1 Interrupt detect!\n");
axi_gpio_channel1_val_new = XGpio_DiscreteRead(Axi_Gpio, AXI_GPIO_CHANNEL1);
if((axi_gpio_channel1_val_new ^ axi_gpio_channel1_val_last) & (1 << 0))
{
printf("AXI GPIO CHANNEL1_PIN0 Interrupt detect!\n");
if((axi_gpio_channel1_val_new & (1 << 0)) == 0)
{
printf("LED0 TOGGLE!\n");
led0_val = !led0_val;
}
}
if((axi_gpio_channel1_val_new ^ axi_gpio_channel1_val_last) & (1 << 1))
{
printf("AXI GPIO CHANNEL1_PIN1 Interrupt detect!\n");
if((axi_gpio_channel1_val_new & (1 << 1)) == 0)
{
printf("LED1 TOGGLE!\n");
led1_val = !led1_val;
}
}
axi_gpio_channel1_val_last = axi_gpio_channel1_val_new;
//清除对应AXI GPIO通道引发中断的标志位
XGpio_InterruptClear(Axi_Gpio, AXI_GPIO_CHANNEL1);
}
if(XGpio_InterruptGetStatus(Axi_Gpio) & XGPIO_IR_CH2_MASK)
{
printf("AXI GPIO CHANNEL2 Interrupt detect!\n");
//清除对应AXI GPIO通道引发中断的标志位
XGpio_InterruptClear(Axi_Gpio, AXI_GPIO_CHANNEL2);
}
}
void SetupInterruptSystem_Gpio(XScuGic *GicInstancePtr, XGpioPs *Gpio, u16 GpioIntrId)
{
XScuGic_Config *IntcConfig; //GIC配置信息的驱动实例
//根据中断控制器的器件ID来查找配置信息
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
//根据查找到的配置信息初始化中断控制器
XScuGic_CfgInitialize(GicInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress);
//关联GPIO中断处理程序
XScuGic_Connect(GicInstancePtr, GpioIntrId, (Xil_ExceptionHandler)IntrHandler_Gpio, (void *)Gpio);
//设置GPIO的中断优先级和中断触发类型
XScuGic_SetPriorityTriggerType(GicInstancePtr, XPAR_XGPIOPS_0_INTR, 160, 0x1);
//设置GPIO中断的触发类型,下降沿
XGpioPs_SetIntrTypePin(Gpio, EMIO_PL_FLASH_DRIVE, XGPIOPS_IRQ_TYPE_EDGE_RISING);
//使能GPIO引脚的中断
XGpioPs_IntrEnablePin(Gpio, EMIO_PL_FLASH_DRIVE);
//使能GIC的GPIO中断
XScuGic_Enable(GicInstancePtr, GpioIntrId);
//异常初始化
Xil_ExceptionInit();
//注册中断请求异常的处理程序
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
GicInstancePtr);
//使能异常处理
Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);
}
void IntrHandler_Gpio(void *CallBackRef)
{
XGpioPs *Gpio = (XGpioPs *)CallBackRef;
printf("GPIO Interrupt detect!\n");
if(XGpioPs_IntrGetStatusPin(Gpio,EMIO_PL_FLASH_DRIVE))
{
led2_val = !led2_val;
printf("500ms coming...\n");
//清除对应引脚引发中断的标志位
XGpioPs_IntrClearPin(Gpio, EMIO_PL_FLASH_DRIVE);
}
}
build之后run as→launch on hardware(Single Application Debug),进行下载。
3.下载验证
略。
总结
这次实验打通了PL端和PS端的信号交互。在以前没学zynq的时候,用的是STM32和FPGA完成比赛项目,两者使用杜邦线连接进行信号交互,用zynq的AXI GPIO模块来进行信号交互不仅可以节省PL端的引脚资源还可以避免使用杜邦线来进行不太稳定的连接。