PS和PL共享DDR

这篇具有很好参考价值的文章主要介绍了PS和PL共享DDR。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文中,在SDK中先采用helloworld模板来检查整个工程是否创建成功,得到正确的结果后,再加入PS操作DDR的代码(用的是ZCU102)。本文主要描述整个设计的流程,过程容易忘记,所以记录,也方便自己之后查看,如有不对,请各位提出宝贵建议!

一、Vitis hls部分

1.创建工程
指定工程名和存放位置
PS和PL共享DDR
然后添加设计文件(包含所有的子函数),且指定顶层函数的名称(这里需要注意可能与设计文件名称不一样):
(设计文件和测试文件代码在第一点的最后!!!)
PS和PL共享DDR
然后添加测试文件t,即testbench文件:
PS和PL共享DDR
然后修改part selection为本文需要的板卡ZCU102;Flow Target选项有两种: 可以是Vivado IP Flow Target,也可以是VitisKernel Flow Target。
前者最终导出来的是VivadoIP,用于支持Vivado IP 设计流程;
后者用于Vitis应用加速流程,此时,Vitis HLS会自动推断接口,无需在代码里通过Pragma或Directive的方式定义Interface,最终会输出.xo文件。(这里选择Vivado IP Flow Target,因为设计的IP要导出到vivado中进一步使用):

PS和PL共享DDR
最终创建好的项目结构:
PS和PL共享DDR
HLS代码:

int share_dram_core(int write_nums,int read_nums,
					volatile float * data_ptr,
					int location_idx,int write_loop_idx,int read_loop_idx,
					int read_sum){
#pragma HLS INTERFACE m_axi depth=75 port=data_ptr offset=slave
#pragma HLS INTERFACE s_axilite port=return register
#pragma HLS INTERFACE s_axilite port=write_nums register
#pragma HLS INTERFACE s_axilite port=read_nums register
#pragma HLS INTERFACE s_axilite port=location_idx register
#pragma HLS INTERFACE s_axilite port=write_loop_idx register
#pragma HLS INTERFACE s_axilite port=read_loop_idx register
#pragma HLS INTERFACE s_axilite port=read_sum register

	location_idx=0;
	write_loop_idx=0;
	read_loop_idx=0;
	read_sum=0;

	for(int read_loc=0;read_loc<read_nums;read_loc++){
		read_sum+=data_ptr[read_loc];
		read_loop_idx++;
	}
	location_idx=1;//Done read process

	volatile float *write_ptr=&data_ptr[read_nums];

	for(int write_loc=0;write_loc<write_nums;write_loc++){
		write_ptr[write_loc]=write_loc;
		write_loop_idx++;
	}
	location_idx=2;//done write process

	return 1; //return=1 means done
}

2.项目验证
这个阶段主要进行 C仿真,C综合,C和RTL协同仿真,打包导出IP:

(1)首先是C仿真:
PS和PL共享DDR
(2)然后是C综合:(注:有些代码和结构是不可被Vitis HLS综合的,包括动态分配存储空间、与操作系统相关操作等)
PS和PL共享DDR
在测试文件中出现了malloc动态内存分配,但是可以综合成功。这是因为我们指定了要综合的顶层函数的名称(指定不是测试文件,而是设计文件,因此动态内存分配不用考虑,只是测试),此处填写的待综合的函数名称为“share_dram_core”:
PS和PL共享DDR
(3)接下来进行C RTL的协同仿真:
这里选择vivado自带的仿真器:Vivado XSIM,也可以选择其它的,但是需要指定其它仿真器的位置。其次,对于Dump Trace,选择port才可以输出的波形(如果默认好像是不会输出波形):
PS和PL共享DDR
最终协同仿真成功的界面如下:
PS和PL共享DDR
可以点击左上角的波形图标即可查看输出波形:
PS和PL共享DDR
注:补充:下面这种情况会导致在C仿真和C综合阶段无误,但是协同仿真的时候会报错:
PS和PL共享DDR
报错的原因是:
对于m_axi类型的接口,其depth深度的设置要和开辟的内存的大小相同:(但是试验测试的时候发现大一点也是可以的,比如这里开辟50个内存单元,如果depth设置为50-100得到的协同仿真结果都正确,但是设置为200就会报错)。
PS和PL共享DDR
(4)以上三步成功后就可以将设计好的IP导出:
这里可以不需要设置,直接导出即可:
PS和PL共享DDR
注:一般导出都会报错:
PS和PL共享DDR
解决方案是:
到这个网址下载一个补丁文件,然后将y2k22_patch这个文件夹拷贝到安装Vivado的文件夹:
PS和PL共享DDR
在上图的位置下打开WIndows PowerShell ,执行
python .\y2k22_patch\patch.py命令,等待执行完成即可,如下图所示:
PS和PL共享DDR
再次导出,出现下图所示即导出成功:
PS和PL共享DDR
在vivado中调用该IP:
PS和PL共享DDR
将上图中所显示的路径下的压缩包复制到vivado项目下的专门存储IP核的文件下(这个文件是自己定义,如下图所示):
PS和PL共享DDR
最终在Vivado中进行调用即可:
调用之前需要指定专门存储IP的文件的路径:
PS和PL共享DDR

