在这篇博客中涉及zynq开发的入门环节:MIO、EMIO、调用自定义IP
我使用的zynq型号为zynq-7020,相比7010和7000,拥有较多的可编程逻辑资源
Zynq7000 系列芯片有 54 个 MIO(multiuse I/O),它们分配在GPIO的Bank0和Bank1,隶属于PS部分,这些 IO 与 PS 直接相连。不需要添加引脚约束,MIO 信号对 PL 部分是透明的,不可见。
所以对 MIO 的操作可以看作是纯 PS 的操作。即与单片机直接控制GPIO类似,只需配置一些寄存器即可。
通过查阅zynq编程手册ug585(可从xilinx官网下载)可得,GPIO 的控制和状态寄存器基地址为: 0xE000_A000,vivado SDK 软件底层操作是对于内存地址空间的,所以进行 PS 与 PL 交互时,需要经常查阅zynq的相关手册来获得所需要的寄存器地址。
DATA_RO: 此寄存器使能软件观察 PIN 脚,当 GPIO 被配置成输出的时候,这个寄存器的值会反应输出的 PIN 脚情况。
DATA:此寄存器控制输出到 GPIO 的值,读这个寄存器的值可以读到最后一次写入该寄存器的值。注意这个寄存器是用来读的。
MASK_DATA_LSW:位操作寄存器,写入 GPIO 低 16bit 其他没有改变的位置保存原先的状态
MASK_DATA_MSW:位操作寄存器,写入 GPIO 高 16bit 其他没有改变的位置保存原先的状态
DIRM:此寄存器控制输出的开关,当 DIRM[x]==0 时候,禁止输出
OEN: 输出使能,当 OEN[x]==0 的时候输出关闭, PIN 脚处于三态
因此 ,如果要读 IO 状态就得读 DATA_RO 的值 ,如果是对某一位进行操作就是写
MASK_DATA_LSW/MASK_DATA_MSW
创建zynq工程,选择对应的芯片型号,在block design中添加PS,配置zynq-7000的PS,包括时钟、DDR、串口、网口等必须配置的选项(参考使用的核心板进行配置)
生成顶层HDL文件,生成比特流,导出.bit文件,连接SDK
创建空工程,开始编写PS端代码,main函数如下
#include "xgpiops.h"
#include "sleep.h"
int main()
{
static XGpioPs psGpioInstancePtr;
XGpioPs_Config* GpioConfigPtr;
int iPinNumber= 7; //LD9连接的是MIO7
u32 uPinDirection = 0x1; //1表示输出,0表示输入
int xStatus;
//--MIO的初始化
GpioConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
if(GpioConfigPtr == NULL)
return XST_FAILURE;
xStatus = XGpioPs_CfgInitialize(&psGpioInstancePtr,GpioConfigPtr, GpioConfigPtr->BaseAddr);
if(XST_SUCCESS != xStatus)
print(" PS GPIO INIT FAILED \n\r");
//--MIO的输入输出操作
XGpioPs_SetDirectionPin(&psGpioInstancePtr, iPinNumber,uPinDirection);//配置MIO输出方向
XGpioPs_SetOutputEnablePin(&psGpioInstancePtr, iPinNumber,1);//配置MIO的第7位输出
while(1)
{
XGpioPs_WritePin(&psGpioInstancePtr, iPinNumber, 1);//点亮MIO的第7位输出1
sleep(1); //延时
XGpioPs_WritePin(&psGpioInstancePtr, iPinNumber, 0);//熄灭MIO的第7位输出0
sleep(1); //延时
}
return 0;
}
MIO 分配在 bank0 和 bank1 直接与 PS 部分相连, EMIO 分配在 bank2 和 bank3 和 PL 部分相连。除了 bank1 是 22-bit 之外,其他的 bank 都是 32-bit。所以 MIO 有 53 个引脚可供我们使用,而 EMIO 有 64 个引脚可供我们使用。
使用 EMIO 的好处就是,当 MIO 不够用时, PS 可以通过驱动 EMIO 控制 PL 部分的引脚,接下来就来详细介绍下 EMIO 的使用。
EMIO 的使用和 MIO 的使用其实是非常相似的。区别在于, EMIO 的使用相当于 PS + PL 的结合使用的例子。所以, EMIO 需要分配引脚,以及编译综合生成 bit 文件。
EMIO 的配置方法与MIO相似,只需要查找手册中的寄存器地址以及对应的寄存器配置方法即可。
以一个流水灯程序为例,PS 给 PL 的 IP 核提供时钟,不参与逻辑设计。
若要在SDK中对IP核进行操控,则需要使用AXI总线协议接口的IP核,编写逻辑时应添加AXI协议接口;或直接在创建IP核时选择AXI Lite4 IP
module LED_ML(
input CLK_i,//100MHZ
input RSTn_i,
output reg [3:0]LED_o
);
reg [31:0]C0;
always @(posedge CLK_i)
if(!RSTn_i) begin
LED_o <= 4'b0001;
C0 <= 32'h0;
end
else begin
if(C0 == 32'd49_999_999)//1s
end
C0 <= 32'h0;
if(LED_o == 4'b1000)
LED_o <= 4'b0001;
else LED_o <= LED_o << 1;
end
else begin
C0 <= C0 + 1'b1;
LED_o <= LED_o;
end
end
endmodule
在vivado中将Verilog代码生成IP核,加到zynq工程的block design中,将PS的时钟连接到IP核的时钟输入,运行代码即可观察到流水灯。