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

文章目录

  • 自定义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.mzph.cn/web/2679.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java使用XStream将压缩成gz格式xml文件转换成List详解及问题

Java使用XStream将压缩成gz格式xml文件转换成List详解及问题 前言 这次说是写文章,感觉更是像填坑,几年前我就写过vo对象list转换成xml并压缩的相关文章 Java将数据生成XML文件并进行压缩成GZ格式 那会都没发现没有怎么解压缩,一个工具类整整写了一天,遇到了很多问题,…

机器人自动驾驶时间同步进阶

0. 简介 之前时间同步也写过一篇文章介绍机器人&自动驾驶中的时间同步。在最近的学习中发现一些额外需要阐述学习的内容&#xff0c;这里就再次写一些之前没写到的内容。 1. NTP NTP 是网络时间协议&#xff0c;用来同步网络中各计算机时间的协议&#xff0c;把计算机的时…

「PHP系列」PHP 发送电子邮件详解

文章目录 一、PHP发送电子邮件二、PHP mail() 函数1. 函数原型2. 参数说明3. 返回值4. 常见的 $headers 属性5. 注意事项6. 示例 三、相关链接 一、PHP发送电子邮件 在 PHP 中&#xff0c;你可以使用内置的 mail() 函数来发送电子邮件。然而&#xff0c;mail() 函数在发送邮件…

FPGA verilog 模板设计示例(持续更新)

重温一下大道至简的至简设计法&#xff0c;正式开发两年多回顾当时的设计方法&#xff0c;又有了更多的体会和感触&#xff0c;希望将模块化运用起来会更有条例。1 FPGA设计代码模板 信号命名规范&#xff1a; 1 clk 表示时钟信号小写 2 rstn 表示高电平复位信号 小写 3 rst_n…

品牌差异化战略:Kompas.ai如何打造独特的内容声音

在当今竞争激烈的商业环境中&#xff0c;品牌差异化已成为企业获取市场优势的关键策略。一个鲜明的品牌形象和独特的内容声音不仅能够帮助企业吸引目标客户&#xff0c;还能够在消费者心中建立起独特的地位。本文将深入探讨品牌差异化的重要性&#xff0c;分析Kompas.ai如何帮助…

centos操作命令

CentOS操作命令包括但不限于以下几种&#xff1a; 系统操作命令&#xff1a; 关机、重启及登出&#xff1a; shutdown -h now&#xff1a;关闭系统。init 0 或 telinit 0&#xff1a;关闭系统。shutdown -r now&#xff1a;重启系统。reboot&#xff1a;重启系统。logout&…

Ubuntu搭建Python虚拟环境:virtualenv

1 缘起 一阶段&#xff1a;Python开发&#xff0c;使用Windows环境&#xff0c;使用的相关依赖在Windows环境都能使用&#xff1b; 进入二阶段&#xff0c;开发了一个新功能&#xff0c;使用了k8s&#xff0c;Python依赖为&#xff1a;easy_k8s&#xff0c; 刚好&#xff0c;e…

揭秘 IDM:下载管理大师的全面指南与实用技巧深度解析

IDM&#xff08;Internet Download Manager&#xff09;是一款流行的下载管理软件&#xff0c;它可以帮助用户以更快的速度下载文件&#xff0c;并且支持多种协议和浏览器。IDM 通过将大文件分割成多个部分并同时下载这些部分来加快下载速度&#xff0c;这种技术被称为多线程下…

Linux中手工创建一个用户

当我们需要新创建一个用户时&#xff0c;有两种方法 1&#xff0c;使用useradd命令&#xff1a; [rootlocalhost /]# useradd tmg 然后给它设置一个密码 [rootlocalhost etc]# passwd tmg Changing password for user tmg. New password: BAD PASSWORD: The password is a…

通过 USB 或网络控制安卓设备:无需 root 权限 | 开源日报 No.231

