一、基本概念&本节任务
0.写在前面
(资料图片仅供参考)
本来是想先做ov5640的LCD显示实验的,OV5640和LCD都能点亮了,但是我想当然地把OV5640的数据直接接到了LCD上,显示出来频闪很厉害,不可用,还是先继续学习AXI吧。开学之前争取把AXI总线学完,能操作内存或者直接内存访问的话,按帧存储数据再读出显示可能会好很多。
1.本节任务
本章的实验任务是 PS 将串口接收到的数据写入 BRAM,然后从 BRAM 中读出数据,并通过串口打印出来;与此同时,PL 从BRAM中同样读出数据,并通过ILA来观察读出的数据与串口打印的数据是否一致。
2.BRAM
BRAM(Block RAM)是PL部分的存储器阵列,PS和PL通过对BRAM进行读写操作,来实现数据的交互。在PL中,通过输出时钟、地址、读写控制等信号来对BRAM 进行读写操作;在PS中,处理器并不需要直接驱动BRAM的端口,而是通过AXI BRAM控制器来对BRAM进行读写操作。
对于少量、不连贯数据,使用BRAM是很好的选择,而对于大量连续的数据,ZYNQ7020只有4.9Mb的BRAM,使用DMA(直接内存访问)是更好的选择,这个过后会学到。
AXI BRAM IP核简介,可以配置为AXI4或AXI4 Lite接口。
二、程序设计
1.Vivado
①新建工程
添加BRAM控制器、BRAM、PS IP核
可以选择关掉ECC、安全电路
基本框架搭建完成
②创建读BRAM IP核
新建一个带AXI4接口的IP核
此时在IP Catalog中就有了刚才打包的IP核
由于选择了生成一个带AXI接口的IP核,VIVADO帮我们做好了AXI接口
新建设计文件,添加一个读BRAM模块(这里直接copy正点原子的代码了):
根据接口要求,在两个上层模块加入地址、时钟、使能、复位等信号。
在AXI例化的模块中加入RAM的端口
在第二层的模块中例化bram读取模块,同时用寄存器0,1,2分别传输读开始、起始地址、读数据长度等信号。
③封装IP核
修改好IP核后进行刷新
对于我们新增的ram端口,我们可以把它封装成一个总线。如果不封装,在Block design中就需要一个一个连线。
对总线接口命名,官方给出了一些接口的类型,我们选择BRAM,并对其进行映射。
并在Parameters中加入主机类型,否则后续会报警告
④加入读BRAM IP核
完成后重新封装整个IP,并在原工程中加入这个IP核,此时可以看见BRAM的端口封装好了(寄我才发现名字错了)
与之前对应的参数
在Address Editor中可以设置BRAM的大小,下面可以改为4K(字节),由于宽度为32位,所以深度为1024位,
⑤添加ILA
综合好后点击综合选项的Set Up Debug,在Netlist中添加BRAM生成器的端口,我们在PL中读端口B,所以加入端口B的地址、数据输出、使能信号的端口,并选择Domain时钟。
深度为1024位
2.Vitis工程
在xparameters.h中,有BRAM控制器、BRAM、自定义IP核pl_bram_rd的各个参数。
在xbram_hw.h中定义了两个函数如下所示,XBram_WriteReg用于向Bram写数据,第一个参数为Bram器件基地址,第二个参数为要写入数据的地址(我们选了4K大小,所以这里只能写0~1023),第三个参数为要写入Bram的数据(最大32位)。
XBram_ReadReg用于向Bram读数据,第一个参数为Bram器件基地址,第二个参数为要读取数据的地址,返回读出的数据。
①写入Bram和PL读Bram
这里的START_ADDR为0,BRAM_DATA_BYTE为4(即4字节),即i=0,每次从BRAM的0地址开始写入数据。当i小于4*总数据长度时,i=i+4。
即这里向BRAM写入数据,每次的地址偏移量为4字节。
②读Bram数据并发送至上位机
③完整代码
④发送数据,观察ILA
设置ILA触发条件,在向开发板串口发送“WritetoBram”,开发板返回数据:
三、总结
春节过完不写Vitis感觉都快忘了,由于不涉及PS的外设,所以这里不用在查找配置信息、初始化器件之类的了。过几天继续深挖AXI总线,学习AXI写入DDR和DMA。