ZYNQ笔记(六):自定义IP核-LED呼吸灯

 版本:Vivado2020.2(Vitis)

任务:通过自定义一个 LED 呼吸灯 IP核,来控制 PL 端 LED 实现呼吸灯效果,同时 PS 端可通过 AXI 接口来控制呼吸灯的开关和呼吸频率。

目录

一、介绍

二、创建自定义IP核

1.创建IP管理工程

2.创建IP

3.编辑IP

4.打包IP

5.使用IP

三、硬件设计

四、软件设计

五、效果


一、介绍

        Vivado自定义IP核(IP Integrator)是Xilinx FPGA设计工具Vivado中的一项重要功能,它允许开发者创建、封装和复用自定义的硬件功能模块。

主要特点

  1. 模块化设计:将特定功能封装为独立IP核,便于复用

  2. 标准化接口:支持AXI、APB等标准接口协议

  3. 参数化配置:IP核可配置参数,适应不同应用场景

  4. 简化集成:通过IP Integrator图形化界面快速搭建系统

二、创建自定义IP核

1.创建IP管理工程

        首先创建一个管理自定义IP的工程:打开 Vivado,进入 Vivado 界面后,点击 Tasks 栏中的 “Manage IP” 。在弹出的选项中选择 “New IP Location”,然后设置 Manage IP 核的属性,指定工程路径,路径为:F:/ZYNQ/ Embedded_Vitis/custom_ip,其它保持默认即可。点击“Finish”完成 Manage IP 工程的创建。注意,Part 一栏中设置开发板的型号,在后面的工程中可以重新指定,这里直接保持默认。

2.创建IP

        (1)创建一个新IP:点击菜单 栏的“Tools”,选择“Create and Package New IP”。

        接下来选择封装 IP 或者创建一个带 AXI4 接口的 IP 核,因为 PL与 PS 端需通过 AXI 接口通信,这里选择创建一个带 AXI 接口的 IP 核,选中“Creat a new AXI4 peripheral”

       设置IP名称、版本、显示名称、描述、存放路径,这里直接设置名称其他保持默认即可,存放路径默认位于当前IP管理工程目录下。

        (2)AXI接口设置:

配置项选项/值说明
Name(名称)S0_AXI设置接口名称
Interface Type(接口类型)Lite

Lite、Full 和 Stream三种接口类型可选:

AXI4-Lite 接口是简化版的 AXI4 接口,用于较少数据量的存储映射通信;AXI4-Full 接口是高性能存储映射接口,用于较多数据量的存储映射通信;AXI4-Stream 用于高速数据流传输,非存储映射接口。

本次实验只需少量数据的通信,因此接口类型选择 Lite 接口。

Interface Mode(接口模式)Slave接口模式有 Slave(从机)和 Master(主机)两种模式可选,AXI 协议是主机和从机通过“握手”的方式建立连接,这里选择默认的 Slave 接口模式。

Data Width

(数据宽度)

32位数据位宽保持默认,即 32 位位宽。

Memory Size

(存储器大小)

不可设置在 AXI4-Lite 接口模式下,该选项不可设置。

Number of Registers

(寄存器数量)

默认值配置寄存器的数量,在嵌入式软件如C代码中,可以通过读写这些寄存器的地址来控制 IP 核或获取 IP 核状态等操作。

这里数量足够,保持默认。

         创建完成,可以在IP目录看到多了一个用户IP目录,下面是vivado自带的IP目录:

3.编辑IP

        (1)操作如图所示,命名和工程路径保持默认即可。

       (2) 进入IP工程后打开模块文件,顶层文件已经对 AXI 接口模块进行了例化,下面还有实现 AXI接口模块.

        两个模块都可以根据用户需求进行自定义修改:包括自定义参数、端口、逻辑功能。需注意原有的代码不要修改,一般只进行功能添加。

        也可以添加设计源文件编写自定义功能,再进行例化。

        (2)直接新建一个设计源文件,以实现LED呼吸灯功能。存放路径在管理IP工程的目录下的一个名为hdl目录中(可以看到自带的顶层模块文件和 AXI 接口模块文件都存放在这里)

        (3)设计好LED呼吸灯模块代码后(传送门:LED呼吸灯模块),将其例化到 AXI 接口模块中,并添加相应的自定义端口及参数,如图所示通过读写模块内寄存器对自定义IP进行控制,这些寄存器已经在前面步骤配置过。

        在 AXI 接口模块中例化自定义模块、添加输出端口、添加参数定义

        在顶层模块中补全模块例化端口及参数、添加自定义端口、添加参数定义

        (4)保存后进行综合、综合通过。

