ZYNQ7000系列学习之自定义模块构成IP
Posted electricdream
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZYNQ7000系列学习之自定义模块构成IP相关的知识,希望对你有一定的参考价值。
ZYNQ的自定义IP
1、实验原理
在vivado中可以将自己写的verilog模块封装成IP核,并入bd设计,有效地提高了PS到PL的设计内联能力。同时,这部分的学习可以将verilog的基础知识转移到嵌入式设计中。所以,这是一个基本的能力。
2、实验操作
一、创建工程
这一步根据自己的开发板选型即可。没有特殊的设置。
二、新建文件
在source的hierarchy(层次)中添加文件user_gpio.v,就是通过自定义的模块实现GPIO的传输。模块的功能很简单,就是将输入连到输出。
module user_gpio( input wire gpio_in, input wire [3:0] ps_gpio_in, output wire gpio_out, output wire [3:0] ps_gpio_out ); assign gpio_out = gpio_in; assign ps_gpio_out[3:0] = ps_gpio_in[3:0]; endmodule
代码参考小熊猫课堂。
三、基于AXI总线的IP打包
基于AXI总线的IP打包可以将IP快速地部署到总线上,可以与总线上的其他设备充分交互,自然也可以通过总线的引脚接出芯片。
tool》【单击】create and package new IP》next》【选择】Create AXI4 Peripheral》next》 寄存器数量选择4》【选择】edit》finish
在新弹出的窗口中,就是IP核的编辑界面,其与工程界面分立,说明不依赖于特定工程存在。
在这个窗口可以编辑AXI总线IP核。
和verilog的模块间的调用一样,在IP核的顶端和子模块中加入端口声明也是端口输入输出,例化用点连接。值得注意的是,这里只例化两个端口gpio_in和gpio_out,而对于ZYNQ内核端的输入输出信号在这里并不连接,作为空置引脚。在后面会连接到寄存器。
为了使AXI寄存器控制起效和简洁,需要更改某些寄存器的设置。
在如图所示的位置更改112~114三行代码。从reg变成wire应该好理解,我们做的模块功能单一,不需要使用reg变量实现控制的目的。其他两个变量则是多余的变量。从前面寄存器数量最小为4可以得到,该IP设计默认至少使用4个寄存器,而我们这里太简单,只需两个,所以需要手动删除。
改完之后将下面所有的报错点屏蔽掉,即可完成配置。
这里也从一个侧面说明几个寄存器之间不存在直接关联。
在子模块的尾部插入如下代码:
// User logic ends wire [3:0] ps_gpio_in; wire ps_gpio_out; assign ps_gpio_out = slv_reg0; assign slv_reg1 = ps_gpio_in; user_gpio test( .gpio_in(gpio_in), .gpio_out(gpio_out), .ps_gpio_in(ps_gpio_in), .ps_gpio_out(ps_gpio_out) );
这里也解释了前面为什么要使用wire型的slv_reg1,主要是节约赋值时间。
如果以后有时间可以学习AXI总线协议的话,或许就可以看懂现在的模块,现在不做讨论,主要了解如何在AXI的IP上搭建verilog的自定义IP。
四、打包整合后的工程
tools》Create and package new IP》next》package your current project》next》overwrite》finish
这一步的操作就可以将整合后的工程打包在一个IP。这里也有将这个工程IP添加到全局的设置,如果有需要的可以尝试一下。
五、bd设计,调用自定义IP
首先创建bd文件,然后调用zynq内核,这部分是基础操作,不做过多的说明。
配置内核也是按照开发板的习惯配置。需要添加UART和DDR,其他的基本默认。(在前面的基础实验中的操作都适用)(例如bank0和bank1的电压,我的是3.3和1.8)
调用自定义的IP加入设计
直接搜索输入user好像会自动显示自定义IP,没有试过其他的,我的可以。
加入之后就先自连,再引线,有强迫症的可以用一下整理。
这时候需要引出输入输出引脚到芯片外部,直接在引脚上右击,然后make external,就可以直接连上外部引脚(当然,你得配置管脚以到具体的引脚)。
这时候的bd设计就已经完成了。
这里要注意系统分配的寄存器地址。在多个自定义设计中可能会用到。这个地址也会直接影响后面的软件操作。
六、构建硬件平台
bd文件只不过是一个IP集合,没有例化,自然不能直接往里面写软件。
在所属bd文件上右击》generate product 》create HDL wizard
这两步理解一下。generate productor是用于例化IP核的。bd文件将所有IP核的关系描述清楚后,需要将设计转化为具体的verilog模块来实现这种关系。至于create HDL wizard,就是自动例化顶层,相当于系统自动将bd的头部用verilog包装(你默认语言是verilog的话)。
分配引脚:在 open elboarded design中分配好管脚。
就可以综合映射得到bit流文件。操作上可以直接生成bitstream。
然后生成硬件平台,这就意味着硬件设计的结束。作为硬件开发者来说,就可以收工了。但是,了解软件部分的设计可以有效提高硬件的设计视野,这也是比较重要的部分。
此外,一定要在Tcl Console中查看一下hardware是否成功。vovado不会自动跳转到tcl,所以要注意一下。反正我的licence在这里总是失效。好像重启软件有用,也没啥好的解决方案。
这里还需要勾选包含bitstream,这个不要忘了。
七、软件设计
进入vitis,出现初始界面。这个过程比较长,不用太过惊讶。
一般来说,vitis默认的进入界面是上次的界面,所以需要整理一下。
加载硬件的方法在前面的GPIO实验中已经说明过了,这里就简述。
new》新建app》输入工程名》创建硬件平台(第二面,加号选择工程的xsa文件)》默认到底。
打开helloworld.c文件:
替换为
#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "sleep.h" #include "string.h" #define IIC_BASEADDRESS 0x43C00000 #define REG0_OFFSET 0 #define REG1_OFFSET 4 u32 gpio_input_value=0; char buf_print[64]={0}; int main() { int i=0; init_platform(); print("Hello World "); while(1) { for(i=0;i<64;i++)buf_print[i]=0; gpio_input_value=Xil_In32(IIC_BASEADDRESS+REG1_OFFSET); sprintf(buf_print,"input gpio_value=%d ",gpio_input_value); print(buf_print); Xil_Out32(IIC_BASEADDRESS+REG0_OFFSET,0); sleep(1); Xil_Out32(IIC_BASEADDRESS+REG0_OFFSET,0xffffffff); sleep(1); } cleanup_platform(); return 0; }
代码源自小熊猫课堂
这里同样不分析代码的内容,这是另外一个系列的学习内容,这里只是作为长见识。
保存---编译---调试---运行
就可以快速地将代码运行在开发板上。
3、实验结果
由于前面例化IP核时一个端口声明出现错误,而且当时没有做综合。导致又重来了一遍。教训呀。
这里总结一下更改的经验:
1、不要该IP的顶端,因为后面的输入输出信号与这里直接相关,牵一发而动全身。
2、不要省略每一个检查步骤,因为那都是用时间堆出来的教训。
3、更改的话以内部修改为主,不得已才去动外部设计。
4、总结
不知道是不是由于从SDK移植的代码不适用于vitis,还是代码设置出现错误,最后只是灯闪烁,IO和UART均不工作。果然还是要自己写代码。以后有机会再修正吧,目前暂时这样做。
以上是关于ZYNQ7000系列学习之自定义模块构成IP的主要内容,如果未能解决你的问题,请参考以下文章