当前位置:   article > 正文

Vivado开发套件设计笔记(3)——加法器设计——指针(下)_vivado加法器ip核

vivado加法器ip核


接上一篇博文 《Vivado开发套件设计笔记(3)——加法器设计——指针(上)》

上一篇博文为读者介绍了 HLS 中基于 数组float型四则运算IP核 的制作,然后在 Vivado 中把 IP核 加入到工程中与 ZYNQ Processing System 相连,然后导出硬件信息供给 SDK 用,至于 SDK 怎么用这个自定义的 四则运算IP核 ?笔者在这一篇博文继续给读者讲解。

4 SDK设计

Vivado 软件中运行 SDK 后会出现下面的界面(读者会发现这款 SDK 是用 Eclipse 开发的)。上面两个框是我们的硬件信息,下面的框框内的 add_0 就是 加法器IP核 导出的硬件信息了。

在这里插入图片描述

(1)创建工程

在菜单栏点击 File —— New —— Application Project ,弹出创建工程界面,输入项目名为 add (英文的无空格就可以),如下图所示,然后点击 Next

在这里插入图片描述
然后选择工程模板,选择 Hello World 工程模板,如下图。

在这里插入图片描述
工程创建成功后如下图所示。

在这里插入图片描述

(2)程序设计

点开导航栏左侧的 Project Explorer 会发现里面有很多的文件,其中最最重要的就三个:第一个是 arith/src/Helloworld.c ,这个 c文件 里面有ZYNQ的CPU程序入口 main函数 ;第二个是 arith_bsp/ps7_cortexa9_0/include/xparameters.h ,这个头文件里面有我们所用到的 四则运算IP核 映射到FPGA的DDR中的内存地址和相关驱动参数(这些是 自动生成 的);第三个是add_bsp/ps7_cortexa9_0/include/xarith.h ,其命名方式是与读者设计的 IP核命名 相关,在其前面加上一个 ‘x’ 而已,比如我们的加法器是 arith ,因此它的命名方式就是 xarith.h ,这里面存放着我们调用自定义 四则运算IP核 的库函数(或者叫做 驱动)。

有了以上三个文件,就可以开始 搞事情 了。

第一步,点开 helloworld.c ,输入以下代码。

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xarith.h"