4.打包IP

        (1)开始设置 IP 封装,将界面切换至 Package IP,如果关闭的话,可以通过 IP-XACT 界面下的 component.xml 重新打开。

        首先是IP信息:名称、版本、显示名、描述、IP在目录(Categories),这里都保持默认。

        (2)第二栏添加IP支持芯片型号,点击 Family 一栏下的“+”图标,选择“Add Family Explicitly”这里勾选“zynq(zynq-7000)”,表示该 IP 核支持 zynq 器件。Life-cycle 当前IP产品生命周期,这里选择“Pre-Production”(不知道有什么用)。如图所示因为之前添加过了所以已经显示有ZYNQ系列了。

        (3)配置参数栏:点击界面上的“Merge Changes from Gile Groups Wizard”,如下图所示:

        然后会出现自定义参数栏,双击配置,弹出页面勾选“Visible in Customization GUI”,将此参数显示在 GUI 参数界面中; Format 格式“long”; 勾选“Specify Range”来设定此参数范围。将 Type 改为“Range of integers”,范围和默认值根据自己模块参数设置,点击“OK”。(之后参数将移动到上面一栏的参数中)

        (4)在GUI一栏中就可以预览IP了:包括端口、参数。最后点击打包IP按钮进行封装。        成功后就可以关闭工程界面了。

        (5)IP 封装完成后,在 IP 所在路径:(...\custom_ip\ip_repo\breath_led_ip_1.0\drivers\breath_led_ip_v1_0\src) 目录下,Vivado 软件会自动生成.c 和.h 文件,方便在 Vitis 软件中对 IP 核进行操作,如下图所示:

        注意 : 在Vitis 开发环境下,上图中 Makefile 文件里的语句是需要修改的,如果不修改,当包含该 IP 的硬件(xsa)文件导出 到 vitis 后,对 vitis 工程进行编译就会报错,报错信息为“xxx.h: No such file or directory”。因此需要在使用该 IP 前完成修改: Makefile 修改方法

5.使用IP

        创建完成后,在工程中添加IP目录中是没有自定义IP的,需要手动进行关联:

        途中勾选需要添加的IP,最后点击OK。

        最后就能在IP目录里面找到自定义的IP进行使用了,需要修改IP也可以直接右键进行编辑IP。

三、硬件设计

整体设计框架

        注意: IP 在 PL 端实现的 ,LED是通过 IP 直接控制的,LED不属于GPIO。

        (1)ZYNQ 的配置需要注意使用到了AXI协议接口,PL端时钟接口、复位接口都需要保留,此外的一些配置不再赘述,如Bank电压、UART串口配置(用于debug)等等。

        (2)如图所示为自定义的 LED 呼吸灯 IP 配置,可以设置默认参数。

        (3)PS端输出给PL端的时钟(M_AXI_GP0_ACLK)根据IP的时钟要求进行设置,本次选着PLL产生的100MHz时钟以驱动PL端IP。

        (4)最后整体 bd 设计部分如图所示:设计检查、Generate Output Products、 Create HDL Wrapper、管脚约束、Gnerate Bitstream、Export Hardware(包含比特流文件)、启动Vitis

四、软件设计

        因为需要对自定义IP的寄存器进行读写,实现控制效果,使用到的读写函数在图示目录下查看,在头文件可以看到写寄存器函数定义(其他函数定义也在里面),设计时通过定义的读写函数对寄存器进行操作。

        自定义 IP 的各寄存器地址偏移量在上述的头文件可以看到,而 IP 的基地址可以在"xparameters.h"中查找到,如图所示:

        宏定义控制信号寄存器偏移量时,需要和前面的硬件设计向对应:slv_reg0第0位控制LED灯开启和关闭、slv_reg1第0位控制设置呼吸灯速率的使能,slv_reg2第3位设置呼吸灯速率。

#include "breath_led_IP.h"  //自定义IP头文件(包含对IP寄存器进行读写的函数)
#include "xil_printf.h"
#include "xparameters.h"
#include "sleep.h"

//======================用户自定义宏======================//

#define LED_IP		XPAR_BREATH_LED_IP_0_S0_AXI_BASEADDR //宏定义breath_led_IP寄存器基地址

#define LED_EN		BREATH_LED_IP_S0_AXI_SLV_REG0_OFFSET //宏定义led_en  对应寄存器(slv_reg0)地址偏移量
#define SPEED_EN	BREATH_LED_IP_S0_AXI_SLV_REG1_OFFSET //宏定义speed_en对应寄存器(slv_reg1)地址偏移量
#define SPEED		BREATH_LED_IP_S0_AXI_SLV_REG2_OFFSET //宏定义speed   对应寄存器(slv_reg2)地址偏移量

//======================主函数======================//
int main()
{
	u32 speed = 0x0;

	xil_printf("LED Breath IP Test! \r\n");

	BREATH_LED_IP_mWriteReg(LED_IP, LED_EN, 0x1); //打开LED呼吸灯

	for (int i=0 ; i<8 ; i++)  //每两秒切换一次速率并串口打印
	{
		BREATH_LED_IP_mWriteReg(LED_IP, SPEED_EN, 0x1); //使能呼吸灯速率设置
		BREATH_LED_IP_mWriteReg(LED_IP, SPEED,  speed); //设置LED呼吸速率
		BREATH_LED_IP_mWriteReg(LED_IP, SPEED_EN, 0x0); //屏蔽呼吸灯速率设置
		speed += 0x1;
		xil_printf("Current Speed: %d\r\n",
				BREATH_LED_IP_mReadReg(LED_IP, SPEED)); //打印呼吸灯当前速率
		sleep(2);//延时2s
	}

	BREATH_LED_IP_mWriteReg(LED_IP, LED_EN,   0x0);	//关闭LED呼吸灯

	return 0;
}

五、效果

        上板后串口打印debug信息,之后每两秒LED呼吸灯速率加快一次同时串口打印当前速率,遍历完所有速度等级后(8个),LED灯熄灭。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值