ZYNQ之嵌入式开发04——自定义IP核实现呼吸灯、固化程序

news/2024/5/20 12:05:16

文章目录

  • 自定义IP核——呼吸灯实验
  • 固化程序

自定义IP核——呼吸灯实验

Xilinx官方提供了很多IP核,在Vivado的IP Catalog中可以查看这些IP核,在构建自己复杂的系统时,只使用Xilinx官方的免费IP核一般满足不了设计的要求,因此很多时候需要用户自定义IP核。自定义IP核有很多好处,比如可以定制系统设计和复用,可以在IP核中加入license有偿提供给别人使用,简化系统设计等。用ZYNQ系统设计IP核,最常用的就是使用AXI总线将PS同PL部分的IP核连接起来。
本实验将通过自定义一个LED IP核来控制PL LED呈现呼吸灯的效果,并且PS端可以通过AXI接口来控制呼吸灯的开关和呼吸的频率。
在创建工程之前先创建一个自定义IP核的存放位置。
在这里插入图片描述
选择创建AXI4接口。
在这里插入图片描述
可以自定义一个IP核的名称。
在这里插入图片描述
这里保持默认设置即可。
在这里插入图片描述
信息汇总界面,点击Finish即可完成创建。
在这里插入图片描述
创建完成后就可以在IP库中看到自定义的AXI接口了。
在这里插入图片描述
在该条目上右键选择Edit in IP Packager,选择默认,点击OK后就打开了下图所示的新界面。
在这里插入图片描述
添加一个呼吸灯源文件,位置就存放在自定义IP核的目录下。
在这里插入图片描述
在新建的源文件中添加下面的Verilog代码,其作用是实现呼吸灯。