二、vivado部分

1.创建工程项目
PS和PL共享DDR
PS和PL共享DDR
选择板卡:
在这里插入图片描述
PS和PL共享DDR
注:如果有些板卡没有,可以试着升级vivado的版本,点击下图红色框进行升级:PS和PL共享DDR
项目创建成功:
PS和PL共享DDR
2.搭建系统框图:
PS和PL共享DDR
完成之后的系统框图:(这里实现的是PS与PL实现共享DDR)
这里需要引入HLS开发的IP,因此需要在Vivado中的IP set界面指定管理这些IP的文件的位置(前面有提)。
系统框图一:
PS和PL共享DDR
系统框图二:
PS和PL共享DDR
仔细对比在vivado中搭建的两个系统框图,有不同的地方,如ZYNQ的从接口类型从S_AXI_HP0_FPD变为S_AXI_LPD;ZYNQ的主接口M_AXI_HPM0_FPD变为M_AXI_HPM0_LPD;此外最关键的一个改变是复位那里,这样改的原因还不是算很清楚,后续补充!这里采用第二种框图(第一种可能会导致内存有错误)。

注:对于ZYNQ ultraScale+ Mpsoc设置(双击即可打开下面的界面)需要注意:不用的外设可以进行裁剪,但所以在使能或者失能一些功能外设的时候需要留意。比如在SDK/Vitis中用到串口打印,那么必须在上图中使能并且正确配置uart0,否则会报错。
此外,对于DDR的配置极为重要,如果出错,那么在SDK中会有很多问题(后面会提到)!!!
PS和PL共享DDR
搭建完成之后:进行下一步。
3.生产bit流文件,然后导出到Vitis中:
首先生成.v文件:
PS和PL共享DDR
然后直接点击Generate Bitstream,会自动进行仿真、综合、实现、生成比特流文件:
PS和PL共享DDR
完成之后,点击file下面的export,将其导出:PS和PL共享DDR
如下图,导出后的是.xsa文件(该文件会在Vitis创建硬件平台工程platform工程时使用),其路径如下图所示:
PS和PL共享DDR
之后在vivado中启动vitis进行PS端的开发:
PS和PL共享DDR

三、Xilinx Vitis部分

指定工作空间路径:
PS和PL共享DDR
1、创建硬件平台工程(platform工程):
PS和PL共享DDR
对硬件平台工程(platform工程)命名:
PS和PL共享DDR
选择vivado导出的xsa文件:
PS和PL共享DDR
点击finish即可:
PS和PL共享DDR
创建好的硬件平台工程如图红色方框内:该platform工程下还有两个工程,分别是FSBL工程、standalone on psu_cortexa53_0工程。其中的FSBL工程是上一张图中的“generate boot components”的复选框选中而产生的

注:这一点和之前的SDK不同,SDK中需要手动创建FSBL工程,如果不创建,程序可能无法正确运行。结合FSBL的一个功能,即如果镜像中有bitstream文件部分,则用它配置PL部分。所以通过实验,我的理解是,如果用到了PL部分,但没有创建FSBL工程,那么运行就会报错。)

PS和PL共享DDR
2、创建软件工程:
选择上一步创建好的硬件平台:
PS和PL共享DDR
给软件工程命名:

实验过程中发现,如果直接创建DDR工程,可能同时会出现很多问题 ,所以建议先选择创建一个helloworld工程,先验证工程的创建是否正确,验证串口的打印输出是否正确,验证单步调试是否正确等:

PS和PL共享DDR
这一步默认即可,点击next:
PS和PL共享DDR
选择hello world模板:
PS和PL共享DDR
创建好的软件工程如下图所示:
PS和PL共享DDR
3、硬件调试(验证hello world工程)
因为代码中有print,要在控制台查看打印输出的内容,这里使用Vitis自带的串口调试工具,因此需要调出terminal窗口:
PS和PL共享DDR
配置串口和波特率:
PS和PL共享DDR

串口驱动安装的补充:
下载一个串口驱动
通过window更新完成驱动安装

接着编译hello world软件工程(build project),编译方法和结果如下图所示:
(注:还有一点是Vitis和SDK不同的地方,就是工程的编译,之前的SDK在保存项目的同时就会自动进行编译;但是Vitis不会,需要单独进行build project,编译之后才会生成.elf文件)
PS和PL共享DDR
开启板卡,连接好JTAG和USB等接口,然后选择“helloworld”,右键,选择“Run as”,把程序运行起来,“Run as”里又有很对选项,这里选择第一个“Launch on Hardware(Single Application Debug)”,使用系统调试,直接运行程序
(注:在上电之前将开发板的启动模式设置到 JTAG 模式,对于ZCU102,就是将SW6调到0000即on on on on):
PS和PL共享DDR
运行的结果如下图所示:
PS和PL共享DDR
可以发现没有成功输出print中的内容!!!
不改变任何代码和软件配置,再次运行,会报错:
PS和PL共享DDR
(上面整个错误,好像可以暂时不管,再运行依次就不会报这个错误了)。
连续运行代码数次,输出的结果如下图所示,发现偶尔会成功输出print中的内容。
PS和PL共享DDR
那么单步调试一下,查看代码是否有运行:设置断点进行调试,会发现程序无法进入main函数的入口,因此调试的机会都没有。尝试多次debug,(类似于运行时偶尔会得到print的结果),偶尔也可以进入main函数入口,进行调试,因此这个问题必须解决,才能正常开发之后的代码。

解决方案如下:

注:在这里,导致这个现象的原因可能是vivado中的配置出现错误
这里有两种方案,第一种是对时钟进行修改,第二种是对DDR重新配置(其实第一种并没有彻底解决,第二种是可行的。但是第一种会出现很神奇的现象,所以写在这里):
方案一:
在Vivado中将PS端时钟频率从33.33Mhz改为50Mhz,每次调试都可以停到main()函数入口处;(每次运行后控制台也会出现内容)
PS和PL共享DDR
但是无论是运行代码还是调试代码,又会出现一个新的问题:打印出来的是乱码:
PS和PL共享DDR

出现乱码的原因还未弄明白!

方案二:如下图所示,重新修改DDR的配置后,便可以成功解决上面的错误:
PS和PL共享DDR
如下图所示,可以正确输出结果:
PS和PL共享DDR
这里对代码的运行和调试做一点补充:
为了保证系统的可靠调试, 最好是右键“Run As -> Run Configuration…”,
可以看一下里面的配置,其中 Reset entire system 是默认选中的,这是跟以前的 Vitis软件不同的。如果系统中还有 PL 设计,还必须选择“Program FPGA”

注:如果把Reset entire system和Program FPGA这两个√取消掉的话,再次Debug的时候,它只会加载.elf程序,不会重新Program FPGA,这的确能节省一些加载Debug的时间,但这么做的话PL端的有些IP核没有复位,再次执行程序的时候就可能会出错!)
因此需要一种解决办法,能够在Debug程序开始前就只Program一遍FPGA,而后只需要relaunch SDK工程。参考方法,该方法是通过在Vivado中增加FCLK_RESET0_N信号,在程序main()函数刚开始的时候就对PL端用程序发出FCLK_RESET0_N信号进行复位。

PS和PL共享DDR
既然可以正确创建helloworld工程,也可以得到正确的结果,下面对SDK自带的memory模板进行测试,也可以得到正确的结果。所以接下来就可以在SDK中编写代码对DDR进行操作(在下一篇文章中):
PS和PL共享DDR
当对helloworld模板和memory模板都测试成功后,因此下面在memory模板的基础上,开始编写PS与PL共享DDR的代码:
代码如下:

//This is the SDK code to test share DRAM
//Write through PS to DDR
//Run PL : read from DDR to PL and write from PL to DDR
//Then read from DDR to PS

#include <stdio.h>
#include <xparameters.h>
#include <stdlib.h>
#include "platform.h" 
#include <xil_cache.h>
#include "xshare_dram_core.h"
#include "platform.h"
XShare_dram_core XShare_dram_core_instance;