int main()
{
	int status;
	int length;
	init_platform();

	float data[4];
	float res[4];
	float ref[4];
	XArith My_IP;

	status = XArith_Initialize(&My_IP, XPAR_ARITH_0_DEVICE_ID);
	if(status == XST_SUCCESS)
		print("IP Initialize Successfully!\n\r");

	data[0] = 10.5;
	data[1] = 5.5;
	data[2] = 8.0;
	data[3] = 0.5;

	ref[0] = data[0] + data[1];
	ref[1] = data[0] - data[1];
	ref[2] = data[2] * data[3];
	ref[3] = data[2] / data[3];

	length = XArith_Write_data_Words(&My_IP, 0, data, 4);
	if(length == 4)
		printf("Write OK!\n\r");
	XArith_Start(&My_IP);

	while(!XArith_IsDone(&My_IP));

	length = XArith_Read_res_Words(&My_IP, 0, res, 4);
	if (length == 4)
		print("Hello World\n\r");


	printf("PS(ARM) : ref[0] = %f, ref[1] = %f, ref[2] = %f, ref[3] = %f \n\r", ref[0], ref[1], ref[2], ref[3]);
	printf("PL(FPGA) : res[0] = %f, res[1] = %f, res[2] = %f, res[3] = %f \n\r", res[0], res[1], res[2], res[3]);

	cleanup_platform();
	return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

首先需要先定义 XArith 类型的结构体 My_IP ,再调用 XArith_Initialize() 初始化 IP核 ,如果返回值为 XST_SUCCESS 即表示初始化成功。然后定义输入到 IP核 的数组 data 和存储返回结果的数组 res ,之后利用库函数 XArith_Write_data_Words() 把变量送到PL端,接着调用 XArith_Start() 启动PL端的 IP核 开始计算,然后利用 while(!XArith_IsDone(&My_IP)); 阻塞方式等待 IP核 运算完毕,最后用 XArith_Read_res_Words() 取得 IP核 的返回结果。最终用ARM和FPGA做计算,对比结果,验证是否有误。

上述的 XArith 结构体类型,以及对 IP核 的调用的库函数(驱动)全部来自于头文件 xarith.h 中。其中 XArith_Initialize() 的第二个参数是 IP核ID ,这个 ID 号到 xparameters.h 头文件中找。所有用到的东西都在下面的截图中。

这里需要补充三点知识:

  • 第一点是数组维度,我们在 HLS 中设置的存储输入数据和输出数据的是2*2的二维数组,而到了 SDK 中,从输入数据到IP核的函数 XArith_Write_data_Words(XArith *InstancePtr, int offset, int *data, int length) 来看,输入时候用到的指针其实是一维的,然后根据输入的第四个形参 length ,把length长的数组一行一行地填充慢 HLS 中的二维数组,也就是说 SDK 中长度为4的 data 数组的第0个到第3个(总共4个)分别放到了 HLS(实际上是IP核) 上对应的第0行第0列、第0行第1列、第1行第0列、第1行第1列这四个位置。

  • 第二点是数据类型,从 XArith_Write_data_Words(XArith *InstancePtr, int offset, int *data, int length) 这一个函数定义来看,我们需要输入的数据其实是 float 型的,但是这里生成的驱动函数的 data 指针是 int 型,经过笔者实验发现,不论在 HLS 上定义的是 int 型还是 float 型,最终生成的驱动函数的数据指针都是 int 型,这个函数送到IP核应该是按照二进制送进去的,float 型变量所占的内存空间是4个字节, int 型也是4个字节,这样直接强制转换完送进去,输出时候用的 XArith_Read_res_Words(XArith InstancePtr, int offset, intdata, int length) 函数再次强制转换之后,结果会跟我们预期的一样。

  • 第三点是赋值,我们定义的 data 变量是 float 型数组,在给这样的 float 型变量赋值的时候,建议是用带小数赋值,或者加强制类型转换,比如我要给一个 float 类型的变量 a 赋0的话,最好用 a = 0.0 或者 a = (float)0 ,笔者认为这样更安全,因为此前自己开发的时候遇到很多次这样的 BUG ,都是处在这个问题上,所以这里提醒笔者以防不小心出了这个 BUG 不好找。

另外,有详细看 xarith.h 文件的读者会发现,例如写数据的函数,会有两个,一个是 XArith_Write_data_Words(XArith *InstancePtr, int offset, int *data, int length),另一个是 XArith_Write_data_Bytes(XArith *InstancePtr, int offset, char *data, int length) ,这里区别在于写数据时候用的是 Words(字节) 还是 char(字符) ,一个是4字节一个是单字节,因为我们用到的是 float 变量,所以用 字节 类型的函数即可,同理读取输出结果的函数也是一样。读者有兴趣可以自行尝试用 字符 类型的函数做实验。

部分截图如下。

在这里插入图片描述

在这里插入图片描述

(3)烧录程序

程序写好之后就可以烧录到板子上了。

第一步先把程序烧录到 ZYNQ 上,如下图所示操作。

在这里插入图片描述
用串口连接PC和开发板,(这里假设读者都已经安装好串口驱动之类的,如果不知道怎么做的,提供开发板的产商应该会给相应的资料,照做即可),打开串口调试助手,看运行结果,如下图所示。可以看到这里程序只运行到初始化这一步,没有之后我们所预想的有打印数据出来,这主要是因为硬件信息未烧录到FPGA中,因此在运行 while(!XAdd_IsDone(&MyAdd)); 会阻塞住不正常运行,到下一步。

在这里插入图片描述

第二步,把程序同时烧录到 ZYNQFPGA 上,操作如下图所示。
在这里插入图片描述
在这里插入图片描述
如果出现下面图示的警告,点 OK ,等待串口助手显示我们预想的结果就可以了。

在这里插入图片描述
如果读者都按照以上操作做完的话,会在串口助手上看到这样的结果,跟我们的预期一样,大功告成。

在这里插入图片描述

这里补充两点:

第一点是为什么要先烧录到ARM再烧录到FPGA,因为一个新的工程如果没有进行烧录到ARM的操作的话,之后烧录到FPGA的操作界面会缺少一个生成的System Debugger,有兴趣的读者可以试一下。

第二点是串口正常连接时的设备显示和串口调试助手的配置,如下图所示。

在这里插入图片描述
在这里插入图片描述
正常安装完USB驱动之后,用USB线把开发板上的UART口和JTAG口分别连到PC上,就可以正常使用了。

至此,所有的操作完成。

5 总结

这篇博文笔者详细的介绍了从HLS上 二维数组float 型数据的 四则运算IP核 的制作,到Vivado上顶层电路的连接,最后到SDK上应用程序的开发与验证,完成了用ARM核控制FPGA完成 四则运算 的任务,并教会读者怎么在HLS中用 数组float 型变量。

我们把流程重新理一遍。

  • HLS制作IP核
    • C仿真(C Simulation)
    • C综合(C Synthesis)
    • C/RTL 联合仿真(C/RTL Cosimulation)
    • 导出RTL(Export RTL)
  • Vivado构建完整电路
    • 把自定义IP核添加到IP Catalog(Add Repository)
    • 创建Block Design并添加自定义IP核以及ZYNQ处理系统,然后配置ZYNQ(Create Block Design)
    • 在Block Design中自动连接ZYNQ和自定义IP核并导出必要端口(Open Block Design)
    • 封装HDL并生成硬件输出(Create HDL Wrapper & Generate Output Products)
    • 运行项目(Run Implementation)
    • 生成bitstream并导出硬件(Generate Bitstream & Export Hardware)
  • SDK开发应用程序
    • 包含自定义IP核对应的驱动头文件(例如 xadd.h)
    • 声明自定义IP核对应的结构体并初始化(例如 XAdd MyAdd)
    • 利用库函数把数据输入到IP核,然后等待IP核运算完毕,再取输出数据
    • 把程序烧录到ARM上
    • 把程序同时烧录到ARM和FPGA上
    • 利用串口调试助手检验设计

以上便是全部操作流程。

当我们需要用到含有大量数据的数组的时候,可以在 HLS 上把形参设置成数组,如果需要用到的数据含有小数的时候,可以 把数组定义为 float 型,之后再 SDK 上把一维的数组按照需要的顺序放到 IP核float 型数据也是直接用驱动函数放进去,在调用 写函数 的时候会有强制类型转换,调用 读函数 的时候也会有强制类型转换,最终会得到我们所希望的结果,所以读者不必担心驱动函数上面 int 型的变量和 float 型变量不匹配的问题。另外,如果在 HLS 上面定义的数组是二维的,那么这个二维数组是按一行一行展开成一个行向量,去和 SDK 上的一维数组对应的,这个地方读者在自己设计的时候需要非常注意。

非常感谢读者读到了这里,这一博文会有很多地方与上一篇博文《Vivado开发套件设计笔记(2)——加法器设计》相似,笔者也是怕读者只读这一篇博文,而没有时间去读上一篇,所以才出此下策,希望读者可以理解。如果不幸让读者感到不悦,笔者将在下一篇博文中介绍 DDR3 的使用,以此谢罪。

6 参考文章

[1]: Xilinx Zynq-7000 嵌入式系统设计与实现(何宾著)
[2]: Vivado开发套件设计笔记(1)——入门简介
[3]: Vivado开发套件设计笔记(2)——加法器设计——变量(上)
[4]: Vivado开发套件设计笔记(2)——加法器设计——变量(下)
[5]: Vivado开发套件设计笔记(3)——加法器设计——指针(上)


原创性声明:本文属于作者原创性文章,小弟码字辛苦,转载还请注明出处。谢谢~

如果有哪些地方表述的不够得体和清晰,有存在的任何问题,亦或者程序存在任何考虑不周和漏洞,欢迎评论和指正,谢谢各路大佬。

需要代码和有需要相关技术支持的可咨询QQ:297461921

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/607788
推荐阅读
相关标签
  

闽ICP备14008679号