[ZYNQ Linux] VCU使用

ZYNQ Linux VCU使用

  • 版本:2023.1

VCU概括

  • VCU是单独的硬核,没有直接挂在PS上,需要PL用相关的IP核进行连接,PS也需要对应的驱动加载
  • 内部有单独的MCU,需要PS加载bootloader和应用程序
  • MCU通过AXI接口读取(执行)位于DDR上应用程序
  • 编解码单元通过单独的HP读取相关数据
  • 编解码常用输入输出图像格式YUV420SP,不支持RGB

PL

核心IP:VCU

  • 这里配置最大支持的编解码格式

BLOCK DESIGN

PS

设备树(自动生成)

c 复制代码
		vcu_0: vcu@a0000000 {
			#address-cells = <2>;
			#clock-cells = <1>;
			#size-cells = <2>;
			clock-names = "pll_ref", "aclk", "vcu_core_enc", "vcu_mcu_enc", "vcu_core_dec", "vcu_mcu_dec";
			clocks = <&misc_clk_0>, <&zynqmp_clk 71>, <&vcu_0 0>, <&vcu_0 1>, <&vcu_0 2>, <&vcu_0 3>;
			compatible = "xlnx,vcu-1.2", "xlnx,vcu";
			interrupt-names = "vcu_host_interrupt";
			interrupt-parent = <&gic>;
			interrupts = <0 89 4>;
			ranges ;
			reg = <0x0 0xa0040000 0x0 0x1000>, <0x0 0xa0041000 0x0 0x1000>;
			reg-names = "vcu_slcr", "logicore";
			encoder: al5e@a0000000 {
				compatible = "al,al5e-1.2", "al,al5e";
				interrupt-parent = <&gic>;
				interrupts = <0 89 4>;
				reg = <0x0 0xa0000000 0x0 0x10000>;
			};
			decoder: al5d@a0020000 {
				compatible = "al,al5d-1.2", "al,al5d";
				interrupt-parent = <&gic>;
				interrupts = <0 89 4>;
				reg = <0x0 0xa0020000 0x0 0x10000>;
			};
		};

相关文件

使用petalinux编译的文件系统中已有这些文件。

文件 说明
xilinx_vcu.ko VCU IP配置模块,内核源码中
dmaproxy.ko allegro.ko al5e.ko al5d.ko 编码器和解码器驱动,没在内核源码中,可以在github上找对应版本的vcu-modules
al5e_b.fw al5e.fw 编码器的bootloader和应用程序,类似的还有解码器的,位于/lib/firmware,用户不能修改

内核驱动 vcu-modules

dmaproxy
  • 为用户空间提供DMA调用的接口,使用内部的DMA控制器
  • 注册字符设备 /dev/dmaproxy
  • 内核:申请DMA通道 → \to →映射缓冲区 → \to →传输 → \to →清理资源
  1. 用户空间打开字符设备,调用ioctl
  2. 内核空间配置DMA传输,挂在等待队列上等待唤醒
  3. DMA传输完成后回调函数,唤醒对应事件
  4. 返回用户空间,结束阻塞
allegro
  • VCU的MCU固件加载和启动接口
  • 主控通信协议(Mailbox 与 MCU 交互)
  • 队列与多用户管理(并发处理)
  • 零拷贝内存管理(DMA-BUF 核心)

邮箱通信实现:基于共享内存实现的环形缓冲区(Ring Buffer)+ 中断,维护一个读指针和写指针,每条消息分为消息头和消息体,将整条消息存入缓冲区,然后触发中断通知对方读取。

al5d
  • 注册字符设备 /dev/allegroDecodeIP,核心是和MCU进行通信控制
al5e
  • 注册字符设备 /dev/allegroIP

用户接口 vcu-ctrl-sw

解码工具 ctrlsw_decoder
  • 输出是NV12,即YUV420SP。
  • 解码如果写入文件的话,帧率比较低。
bash 复制代码
ctrlsw_decoder -in input_file.h264 -avc -out output_file.yuv
ctrlsw_decoder -in 1080P.h264 -avc -noyuv
bash 复制代码
Allegro DVT2 - |AVC|HEVC| Decoder Reference Software v1.0.73 - Copyright (C) 2008-2023
Confidential material