int main()
{
	init_platform();
	print("\n --------------program start------------- \n");

	//read and write param
	int ps_wirte_size=25;
	int ps_read_size=25;
	int core_location_idx=100;
	int core_write_loop_idx=100;
	int core_read_loop_idx=100;
	int core_read_sum=100;
	int core_return_value=100;
	long int dataptr=0;
	volatile float * ps_write_ptr=NULL;
	volatile float * ps_read_ptr=NULL;

	//pointer intialize
//	ps_write_ptr=(volatile float *)malloc((ps_wirte_size+ps_read_size)*sizeof(float));
	ps_write_ptr= (volatile float *)0x10000000;
	ps_read_ptr=&ps_write_ptr[ps_wirte_size];
	if(ps_write_ptr==NULL)print("Malloc ps_write_ptr failure \n");
	if(ps_read_ptr==NULL)print("Malloc ps_read_ptr failure \n");
	memset((void*)ps_write_ptr,0,ps_wirte_size*sizeof(float));
	memset((void*)ps_read_ptr,0,ps_read_size*sizeof(float));

	print("Initialize ps_read_ptr and ps_write_ptr SUCCESS!\n");
	printf("ps_read_ptr is %x \n",(unsigned int)(long)ps_read_ptr);
	printf("ps_write_ptr is %x \n",(unsigned int)(long)ps_write_ptr);

//	for(int cur_print_loc=0;cur_print_loc<ps_read_size;cur_print_loc++){
//		printf("location %d, value %d \n",cur_print_loc,(int)ps_read_ptr[cur_print_loc]);
		printf("location %d \r",cur_print_loc);
		printf("value %f \n",(float)ps_read_ptr[cur_print_loc]);
//	}

	//initialize IPcore
	if(XShare_dram_core_Initialize(&XShare_dram_core_instance, XPAR_XSHARE_DRAM_CORE_0_DEVICE_ID)!=XST_SUCCESS){
		printf("XShare_dram_core_Initialize filed!\n");
		return -1;
	}
	printf("XShare_dram_core_Initialize SUCCESS!\n");

	//get and printf values
	core_location_idx=XShare_dram_core_Get_location_idx(&XShare_dram_core_instance);
	core_write_loop_idx=XShare_dram_core_Get_write_loop_idx(&XShare_dram_core_instance);
	core_read_loop_idx=XShare_dram_core_Get_read_loop_idx(&XShare_dram_core_instance);
	core_read_sum=XShare_dram_core_Get_read_sum(&XShare_dram_core_instance);
	core_return_value=XShare_dram_core_Get_return(&XShare_dram_core_instance);
	printf("core_location_idx=%d \n",core_location_idx);
	printf("core_write_loop_idx=%d \n",core_write_loop_idx);
	printf("core_read_loop_idx=%d \n",core_read_loop_idx);
	printf("core_read_sum=%d \n",core_read_sum);
	printf("core_return_value=%d \n",core_return_value);

	//initialize IPcore value
	XShare_dram_core_Set_write_nums(&XShare_dram_core_instance, ps_read_size);
	XShare_dram_core_Set_read_nums(&XShare_dram_core_instance, ps_wirte_size);
	XShare_dram_core_Set_data_ptr(&XShare_dram_core_instance, ps_write_ptr);

	printf("-------------Core value set SUCCESS! \n");

	//get and printf values
	dataptr=XShare_dram_core_Get_data_ptr(&XShare_dram_core_instance);
	printf("data_ptr=%ld \n",dataptr);
	core_location_idx=XShare_dram_core_Get_location_idx(&XShare_dram_core_instance);
	core_write_loop_idx=XShare_dram_core_Get_write_loop_idx(&XShare_dram_core_instance);
	core_read_loop_idx=XShare_dram_core_Get_read_loop_idx(&XShare_dram_core_instance);
	core_read_sum=XShare_dram_core_Get_read_sum(&XShare_dram_core_instance);
	core_return_value=XShare_dram_core_Get_return(&XShare_dram_core_instance);
	printf("core_location_idx=%d \n",core_location_idx);
	printf("core_write_loop_idx=%d \n",core_write_loop_idx);
	printf("core_read_loop_idx=%d \n",core_read_loop_idx);
	printf("core_read_sum=%d \n",core_read_sum);
	printf("core_return_value=%d \n",core_return_value);

	//IPcore start
	XShare_dram_core_Start(&XShare_dram_core_instance);
	printf("-------------IPCore start SUCCESS! \n");

	//get and printf values
	core_location_idx=XShare_dram_core_Get_location_idx(&XShare_dram_core_instance);
	core_write_loop_idx=XShare_dram_core_Get_write_loop_idx(&XShare_dram_core_instance);
	core_read_loop_idx=XShare_dram_core_Get_read_loop_idx(&XShare_dram_core_instance);
	core_read_sum=XShare_dram_core_Get_read_sum(&XShare_dram_core_instance);
	core_return_value=XShare_dram_core_Get_return(&XShare_dram_core_instance);
	printf("core_location_idx=%d \n",core_location_idx);
	printf("core_write_loop_idx=%d \n",core_write_loop_idx);
	printf("core_read_loop_idx=%d \n",core_read_loop_idx);
	printf("core_read_sum=%d \n",core_read_sum);
	printf("core_return_value=%d \n",core_return_value);

	while(!XShare_dram_core_IsDone(&XShare_dram_core_instance)){
		printf("Calculating...\n");
	}
	printf("IsDone done SUCCESS!\n");

	//get and printf values
	core_location_idx=XShare_dram_core_Get_location_idx(&XShare_dram_core_instance);
	core_write_loop_idx=XShare_dram_core_Get_write_loop_idx(&XShare_dram_core_instance);
	core_read_loop_idx=XShare_dram_core_Get_read_loop_idx(&XShare_dram_core_instance);
	core_read_sum=XShare_dram_core_Get_read_sum(&XShare_dram_core_instance);
	core_return_value=XShare_dram_core_Get_return(&XShare_dram_core_instance);
	printf("core_location_idx=%d \n",core_location_idx);
	printf("core_write_loop_idx=%d \n",core_write_loop_idx);
	printf("core_read_loop_idx=%d \n",core_read_loop_idx);
	printf("core_read_sum=%d \n",core_read_sum);
	printf("core_return_value=%d \n",core_return_value);

	for(int cur_print_loc=0;cur_print_loc<ps_read_size;cur_print_loc++){
		printf("location %3d, value %d \n",cur_print_loc,(int)ps_read_ptr[cur_print_loc]);
	}
	printf("-----------Program end SUCCESS!- \n\n");
//	if(ps_read_ptr != NULL) {
//		free(ps_read_ptr);ps_read_ptr=NULL;
//	}
//	if(ps_write_ptr != NULL){
//		free(ps_write_ptr);ps_write_ptr=NULL;
//	}
	return 0;
}

