当前位置: 首页 > news >正文

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灯熄灭。

相关文章:

  • [特殊字符] 第十二讲 | 地统计学基础与克里金插值法(Kriging)建模实践
  • JavaScript异常机制与严格模式
  • 源码编译 Galera、MySQL 5.7 Wsrep 和安装 MySQL 5.7 Galera集群
  • JavaScript数组方法:`some()`的全面解析与应用
  • 简单使用linux
  • 论文精度:基于LVNet的高效混合架构:多帧红外小目标检测新突破
  • python推箱子游戏
  • Linux进阶命令
  • Linux 进程内存监控:Linux 内存调优之进程内存深度监控
  • 使用freebsd-update 升级FreeBSD从FreeBSD 14.1-RELEASE-p5到FreeBSD 14.2-RELEASE
  • 现代处理器的调度策略,调度优先级,亲和性是什么意思?
  • Python中for循环及其相关函数range(), zip(), enumerate()等
  • Docker部署jenkins
  • 深度解析:如何高效识别并定位问题关键词
  • C#打开文件及目录脚本
  • Ubuntu 系统深度清理:彻底卸载 Redis 服务及残留配置
  • 工程师 - 场效应管分类
  • Python使用闭包实现不修改源码添加功能详解
  • 权限的概念
  • 明明包含了头文件,为何还是显示未定义错误?
  • 网站流量排名 全球/上海关键词优化排名软件
  • 怎么把个人做的网站上传到网上/重庆网络推广
  • 做网站的大型公司/百度站长平台账号购买
  • 广州动态网站开发/写软文的app
  • 比利时网站的后缀/百度网站怎么提升排名
  • 做酒的网站/百度健康人工客服电话24小时