1. 项目缘起与整体方案设计RV1126这颗芯片在视觉类嵌入式项目里出镜率相当高四核Cortex-A7加内置NPU的配置跑轻量级图像采集和推理任务绰绰有余。但真正上手把MIPI CSI-2接口的Sensor数据通过V4L2框架采集成RGB888格式中间踩的坑远比想象中多。我这次做的项目需求很明确用RV1126的MIPI CSI-2接口接一颗RAW Sensor最终在应用层通过V4L2拿到RGB888格式的图像数据用于后续的显示和算法处理。为什么强调RGB888因为很多Sensor原生输出的是Bayer RAW格式比如RGGB、BGGR这种数据人眼没法直接看必须经过ISP处理才能转成YUV或RGB。而RGB888每个像素占3字节色彩信息完整适合直接送显示或做颜色相关的算法。但代价是数据量大对内存带宽和DMA效率要求高。所以整个方案的核心矛盾就变成了如何在RV1126的硬件管线上把MIPI CSI-2接收到的RAW数据高效地转成RGB888并送到用户空间。方案选型上我考虑过三条路。第一条是走RKISP的3A处理管线用rkaiq库做自动曝光和白平衡再通过V4L2的capture节点拿NV12最后在应用层用RGA转RGB888。第二条是绕过ISP直接用V4L2的mplane接口从Sensor拿RAW然后在用户空间用软件做去马赛克。第三条是配置ISP的直通模式让硬件完成RAW到RGB888的转换V4L2直接出RGB888。第一条路最稳但多了一次格式转换延迟和CPU占用都上去了。第二条路CPU占用太高RV1126的A7核跑软件去马赛克1080P30fps基本没戏。第三条路最理想但需要ISP驱动和Sensor驱动配合得当配置稍有问题就出不了图。最终我选了第三条路为主、第一条路作为备选验证的方案。下面把整个实战过程拆开讲。1.1 硬件链路与数据流向梳理先理清楚数据从Sensor到用户空间的完整路径。RV1126的MIPI CSI-2控制器接收Sensor通过差分信号发来的RAW数据写入DDR中的缓冲区。ISP模块从DDR读取RAW数据经过黑电平校正、去马赛克、色彩矩阵、Gamma等处理输出RGB888写入另一个缓冲区。V4L2驱动负责管理这些缓冲区应用层通过VIDIOC_DQBUF拿到填好数据的buffer。这里有个关键点RV1126的ISP和V4L2是两套驱动但共享内存。ISP驱动负责配置硬件管线V4L2驱动负责buffer管理和格式协商。两者通过media controller框架关联。如果media链路没配通V4L2那边VIDIOC_STREAMON会直接报错。硬件连接上MIPI CSI-2的时钟 lane 和数据 lane 的极性、速率必须和Sensor手册严格对应。我用的Sensor是两lane配置每lane速率是MIPI时钟的2倍DDR模式。RV1126的MIPI PHY需要配置成对应的lane数和速率档位这个在设备树里通过rockchip,csi2-param节点设置。1.2 为什么选V4L2而不是直接操作ISP寄存器有人可能觉得直接写ISP寄存器更直接但V4L2的好处是标准化。buffer管理、格式协商、流控这些脏活累活都由框架处理了应用层只需要ioctl调用。而且RV1126的SDK里ISP驱动已经封装好了自己写寄存器反而容易把管线搞挂。V4L2的mplane接口对多平面格式支持也好RGB888虽然是单平面但后续如果要加metadata平面mplane接口扩展性更好。另一个考虑是调试便利性。V4L2有v4l2-ctl这个工具可以快速枚举格式、试各种参数不用反复编译内核模块。我前期调格式的时候基本靠v4l2-ctl把ISP支持的格式全试了一遍确认RGB888在支持列表里才继续往下做。2. 内核驱动与设备树配置细节驱动层的配置是整个项目的地基地基没打好后面全是坑。RV1126的SDK里MIPI CSI-2和ISP驱动都是现成的但设备树的配置需要根据具体Sensor和板级硬件来改。我用的SDK版本是RV1126_LINUX_SDK_V2.2.5不同版本设备树节点名可能略有差异但整体结构一致。2.1 MIPI CSI-2控制器节点配置MIPI CSI-2的控制器节点在设备树里叫csi2挂在mipi_csi2下。关键参数包括lane数、频率、数据格式。我用的两lane配置每lane 500Mbps对应设备树里这样写csi2 { status okay; ports { port0 { reg 0; csi2_in: endpoint { remote-endpoint sensor_out; >isp0 { status okay; ports { port0 { reg 0; isp_in: endpoint { remote-endpoint csi2_out; }; }; port1 { reg 1; isp_out: endpoint { remote-endpoint v4l2_out; bus-width 24; >struct v4l2_requestbuffers req {0}; req.count 4; req.type V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; req.memory V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_REQBUFS, req) 0) { perror(VIDIOC_REQBUFS); return -1; }申请完buffer后用VIDIOC_QUERYBUF查每个buffer的偏移和长度然后mmap到用户空间。这里有个细节RV1126的ISP buffer是DMA连续的mmap的时候要设PROT_READ | PROT_WRITEMAP_SHARED。如果设成MAP_PRIVATE拿到的数据可能是空的。3.3 流启动与帧采集buffer入队用VIDIOC_QBUF全部入队后VIDIOC_STREAMON启动流。然后循环VIDIOC_DQBUF拿填好数据的buffer。RGB888的数据在v4l2_buffer.m.planes[0].bytesused里长度是width * height * 3。struct v4l2_buffer buf {0}; struct v4l2_plane planes[1] {0}; buf.type V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; buf.memory V4L2_MEMORY_MMAP; buf.m.planes planes; buf.length 1; if (ioctl(fd, VIDIOC_DQBUF, buf) 0) { perror(VIDIOC_DQBUF); return -1; } // 处理planes[0].bytesused长度的数据 // 处理完后重新入队 ioctl(fd, VIDIOC_QBUF, buf);实测下来1920x108030fps的RGB888流CPU占用大概在15%左右四核A7主要是memcpy和格式转换的开销。如果直接送显示可以省掉memcpy用DMA直接搬。3.4 帧率控制与丢帧处理RV1126的ISP在RGB888模式下帧率会受限于DDR带宽。1920x108030fps的RGB888数据率是192010803*30 ≈ 186MB/s加上RAW的读取和ISP内部处理DDR带宽占用不小。如果同时跑NPU推理帧率可能会掉到20fps左右。丢帧处理上V4L2的DQBUF如果返回EAGAIN说明当前没有可用buffer可以稍等再试。如果一直拿不到buffer可能是ISP管线卡住了需要检查media链路和ISP的中断计数。我一般会在应用层加个超时超过500ms没拿到帧就重新初始化V4L2。4. 常见问题与排查技巧实录调这个项目的时候踩了不少坑有些是RV1126特有的有些是V4L2通用的。整理成速查表方便对照排查。现象可能原因排查方法解决方法STREAMON报错EINVALmedia链路未打通media-ctl -p检查链路用media-ctl -l配置链路DQBUF一直超时ISP未出图cat /proc/rkisp0-vir0看ISP状态检查Sensor的streamon是否成功图像偏绿Bayer顺序配错查Sensor的mbus_code改成正确的Bayer格式图像有横条纹MIPI速率不匹配示波器测MIPI时钟调整link_freq和PHY配置帧率只有15fpsDDR带宽不足cat /proc/meminfo看带宽降低分辨率或改用NV12图像下半部分花屏buffer高度未对齐检查height是否2对齐向上对齐到偶数mmap后数据全0mmap标志错误检查PROT_READ改成MAP_SHARED颜色偏暗Gamma未配置查ISP的Gamma表加载默认Gamma参数4.1 ISP管线卡死的恢复方法ISP管线卡死是RV1126上比较烦人的问题表现为DQBUF一直超时/proc/rkisp0-vir0里的帧计数不增长。这时候光重启应用没用得把ISP驱动重新加载。我一般用rmmod rkisp modprobe rkisp但要注意先停掉所有打开video节点的进程否则rmmod会失败。如果rmmod也失败说明有进程还占着设备。用lsof /dev/video*查一下把占用的进程kill掉再rmmod。实在不行就重启但重启前最好把dmesg保存下来方便分析卡死原因。4.2 颜色异常的快速定位颜色异常分几种偏绿、偏红、偏蓝、整体偏暗。偏绿一般是Bayer顺序错了RGGB配成了BGGR。偏红或偏蓝可能是白平衡没收敛需要等ISP的3A算法跑一会儿。整体偏暗是Gamma没配RV1126的ISP默认Gamma是线性的需要加载Sensor对应的Gamma表。我一般先用v4l2-ctl抓一帧RAW用工具转成RGB看看颜色对不对。如果RAW的颜色是对的那问题就在ISP的配置上。如果RAW的颜色就不对那问题在Sensor的寄存器配置上。4.3 多进程访问冲突的处理RV1126的ISP capture节点不支持多进程同时打开。如果两个进程同时打开同一个video节点第二个会报EBUSY。解决办法是用一个进程做采集然后通过共享内存或socket把数据分发给其他进程。我一般用POSIX共享内存采集进程写其他进程读用信号量做同步。5. 性能优化与扩展思路RGB888的数据量大优化空间也大。我试过几个方向效果比较明显的是用RGA做格式转换和缩放。如果最终显示只需要720P可以在ISP输出1080P RGB888后用RGA缩到720P比ISP直接出720P的画质好因为ISP的缩放是硬件做的RGA的缩放算法更灵活。另一个优化是减少memcpy。V4L2的buffer是mmap到用户空间的如果后续处理不需要修改数据可以直接把mmap的指针传给显示模块省掉一次拷贝。RV1126的显示模块支持DMA直接读DDR只要物理地址连续就行。V4L2的mmap buffer物理地址是连续的可以直接用。扩展方面如果要做多路采集RV1126只有一个MIPI CSI-2控制器但可以通过MIPI Switch扩展多路。不过多路同时出RGB888对DDR带宽压力很大建议多路用NV12需要RGB888的时候再转。NPU推理一般用NV12就够了不需要RGB888所以实际项目里RGB888和NV12可以按需切换。我在实际项目里最后是这么用的预览用RGB888送显示推理用NV12送NPU。两个流从ISP的不同输出端口出互不干扰。ISP支持多路输出配置好之后一路RGB888一路NV12带宽也够用。这个方案跑下来很稳1080P30fps预览加1080P15fps推理CPU占用不到40%。