vivado vitis得到的最终结果如下图所示:
PS和PL共享DDR
补充:
vivado中的地址分配需要注意:偏移地址必须与范围字段对齐。
对其规则:便宜地址的最低有效位包含N个0,N值取决于range字段即range=2^N,因此并不是可以随意设定地址。
PS和PL共享DDR

在address editor中,

vitis中的lscript.ld文件的内存分配:
PS和PL共享DDR

!!!!!!!!!!!!!友情提示!!!!!!!!!!!!!!!
Xilinx Vitis 、Vivado、Vitis HLS这三个软件的启动文件不是.exe,当删除快捷方式后,通过以下方法打开:
这里我当时以为exe就是启动文件,结果打不开,所以重装了一次vivado,浪费了时间:
(1)Xilinx Vitis 启动文件:
PS和PL共享DDR
(2)Vivado
PS和PL共享DDR
(3)Vitis HLS
PS和PL共享DDR文章来源地址https://www.toymoban.com/news/detail-404339.html

到了这里,关于PS和PL共享DDR的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ZYNQ PS与PL通过AXI-LITE连接,在Linux下直接读写PL的物理地址,实现PS与PL的交互

    ZYNQ开发,如果PL与PS的交互方式仅为AXI-Lite总线的话,在Linux下可以通过直接访问PL的寄存器物理地址来实现PS-PL的数据交互。 测试代码的PC开发平台为Ubuntu18.04,QT5。 ZYNQ为7020,并移植了Linux系统和Ubuntu16.04的最小系统。 将PL的程序封装成IP核,通过AXI-LITE与PS连接,对外是18个寄

    2024年04月10日
    浏览(49)
  • ZYNQ学习笔记(四):PL与PS数据交互——基于BRAM IP 核的(PS端读写+PL端读)控制实验

    说起PS、PL数据交互,常见的有IO方式:MIO EMIO GPIO,还有利用BRAM或FIFO等,在上一篇文章ZYNQ学习笔记(三):PL与PS数据交互—— UART串口+AXI GPIO控制DDS IP核输出实验咱们学会了如何利用AXI GPIO IP核来实现PS(写)与PL(读)的数据交互,那么这篇文章来学习如何使用BRAM~ 本次实验

    2024年02月05日
    浏览(57)
  • zynq板上PS端给PL端复位

    最近接触zynq板-zcu104,记录一些实验笔记。 LED闪烁 在vivado中新建一个工程,命名为led-test。添加top.v文件。 其中,top模块接入zcu104开发板的clk_300_p/n信号,通过clock wizard转换为单端始终clock,接入到led闪烁模块led.v 其中,led模块通过一个24bit的计数器,经过相等间隔厚,让led灯

    2024年02月11日
    浏览(40)
  • PS和PL使用BRAM进行数据交互

    BRAM(Block RAM)是 PL 部分的存储器阵列,PS 和 PL 通过对 BRAM 进行读写操作,来实现数据的交互。在 PL 中,通过输出时钟、地址、读写控制等信号来对 BRAM 进行读写操作。而在 PS 中,处理器并不需要直接驱动 BRAM 的端口,而是通过 AXI BRAM 控制器来对 BRAM 进行读写操作。AXI BR

    2024年02月02日
    浏览(39)
  • FPGA的PS还有什么PL是什么意思

    在FPGA中 PS: 处理系统 (Processing System) :就是与FPGA无关的ARM的SOC的部分。 PL: 可编程逻辑 (Progarmmable Logic) : 就是FPGA部分。之所以叫PL,而不是叫FPGA,用英文简写可能便于理解区分,或者显得比较专业吧(/滑稽脸) 对于ZYNQ,,就是两大功能块,PS 部分和 PL部分, ARM的SOC部分,

    2024年02月11日
    浏览(41)
  • zynq的PL向PS提供时钟和复位

    最近买了一块矿卡蚂蚁T9+,它的资源比EBAZ4205丰富。 需要矿卡资料包的朋友可以从这下载。里面包含蚂蚁T9+和EBAZ4205原理图和几个EBAZ4205例程,还有一些相关的pdf文档。 link 首先从fpga学起,可惜PL没有焊晶振,只好从PS端引,下面以点灯为例。 打开vivado,工具栏file -- project -

    2024年02月15日
    浏览(48)
  • FPGA - ZYNQ 基于EMIO的PS和PL交互

    Xilinx ZYNQ 系列的芯片,GPIO分为 MIO 、 EMIO 、 AXI_GPIO 三种方式。 MIO    :固定管脚,属于PS端,也就是ARM端。 EMIO   :通过PL扩展,使用时需要分配 PL ( FPGA ) 管脚,消耗PL端资源。 AXI_GPIO :封装好的IP核,PS通过M_AXI总线可以控制PL的IO接口,使用时,消耗管脚资源和逻辑资源。

    2024年04月26日
    浏览(37)
  • ZYNQ使用AXI DMA(Scatter/Gather)模式进行PL与PS数据交互附源码(ps端移植freertos或者裸机)

    AXI DMA 操作需要先提供一个在内存中驻留的不变空间,用于存储需要进行的DMA操作。形容这“每一次操作”的东西叫做Buffer Descriptor,缩写叫BD,这些BD是连接成链表的形式的,因为BD会动态增加,而预先分配存储BD的空间是恒定的,因此BD被连成一个环(BD Ring),其实就是一个循

    2024年02月09日
    浏览(40)
  • fpga 通过axi master读写PS侧DDR的仿真和上板测试

           FPGA和ARM数据交互是ZYNQ系统中非常重要的内容。PS提供了供FPGA读写的AXI-HP接口用于两者的高速通信和数据交互。一般的,我们会采用AXI DMA的方式去传输数据,DMA代码基本是是C编写,对于FPGA开发者来说不利于维护和debug。本文提供一种手写AXI_MASTER接口用于PL 向DDR指定位

    2024年04月12日
    浏览(38)
  • AXI_UART调试说明-PS使用AXI_Uartlite拓展PL端串口资源

    ** ** 注:本例程是在xc7z010clg400_1实现,若导入至复旦微电子需更改为xc7z045iffg900-2L (目录中带*号的可略过) 背景:PS端UART资源有限,难以满足实际运用中多串口的需求。 具体方法:PS通过AXI总线调用PL的资源进行UART的拓展,本说明采用vivado自带的IP核AXI Uartlite完成,属于AX

    2024年02月05日
    浏览(111)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包