barry-ran/QtScrcpy Stars: 15.6k License: Apache-2.0 QtScrcpy 是一款支持通过 USB 或网络显示和控制 Android 设备的实时显示控制软件&#xff0c;不需要 root 权限。 其主要功能和优势包括&#xff1a; 轻量化&#xff08;仅显示设备屏幕&#xff09;高性能&#xff08;3…

RAG:智能图书馆员引领AI的知识之旅

想象一下&#xff0c;你是一个法官&#xff0c;面对一个复杂的案件&#xff0c;你需要查阅大量的法律文献来找到相关的案例和法律条文。在AI的世界里&#xff0c;也有一个类似的“法官”——大型语言模型&#xff08;LLMs&#xff09;。它们能够回答各种问题&#xff0c;但有时…

vue 表格获取当前行索引,加颜色

vue 表格获取当前行索引&#xff0c;加颜色 <span styledisplay:inline-block;width:10px;height:10px;border-radius:50% :style"{background:color[scope.$index]}" />//定义颜色color: [#5387F7, #A794E0, #F3543C, #999999, #77D3F8, #FFA1B4, #26CEBA, #…

关于Linux系统的配置文件(UBOOT、Kernel、rootfs)

对于编译 U-Boot、内核和根文件系统&#xff0c;每个部分都需要相应的配置文件&#xff0c;这些配置文件指定了编译过程中的选项、参数和设置。以下是每个部分的配置文件中可能包含的内容&#xff1a; U-Boot 配置文件&#xff08;一般是 config.mk 或 defconfig 文件&#xf…

【k8s】(一)kubernetes1.29.4离线部署之-安装文件准备

&#xff08;一&#xff09;kubernetes1.29.4离线部署之-安装文件准备 &#xff08;二&#xff09;kubernetes1.29.4离线部署之-镜像文件准备 &#xff08;三&#xff09;kubernetes1.29.4离线部署之-环境初始化 &#xff08;四&#xff09;kubernetes1.29.4离线部署之-组件安装…

C++从入门到精通——C++动态内存管理

C动态内存管理 前言一、C/C内存分布分类1分类2题目选择题sizeof 和 strlen 区别示例sizeofstrlen 二、C语言中动态内存管理方式malloc/calloc/realloc/free示例例题malloc/calloc/realloc的区别malloc的实现原理 三、C内存管理方式new/delete操作内置类型new和delete操作自定义…

vue3 引入@tsparticles/vue3和@tsparticles/slim 实现粒子特效

1.安装&#xff1a; yarn add tsparticles/vue3 tsparticles/slim2.main.ts 引入 import Particles from "tsparticles/vue3"; import { loadSlim } from "tsparticles/slim";app.use(Particles as any, {init: async (engine: any) > {await loadSli…

力扣刷题 70.爬楼梯

题干 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法可以爬到楼顶。 1. 1 阶 1 阶 2. 2 阶 示例 2&…

电子邮件免费版有哪些?免费注册电子邮箱

电子邮件有付费版和免费版两种类型&#xff0c;付费版通常具有更大的电子邮箱容量和更强大的电子邮箱功能。但是对于我们个人用户或者是中小型企业来说注册电子邮箱免费版的就够日常使用了。电子邮件的免费版提供商有Zoho Mail、微软、腾讯等&#xff0c;今天我们就来具体了解下…

探索简站WordPress主题:jianzhanpress.com的魅力所在

着互联网的普及和发展&#xff0c;越来越多的人开始关注网站建设。作为最受欢迎的内容管理系统之一&#xff0c;WordPress为无数站长提供了便捷、高效的建站体验。而在众多WordPress主题资源中&#xff0c;jianzhanpress.com以其丰富的主题数量和高质的设计赢得了广大WordPress…

Ubuntu系统的初始化

1. 更新系统 sudo apt update && sudo apt upgrade -y2. 安装必要的软件包 sudo apt install -y build-essential curl git vim3. 配置SSH sudo apt install -y openssh-server sudo systemctl enable ssh sudo systemctl start ssh4. 配置时间同步 sudo apt insta…