在嵌入式视觉系统开发中,双摄像头配置已经成为智能硬件的主流选择。RV1126作为Rockchip推出的高性能视觉处理芯片,其双摄方案在安防监控、工业检测等领域有着广泛应用。我最近在项目中移植IMX577双摄驱动时,踩过不少坑,这里把实战经验分享给大家。
IMX577是索尼推出的1/2.3英寸CMOS传感器,支持12MP分辨率(4048x3040),采用Bayer阵列。每个原始帧大小约18MB,这意味着视频处理流水线中需要频繁分配大块内存。从RK3588平台移植驱动时,有三个关键修改点需要注意:
第一是通道信息结构的移植。需要将RKMODULE_GET_CHANNEL_INFO宏定义及struct rkmodule_channel_info结构体完整拷贝过来,这是Rockchip特有的传感器控制接口。
第二是修改mbus配置类型。原驱动中的V4L2_MBUS_CSI2_DPHY需要改为V4L2_MBUS_CSI2,因为RV1126的MIPI接口配置与RK3588有所不同。
第三是函数挂载位置调整。imx577_g_mbus_config函数需要挂载到v4l2_subdev_video_ops结构体,而不是v4l2_subdev_pad_ops,这点特别容易出错。
双摄驱动的DTS配置是系统正常工作的基础。在RV1126上,两个摄像头通道的配置有所区别:
通道1(主摄)的路径是:sensor -> csi_dphy0 -> mipi_csi2 -> rkcif_mipi_lvds -> rkisp_vir0
通道2(副摄)的路径是:sensor -> csi_dphy1 -> rkisp_vir1
这种配置下,启动ispserver并访问video节点时,内核突然崩溃,报错"Unable to handle kernel paging request at virtual address ecc00000"。从崩溃堆栈看,问题出在DMA缓冲区映射阶段。
分析内核启动日志中的内存布局信息很关键:
code复制[ 0.000000] vmalloc : 0xed000000 - 0xff800000 ( 296 MB)
[ 0.000000] lowmem : 0xb0000000 - 0xecc00000 ( 972 MB)
[ 0.000000] Reserved memory: created CMA memory pool at 0x2dc00000, size 256 MiB
可以看到,CMA-ISP区域(0x2DC00000-0x3DC00000)与lowmem区域(0xB0000000-0xECC00000)存在地址空间重叠的风险。当CMA分配器从高地址分配内存时,可能在lowmem中找不到对应的映射地址。
启用CONFIG_CMA_DEBUGFS=y配置后,可以通过/sys/kernel/debug/cma/cma-isp/base_pfn查看CMA区域详细信息。实测发现CMA基址为0x2DC00000,正好与DTS中isp_reserved配置一致。
问题的根源在于CMA分配器的工作机制:它优先从物理内存高地址分配空间,然后映射到lowmem区域使用。但在32位Linux系统中,lowmem通常无法覆盖全部物理内存。当CMA分配的物理内存超出lowmem映射范围时,就会导致访问越界。
具体到我们的案例:
计算可知,CMA区域末端距离lowmem上限只有16MB余量。当视频处理需要分配多个18MB的帧缓冲区时,很容易就会突破这个界限。
最直接的解决方案是调整DTS中的CMA配置,限制分配范围不与lowmem冲突。具体修改如下:
dts复制&isp_reserved {
alloc-ranges = <0x10000000 0x10000000>;
size = <0x10000000>;
};
这个方案通过alloc-ranges参数明确指定CMA分配范围,确保不会触及lowmem边界。优点是保留了CMA连续内存分配的性能优势,对现有代码改动小。但缺点是没有从根本上解决内存利用率低的问题,大块连续内存分配仍然可能导致碎片化。
更彻底的解决方案是放弃CMA,改用系统的DMA Scatter-Gather机制。这需要修改ISP驱动中的内存分配策略:
c复制// driver/media/platform/rockchip/isp/hw.c
static int rkisp_hw_probe(struct platform_device *pdev) {
...
if (is_mem_reserved) {
hw_dev->mem_ops = &vb2_rdma_sg_memops;
} else if (hw_dev->is_mmu) {
hw_dev->mem_ops = &vb2_dma_sg_memops;
}
...
}
对应的DTS修改是注释掉memory-region的引用:
dts复制rkisp {
// memory-region = <&isp_reserved>;
};
vb2_dma_sg_memops分配器会使用链表管理分散的内存块,不要求物理连续。虽然理论性能略低于CMA,但在实际测试中,视频处理帧率几乎没有差异。这个方案的优点是内存利用率高,可以更好地应对大内存需求场景。
在激光雷达融合应用中,精确的曝光时刻同步至关重要。默认配置使用EOF(帧结束)中断时间戳,我们改为SOF(帧开始)中断以获得更准确的时间参考。
对于主摄(通道1),修改点在:
对于副摄(通道2),修改点在:
这个优化使得双摄曝光时刻的时间戳误差控制在毫秒级以内,满足了激光雷达同步需求。
调试过程中,USB RNDIS网络配置非常有用。RV1126 BSP已经内置了USB Gadget支持,只需在/etc/init.d/.usb_confg文件中添加usb_rndis_en即可启用。但要注意Windows下的驱动兼容性问题,建议单独配置RNDIS而不与ADB共用。
DHCP服务器配置也很重要:
sh复制# buildroot配置
BR2_PACKAGE_DHCP=y
BR2_PACKAGE_DHCP_SERVER=y
# dhcpd.conf配置
subnet 192.168.3.0 netmask 255.255.255.0 {
range 192.168.3.10 192.168.3.20;
}
启动顺序问题需要特别注意,建议在自定义启动脚本中重新调度网络服务:
sh复制/etc/init.d/S40network restart
/etc/init.d/S80dhcp-server restart
RV1126的最新SDK已经支持双摄拼接功能,但完整度有待提高。关键点在于:
遇到的典型问题包括:
在实际项目中,双摄驱动的稳定性往往取决于这些细节问题的处理。建议在前期就建立完整的内存检测机制,避免后期出现难以定位的越界问题。