`timescale 1ns / 1ps
module breath_led(input sys_clk,   //时钟信号input sys_rst,  //复位信号input sw_ctrl,  //呼吸灯开关控制信号input set_en,  //设置呼吸灯频率设置使能信号input [9:0] set_freq_step,  //设置呼吸灯频率变化步长output led
);parameter START_FREQ_STEP = 10'd100;   //设置频率步长初始值
reg [15:0] period_cnt;   //周期计数器
reg [9:0] freq_step;  //呼吸灯频率间隔步长
reg [15:0] duty_cycle;  //设置高电平占空比的计数点
reg inc_dec_flag;  //用于表示高电平占空比的计数值,1-递减,0-递增
wire led_t;assign led_t = (period_cnt <= duty_cycle)?1'b1:1'b0;  
//assign led = led_t & sw_ctrl;    //LED是高电平点亮
assign led = ~(led_t & sw_ctrl);    //LED是低电平点亮always@(posedge sys_clk) beginif(!sys_rst || !sw_ctrl || period_cnt == 16'd50000)  //周期信号计数器在0-50000之间period_cnt <= 16'd0;elseperiod_cnt <= period_cnt + 16'd1;
endalways@(posedge sys_clk) begin    //设置频率间隔,在1-1000之间if(!sys_rst)freq_step <= START_FREQ_STEP;else if(set_en) beginif(set_freq_step == 0)freq_step <= 10'd1;else if(set_freq_step > 10'd1000)freq_step <= 10'd1000;elsefreq_step <= set_freq_step;end
endalways@(posedge sys_clk) begin   //设定高电平占空比的计数值if(sys_rst == 1'b0 || !sw_ctrl) beginduty_cycle <= 16'd0;inc_dec_flag <= 1'b0;endelse if(period_cnt == 16'd50000) begin   //计数满一个周期就调节占空比if(inc_dec_flag) begin  //占空比递减if(duty_cycle == 16'd0)inc_dec_flag <= 1'b0;  //减至0开始递增else if(duty_cycle < freq_step)duty_cycle <= 16'd0;elseduty_cycle <= duty_cycle - freq_step;endelse beginif(duty_cycle >= 16'd50000)inc_dec_flag <= 1'b1;    //加到最大开始递减else duty_cycle <= duty_cycle + freq_step;endendelseduty_cycle <= duty_cycle;  //计数不满一个周期时,占空比保持不变
end   
endmodule

在顶层和第二层的.v文件中都添加下面的内容。
在这里插入图片描述
在顶层文件中例化AXI总线接口处添加下面的代码。
在这里插入图片描述
在第二层.v文件的endmodule之前添加下面的例化代码。

	// Add user logic here
breath_led #(.START_FREQ_STEP(START_FREQ_STEP))u_breath_led(.sys_clk(S_AXI_ACLK),.sys_rst(S_AXI_ARESETN),.sw_ctrl(slv_reg0[0]),    //reg0的最低位是开关.set_en(slv_reg1[31]),    //reg1的最高位是设置频率步长使能.set_freq_step(slv_reg1[9:0]),   //reg1的低10位是设置频率步长.led(led));

代码添加完成之后跑一下综合,没有问题就可以进行后续操作了。
在这里插入图片描述
打开IP核封装界面。
在这里插入图片描述
在兼容性这一项中添加ZYNQ芯片族。
在这里插入图片描述
对自定义的参数进行设置,使其可见。
在这里插入图片描述
重新封装自定义IP,然后关闭该工程。
在这里插入图片描述
接下来创建一个呼吸灯的工程,步骤和之前的类似。
在这里插入图片描述
工程创建完毕之后,将自定义的IP核添加进来。
在这里插入图片描述
添加成功后就可以在IP库中看到自定义的IP核了。
在这里插入图片描述
随后点击Create Block Design进入IP核配置界面。
在这里插入图片描述
添加ZYNQ IP核,添加UART口并配置DDR,添加自定义的呼吸灯IP核,双击后可以修改其开始频率步长。
在这里插入图片描述
两个IP核创建成功之后让其自动连接,同时在led口上右击选择Make External添加端口。
在这里插入图片描述
验证框图没有问题后就可以生成输出产品和HDL封装,给led端口分配管脚,完成后就可以生成比特流文件了。导出硬件,然后启动SDK进行代码编程。
在xparameters.h文件中找到自定义IP核的相关定义如下。

#define XPAR_BREATH_LED_IP_0_DEVICE_ID 0
#define XPAR_BREATH_LED_IP_0_S0_AXI_BASEADDR 0x43C00000
#define XPAR_BREATH_LED_IP_0_S0_AXI_HIGHADDR 0x43C0FFFF

在BSP目录下生成了自定义IP核相关的C代码,在编写程序的时候可以参考。
在这里插入图片描述
最终SDK端编写的C代码如下。

#include "stdio.h"
#include "xparameters.h"
#include "breath_led_ip.h"
#include "xil_io.h"
#include "sleep.h"#define  LED_IP_BASEADDR   XPAR_BREATH_LED_IP_0_S0_AXI_BASEADDR
#define  LED_IP_REG0   BREATH_LED_IP_S0_AXI_SLV_REG0_OFFSET
#define  LED_IP_REG1   BREATH_LED_IP_S0_AXI_SLV_REG1_OFFSETint main()
{printf("breath_led test!\n");int set_freq_flag = 0;int led_state;while(1){if(set_freq_flag == 0){BREATH_LED_IP_mWriteReg(LED_IP_BASEADDR, LED_IP_REG1, 0x800000ff);  //最高位要使能,设置频率步长为255set_freq_flag = 1;}else{BREATH_LED_IP_mWriteReg(LED_IP_BASEADDR, LED_IP_REG1, 0x8000001f);  //设置频率步长为31set_freq_flag = 0;}led_state = BREATH_LED_IP_mReadReg(LED_IP_BASEADDR, LED_IP_REG0);if(led_state == 0){//打开呼吸灯BREATH_LED_IP_mWriteReg(LED_IP_BASEADDR, LED_IP_REG0, 1);printf("Breath led on!\n");}sleep(5);led_state = BREATH_LED_IP_mReadReg(LED_IP_BASEADDR, LED_IP_REG0);if(led_state == 1){//关闭呼吸灯![请添加图片描述](https://img-blog.csdnimg.cn/direct/00281d89d6de4ad5a24be9e407bfeaf7.gif)BREATH_LED_IP_mWriteReg(LED_IP_BASEADDR, LED_IP_REG0, 0);printf("Breath led off!\n");}sleep(1);}return 0;
}

通过给相应的寄存器写值设置频率步长或者打开关闭呼吸灯。最终开发板上的验证效果如下动图所示。
请添加图片描述
在SDK终端窗口中也交替打印了程序中设置的语句,如下图所示。
在这里插入图片描述
如果自定义的IP核需要修改Verilog代码,需要在框图上右击选择Edit in IP Packager,然后找到相应的位置修改,完成后需要在框图界面重新加载,将代码中所做的更新同步到框图中,然后重新生成产品和比特流文件,导出到硬件,然后启动SDK编程。


固化程序

固化程序的例子以呼吸灯实验为例,拷贝该项目,然后打开拷贝的项目进行操作。为了让开发板支持从SD卡启动,也支持从Flash启动,需要先对IP核进行相关配置。
SD卡在原理图中的连接如下图所示。
在这里插入图片描述
对照原理图勾选Flash和SD卡外设。
在这里插入图片描述
依照原理图,Bank0设置为3.3V,Bank1设置为1.8V。
在这里插入图片描述
配置完成后生成输出产品,然后生成比特流文件,导出到硬件,启动SDK,将源文件添加进去,在bsp文件目录上右击进行板级支持包设置,勾选赛灵斯文件系统,点击OK。
在这里插入图片描述
创建一个新工程,命名为FSBL(First Stage Bootloader,第一阶段引导加载程序),如下图所示。
在这里插入图片描述
点击下一步,选择ZYNQ模板工程。
在这里插入图片描述
FSBL文件目录下包含了很多文件,这里保持默认即可,然后选中工程文件名,点击菜单栏Xilinx,点击Create Boot Image,生成文件BOOT.bin,该文件是由FSBL、比特流、elf三个文件合成的。
在这里插入图片描述
在工程中的bootimage文件夹中就生成了BOOT.bin文件,将其拷贝到SD卡中。
在这里插入图片描述
断开开发板的JTAG线,UART线也断开,只给开发板连接电源线即可,将SD卡插入到开发板的卡槽中,然后启动开发板,开发板上电后,LED就已经开始以呼吸灯的状态工作了,开发板上运行结果和上面一致,这就说明程序固化成功了。
如果要固化到Flash中,需要给开发板连接JTAG线并上电,然后点击菜单栏Xilinx—>Program Flash,按照下图进行配置。
在这里插入图片描述
如果在烧写时碰到下面的错误,可能是你开发板的模式设置不正确,调整开发板上的跳帽到JTAG模式。
在这里插入图片描述
中断打印下面的语句就下载成功了!
在这里插入图片描述
然后关闭电源,将跳帽改到QSPI启动,但是这个时候又出现问题了,程序并没有像预想的那样在开发板上执行。
划重点,这里我鼓捣了半天才整明白!
FSBL文件夹下main.c一改动就会自动编译生成FSBL.elf文件,而这个文件是生成BOOT.bin的文件之一,与此同时,这个文件也是烧写Flash时需要用到的文件。把程序烧写进Flash时需要使用JTAG接口,因此需要在FSBL文件夹下的main.c文件中的第386行添加下面的代码。

BootModeRegister = JTAG_MODE;

添加完成后保存,就会自动生成FSBL.elf文件。
在这里插入图片描述
然后使用把这个FSBL.elf文件和前面生成的BOOT.bin通过JTAG接口烧写到Flash中,然后断电,改变跳帽位置,就可以从Flash启动了。这里重点要强调的是,生成BOOT.bin文件时,用的FSBL.elf文件不需要添加那一行代码,而通过JTAG接口烧写到Flash时的FSBL.elf文件则必须要添加那一行代码。
烧写成功之后,改变跳帽到QSPI,开发板只连接电源线,上电之后的结果如下动图所示。
请添加图片描述
这就说明开发板从Flash启动成功了!


参考视频:
正点原子手把手教你学ZYNQ之嵌入式开发


http://www.mrgr.cn/p/88471284

相关文章

Android Dalvik虚拟机JNI方法的注册过程分析

Dalvik虚拟机在调用一个成员函数的时候&#xff0c;如果发现该成员函数是一个JNI方法&#xff0c;那么就会直接跳到它的地址去执行。也就是说&#xff0c;JNI方法是直接在本地操作系统上执行的&#xff0c;而不是由Dalvik虚拟机解释器执行。由此也可看出&#xff0c;JNI方法是A…

STM32H750时钟频率和功耗以及RTC功能测试

STM32H750时钟频率和功耗和RTC功能测试 &#x1f4cc;相关篇《STM32H750片外QSPI启动配置简要》 ✨在使用STM32CubeMX修改STM32H750时钟树参数时&#xff0c;如果使用软件自动求解&#xff0c;这是一个非常耗时的操作&#xff0c;有时候还不一定成功&#xff0c;还是推荐使用手…

数据库中间件-He3Proxy

什么是数据库中间件? 随着互联网行业的蓬勃发展,业务访问量、数据量激增,传统数据库的单库、大表已成为业务发展的瓶颈,进而衍生出数据库主从实例、分库分表等方案,为减少数据库层变动对业务开发带来的复杂性,一种连接应用与数据库桥梁的工具孕育而生,即数据库中间件,它…

JAVA前端快速入门基础_javascript入门(01)

写在前面:本文用于快速学会简易的JS&#xff0c;仅做扫盲和参考作用 1.JS是什么 JavaScript是一门跨平台&#xff0c;面向对象的脚本语言(即不需要编译&#xff0c;可以直接通过浏览器进行解释)。JS和Java是两门完全不相同的语言&#xff0c;但是基础的语法是类似的 2.JS的引…

MySQL学习之explain

from之后的查询得到的表叫做衍生表,是临时表数据,生成临时表之后的数据是无法使用索引的,如果数据量大查询效率就会比较低,这就是查询要尽量少使用子查询这些临时表。explain详解 id: 表示查询序号,也可以表示优先级;当值都不一样的时候,值越大表示优先级越高,越先执行…

实验12-使用keras预训练模型完成猫狗识别

版本python3.7 tensorflow版本为tensorflow-gpu版本2.6 运行结果: 这里我用Gpu进行加速,训练一回9秒,如果不启用gpu,训练一回会很慢。 代码:#-*- codeing = utf-8 -*- #@Time : 2022/10/2 11:44 #@Author : 程浩 #@File : 猫狗识别.py #@Software: PyCharm import tensor…

KVM虚拟机迁移(静态)

1.查看虚拟机状态,确认关闭状态 virsh list --all 2.查看虚拟机文件位置 virsh domblklist zabbix3.导出配置文件并查看导出文件 virsh dumpxml zabbix > /root/zabbix.xml 4.把刚导出的配置文件传到目的服务制定路径(路径为虚拟机配置文件位置)scp zabbix.xml 10.10.7.1…

实验11-使用keras完成逻辑回归

版本python3.7 tensorflow版本为tensorflow-gpu版本2.6 运行结果: 代码:import numpy as npfrom keras.models import Sequential from keras.layers import Dense, Dropout, Activation, Flatten import matplotlib.pyplot as plt from sklearn import datasets# 样本数据集…

【工具-PyCharm】

工具-PyCharm ■ PyCharm-简介■ PyCharm-安装■ PyCharm-使用■ 修改主题■ 设置字体■ 代码模板■ 解释器配置■ 文件默认编码■ 快捷键■ 折叠■ 移动■ 注释■ 编辑■ 删除■ 查看■ 缩进■ 替换 ■ PyCharm-简介 官方下载地址 Professional&#xff1a;专业版&#xff0…

Linux KASAN使用与实现原理

一、KASAN工具使用 KASAN工具&#xff1a;Kernel Address SANitizer(KASAN)是一种动态内存安全错误检测工具&#xff0c;主要功能是检查内存越界访问和使用已释放内存的问题。 1.1 KASAN宏控开关 KASAN有三种模式&#xff1a;1.通用KASAN&#xff1b;2.基于软件标签的KASAN&…

实验8-1tensorboard可视化+实验8-2tensorboard案例

版本python3.7 tensorflow版本为tensorflow-gpu版本2.6 实验8-1tensorboard可视化运行结果:代码:import tensorflow as tf# 创建默认图 graph = tf.compat.v1.get_default_graph()# 定义命名空间 with graph.as_default():with tf.name_scope(input):# fetch:就是同时运行多…

科技论文网站:中国科技论文在线

文章目录 1. Intro2. Main3. Cons Evaluation彩蛋&#xff1a;科学素质 这是作者最后一次发 这种类型的宣传 科普文章 1. Intro 中国科技论文在线是经教育部批准&#xff0c;由教育部科技发展中心主办&#xff0c; 利用现代信息技术手段&#xff0c;打破传统出版物的概念&…

虚方法

若一个实例方法声明前带有virtual关键字,那么这个方法就是虚方法。虚方法与非虚方法的最大不同是,虚方法的实现可以由派生类所取代,这种取代是通过方法的重写实现的(以后再讲)虚方法的特点:虚方法前不允许有static,abstract,或override修饰符虚方法不能是私有的,因此不能…

【Vue】如何使用Webpack实现打包操作

一、Webpack介绍 Webpack最主要的作用就是打包操作&#xff0c;由两个核心部分构成分别是“出口”与“入口”。wbepack是现在比较热门的打包工具了&#xff0c;它可以将许多松散耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源。说的直白一点&#xff0c;通过webpac…

RPC(远程过程调用)详解

一、RPC是什么 RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。 二、RPC需要解决的问题 1、Call ID映射 我们怎么告诉远…

【基础算法总结】双指针算法二

双指针 1.有效三角形的个数2.和为S的两个数字3.和为S的两个数字4.四数之和 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.有效三角形的个数…

前端工程化Vue使用Node.js设置国内高速npm镜像源(踩坑记录版)

前端工程化Vue使用Node.js设置国内高速npm镜像源&#xff08;踩坑记录版&#xff09; 此篇仅为踩坑记录&#xff0c;并未成功更换高速镜像源&#xff0c;实际解决方法见文末跳转链接。 1.自身源镜像 自身镜像源创建Vue项目下载速度感人 2.更改镜像源 2.1 通过命令行配置 前提…

京东web端h5st—4.7逆向分析

声明 本文章中所有内容仅供学习交流,抓包内容、敏感网址、数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 目标网站 aHR0cHM6Ly93d3cuamQuY29tLw== 分析流程了解h5st 看了sha256相关加密算法逻辑b…

API和微服务设计的优化方式有哪些?

在构建响应迅速、用户体验良好的应用程序中&#xff0c;API性能的优化至关重要。在构建高性能的API时&#xff0c;采取综合策略是至关重要的。通过采用一系列策略&#xff0c;我们可以确保API在处理请求时高效运行&#xff0c;提供流畅的服务。 一、API和微服务设计的优化可以…

XYCTF2024-web-wp

怎么全是傻逼绕过题。 不想评价,就随便打着玩,除了最后一道java反序列化搞心态,其他的ak了:简单题不想说,http注意一下代理是用Via就行,warmup直接:http://xyctf.top:37034/?val1=240610708&val2=QNKCDZO&md5=0e215962017&XYCTF=240610708&XY=24061070…