Resolution: 1920x1088
FourCC: NV12
Profile: 100
Level: 42
Bitdepth: 8
Crop top: 0
Crop bottom: 8
Crop left: 0
Crop right: 0
Display resolution: 1920x1080
Sequence picture: progressive
Buffers needed: 8 of size 3342336

  Displayed picture #433    - Complete

Decoded time = 2.4220 s;  Decoding FrameRate ~ 179.1908 Fps; Frame(s) conceal = 0
编码工具 ctrlsw_encoder
  • 使用vcu-ctrl-sw里的文件进行测试,配置文件指定参数。
bash 复制代码
ctrlsw_encoder -cfg test/config/encode_example.cfg
bash 复制代码
Allegro DVT2 - |AVC|HEVC| Encoder Reference Software v1.0.73 - Copyright (C) 2008-2023
Confidential material

  Encoding picture #9      - Flushing...

Achieved bitrate = 703.2600 Kbps
10 pictures encoded. Average FrameRate = 1428.5714 Fps

标准化中间件 vcu-omx-il

  • https://github.com/Xilinx/vcu-omx-il
  • 基于vcu-ctrl-sw实现的一个标准的API,编译出来是一个库文件
  • OpenMAX IL 集成层,OpenMAX Integration Layer (简称OpenMAX IL 或 OMX IL)
  • 一个由 Khronos 集团(也是 OpenGL 标准的制定者)维护的开放、免版税的标准 API。
  • 它的核心使命是提供一套标准化的接口,让上层应用(或多媒体框架)能够以一种统一的方式,去加载、控制、连接和卸载硬件或软件的多媒体编解码组件(如 H.264 编码器、JPEG 解码器),从而实现"一次编写,到处运行"的跨平台可移植性。

GStreamer插件 gst-plugins-vcu

软件模拟源测试
  • 编码
  • UDP推流
bash 复制代码
gst-launch-1.0 -v videotestsrc is-live=true ! \
video/x-raw,format=NV12,width=1920,height=1080,framerate=60/1 ! \
omxh265enc periodicity-idr=60 ! \
video/x-h265,alignment=nal ! \
h265parse config-interval=1 ! \
mpegtsmux alignment=7 ! \
udpsink host=192.168.3.88 port=5004 sync=false

问题记录

  1. Mcu didn't start (no ping after startup, is mcu enabled ?)

    al5e和al5d驱动加载失败,重新编译FSBL后解决。原因是添加VCU IP后会自动使能PS的几个HP接口,需要重新编译FSBL(Bootloader)。如果未开启会导致MCU的AXI通信异常。以下是M_AXI_MCU接口异常和正常情况。

    异常MCU AXI通信,读取数据大部分都是一样的,和DDR不一致。

    正常MCU AXI通信。

  2. Mcu didn't start (no ping after startup, is mcu enabled ?)

    在AXI通信正常的情况下,依旧报这个错。判断MCU是否启动的原理是通过中断读取MCU消息,中断错误也会出现这个问题。多个PL到PS中断的话,自动生成VCU设备树的中断号和实际不符,比如仍为第一个89。

其他

CPU Cache取指缺失时,从DDR中取数据到Cache行中。这里取数据的过程用的是AXI4协议,传输类型是WRAP类型,只会取一个cache行的数据,如果长度超过后会从头开始。

比如一行是32B,第一个地址是0xD8,第二个是0xDC,再往后超过该行范围,第三个从0xC0开始开始。

相关推荐
wacsii1 小时前
【Linux进程(二)】深入 Linux 内核:进程状态切换与底层数据结构的秘密
linux·服务器
R&L_201810011 小时前
LINUX CPU 热点分析
linux
CodeYp20192 小时前
第6讲:Ext 系列文件系统
linux·文件系统·ext
爱吃香菜的初学者2 小时前
十九.Linux——TCP协议(1)
linux·网络·tcp/ip
Zevalin爱灰灰2 小时前
Linux入门第二部分(ARM裸机篇) 第三章 汇编LED驱动实验
linux·汇编·arm开发
EVEN-09132 小时前
Linux-IPC进程间通信
linux·运维·服务器
多弗朗皮卡丘2 小时前
Linux 进程信号
linux·运维·服务器
^乘风破浪^2 小时前
Kali配置i3wm教程1
linux·kali·i3wm
qeen872 小时前
【Linux】动静态库的链接与加载过程
linux·运维·系统编程