Zynq学习之路——入门篇I

Zynq开发I

在这篇博客中涉及zynq开发的入门环节:MIO、EMIO、调用自定义IP
我使用的zynq型号为zynq-7020,相比7010和7000,拥有较多的可编程逻辑资源

MIO

介绍

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的相关手册来获得所需要的寄存器地址。

如图所示为MIO的内部构造
Zynq学习之路——入门篇I_第1张图片

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

使用范例

  1. 创建zynq工程,选择对应的芯片型号,在block design中添加PS,配置zynq-7000的PS,包括时钟、DDR、串口、网口等必须配置的选项(参考使用的核心板进行配置)

  2. 配置MIO,即在双击PS进入配置后,勾选MIO Configuration中的GPIO MIO,如下图所示
    Zynq学习之路——入门篇I_第2张图片

  3. 由于没有使用PL部分,故PL部分的时钟可以用PS的时钟提供,即连接M_AXI_GP0_ACLK 与 FCLK_CLK0
    Zynq学习之路——入门篇I_第3张图片

  4. 生成顶层HDL文件,生成比特流,导出.bit文件,连接SDK

  5. 创建空工程,开始编写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;
}
  1. 分析代码
    XGpioPs_Config: 结构体,存放GPIO的设备地址和基地址
    XGpiops_Lookupconfig(): xilinx 官方提供的 GPIO 查找配置函数,参数为要查找的 GPIO 基地址。
    基地址可从xparameters.h中查看:BSP支持包(此处为MIO_Test_bsp)->Ps7_Cortexa9_0->include->xparameters.h,双击打开它 。若未找到 ,则在主界面下的
    System.mss 界面点击 Re-generate BSP Sources,重新生成 BSP 支持包,等待重新更新。
    xStatus=XGpioPs_CfgInitialize(&psGpioInstancePtr,GpioConfigPtr,GpioConfigPtr
    ->BaseAddr); 该函数进行GPIO初始化,xilinx封装的和STM32的库函数很相像,所以配置起来得心应手。

EMIO

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控制自定义IP核

以一个流水灯程序为例,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核的时钟输入,运行代码即可观察到流水灯。

你可能感兴趣的:(Zynq)