当前位置: 首页 > news >正文

基于AXI模块的视频流传输(ps控制篇)

在生成VDMA,GPIO,IIC后,会生成对于的bsp板级包。这里我不打算进行深入学习(不会尝试自己去写这份ps代码),要求能较为深入理解ps工作的原理即可,依旧不去细看HDMI模块相关。
image
首先导入了几个库,然后定义了几个宏,这里有一个要注意的,define这里有的根据英文意思就能知道分别对应什么功能,但是#define VGA_VDMA_ID XPAR_AXIVDMA_0_DEVICE_ID中,需要看自己生成的VDMA(传给HDMI的通道)是编号0还是编号1,这里VGA实际上指的是HDMI,要把编号对上。下面四个define并没有被引用,因此作用我没去探究。

接下来就是几个结构体变量的声明,
image
基本都是类似这样,这个指针指向的还有点泛,结构体下还有结构体变量,但是大致意思能知道就行。都有英文解释的。然后就是声明两个数组,第一个是用于存储三个帧图像,第二是指针数组变量。
image
简单说一下这部分,DISPLAY_NUM_FRAMES是3,意味着有三帧缓冲,而由于我c语言很多都忘记了,所以这里插入两道指针题目:
image
这是利用指针修改数据
image
这是指针数组打印,值得一提的是,指针数组在作为参数引入函数时,不需要&符号,就会传递指向第一行的地址,然后函数接收时,由于接收来自第一行的指针变量,但是实际上数组每行有三个元素,因此传递时还是需要[3]作为后缀。理解不了也没事不影响。
然后pFrames[i] = frameBuf[i];相当于指向第i行的数据被赋值为右边的数组,这里也需要注意,等号右边的数组是不需要解引用*的。然后memset就是【指向的基地址,赋值,大小】,所以这样看会发现这三帧图像的数据都被设置为0。接下来是DCacheFlush,由于DDR3内存量过大,因此CPU一般访问DDR3时,会顺手把这个数据放在Cache上,缓存离CPU比较近,所以访问快,这是一个提高效率的方法,如果CPU要写入什么数据,也会先把数据写到缓存,然后后面如果CPU对同个地址再次写入,就会把原来的数据挤压到DDR3里面,然后缓存就存储新数据。这是一种常见的加速,但是会导致如果其他主机访问DDR3的数据,就可能这个数据还在缓存上没更新,所以这里需要缓存冲刷,将缓存上的数据更新到DDR3上,因为DDR3要被VDMA读取。
i2c_init(&ps_i2c0, XPAR_XIICPS_0_DEVICE_ID,40000);我觉得应该和串口很像,串口的话有一个Tx_BUF,往这个寄存器写入数据串口就会以串口协议发送这个1字节的数据,因此协议是硬件上实现的,然后我看了IIC.c和.h文件,发现也都是往寄存器写入数据的函数或者读取,所以我猜对了。但是这里是初始化,和配置iic还不一样。我们深入看一下代码:
image
主函数传入了一个空的iic结构体,ps端生成的iic0的ID,以及40000。可以发现该函数借助这个ID找到了iic0的配置这一结构体(Lookup函数)
image
可以发现这个函数只是简单的返回一下iic的配置config。然后就进入XIicPs_CfgInitialize(Iic, Config, Config->BaseAddress);函数了,点进去稍微看一下,不难发现它在把config的各个变量全部交给iic,可是由于iic的变量名和config不一样,所以更细节的东西不了解,只是知道config把它的配置,基地址啥的全部告诉了iic指针。相当于说,这个函数让iic指针成为我们IIC0设备的新词根我们可以直接拿来用它内部的结构体。
接下来就是setclk,这个姑且理解为设置为40KHz时钟吧(由传入参数决定),然后就是wait到iic空闲即可返回。
image
接下来是gpio,由前面的能知道,这里的初始化,实际上是将设备名称ID的结构体往新建的指针变量上代入,所以我们只要知道后面根据这个新结构体指针cmos_rstn就能控制这个gpio就行。
由于gpio是inout通道,要先配置好,XGpio_SetDataDirection(&cmos_rstn, 1, 0x0); 是往一号通道写入0,gpio可以设置为双通道,所以用1,2来编号,0是输出,1是输入。后面就是简单的往1号通道写入1,然后等一会,写入0,等一会,写入1开启cmos即可。
sensor_init(&ps_i2c0);由于我们前面知道i2c_init函数以及将XPAR_XIICPS_0_DEVICE_ID对应的各参数给了ps_i2c0结构体指针,并且配置了时钟频率为40KHz,这里比较简单,直接看
image
sensor_init就是往iic指针里面的各个地址写入各个数据来配置cmos,看一下他们的递进关系从底层开始:iic_reg16_write->ov5640_write->sensor_write_array->sensor_init
image
传入一个指针结构体,iic的地址,以及iic内部寄存器的地址和要写入的数据。
image
ov5640_write只是简单调用一下,不过iic地址写为3c这里我也不理解,可能在数据手册里,等我后面看看。然后就是sensor_write_array函数,也都比较简单,顶层也只是调用这个函数,看一下知道怎么用结构体指针实现即可。
vdmaConfig = XAxiVdma_LookupConfig(VGA_VDMA_ID);这个更是演都不演了,直接在主函数调用,就是找到VGA对应VDMA的配置然后传给vdmaconfig,XAxiVdma_CfgInitialize(&vdma, vdmaConfig, vdmaConfig->BaseAddress);也是一样,把这个vdma的所有信息全部传给vdma指针。
Status = DisplayInitialize(&dispCtrl, &vdma, DISP_VTC_ID, DYNCLK_BASEADDR,pFrames, DEMO_STRIDE);这个的话就只是把对应的信息传给dispctrl指针结构体而已。
image
就只是把这些信息配置好而已。为HDMI显示部分不做赘述。只知道是用来配置vtc,mmcm,对应vdma的即可。
然后就是DisplayStart(&dispCtrl);是为了让他们协调工作把视频流输出。
memset(dispCtrl.framePtr[dispCtrl.curFrame], 0, 1920 * 1080 * 3);这里发现将dispctrl(HDMI显示相关)的帧指针下的当前指针全部清0了,应该是再加一层保障吧,由于前面清0过了我觉得无所谓这个函数。
最后开始开启视频流→DDR3的VDMA:vdma_write_init(XPAR_AXIVDMA_1_DEVICE_ID,1280 * 3,720,1280 * 3,(unsigned int)dispCtrl.framePtr[dispCtrl.curFrame]);这个就是上一节提到的,把这些参数给VDMA它会更好的布局然后传给DDR3至于为什么要乘3,是因为3字节。配置的东西,直接调用即可,然后你会发现这里好像并没有给VDMA配置3个缓冲帧,可以初步判断应该是在硬件上去配置,就是在VDMA上设置三个缓冲帧(两个都要),然后记得初始化3个帧的空间即可。

