Day9上午1
讲两种 PS 向 PL 传输数据的办法
昨天数字识别的结果是通过 vio 控制的,如果实现全硬件的数字识别,那也是在 PL 端完成,所以用 PL 端把 vio 换掉就行
但是纯硬件的话会比较难,这边用软件识别的方法作为一个保底
也就是在 vitis 的 main.c 里面编写识别的算法
所以需要一种手段,把识别结果从 main.c 送到 PL 端
打开昨天显示黑框+数字,把 vio 删掉
先讲一种 HI 总线的方案
我们要对官方的 IP 进行一定修改,这边创建一个新的 IP

选择建一个 HI 通道的

对着他的路径去建立一个文件夹 ip_repo,把这个 IP 存起来

孩子们,一定要找到正确的路径啊,狡兔三窟也要修改一个后就全修改啊
这里可以看到他的一个原理图,是一个类似总线的形式,最后是 PS 往 PL 里面写东西
总线模式有三种,前两个比较像,是 HI 接口的一些模式
Life 比较简单,但是处理不了突发的传输,不过本工程无需顾虑,就选 Life 就行

因为他相当于是 arm 核上的 CPU 的一个从属存储,所以选 Slave 模式
默认配置是 4 个寄存器,是 32 位


左边这个 IP 是验证的,右边这个 IP 是接收的,最后会包装成一个顶层
数据从 M_AXI 到 S00_AXI ,存储到刚才的四个寄存器里面
但是四个寄存器不能作为终点,期望是让他作为输出给到 vga 识别模块,所以要对右边模块进行修改

这里从外部找到这两个 .v 文件

这个名称较短的文件,是展示了 IP 核的一个顶层,内化了 AXI 这个模块,以及上面有相应的输入输出


文件名长的这个是底层,这里就是刚才配置生成的 4 个寄存器,这四个的地址分别是 HI 地址 $+4n$
寄存器地址是以字节为单位,一个比特是 8 位,而 32 位就是 +4

这边我们是让 PS 端往 reg0 那个寄存器里面写东西,想让他作为输出
本文件的第一个括号是参数,第二个括号是接口
把刚才的 reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0; 剪切过来,并改为 output 作为输出
而刚才那个位置就可以删掉了

再到刚才顶层的那个 IP
在下面修改,其中 "." 是他在底层的名称,而括号内是在顶层的名称

顶层模块只是把底层模块的输出,连到顶层模块的 OI 口,所以上面只是一个连线,用 wire 的数据类型

回到 vivado,可见这里多了这个模块

打开之前项目的 design

这边再加入新的 IP

他大概会卡卡的,一开始还是不显示输出端

那就是在这里修改


让上面那个全是✅️就可以出来了,然后这样刷新一下就好了

有了右边的接口,就如下连线,Run Connection Automation

自动连线后,可见 S00_AXI 连到了 M01
这是说明从 ZYNQ 出来之后,分为两路
一路是给 VDMA 到输出,一路是给到新模块

可以跑综合+比特流应用模块了
vitis 这里可以看到他的地址

这个文件显示了所有的地址信息

要对之前代码进行修改,下面是新代码
#include <stdio.h> #include "xil_io.h" #include "xparameters.h" #include "xil_types.h" #include "xil_cache.h" #include "sleep.h" #define VDMA_BASEADDR XPAR_AXI_VDMA_0_BASEADDR #define VDMA_FRAME0 0x01000000 //视频帧缓冲区使用的内存起始地址 #define AXI_LITE_BASEADDR 0x43C00000 //AXI_LITE地址 #define STRIDE 1024 #define HSIZE 1024 #define VSIZE 720 int main(){ //VDMA写通道配置 Xi1_Out32(VDMA_BASEADDR+θx30, 0x1); Xi1_Out32(VDMA_BASEADDR+0xAC, VDMA_FRAME0); Xi1_Out32(VDMA_BASEADDR+0xA8, STRIDE*2); Xi1_Out32(VDMA_BASEADDR+0xA4, HVSIZE); Xi1_Out32(VDMA_BASEADDR+0xA0, VSIZE*2); Xi1_Out32(VDMA_BASEADDR, 0x1);//开启VDMA Xi1_Out32(VDMA_BASEADDR+θx5c, VDMA_FRAMEe);//帧缓冲区基地址 Xi1_Out32(VDMA_BASEADDR+θx58, STRIDE*2);//步长(字节数,16位像素=2字节/像素) Xi1_Out32(VDMA_BASEADDR+0x54, HSIZE*2);//水平尺寸(字节数) Xi1_Out32(VDMA_BASEADDR+θx50, VSIZE);//垂直尺寸(行数) for(int i=0; i<=100;i++){ Xi1_Out32(AXI_LITE_BASEADDR,i%10); usleep(100000); } return 0; }
1. 这里要加一个头文件 sleep.h ,进行微秒级的控制


2. 这里加了一个 AXI 的地址


3. 在最后加了一个循环,要往 AXI 这个地址里面写东西,这个循环就是往里面放变化的数字
这个 sleep 模块里面的单位是微秒,也就说0.1秒进行一次循环

浙公网安备 33010602011771号