海思Hi3531D通过IT6801实现HDMI转BT1120视频采集全流程解析
1. 项目缘起:从HDMI到BT1120的“翻译”难题
最近在折腾一个基于海思Hi3531D的视频处理项目,核心需求是把一路标准的HDMI视频信号“喂”给Hi3531D的VI(视频输入)模块进行处理。听起来很简单,不就是接根线吗?但实际一上手就发现,问题没那么简单。Hi3531D的VI模块通常接收的是并行的数字视频信号,比如BT1120、BT656这类格式,而HDMI是一个包含视频、音频、控制信息的复杂串行协议,两者根本“语言不通”。这就好比你想让一个只懂方言的人听懂普通话新闻直播,中间必须有个翻译官。在这个项目里,IT6801这颗芯片,就是我们要找的“翻译官”——一款专门将HDMI信号解码并转换成并行数字视频输出的桥接芯片。
选择IT6801的原因很实际:它支持HDMI 1.4,能处理常见的1080P@60Hz及以下分辨率,输出格式正好包含我们需要的BT1120(16位YUV422),而且外围电路相对成熟,成本可控。网上关于Hi3531D和IT6801的资料都有,但把它们俩搭配起来,从硬件连接到软件驱动调试,再到图像稳定采集的完整记录却不多。很多帖子要么只讲硬件原理图,要么只贴几句配置代码,真正在调试中遇到的时序问题、寄存器配置细节、图像异常排查这些“坑”,往往一笔带过。这篇手记,就是记录我把IT6801成功配置为Hi3531D的BT1120输入源,并稳定驱动VI模块的完整过程,重点会放在那些容易让人卡住的关键步骤和排查思路上。
2. IT6801硬件设计要点与Hi3531D的对接
硬件是基础,连接不对,软件调死也没用。IT6801和Hi3531D的硬件对接,核心是理解BT1120接口的电气特性和时序关系。
2.1 IT6801输出引脚与BT1120信号映射
IT6801作为HDMI接收端,其并行输出接口模式需要配置为“BT1120模式”。在这个模式下,其关键输出引脚与BT1120标准对应关系如下:
- 数据线(Y[7:0], C[7:0]):对应BT1120的16位数据总线
DATA[15:0]。这里需要特别注意位序对齐。通常,IT6801的Y[7:0]输出Y(亮度)分量,C[7:0]输出CbCr(色度)分量。在BT1120的YUV422格式中,数据在时钟沿交替输出Y和C(Cb或Cr)。因此,我们需要将Y[7:0]连接到DATA[15:8],C[7:0]连接到DATA[7:0](具体映射需根据芯片数据手册和Hi3531D的接收习惯调整,有时可能需要高低位互换)。 - 时钟线(CLK):IT6801输出的像素时钟
PCLK,直接连接到Hi3531D VI的输入时钟引脚。这个时钟的频率取决于输入的HDMI分辨率(如1080P@60Hz的像素时钟约为148.5MHz)。这是整个接口同步的“心跳”,必须保证信号质量。 - 行场同步信号(HSYNC, VSYNC):IT6801会输出行有效(HDE)和场有效(VDE)信号,或者行同步(HSYNC)、场同步(VSYNC)信号。Hi3531D的VI接口通常支持多种同步模式,我们需要根据IT6801的输出模式来配置VI的同步极性。更常见的做法是使用
HSYNC和VSYNC。 - 数据使能信号(DE):BT1120标准有时也使用数据使能(DE)信号来标识有效数据区间。IT6801也支持输出DE信号。如果使用DE模式,则HSYNC和VSYNC可能就不需要了,或者作为辅助参考。Hi3531D的VI同样支持DE同步模式,配置上更简洁。
注意:硬件连接前,务必仔细核对IT6801数据手册中“BT1120 Output Mode”的引脚定义表和时序图,以及Hi3531D《硬件设计指南》中VI接口的引脚说明。两者的电压域(通常是3.3V)也需要匹配。时钟和数据线的PCB走线应尽可能等长,以减少时序偏移。
2.2 电源、复位与I2C配置电路
除了数据接口,IT6801的正常工作离不开几个基础电路:
- 电源:需要干净的3.3V和1.2V(或1.8V,具体看芯片型号)电源,为数字核心和IO供电。电源引脚附近必须放置足够且容值搭配合理的去耦电容(如10uF + 0.1uF),这是芯片稳定工作的基石,尤其是处理高频像素时钟时。
- 复位电路:一个简单的RC复位电路,确保上电后芯片能可靠复位。复位引脚(RESET#)通常低电平有效,需要保持一定时间的低电平后再拉高。
- I2C配置接口:IT6801的工作模式、输出格式、中断等全部通过内部的寄存器来配置,而访问这些寄存器需要通过I2C总线。需要将IT6801的I2C引脚(SCL, SDA)连接到主控(这里就是Hi3531D)的I2C控制器上,并加上拉电阻。同时,IT6801的I2C设备地址需要通过其硬件地址引脚(如ADDR0)的电平来决定,例如接地表示地址0x48。
- HDMI输入检测:IT6801的
HPD(热插拔检测)引脚需要按照HDMI标准,通过一个上拉电阻(通常47kΩ)接到5V电源,并通过一个缓冲电路连接到HDMI接口的HPD引脚。当HDMI源设备插入时,它会检测到这个电压变化,从而开始握手通信。RXSENSE引脚用于检测TMDS信号是否存在。
硬件焊接并检查无误后,就可以上电,进入软件调试阶段了。如果硬件有问题,后续的软件调试会举步维艰,常见现象包括I2C通信失败、无时钟输出、图像数据全乱等。
3. Hi3531D SDK中VI模块的配置逻辑
Hi3531D的SDK提供了强大的视频处理平台(MPP),VI模块是入口。我们的目标是将IT6801输出的BT1120信号,正确配置为VI的一个物理通道(Pipe)和扩展通道(Channel)的输入源。
3.1 MPP系统与VI初始化流程
首先,需要理解海思MPP的基本初始化流程,这是所有业务的基础:
// 1. 配置系统参数(VB池、时钟等) HI_S32 s32Ret; VB_CONFIG_S stVbConf; MPP_SYS_CONF_S stSysConf; // 设置视频缓存池(Video Buffer)大小,这是存放原始图像数据的内存区域 // 需要根据分辨率、帧率、buffer数量精确计算 memset(&stVbConf, 0, sizeof(VB_CONFIG_S)); stVbConf.u32MaxPoolCnt = 2; // ... 计算并填充各个VB块的大小 ... // 配置系统参数并初始化 memset(&stSysConf, 0, sizeof(MPP_SYS_CONF_S)); stSysConf.pstVbConf = &stVbConf; s32Ret = HI_MPI_SYS_SetConf(&stSysConf); s32Ret = HI_MPI_SYS_Init(); // 2. 初始化VI模块 s32Ret = HI_MPI_VI_Init();VB池的配置是关键,如果分配不足,会导致后续创建通道失败。对于1080P的YUV422图像,一帧图像的大小为1920 * 1080 * 2 bytes ≈ 4 MB。假设我们需要缓存3帧,那么这个VB块的大小至少需要12MB。
3.2 VI设备、物理通道与扩展通道的关联
海思的VI模块概念稍显复杂,需要理清:
- VI Dev(设备):对应一个物理的传感器或解码芯片接口。对于BT1120输入,我们使用
VI_DEV_BT1120_0(假设接在BT1120接口0上)。 - VI Pipe(物理通道):隶属于某个Dev,负责实际的图像数据采集、预处理(如降噪、去马赛克)。一个Dev下可以有多个Pipe。
- VI Chn(扩展通道):隶属于某个Pipe,可以理解为数据出口。一个Pipe下的多个Chn可以输出不同尺寸、格式的图像(例如一个Pipe抓1080P,其下的Chn0输出1080P给编码,Chn1缩放输出720P给预览)。
在我们的场景中,IT6801接在BT1120接口上,所以:
- 我们需要配置一个
VI_DEV_BT1120_0设备。 - 在该设备下,创建一个Pipe(例如Pipe 0)。
- 在这个Pipe下,创建一个Chn(例如Chn 0)用于输出图像。
配置的核心是填充VI_DEV_ATTR_S、VI_PIPE_ATTR_S和VI_CHN_ATTR_S这三个结构体。其中VI_DEV_ATTR_S的配置必须与IT6801输出的信号格式严格一致。
3.3 关键结构体:VI_DEV_ATTR_S的配置详解
这是连接硬件信号和软件驱动的桥梁,任何一项配错,图像都可能无法采集或异常。
VI_DEV_ATTR_S stDevAttr; memset(&stDevAttr, 0, sizeof(VI_DEV_ATTR_S)); // 接口模式:BT1120标准模式 stDevAttr.enIntfMode = VI_MODE_BT1120_STANDARD; // 工作模式:多路复用模式(对应BT1120的YUV422交错数据) stDevAttr.enWorkMode = VI_WORK_MODE_1Multiplex; // 输入数据顺序:Y和C交替 (C = Cb/Cr) stDevAttr.au32CompMask[0] = 0xFF000000; // Bit31:24 对应DATA[15:8]? 需要根据硬件连接确认 stDevAttr.au32CompMask[1] = 0x00FF0000; // Bit23:16 对应DATA[7:0]? 这里映射是关键! stDevAttr.enScanMode = VI_SCAN_PROGRESSIVE; // 逐行扫描 // 时序配置 - 必须与IT6801输出的时序完全匹配! stDevAttr.stSynCfg.enVsync = VI_VSYNC_PULSE; // 垂直同步脉冲 stDevAttr.stSynCfg.enVsyncNeg = VI_VSYNC_NEG_HIGH; // VSYNC极性:高有效 stDevAttr.stSynCfg.enHsync = VI_HSYNC_PULSE; // 水平同步脉冲 stDevAttr.stSynCfg.enHsyncNeg = VI_HSYNC_NEG_HIGH; // HSYNC极性:高有效 stDevAttr.stSynCfg.enVsyncValid = VI_VSYNC_VALID_NEG_HIGH; // VBLANK极性 stDevAttr.stSynCfg.enHsyncValid = VI_HSYNC_VALID_NEG_HIGH; // HBLANK极性 // 如果使用DE模式,则配置会简化为 stDevAttr.stSynCfg.enSynMode = VI_SYN_MODE_DE // 图像尺寸 stDevAttr.stSize.u32Width = 1920; stDevAttr.stSize.u32Height = 1080; // 帧率(应与输入信号一致,用于内部buffer管理) stDevAttr.stFrameRate.s32SrcFrameRate = 60; stDevAttr.stFrameRate.s32DstFrameRate = 60; // 数据格式 stDevAttr.enPixFmt = PIXEL_FORMAT_YVU_PLANAR_422; // YUV422平面格式,VI常用 // 注意:BT1120线上传输的是YUV422交错格式,但VI模块内部会将其转换为平面格式存储。这里最易出错的点是au32CompMask和同步极性。au32CompMask定义了输入数据总线(DATA[15:0])的哪几位对应Y分量,哪几位对应C分量。这需要根据硬件原理图上IT6801数据线到Hi3531D数据线的具体连接顺序来决定。同步极性(enHsyncNeg,enVsyncNeg)则必须用示波器测量IT6801实际输出的HSYNC和VSYNC波形来确定:有效同步脉冲期间,是高电平还是低电平?配置反了,VI就无法正确找到一帧图像的起始位置。
4. IT6801寄存器配置与I2C驱动调试
硬件连接和VI参数都准备好了,但IT6801本身还是个“黑盒”,需要将它配置成我们需要的模式。这需要通过Hi3531D的I2C控制器,向IT6801的寄存器写入特定的值。
4.1 I2C通信基础与海思操作接口
首先,确保Hi3531D的I2C控制器驱动已加载,并在设备树(DTS)或板级配置中正确配置了引脚复用和时钟。海思SDK提供了hi_i2c的操作接口。
一个典型的IT6801寄存器写入函数如下:
#include "hi_i2c.h" int it6801_i2c_write_byte(unsigned char dev_addr, unsigned short reg_addr, unsigned char data) { HI_S32 s32Ret; I2C_DATA_S i2c_data; unsigned char buf[2] = { reg_addr >> 8, reg_addr & 0xFF }; // 寄存器地址,16位 buf[2] = data; // 要写入的数据 i2c_data.pbuf = buf; i2c_data.len = 3; // 地址(2字节) + 数据(1字节) i2c_data.dev_addr = dev_addr; // IT6801的I2C地址,如0x48 i2c_data.reg_addr = 0; // 这里reg_addr已包含在buf中,此项可置0或忽略 i2c_data.reg_addr_num = 0; // 地址字节数,已在buf中体现 // 假设使用I2C通道0 s32Ret = hi_i2c_write(0, &i2c_data); if (s32Ret != HI_SUCCESS) { printf("I2C write failed at reg 0x%04x, ret = 0x%x\n", reg_addr, s32Ret); return -1; } return 0; }调试的第一步是验证I2C通信是否正常。可以尝试读取IT6801的芯片ID寄存器(例如0x00和0x01),看是否能返回正确的值(如0x68, 0x01)。如果读失败,检查:
- I2C总线是否有上拉电阻(通常4.7kΩ)。
- SCL和SDA线是否接反、虚焊。
- Hi3531D的I2C控制器配置(时钟频率是否合适,通常用100kHz调试)。
- IT6801的电源和复位是否正常。
4.2 IT6801关键寄存器配置序列
IT6801的配置寄存器多达数百个,但核心配置围绕几个方面:系统复位、输入检测、视频解码、输出格式设置。以下是一个简化的配置流程,用于实现HDMI转BT1120 YUV422输出:
系统复位与初始化:写入系统控制寄存器,进行软复位,等待复位完成。
it6801_i2c_write_byte(0x48, 0x04, 0x01); // 软件复位 usleep(10000); // 等待复位稳定使能HDMI输入检测:配置相关寄存器,使能HPD和RXSENSE检测。
it6801_i2c_write_byte(0x48, 0x10, 0x01); // 使能HPD控制 it6801_i2c_write_byte(0x48, 0x11, 0x01); // 设置HPD为高,通知源设备配置输入颜色空间和视频格式:告诉IT6801输入的是HDMI信号,并开始解码。
it6801_i2c_write_byte(0x48, 0x0A, 0x10); // 选择HDMI输入端口 it6801_i2c_write_byte(0x48, 0xBC, 0x00); // 配置输入颜色空间为RGB/YUV444 // ... 更多关于输入格式的配置核心:配置并行输出接口为BT1120模式:这是最关键的一步。
// 设置输出接口为并行数字输出 it6801_i2c_write_byte(0x48, 0x15, 0x80); // 使能并行输出 // 设置输出格式为YUV422 it6801_i2c_write_byte(0x48, 0x17, 0x0C); // 输出格式寄存器,0x0C通常对应YUV422 // 设置输出数据位宽和同步模式 it6801_i2c_write_byte(0x48, 0x19, 0x07); // 输出控制,可能包含DE/HSYNC/VSYNC选择 // 设置BT1120特定模式 it6801_i2c_write_byte(0x48, 0x1A, 0x40); // 设置为BT1120输出模式 // 配置同步极性(需与VI配置匹配!) it6801_i2c_write_byte(0x48, 0x1B, 0x00); // 例如,00表示HSYNC和VSYNC高有效读取EDID和自动配置(可选):IT6801可以读取HDMI源设备的EDID信息,并自动配置输出分辨率以匹配输入。这通常通过一系列寄存器操作完成,也可以手动强制设置输出时序。
重要提示:以上寄存器地址和值仅为示例,绝对不能直接照抄!必须依据你所使用的IT6801芯片的具体型号和版本,查阅其官方数据手册(Datasheet)或编程指南(Programming Guide)。不同版本、不同封装的IT6801,寄存器定义可能有差异。最好的方法是找到原厂的参考配置代码(C Code)。
4.3 调试技巧:如何验证配置是否生效
- 测量时钟:用示波器测量IT6801的PCLK引脚。如果配置成功,在接入有效的HDMI信号后,应该能看到稳定、频率正确的像素时钟波形(如1080P@60Hz约为148.5MHz方波)。如果没有时钟,说明IT6801可能未正确锁定HDMI信号或输出未使能。
- 测量同步信号:测量HSYNC和VSYNC引脚。应该能看到与帧率、行频对应的脉冲信号。观察其极性和宽度。
- 读取状态寄存器:通过I2C读取IT6801的状态寄存器(如0x0E),可以查看是否成功锁定HDMI信号(Lock位)、检测到的分辨率、颜色深度等信息。这是软件判断硬件状态的重要依据。
- Hi3531D端检测:在初始化VI Dev时,如果配置正确,调用
HI_MPI_VI_EnableDev后,可以尝试读取VI的某些状态(虽然SDK直接接口不多),或者观察系统是否报错。更直接的方法是,在使能VI Chn后,去获取一帧图像数据,看是否能成功拿到,以及数据是否合理。
5. 图像采集测试与典型问题排查
当硬件连接、IT6801配置、VI初始化都完成后,就进入了最后的联调测试阶段:让Hi3531D真正把图像数据读出来。这里使用海思MPP的标准流程:使能通道,启动流,然后从通道中获取图像缓冲区(VB)。
5.1 完整的VI通道使能与图像获取流程
// 1. 配置并启用VI Dev (使用前面定义的stDevAttr) s32Ret = HI_MPI_VI_SetDevAttr(VI_DEV_BT1120_0, &stDevAttr); s32Ret = HI_MPI_VI_EnableDev(VI_DEV_BT1120_0); // 2. 配置并启用VI Pipe VI_PIPE_ATTR_S stPipeAttr; // ... 配置Pipe属性,通常与Dev属性关联或简化 s32Ret = HI_MPI_VI_SetPipeAttr(VI_PIPE_BT1120_0, &stPipeAttr); // Pipe 0 对应 Dev 0 s32Ret = HI_MPI_VI_EnablePipe(VI_PIPE_BT1120_0); // 3. 配置并启用VI Chn VI_CHN_ATTR_S stChnAttr; stChnAttr.enCapSel = VI_CAPSEL_BOTH; // 采集奇偶场 stChnAttr.stSize.u32Width = 1920; stChnAttr.stSize.u32Height = 1080; stChnAttr.enPixelFormat = PIXEL_FORMAT_YVU_PLANAR_422; stChnAttr.enCompressMode = COMPRESS_MODE_NONE; // 无压缩 s32Ret = HI_MPI_VI_SetChnAttr(VI_PIPE_BT1120_0, VI_CHN_0, &stChnAttr); s32Ret = HI_MPI_VI_EnableChn(VI_PIPE_BT1120_0, VI_CHN_0); // 4. 开始接收图像数据流 s32Ret = HI_MPI_VI_StartStream(VI_PIPE_BT1120_0, VI_CHN_0); // 5. 主循环中获取图像帧 VIDEO_FRAME_INFO_S stFrameInfo; while (1) { // 获取一帧图像,超时时间设为1000ms s32Ret = HI_MPI_VI_GetChnFrame(VI_PIPE_BT1120_0, VI_CHN_0, &stFrameInfo, 1000); if (s32Ret == HI_SUCCESS) { // 成功获取到帧!stFrameInfo包含图像数据指针(VB物理地址)、宽高、时间戳等 printf("Got a frame! Addr: %p, Size: %dx%d\n", stFrameInfo.stVFrame.vir_addr[0], stFrameInfo.stVFrame.u32Width, stFrameInfo.stVFrame.u32Height); // 在这里可以对图像进行处理(如显示、编码、分析)... // 处理完毕后,必须释放这一帧,否则VB池会耗尽 s32Ret = HI_MPI_VI_ReleaseChnFrame(VI_PIPE_BT1120_0, VI_CHN_0, &stFrameInfo); } else if (s32Ret == HI_ERR_VI_NO_BUF) { printf("No buffer available.\n"); } else { printf("Get frame failed: 0x%x\n", s32Ret); } usleep(33000); // 粗略控制循环频率 }如果HI_MPI_VI_GetChnFrame成功返回,并且stFrameInfo中的宽高信息正确,那么恭喜,最艰难的一步已经迈过。你可以将获取到的图像数据(通常是YUV平面数据)保存为文件,用YUV查看工具(如YUV Player)检查图像内容是否正确。
5.2 典型问题现象与排查思路
在实际调试中,很少能一次成功。以下是几种常见问题及排查方向:
| 问题现象 | 可能原因 | 排查步骤 |
|---|---|---|
HI_MPI_VI_GetChnFrame始终返回超时或错误 | 1. VI Dev/Pipe/Chn 未成功使能。 2. IT6801无视频信号输出。 3. VI设备属性(时序、极性)配置错误。 4. VB池配置不足或未初始化。 | 1. 检查每一步HI_MPI_VI_EnableXXX的返回值。2. 用示波器测IT6801的PCLK、HSYNC、VSYNC、DATA是否有信号。 3.重点核对 VI_DEV_ATTR_S中的enIntfMode,enWorkMode,au32CompMask, 同步极性,与IT6801实际输出是否一致。4. 确认 HI_MPI_SYS_Init前VB池大小计算正确且足够。 |
| 能获取到帧,但图像错乱、花屏、颜色异常 | 1. 数据位序 (au32CompMask) 配置错误。2. 像素格式 ( enPixFmt) 不匹配。3. IT6801输出格式(如YUV顺序)与VI预期不符。 4. 时钟抖动或数据线干扰严重。 | 1. 尝试交换au32CompMask中Y和C分量的位掩码。2. 确认IT6801配置为YUV422输出,并尝试更改YUV顺序(Y/Cb/Cr 还是 Y/Cr/Cb)。 3. 尝试更改VI的 enPixFmt(如PIXEL_FORMAT_YUV_PLANAR_422和PIXEL_FORMAT_YVU_PLANAR_422互换)。4. 用示波器检查PCLK和数据线的信号完整性,看是否有过冲、振铃或噪声。 |
| 图像有固定位置的竖线或横线干扰 | 1. 时序参数中的消隐期(Blanking)设置不对。 2. 内存访问越界或VB块边界不对齐。 | 1. 核对VI_DEV_ATTR_S中的stSynCfg时序参数,特别是u32HsyncHfb,u32HsyncAct,u32HsyncHbb,u32VsyncVfb,u32VsyncVact,u32VsyncVbb。这些值需要根据输入视频的精确时序来设定。可以先用IT6801的自动检测功能,或查阅标准视频时序表(如CEA-861)。2. 检查VB池配置,确保为图像分配的内存块是连续且对齐的。 |
| 图像闪烁、不稳定 | 1. 时钟不稳定。 2. VI帧率与输入信号帧率不匹配。 3. 电源噪声。 | 1. 测量PCLK的时钟抖动(Jitter)。 2. 检查 stDevAttr.stFrameRate的配置,确保与HDMI源输出帧率一致。3. 检查IT6801和Hi3531D的电源纹波,加强电源滤波。 |
5.3 一个实用的调试技巧:保存原始YUV数据
在排查图像问题时,将获取到的原始帧数据保存为文件是最直接的方法。可以写一个简单的函数,将stFrameInfo.stVFrame.vir_addr[0](Y分量地址)、vir_addr[1](V分量地址)、vir_addr[2](U分量地址)指向的数据,按照YUV420或YUV422平面格式写入文件。然后在PC上用专业的YUV播放器(如7yuv、YUV Player Deluxe)打开,可以非常直观地看到图像是颜色错误、错位、还是撕裂,这能极大缩小问题范围。
例如,发现图像整体偏绿,很可能就是Y和UV分量的数据映射反了;如果图像像老式电视雪花,可能是数据线接触不良或时钟不同步。
6. 进阶话题:稳定性优化与分辨率自适应
当基本功能调通后,我们还需要考虑系统的稳定性和鲁棒性。
6.1 信号锁存与中断处理
IT6801在状态变化(如HDMI信号插入、拔出、分辨率改变)时,可以通过中断引脚(如INT)通知主控。我们可以将Hi3531D的GPIO配置为中断输入模式,连接到IT6801的INT引脚。在中断服务程序中,读取IT6801的中断状态寄存器,判断事件类型,并做出相应处理(如重新初始化VI参数)。这比轮询方式更高效、更及时。
6.2 分辨率自适应处理
我们的初始配置固定了分辨率(如1920x1080)。但如果HDMI源设备切换了分辨率(例如从1080P切换到720P),当前的VI配置就会失效。实现自适应有两种思路:
- 被动检测与重启:在中断中检测到分辨率变化后,先
HI_MPI_VI_DisableChn,HI_MPI_VI_DisablePipe,HI_MPI_VI_DisableDev,然后根据IT6801读取到的新分辨率参数(如通过寄存器0x0E, 0x0F等),重新计算并设置VI_DEV_ATTR_S、VI_PIPE_ATTR_S等,再重新启用。这个过程会有短暂的黑屏或丢帧。 - 预先配置与切换:海思VI支持多个“设备属性集”。我们可以预先配置好几套常见分辨率(1080P, 720P, 576P等)的参数。当检测到分辨率切换时,调用
HI_MPI_VI_SetDevAttr快速切换到另一套属性,可能不需要完全关闭设备,体验会更流畅。但这需要更精细的测试。
6.3 降低CPU占用的设计
在while(1)循环中不断调用HI_MPI_VI_GetChnFrame是阻塞式的,会占用一个CPU核。在生产环境中,更好的做法是:
- 使用VB池回调机制:海思MPP支持设置VB池用完或补充的回调函数,可以在数据就绪时通知应用,避免忙等待。
- 绑定到VO或VPSS:直接将VI通道与视频输出(VO)或视频处理子系统(VPSS)绑定,数据通过硬件通路自动传递,不经过CPU搬运,效率最高。例如,可以将VI Chn绑定到VPSS的Grp和Chn,进行缩放、裁剪等处理,再送给编码或显示。
调试这类嵌入式视频项目,示波器和逻辑分析仪是眼睛,数据手册和参考代码是地图,而耐心和系统的排查方法则是走下去的腿。从IT6801的I2C寄存器配置,到海思VI复杂的属性结构,每一步都可能藏着一个小坑。最深刻的体会就是:时序和极性是数字视频接口的“方言”,两边的设备必须说同一种方言才能对话。务必确保IT6801输出的同步信号极性、数据顺序与Hi3531D VI的配置一字不差。当图像终于稳定出现的那一刻,之前所有的折腾都值了。这个方案为Hi3531D这类本身不带HDMI输入的视频处理芯片,提供了一种稳定可靠的HDMI视频接入能力,在数字标牌、视频会议终端、工业视觉等领域都有不小的应用潜力。