0.前言
通过一个简单的工程,实现对axi_gpio核基本功能的介绍
1.AXI GPIO简介
AXI GPIO IP 核为 AXI 接口提供了一个通用的输入/输出接口。与 PS 端的 GPIO 不同,AXI GPIO 是一个软核(Soft IP),即 ZYNQ 芯片在出厂时并不存在这样的一个硬件电路,而是由用户通过配置 PL 端的逻辑资源来实现的一个功能模块。而 PS 端的 GPIO 是一个硬核(Hard IP),它是一个生产时在硅片中实现的功能电路。
AXI GPIO 可以配置成单通道或者双通道,每个通道的位宽可以单独设置。另外通过打开或者关闭三态缓冲器,AXI GPIO 的端口还可以被动态地配置成输入或者输出接口。其顶层模块的框图如下所示:
模块的左侧实现了一个 32 位的 AXI4-Lite 从接口,用于主机访问 AXI GPIO 内部各通道的寄存器。当右侧接口输入的信号发生变化时,模块还能向主机产生中断信号。不过只有在配置IP 核时选择“使能中断”,才会启用模块的中断控制功能。
2.PL端设置
新建工程打开bd,首先添加zynq核并设置zedboard预设
添加axi_gpio核
axi_gpio核配置界面如下,首先是可以通过勾选all inputs或all outputs来设置axi_gpio核的方向,也可以不勾选,通过ps进行方向的设置,设置方式和gpio硬核相似,建议在这里勾选设置好方向,这样我们在ps端就可以直接通过Xil_In或是Xil_Out进行读写,方便很多。
然后是设置位宽和默认的一个输出值。
勾选enable dual channel后可以使能第二路gpio端口,设置方法与第一路相同
最后下面还有一个中断的使能接口,勾选之后就会出现一个中断的接口
3.通过Xil_In或是Xil_Out对AXI GPIO进行读写
我们添加两个axi_gpio,分别设为输入和输出,都为8位宽
有的时候可能出现GPIO的位宽无法设置或是在自动连续后改变了的情况出现,此时需要注意一下在设置界面中board interface要选择custom
添加一个设计模块,将输入的值加1后输出
`timescale 1ns / 1ps
module plus1(
input clk,
input [7:0] data_i,
output [7:0] data_o
);
reg [7:0] data;
always@(posedge clk)begin
data = data_i + 1;
end
assign data_o = data;
endmodule
最终连接好后bd如图
两个gpio核地址
SDK部分
打开SDK创建工程,main函数代码如下,这里需要注意的是,Xil_In和Xil_Out函数需要与前面设置的gpio的输入输出对应,比如我们前面设置的gpio1是输出,因此,需要用Xil_Out去对gpio1进行输出数据,gpio0是输入,因此,要用Xil_In通过gpio0进行读取数据,读写用反的话就无法实现相应功能。
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xil_io.h"
int main()
{
init_platform();
UINTPTR addr;
u32 data;
addr = 0x41210000;
data = 0x10;
Xil_Out8(addr,data);
printf("data_o = 0x%x\n",data);
addr = 0x41200000;
data = Xil_In8(addr);
printf("data_i = 0x%x\n",data);
cleanup_platform();
return 0;
}
最后,我们可以看见terminal和memory内的数据,输出的数据加1后返回,对应的地址内也有相应的数据,此次实验完成
4.通过AXI GPIO读写函数进行读写
BD的设计采样一个AXI GPIO双通道的形式
其中自建RTL也是简单实现对输入加一后输出的功能
`timescale 1ns / 1ps
module axi_gpio_test(
input clk,
input rst,
input [31:0] din,
output wire [31:0] dout
);
reg [31:0] data;
always @(posedge clk)begin
if(rst)
data <= 0;
else
data <= din + 1;
end
assign dout = data;
endmodule
生成比特流后导出硬件平台
SDK部分
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xgpio.h"
#include "xparameters.h"
#include "xil_io.h"
#define channel_1 1U
#define channel_2 2U
XGpio axiGpio0;
int main()
{
XGpio_Initialize(&axiGpio0,XPAR_GPIO_0_DEVICE_ID);
XGpio_SetDataDirection(&axiGpio0,channel_1,0); //通道1设置为输出,即第三个参数1为输入,0为输出
XGpio_SetDataDirection(&axiGpio0,channel_2,0xFFFFFFFF); //通道2设置为输入,0xFFFFFFFF表示32为全部设置为输入
u32 ReadData,i;
for(i=0;i<10;i++)
{
XGpio_DiscreteWrite(&axiGpio0,channel_1,i); //这里用gpio写函数,实现的功能与下面的Xil_Out32(0x41200000,i)相同。
//Xil_Out32(0x41200000,i);
ReadData = XGpio_DiscreteRead(&axiGpio0,channel_2);
printf("read data = %d \n",ReadData);
}
return 0;
}