再接再厉!

http://www.hskmm.com/?act=detail&tid=25719

相关文章:

  • lora的各种变体
  • Kubernetes Deployment:部署与管理应用指南
  • GO+RabbitMQ+Gin+Gorm+docker 部署 demo - 实践
  • Python测试
  • 免费文字转语音 AI 工具 All In One
  • 【闲话】2025.9.24 记梦
  • 酷派Cool20/20S/30/40手机安装Play商店-谷歌三件套-GMS方式
  • Cloudflare洛杉矶数据中心维护通知:技术架构与影响解析
  • 实验
  • StarTree支持Apache Iceberg扩展湖仓用例
  • 偏微分方程的解
  • selenium基础 - 教程
  • 2025.10.6模拟赛
  • 费马小定理的证明
  • 威尔逊定理的证明
  • 实用指南:HTML实现端午节主题网站:龙舟争渡,凭吊祭江诵君赋
  • 深入解析:rknn优化教程(一)
  • WannaCry勒索病毒数字取证与安全监控实战指南
  • 吴恩达深度学习课程一:神经网络和深度学习 第二周:神经网络基础(二)
  • 08. 自定义组件
  • 20251006 模拟测 总结
  • 数据源切换之道
  • 完整教程:tryhackme——Abusing Windows Internals(进程注入)
  • 向量存储vs知识图谱:LLM记忆系统技术选型
  • QBXT2025S刷题 Day5
  • FFT 学习笔记
  • Ai元人文系列:领域协同深耕:构建人机价值共生的文明实践框架
  • NFL统一数据生态系统技术架构解析
  • 复习题集
  • 实用指南:SCDN如何同时保障网站加速与DDoS防御?