RK平台车载摄像头开发:从底层到应用的全面解析

电子说

1.4w人已加入

描述

 

 

 

在智能汽车快速发展的今天,车载摄像头作为环境感知、辅助驾驶的核心部件,其稳定性、实时性和安全性直接影响着整车的智能化体验。瑞芯微(Rockchip)凭借其高性能的 SoC 平台和完善的车载摄像头开发框架,为开发者提供了一套高效、可靠的车载摄像头解决方案。本文将基于瑞芯微车载摄像头开发指南,从驱动开发、中间件使用到应用层实战,全面解析 RK 平台车载摄像头的开发流程与技术要点,配套完整可落地的代码示例,手把手带你完成车载摄像头全链路开发。

 

 

一、系统整体架构:车载摄像头开发的基础框架

智能汽车

 

 

 

1.1 系统模块与框架

 

 

瑞芯微车载摄像头系统是一套经过精心设计的中间件软件系统,旨在满足汽车行业严格的高效、安全和可靠性标准。整个系统采用分层设计,从底层硬件到上层应用全链路覆盖,核心模块如下:

 

 

层级

 

 

核心模块

 

 

核心职责

 

 

内核驱动层

 

 

SEDES 驱动层

 

 

负责Maxim SerDes串行解串器、远端Sensor的驱动适配,实现长距离图像数据的采集、传输与解析

 

 

核心中间件层

 

 

RVCAM 中间件

 

 

车载摄像头方案的核心,提供统一的摄像头数据管理、虚拟多摄多开、算法扩展、跨系统通信能力,屏蔽底层硬件差异

 

 

硬件抽象层

 

 

EVS HALAutomotive HAL3

 

 

对接AAOS车载安卓标准框架,为倒车影像、环视、座舱相机应用提供标准化接口

 

 

应用层

 

 

EVS APPNative/APK应用

 

 

实现倒车影像、360°环视、行车记录、DMS舱内监控等业务功能

 

 

1.2 安全与质量标准

 

 

车载系统对安全性要求极高,瑞芯微车载摄像头系统完全符合汽车行业的安全标准,包括ISO26262 功能安全标准,确保在各种工况下的稳定运行。

 

 

编码规范:遵循MISRA-C/MISRA-C++ 编码规范,通过Google C++ Lint做代码审查,减少潜在缺陷;

 

 

故障防护:内置FMEA故障模式与影响分析机制,支持摄像头热插拔检测、故障诊断与恢复;

 

 

功能安全:以FuSa功能安全为核心设计,确保系统出现故障时能以安全方式响应。

 

 

1.3 功能开发路线图

 

 

瑞芯微为车载摄像头系统规划了完善的功能开发路线,以满足不同车载场景的需求:

 

 

已完成功能:YUV 摄像头虚拟多摄映射、SerDes 多路 RAW + ISP 支持;

 

 

开发中功能:单 SerDes 多 MIPI PHY 输出、车辆电源管理事件订阅、摄像头热插拔支持;

 

 

规划中功能:低延时系统优化、ISP HAL 支持虚拟多摄、摄像头诊断功能、第三方摄像头接口扩展、SOME/IP车载服务、多传感器融合框架等。

 

 

二、SEDES 驱动开发:摄像头数据传输的底层基石

 

 

车载摄像头与消费级摄像头最大的差异,在于通过SerDes芯片实现长距离同轴/双绞线传输,这也是车载摄像头开发的第一个核心门槛。瑞芯微提供了完整的Maxim Camera SerDes V3驱动框架,完美适配主流车规级SerDes芯片与Sensor组合。

 

 

2.1 Maxim Camera Serdes 驱动概述

 

 

Maxim(美信)的GMSL SerDes是车载场景最常用的串行解串器方案,瑞芯微驱动已原生支持以下芯片组合:

 

 

近端解串器

 

 

远端串化器

 

 

远端Sensor

 

 

MAX96712MAX96722MAX96716MAX96718

 

 

MAX9295MAX96715MAX96717

 

 

OV2311/OV2312OX01F10OX03J10SC320ATOS04A10

 

 

驱动基于Linux media框架设计,核心分为近端解串器(Local)驱动远端设备(Remote)驱动两大部分,通过I2C-MUX技术实现远端多设备的独立控制,将多路摄像头数据通过不同MIPI VC通道隔离,最终输出给SoCISP/CIF模块。

智能汽车

 

 

 

2.1.1 驱动目录结构

 

 

Maxim Camera Serdes 驱动的目录结构清晰,所有代码均在内核源码的drivers/media/i2c/maxim/路径下,便于开发者适配和扩展:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
kernel/drivers/media/i2c/maxim/├── Kconfig                 # 驱动总配置入口├── Makefile                # 驱动总编译规则├── local/                  # 近端解串器驱动│   ├── maxim2c/            # 双路解串器驱动(MAX96716/MAX96718)│   │   ├── Kconfig、Makefile│   │   ├── maxim2c_drv.c   # 驱动入口、I2C设备管理│   │   ├── maxim2c_link.c  # GMSL链路管理│   │   ├── maxim2c_video_pipe.c # 视频管道映射│   │   └── maxim2c_mipi_txphy.c # MIPI输出PHY配置│   └── maxim4c/            # 四路解串器驱动(MAX96712/MAX96722)│       └── 结构同maxim2c└── remote/                 # 远端设备驱动    ├── Kconfig、Makefile    ├── max9295.c/max96715.c/max96717.c # 串化器驱动    ├── ov231x.c/ox03j10.c/sc320at.c   # YUV Sensor驱动    ├── os04a10.c                      # RAW Sensor驱动参考    └── dummy.c                        # 虚拟Sensor调试驱动

2.1.2 config 宏配置

 

 

驱动功能的裁剪与使能,通过内核config宏配置完成,需要在芯片对应的defconfig文件中添加以下配置,可根据实际硬件选型裁剪:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
# ========== Maxim SerDes 驱动总开关 ==========CONFIG_VIDEO_MAXIM_SERDES=y# ========== 近端解串器驱动使能 ==========# 4路解串器(MAX96712/MAX96722)CONFIG_VIDEO_MAXIM_DES_MAXIM4C=y# 2路解串器(MAX96716/MAX96718)CONFIG_VIDEO_MAXIM_DES_MAXIM2C=y# ========== 远端串化器驱动使能 ==========CONFIG_VIDEO_MAXIM_SER_MAX9295=yCONFIG_VIDEO_MAXIM_SER_MAX96715=yCONFIG_VIDEO_MAXIM_SER_MAX96717=y# ========== 远端Sensor驱动使能 ==========CONFIG_VIDEO_MAXIM_CAM_DUMMY=y       # 调试用虚拟SensorCONFIG_VIDEO_MAXIM_CAM_SC320AT=y     # 思特威SC320ATCONFIG_VIDEO_MAXIM_CAM_OV231X=y      # 豪威OV2311/OV2312CONFIG_VIDEO_MAXIM_CAM_OX01F10=y     # 安森美OX01F10CONFIG_VIDEO_MAXIM_CAM_OX03J10=y     # 安森美OX03J10CONFIG_VIDEO_MAXIM_CAM_OS04A10=y     # 豪威OS04A10(RAW Sensor)

2.2 DTS 配置详解:硬件参数的关键配置

 

 

DTSDevice Tree Source)设备树配置,是SerDes驱动适配的核心,90%的驱动适配工作都集中在DTS配置上。瑞芯微官方提供了EVB板的参考配置,我们以RK3588M + MAX96712 4路解串器为例,拆解完整的DTS配置细节。

 

 

2.2.1 I2C Init Sequence 的 DTS 配置

 

 

SerDes芯片的寄存器配置繁多,驱动提供了标准化的I2C初始化序列配置方式,无需修改驱动代码,直接在DTS中配置寄存器序列即可,解串器、串化器、Sensor均可使用该配置方式。

 

 

完整配置示例

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
link-init-sequence {    // 单个配置项的字节长度:reg地址长度 + 寄存器值长度 + mask长度 + 延时长度 = 2+1+1+1=5    seq-item-size = <5>;    reg-addr-len = <2>;    // 寄存器地址长度:2表示16位地址    reg-val-len = <1>;     // 寄存器值长度:1表示8位数据    // 配置序列格式:寄存器地址 寄存器值 掩码 延时(ms) 保留位    init-sequence = [        14 D1 03 00 00  // 配置VGA高增益,寄存器0x14D1写入0x03        14 45 00 00 00  // 关闭SSC扩频,寄存器0x1445写入0x00        04 0A 01 00 00  // 使能链路A,寄存器0x040A写入0x01    ];};

2.2.2 解串器核心节点与Dummy Sensor配置

 

 

首先需要在SoC对应的I2C总线节点下,添加解串器的基础设备节点,将解串器抽象为虚拟Sensor设备,完成电源、时钟、GPIOMIPI输出端口的基础配置。

 

 

完整配置示例

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
/* 以RK3588M的I2C6总线为例,挂载MAX96712解串器 */&i2c6 {    status = "okay";    #address-cells = <1>;    #size-cells = <0>;    pinctrl-names = "default";    pinctrl-0 = <&i2c6m3_xfer>;    /* MAX96712 4路解串器核心节点 */    max96712_dphy3: max96712@29 {        compatible = "maxim4c,max96712";        status = "okay";        reg = <0x29>;  // 解串器I2C 7位地址        clock-names = "xvclk";        clocks = <&max96712_dphy3_osc0 0>; // 外部时钟输入        /* 电源域与电源配置 */        power-domains = <&power RK3588_PD_VI>;        rockchip,grf = <&sys_grf>;        vcc1v2-supply = <&max96712_dphy3_vcc1v2>; // 1.2V电源        vcc1v8-supply = <&max96712_dphy3_vcc1v8>; // 1.8V电源        pwdn-supply = <&max96712_dphy3_pwdn_regulator>; // 掉电控制电源        poc-supply = <&max96712_dphy3_poc_regulator>;  // 远端摄像头PoC同轴供电        /* GPIO与状态引脚配置 */        pinctrl-names = "default";        pinctrl-0 = <&max96712_dphy3_errb>, <&max96712_dphy3_lock>;        lock-gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>; // 链路锁定状态引脚        errb-gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>;  // 错误中断引脚        /* 摄像头模组标识(RK摄像头框架必填) */        rockchip,camera-module-index = <0>;        rockchip,camera-module-facing = "back";        rockchip,camera-module-name = "default";        rockchip,camera-module-lens-name = "default";        /* ========== 1. 输出模式配置 ========== */        support-mode-config {            status = "okay";            bus-format = // 输出数据格式            sensor-width = <1920>;    // 图像宽度            sensor-height = <1440>;   // 图像高度            max-fps-numerator = <10000>;            max-fps-denominator = <300000>; // 30fps            bpp = <16>;               // 每像素比特数            vc-array = <0x10 0x20 0x40 0x80>; // 4路摄像头映射到VC0-VC3        };        /* ========== 2. RAW Sensor ISP路由配置(多路RAW Sensor必填) ========== */        // 使能后,远端Sensor的控制权交给ISP驱动,关闭则由解串器统一管理        remote-routing-to-isp = <0>;        /* ========== 3. MIPI输出端口绑定 ========== */        port {            max96712_dphy3_out: endpoint {                remote-endpoint = <&mipi_dphy3_in_max96712>; // 绑定到SoC的MIPI DPHY3                data-lanes = <1 2 3 4>; // MIPI数据线数量            };        };        /* ========== 4. GMSL链路配置(4路Link对应4个远端摄像头) ========== */        gmsl-links {            status = "okay";            // Link A 链路配置(对应第1路摄像头)            gmsl-link-config-0 {                status = "okay";                link-id = <0>;               // 链路ID:0=Link A,1=Link B,以此类推                link-type = <1>;             // 链路类型:0=GMSL1,1=GMSL2                link-rx-rate = <1>;          // 正向速率:0=3Gbps,1=6Gbps                link-tx-rate = <0>;          // 反向速率:0=187.5Mbps                link-remote-cam = <&max96712_dphy3_cam0>; // 绑定远端摄像头节点                // 链路专属初始化序列                link-init-sequence {                    seq-item-size = <5>;                    reg-addr-len = <2>;                    reg-val-len = <1>;                    init-sequence = [                        14 D1 03 00 00                        14 45 00 00 00                    ];                };            };            // Link B 链路配置(对应第2路摄像头)            gmsl-link-config-1 {                status = "okay";                link-id = <1>;                link-type = <1>;                link-rx-rate = <1>;                link-tx-rate = <0>;                link-remote-cam = <&max96712_dphy3_cam1>;            };            // Link C、Link D 配置以此类推...        };        /* ========== 5. 视频管道配置(实现链路数据到VC通道的映射) ========== */        video-pipes {            status = "okay";            // 管道0:对应Link A的摄像头数据            video-pipe-config-0 {                status = "okay";                pipe-id = <0>;                pipe-idx = <2>;                link-idx = <0>; // 绑定到Link A(link-id=0)                // 管道初始化序列:配置CSI2映射、VC通道、数据类型                pipe-init-sequence {                    seq-item-size = <5>;                    reg-addr-len = <2>;                    reg-val-len = <1>;                    init-sequence = [                        09 0B 07 00 00  // 使能Src/Dst映射                        09 2D 15 00 00  // 映射到CSI2控制器1                        09 0D 1e 00 00  // 配置SRC0 VC=0,DT=YUV422 8bit                        09 0E 1e 00 00  // 配置DST0 VC=0,DT=YUV422 8bit                    ];                };            };            // 管道1:对应Link B的摄像头数据,以此类推...        };        /* ========== 6. MIPI TXPHY输出配置 ========== */        mipi-txphys {            status = "okay";            phy-mode = <0>; // PHY模式:0=2X4Lanes,1=4X2Lanes            phy-force-clock-out = <1>; // 强制输出MIPI时钟,避免无摄像头时PHY不工作            // PHY0配置            mipi-txphy-config-0 {                status = "okay";                phy-id = <0>;                phy-type = <0>; // 0=DPHY,1=CPHY                data-lane-num = <4>;                data-lane-map = <0x4>;            };        };        /* ========== 7. 额外初始化序列(帧同步、GPIO等扩展配置) ========== */        extra-init-sequence {            seq-item-size = <5>;            reg-addr-len = <2>;            reg-val-len = <1>;            init-sequence = [                08 17 01 00 00            ];        };        /* ========== 8. 远端设备I2C-MUX配置(核心!实现远端串化器/Sensor的I2C通信) ========== */        i2c-mux {            #address-cells = <1>;            #size-cells = <0>;            // Link A对应的远端I2C通道            i2c@0 {                #address-cells = <1>;                #size-cells = <0>;                reg = <0>; // 对应link-id=0                // 注意:串化器节点必须写在Sensor节点前面,保证驱动probe顺序                max96712_dphy3_ser0: max96717@41 {                    compatible = "maxim,ser,max96717";                    reg = <0x41>; // 映射后的I2C地址                    ser-i2c-addr-def = <0x40>; // 串化器默认上电地址                    // 串化器初始化序列                    ser-init-sequence {                        seq-item-size = <5>;                        reg-addr-len = <2>;                        reg-val-len = <1>;                        init-sequence = [                            03 02 10 00 00                            14 17 00 00 00                        ];                    };                };                // Link A对应的远端Sensor节点                max96712_dphy3_cam0: sc320at@31 {                    compatible = "maxim,smartsens,sc320at";                    reg = <0x31>; // 映射后的I2C地址                    cam-i2c-addr-def = <0x30>; // Sensor默认上电地址                    cam-remote-ser = <&max96712_dphy3_ser0>; // 绑定对应的串化器                    poc-supply = <&max96712_dphy3_poc_regulator>; // PoC供电                    // RK摄像头框架必填参数                    rockchip,camera-module-index = <0>;                    rockchip,camera-module-facing = "back";                    rockchip,camera-module-name = "default";                    rockchip,camera-module-lens-name = "default";                    // 端口配置(RAW Sensor需绑定到ISP节点)                    port {                        max96712_dphy3_cam0_out: endpoint {                            data-lanes = <1 2 3 4>;                        };                    };                };            };            // Link B对应的远端I2C通道i2c@1,以此类推...        };    };};

2.2.3 RAW Sensor专属DTS配置

 

 

如果使用RAW输出的Sensor,需要额外配置ISP路由,核心修改3处:

 

 

1.解串器节点添加remote-routing-to-isp = <1>,使能多路RAW Sensor路由;

 

 

2.远端Sensorport节点添加remote-endpoint,链接到ISP的输入节点;

 

 

3.SoCrkcif_mipi_lvds节点添加camera-over-bridge属性,开启远端RAW Sensor模式。

 

 

2.3 近端解串器驱动开发

 

 

瑞芯微已经完成了maxim4c4路)和maxim2c2路)解串器的完整驱动实现,常规场景无需修改驱动代码,仅需通过DTS配置即可完成适配。驱动核心能力包括:

 

 

解串器的虚拟Sensor抽象与v4l2 subdev接口实现;

 

 

GMSL链路管理、锁定状态检测、热插拔恢复;

 

 

远端设备的上下电、开关流统一管理;

 

 

MIPI TXPHY配置与CSI-2数据输出控制;

 

 

内置测试彩条Pattern输出,可用于硬件通路调试。

 

 

如果需要自定义扩展,可直接修改对应驱动文件,核心API接口均在maxim4c_api.h/maxim2c_api.h中声明。

 

 

2.4 远端摄像头驱动适配

 

 

对于YUV输出的摄像头模组,模组内部已完成ISP处理,上电后自动加载配置,直接使用官方适配好的Sensor驱动,或dummy驱动即可;对于RAW输出的Sensor,需要基于官方框架完成驱动适配,以下是适配的核心代码细节与8大关键改动点。

 

 

2.4.1 KconfigMakefile配置

 

 

首先在remote/目录下添加新Sensor的编译配置,避免和原生Sensor驱动冲突。

 

 

Kconfig配置示例drivers/media/i2c/maxim/remote/Kconfig):

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
config VIDEO_MAXIM_CAM_OS04A10    tristate "Maxim Remote Sensor OV OS04A10"    depends on VIDEO_MAXIM_SERDES    depends on I2C    help      This driver supports the remote OS04A10 sensor over Maxim SerDes.      To compile this driver as a module, the module will be called maxim-os04a10.

Makefile配置示例drivers/media/i2c/maxim/remote/Makefile):

 

 

  •  
  •  
  •  
# 给驱动模块加maxim-前缀,避免和原生OS04A10驱动重名maxim-os04a10-objs := os04a10.oobj-$(CONFIG_VIDEO_MAXIM_CAM_OS04A10) += maxim-os04a10.o

2.4.2 驱动核心适配代码

 

 

和消费级Sensor驱动相比,SerDes远端Sensor驱动有8个核心改动点,以下是关键代码示例:

 

 

1. 驱动名与compatible适配

 

 

添加maxim,前缀,避免和原生驱动冲突,示例如下:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
static const struct of_device_id os04a10_of_match[] = {    { .compatible = "maxim,ovti,os04a10" }, // 必须加maxim前缀    { /* sentinel */ },};MODULE_DEVICE_TABLE(of, os04a10_of_match);static struct i2c_driver os04a10_i2c_driver = {    .driver = {        .name = "maxim-os04a10"// 驱动名加前缀        .pm = &os04a10_pm_ops,        .of_match_table = of_match_ptr(os04a10_of_match),    },    .probe = &os04a10_probe,    .remove = &os04a10_remove,};module_i2c_driver(os04a10_i2c_driver);

2. 核心数据结构添加SerDes相关成员

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
struct os04a10 {    struct v4l2_subdev sd;    struct media_pad pad;    struct regulator *poc_regulator; // PoC同轴供电,替代原生多电源    struct maxim_remote_ser *serializer; // 绑定的串化器设备    u8 cam_i2c_addr_def; // Sensor默认I2C地址    u8 cam_i2c_addr_map; // 映射后的I2C地址    // 其他原有Sensor参数...};

3. probe函数核心适配

 

 

probe阶段不再做MCLKGPIO、电源的硬件配置,核心完成串化器绑定、PoC电源获取,不再做Chip ID检测(链路未初始化时I2C无法通信)。

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
static int os04a10_probe(struct i2c_client *client, const struct i2c_device_id *id){    struct device *dev = &client->dev;    struct os04a10 *sensor;    int ret;    // 1. 分配驱动结构体    sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);    if (!sensor)        return -ENOMEM;    // 2. 获取PoC供电 regulator(替代原生的多电源配置)    sensor->poc_regulator = devm_regulator_get(dev, "poc");    if (IS_ERR(sensor->poc_regulator)) {        dev_err(dev, "Failed to get PoC regulatorn");        return PTR_ERR(sensor->poc_regulator);    }    // 3. 绑定远端串化器(核心!必须实现)    sensor->serializer = maxim_remote_cam_bind_ser(dev);    if (!sensor->serializer) {        dev_err(dev, "Bind remote serializer failedn");        return -ENODEV;    }    // 传递Sensor的I2C地址信息给串化器    sensor->cam_i2c_addr_def = 0x30// 替换为你的Sensor默认地址    sensor->serializer->cam_i2c_addr_def = sensor->cam_i2c_addr_def;    sensor->serializer->cam_i2c_addr_map = client->addr;    // 4. 初始化v4l2_subdev、media pad等框架代码    // ... 原有Sensor的v4l2框架初始化代码,此处省略...    dev_info(dev, "Maxim remote OS04A10 sensor probe successn");    return 0;}

4. 电源上下电适配

 

 

移除原生的多电源、GPIO复位代码,改为PoC电源控制,示例如下:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
static int __os04a10_power_on(struct os04a10 *sensor){    int ret;    // 开启PoC同轴供电    ret = regulator_enable(sensor->poc_regulator);    if (ret) {        dev_err(&sensor->sd.client->dev, "PoC power enable failedn");        return ret;    }    // 等待电源稳定    usleep_range(1000012000);    return 0;}static int __os04a10_power_off(struct os04a10 *sensor){    return regulator_disable(sensor->poc_regulator);}

5. 开关流接口适配(核心)

 

 

开流阶段才完成串化器初始化、Chip ID检测、Sensor寄存器配置,这是和消费级Sensor最大的区别。

 

 

开流函数完整示例

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
static int __os04a10_start_stream(struct os04a10 *sensor){    struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);    struct device *dev = &client->dev;    struct maxim_remote_ser *serializer = sensor->serializer;    int ret;    // 1. 先初始化串化器    ret = serializer->ser_ops->ser_module_init(serializer);    if (ret) {        dev_err(dev, "Serializer init failed, ret=%dn", ret);        return ret;    }    // 2. 检测Sensor Chip ID(必须在串化器初始化后执行)    ret = os04a10_check_chip_id(sensor);    if (ret) {        dev_err(dev, "Sensor chip id check failedn");        goto err_ser_deinit;    }    // 3. 写入Sensor初始化寄存器序列    ret = os04a10_write_regs(client, sensor->cur_mode->reg_list);    if (ret) {        dev_err(dev, "Sensor init regs write failedn");        goto err_ser_deinit;    }    // 4. 配置v4l2控制参数(曝光、增益等)    ret = __v4l2_ctrl_handler_setup(&sensor->ctrl_handler);    if (ret) {        dev_err(dev, "v4l2 ctrl setup failedn");        goto err_ser_deinit;    }    // 5. 启动Sensor流输出    ret = os04a10_set_streaming(sensor, true);    if (ret) {        dev_err(dev, "Sensor start streaming failedn");        goto err_ser_deinit;    }    // 6. 检测串化器PCLK,确认Sensor数据正常输出    ret = serializer->ser_ops->ser_pclk_detect(serializer);    if (ret) {        dev_err(dev, "Serializer PCLK detect failed, no data inputn");        goto err_stop_stream;    }    dev_info(dev, "OS04A10 start stream successn");    return 0;err_stop_stream:    os04a10_set_streaming(sensor, false);err_ser_deinit:    serializer->ser_ops->ser_module_deinit(serializer);    return ret;}

关流函数完整示例

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
static int __os04a10_stop_stream(struct os04a10 *sensor){    struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);    struct device *dev = &client->dev;    struct maxim_remote_ser *serializer = sensor->serializer;    int ret;    // 1. 停止Sensor流输出    ret = os04a10_set_streaming(sensor, false);    if (ret)        dev_warn(dev, "Sensor stop streaming failedn");    // 2. 反初始化串化器    ret = serializer->ser_ops->ser_module_deinit(serializer);    if (ret)        dev_warn(dev, "Serializer deinit failedn");    dev_info(dev, "OS04A10 stop stream successn");    return 0;}

6. 移除MCLKGPIO相关代码

 

 

SerDes架构下,SensorMCLK、复位引脚均由远端串化器提供,无需SoC控制,直接删除驱动中相关的时钟申请、GPIO配置代码即可。

 

 

三、RVCAM 中间件:车载摄像头应用开发的利器

 

 

RVCAMRockchip Vehicle Camera)是瑞芯微车载摄像头方案的灵魂,它屏蔽了底层硬件差异,提供了统一的API接口,完美解决了车载场景一摄多开、多应用共享、低延时传输、跨系统通信等核心痛点,是应用开发的核心抓手。

 

 

3.1 RVCAM 介绍

 

 

RVCAM是专为车载场景设计的摄像头中间件,核心能力包括:

 

 

虚拟多摄多开:一个物理摄像头可映射为多个虚拟摄像头,支持倒车影像、行车记录、环视应用同时访问,无资源抢占问题;

 

 

全接口适配:同时支持Native API直接调用、AAOS EVS HALAndroid Camera HAL3,满足不同开发场景;

 

 

低开销高性能RK3576M平台四路1080P@30fps摄像头同时开启,CPU占用率仅10%左右;

 

 

跨系统支持:原生支持Android+Linux双系统架构,基于eRPC实现跨系统摄像头控制与数据共享;

 

 

可扩展架构:支持插件式集成图像处理算法,如畸变校正、HDRBEV融合等。

 

 

3.2 RVCAM API 使用指南

 

 

RVCAM提供了极简的C语言API接口,Native应用可直接调用,无需关心底层V4L2驱动细节,以下是API分类与完整的采集流程代码示例

 

 

3.2.1 核心API分类

 

 

API分类

 

 

核心功能

 

 

关键接口

 

 

初始化与终止

 

 

管理RVCAM上下文生命周期

 

 

rvcam_initializervcam_uninitialize

 

 

设备信息查询

 

 

获取摄像头列表与参数

 

 

rvcam_query_inputs

 

 

流管理

 

 

摄像头流的开启/关闭/暂停/恢复

 

 

rvcam_openrvcam_closervcam_startrvcam_stop

 

 

参数管理

 

 

摄像头参数的查询与配置

 

 

rvcam_g_paramrvcam_s_param

 

 

帧数据管理

 

 

图像帧的获取与释放

 

 

rvcam_get_framervcam_release_framervcam_s_buffers

 

 

3.2.2 完整的单摄采集代码示例

 

 

以下是基于RVCAM API实现的摄像头采集全流程代码,可直接用于倒车影像、单路预览等场景:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
#include #include #include #include "rvcam_api.h" // RVCAM API头文件int main(int argc, char *argv[]){    int ret = 0;    rvcam_init_t init_params = {0};    rvcam_input_t *camera_list = NULL;    unsigned int camera_num = 0;    rvcam_hndl_t cam_handle = NULL;    rvcam_frame_info_t frame_info = {0};    int capture_count = 100// 采集100帧    // ========== 1. 初始化RVCAM上下文 ==========    ret = rvcam_initialize(&init_params);    if (ret != 0) {        printf("RVCAM initialize failed, ret=%dn", ret);        return -1;    }    printf("RVCAM initialize successn");    // ========== 2. 查询系统中的摄像头列表 ==========    // 第一次调用:获取摄像头数量    ret = rvcam_query_inputs(NULL0, &camera_num);    if (ret != 0 || camera_num == 0) {        printf("Query camera num failed, ret=%d, num=%dn", ret, camera_num);        goto err_uninit;    }    printf("Found %d cameras in systemn", camera_num);    // 分配内存,第二次调用:获取摄像头详细信息    camera_list = (rvcam_input_t *)malloc(sizeof(rvcam_input_t) * camera_num);    if (!camera_list) {        printf("Malloc camera list failedn");        goto err_uninit;    }    ret = rvcam_query_inputs(camera_list, camera_num, &camera_num);    if (ret != 0) {        printf("Query camera info failed, ret=%dn", ret);        goto err_free_list;    }    // 打印摄像头信息    for (int i = 0; i < camera_num; i++) {        printf("Camera %d: name=%s, resolution=%dx%dn",               camera_list[i].id, camera_list[i].name,               camera_list[i].width, camera_list[i].height);    }    // ========== 3. 打开指定虚拟摄像头(以camId=0为例) ==========    int target_cam_id = 0;    cam_handle = rvcam_open(target_cam_id);    if (!cam_handle) {        printf("Open camera %d failedn", target_cam_id);        goto err_free_list;    }    printf("Open camera %d successn", target_cam_id);    // ========== 4. 配置摄像头参数(可选) ==========    // 示例:设置分辨率、帧率等参数    // rvcam_param_value_t param_val = {0};    // param_val.width = 1920;    // param_val.height = 1080;    // ret = rvcam_s_param(cam_handle, RVCAM_PARAM_RESOLUTION, ¶m_val);    // ========== 5. 启动摄像头数据流 ==========    ret = rvcam_start(cam_handle);    if (ret != 0) {        printf("Start camera stream failed, ret=%dn", ret);        goto err_close_cam;    }    printf("Start camera stream successn");    // ========== 6. 循环采集帧数据 ==========    for (int i = 0; i < capture_count; i++) {        // 获取一帧数据,超时时间500ms        ret = rvcam_get_frame(cam_handle, &frame_info, 5000);        if (ret != 0) {            printf("Get frame %d failed, ret=%dn", i, ret);            continue;        }        // 帧数据处理        printf("Capture frame %d success: timestamp=%llu, width=%d, height=%d, format=%d, buf_fd=%dn",               i, frame_info.timestamp, frame_info.width, frame_info.height,               frame_info.format, frame_info.buf_fd);
        // ========== 此处可添加图像处理、渲染、编码等业务逻辑 ==========        // 例如:通过RGA做格式转换、缩放;通过OpenGL渲染显示;保存为图片/视频等        // 释放帧缓冲区,必须调用,否则会出现缓冲区耗尽        ret = rvcam_release_frame(cam_handle, frame_info.idx);        if (ret != 0) {            printf("Release frame %d failed, ret=%dn", i, ret);        }        // 控制采集帧率        usleep(30000); // 30fps    }    // ========== 7. 停止数据流 ==========    ret = rvcam_stop(cam_handle);    if (ret != 0) {        printf("Stop camera stream failed, ret=%dn", ret);    }    printf("Stop camera stream successn");    // ========== 8. 资源释放 ==========err_close_cam:    rvcam_close(cam_handle);err_free_list:    free(camera_list);err_uninit:    rvcam_uninitialize();    printf("RVCAM resource release donen");    return ret;}

3.3 RVCAM 配置文件详解

 

 

RVCAM的所有物理摄像头配置、虚拟摄像头映射关系,都在rvcam_config.xml中定义,编译后部署到板端/vendor/etc/rvcam_config.xml,是实现多摄多开的核心。

 

 

3.3.1 完整的配置文件示例

 

 

以下是支持4路物理摄像头、一摄三开的完整配置示例,可直接参考修改:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
"1.0" encoding="UTF-8"?><CameraConfig version="0x100">        <board name="Rockchip RK3588 VEHICLE EVB V22 Board">                <cameras>                        <camera id="0">                <entity>m00_b_max96712 6-0029entity>                <subDev>/dev/v4l-subdev5subDev>                <mbusCode>UYVY8_2X8/1920x1440mbusCode>                                <channels>                                        <channel id="0" dev="/dev/video11">                        <cameraModel>Rear_CamcameraModel>                        <stream id="0" format="YUYV" width="1920" height="1440" bufCnt="4"/>                    channel>                                        <channel id="1" dev="/dev/video12">                        <cameraModel>Right_CamcameraModel>                        <stream id="0" format="YUYV" width="1920" height="1440" bufCnt="4"/>                    channel>                                        <channel id="2" dev="/dev/video13">                        <cameraModel>Left_CamcameraModel>                        <stream id="0" format="YUYV" width="1920" height="1440" bufCnt="4"/>                    channel>                                        <channel id="3" dev="/dev/video14">                        <cameraModel>Front_CamcameraModel>                        <stream id="0" format="YUYV" width="1920" height="1440" bufCnt="4"/>                    channel>                channels>            camera>        cameras>                        <inputMapping>                        <inputMap camId="0">                <inputSrc cameraId="0" channelId="0" streamId="0"/>            inputMap>            <inputMap camId="1">                <inputSrc cameraId="0" channelId="1" streamId="0"/>            inputMap>            <inputMap camId="2">                <inputSrc cameraId="0" channelId="2" streamId="0"/>            inputMap>            <inputMap camId="3">                <inputSrc cameraId="0" channelId="3" streamId="0"/>            inputMap>                        <inputMap camId="4">                <inputSrc cameraId="0" channelId="0" streamId="0"/>            inputMap>            <inputMap camId="5">                <inputSrc cameraId="0" channelId="0" streamId="0"/>            inputMap>                        <inputMap camId="6">                <inputSrc cameraId="0" channelId="1" streamId="0"/>            inputMap>        inputMapping>    board>    CameraConfig>

3.3.2 关键配置说明

 

 

board name:必须和主板的device-tree model一致,否则配置不生效;

 

 

camera节点:对应物理解串器设备,channels下的每个channel对应一个物理摄像头通道;

 

 

inputMapping节点:核心的虚拟映射配置,同一个物理channel可以映射给多个inputMap,实现一摄多开;

 

 

camId分配:AAOS系统默认0-3号给EVS使用,Camera HAL34号开始,避免ID冲突导致上层应用找不到设备。

 

 

3.4 RVCAM 调试功能

 

 

RVCAM内置了完善的调试功能,可通过系统属性开启,用于排查帧率、丢帧、多开冲突等问题:

 

 

  •  
  •  
  •  
  •  
# 1. 开启RVCAM调试日志,自动写入文件adb shell setprop persist.vendor.rockchip.rvcam.dbgfile.on true# 2. 设置日志写入间隔(单位:ms,默认200ms)adb shell setprop persist.vendor.rockchip.rvcam.dbgfile.interval 200

调试日志路径:/data/vendor/camera/rvcam_debug.log,日志中包含摄像头开关状态、实时帧率、丢帧统计、buffer状态等关键信息。

 

 

四、EVS 模块:车载视觉应用的核心框架

 

 

EVSExterior View System)是Android Automotive OS专为车载视觉设计的标准框架,核心优势是启动速度快、低延时,能在Android启动早期就完成倒车影像的渲染,满足车规级倒车影像<2s的启动时效要求,是车载后视、环视应用的首选方案。

 

 

4.1 EVS 模块划分与目录介绍

 

 

RK平台的EVS方案完全遵循AAOS标准架构,底层基于RVCAM中间件实现,无需修改核心代码,仅需完成配置即可快速落地。EVS框架分为以下几个核心部分:

 

 

模块

 

 

源码路径

 

 

核心职责

 

 

EVS APP

 

 

packages/services/Car/cpp/evs/apps/default/

 

 

负责图像渲染、车辆状态响应、UI交互、环视拼接

 

 

EVS Manager

 

 

Android12: packages/services/Car/cpp/evs/manager/
Android14: packages/services/Car/cpp/evs/manager/aidl

 

 

中间管理层,封装EVS HAL接口,管理摄像头与显示设备

 

 

EVS HAL

 

 

瑞芯微定制实现,基于RVCAM

 

 

硬件抽象层,对接RVCAM中间件,向上提供标准EVS HIDL/AIDL接口

 

 

CarEvsService

 

 

packages/services/Car/service/

 

 

Java层服务,为APK应用提供EVS接口

 

 

4.2 EVS 核心数据流程

 

 

EVS的核心数据流程分为摄像头数据采集流程显示渲染流程两部分:

 

 

1.摄像头数据流程EVS APP启动后,通过EVS Manager打开EVS HAL的摄像头设备,EVS HAL通过RVCAM获取摄像头帧数据,通过deliverFrame接口将帧数据上报给EVS APPAPP将帧数据存入双Buffer,通过OpenGL ES完成畸变校正、拼接、渲染后,释放buffer给底层。

 

 

2.显示渲染流程EVS APPEVS HAL获取显示Buffer,完成图像绘制后,将Buffer返回给EVS HAL完成上屏显示。

 

 

4.3 EVS 产品配置详解

 

 

EVS的适配核心在于配置文件,分为EVS APP配置、EVS HAL配置、服务与SELinux配置三大部分。

 

 

4.3.1 EVS APP 配置文件

 

 

EVS APP的核心配置文件为config_override.json,编译后部署到板端/vendor/etc/automotive/evs/config_override.json,用于配置车辆参数、显示参数、摄像头内外参、畸变校正参数等,完整配置示例如下:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
{    "car": {        "width": 180,        "wheelBase": 280,        "frontExtent": 90,        "rearExtent": 70    },    "displays": [        {            "displayPort": 0,            "frontRange": 200,            "rearRange": 200        }    ],    "graphic": {        "frontPixel": 23,        "rearPixel": 223    },    // 核心:摄像头参数配置,每个摄像头对应一个节点    "cameras": [        {            "cameraId": "0",            "function": "reverse,park",            "x": 0.0,            "y": -70.0,            "z": 120,            "yaw": 180,            "pitch": -20,            "roll": 0,            "hfov": 130,            "vfov": 100,            "hflip": true,            "vflip": true        },        {            "cameraId": "1",            "function": "right",            "x": 90.0,            "y": 100.0,            "z": 120,            "yaw": 90,            "pitch": -15,            "roll": 0,            "hfov": 130,            "vfov": 100,            "hflip": false,            "vflip": false        },        {            "cameraId": "2",            "function": "left",            "x": -90.0,            "y": 100.0,            "z": 120,            "yaw": -90,            "pitch": -15,            "roll": 0,            "hfov": 130,            "vfov": 100,            "hflip": false,            "vflip": false        },        {            "cameraId": "3",            "function": "front",            "x": 0.0,            "y": 90.0,            "z": 120,            "yaw": 0,            "pitch": -15,            "roll": 0,            "hfov": 130,            "vfov": 100,            "hflip": false,            "vflip": false        }    ]}

关键说明:

 

 

cameraId:必须和rvcam_config.xml中的虚拟摄像头camId一一对应;

 

 

function:定义摄像头的用途,EVS APP会根据车辆档位、转向灯状态自动切换对应摄像头;

 

 

位姿参数x/y/z/yaw/pitch/roll、视场角hfov/vfov:需根据摄像头实际安装位置和参数填写,直接影响环视拼接的效果。

 

 

4.3.2 EVS HAL 配置文件

 

 

EVS HAL的配置文件为evs_configuration_override.xml,部署到板端/vendor/etc/automotive/evs/evs_configuration_override.xml,用于定义EVS HAL向上暴露的摄像头设备信息,完整配置示例如下:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
<evs_config>    <camera>                <device id='0' position='rear'>            <caps>                <supported_controls>                supported_controls>                                <stream id='0' width='1920' height='1440' format='YCRCB_420_SP' framerate='30'/>                <stream id='1' width='1280' height='720' format='YCRCB_420_SP' framerate='30'/>            caps>            <characteristics/>        device>                <device id='1' position='right'>            <caps>                <stream id='0' width='1920' height='1440' format='YCRCB_420_SP' framerate='30'/>            caps>            <characteristics/>        device>                <device id='2' position='left'>            <caps>                <stream id='0' width='1920' height='1440' format='YCRCB_420_SP' framerate='30'/>            caps>            <characteristics/>        device>                <device id='3' position='front'>            <caps>                <stream id='0' width='1920' height='1440' format='YCRCB_420_SP' framerate='30'/>            caps>            <characteristics/>        device>    camera>    <display>                <device id='0' type='display'>            <caps>                <stream id='0' width='1920' height='720' format='RGBA_8888'/>            caps>        device>    display>evs_config>

4.3.3 编译与服务配置

 

 

需要在产品的mk文件中添加EVS相关模块的编译配置,示例如下:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
# Android14 AIDL版本编译配置PRODUCT_PACKAGES +=     evs_app     evsmanagerd     android.hardware.automotive.evs-rvcam     cardisplayproxyd# Android12 HIDL版本编译配置# PRODUCT_PACKAGES += #     evs_app #     evs_manager #     android.hardware.automotive.evs@1.1-rvcam #     android.frameworks.automotive.display@1.0-service

同时,瑞芯微已经提供了配套的rc启动脚本、SELinux权限配置,无需额外修改,直接编译即可。

 

 

五、AutomotiveCamera HAL3 层:安卓框架与硬件的桥梁

 

 

Automotive Camera HAL3(简称 AutHAL3)是瑞芯微为车载场景定制的Camera HAL,对接Android标准Camera2 API,底层基于RVCAM中间件实现,为行车记录、舱内监控、DMS/OMS、拍照录像等应用提供标准化的安卓相机接口。

 

 

5.1 基本功能说明

 

 

Android原生的ExternalCamera HAL相比,AutHAL3完美适配车载场景,核心优势如下:

 

 

基于RVCAM中间件,原生支持一摄多开、多应用同时访问,解决了原生HAL摄像头独占的问题;

 

 

支持Buffer Management功能,降低内存峰值,提升捕获请求响应速度;

 

 

支持Buffer透传功能,减少内存拷贝,降低CPU占用和传输延时;

 

 

兼容Android HIDL/AIDL接口,适配Android12/14系统,无需上层应用修改代码。

 

 

AutHAL3的核心链路:Android Camera Framework → AutomotiveCamera HAL3 → RVCAM中间件 → 底层V4L2驱动 → 物理摄像头。

 

 

5.2 核心功能详解

 

 

5.2.1 BUFFER MANAGEMENT 功能

 

 

Buffer ManagementAndroid 10+推出的可选内存管理机制,核心优势是HAL层按需申请buffer,而非框架层提前分配,减少了内存峰值占用,同时让捕获请求可以更快下发。

 

 

AutHAL3已完整实现该功能,Android14+系统可通过配置文件开启,Android12及以下系统默认开启。

 

 

5.2.2 BUFFER 透传功能

 

 

这是RK AutHAL3的核心优化功能。非透传模式下,图像数据需要经过「V4L2驱动 → RVCAM中间件buffer → HALbuffer → 框架层buffer」两次拷贝;开启透传功能后,框架层的输出buffer直接透传给RVCAM,仅需一次拷贝,CPU占用减半,延时大幅降低。

 

 

该功能默认开启,可通过配置文件关闭。

 

 

5.3 HAL3 产品配置详解

 

 

5.3.1 核心配置文件

 

 

AutHAL3的核心配置文件为automotive_camera_config.xml,编译后部署到板端,完整配置示例如下:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
<CameraHalConfig>        <Provider>        <ignore>                        <id>0id>            <id>1id>            <id>2id>            <id>3id>        ignore>                <CameraIdOffset>-4CameraIdOffset>    Provider>            <BufferManager enabled="false"/>        <HalBufferTransfer enabled="true"/>CameraHalConfig>

关键说明:

 

 

ignore节点:必须配置EVS占用的camId,避免HAL3EVS争抢摄像头资源;

 

 

CameraIdOffsetID偏移配置,例如RVCAMcamId=4,经过-4偏移后,上报给Android框架的camera id0,符合安卓应用的使用习惯。

 

 

5.3.2 编译与服务配置

 

 

在产品mk文件中添加HAL3模块的编译配置,示例如下:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
# Android14 AIDL版本PRODUCT_PACKAGES +=     android.hardware.camera.provider-V1-automotive-impl     android.hardware.camera.provider-V1-automotive-service# Android12 HIDL版本# PRODUCT_PACKAGES += #     android.hardware.camera.provider@2.4-impl-automotive #     android.hardware.camera.provider@2.4-automotive-service

瑞芯微已配套提供了rc启动脚本、SELinux权限配置、兼容性矩阵配置,无需额外修改。

 

 

5.4 调试与性能说明

 

 

5.4.1 核心性能指标

 

 

指标项

 

 

规格说明

 

 

虚拟摄像头数量

 

 

rvcam_config.xml配置决定,无硬件限制

 

 

每路摄像头支持的tall stream数量

 

 

1路(拍照流)

 

 

每路摄像头支持的其他stream数量

 

 

2路(预览/录像流)

 

 

支持的图像格式

 

 

BLOBYCbCr_422_IYCbCr_420_888、厂商自定义格式

 

 

支持的分辨率

 

 

以物理摄像头参数为准,最高支持4K

 

 

支持的帧率

 

 

以物理摄像头参数为准,最高支持60fps

 

 

5.4.2 常用调试命令

 

 

1.查看摄像头信息

 

 

  •  
  •  
# 查看HAL3上报给安卓框架的所有摄像头信息、支持的格式/分辨率/帧率adb shell dumpsys media.camera

2.Camera Trace性能调试

 

 

使用Perfetto工具抓取Camera链路的trace数据,分析帧率、延时、性能瓶颈,完整抓取脚本如下:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
adb shell perfetto   -c - --txt   -o /data/misc/perfetto-traces/camera_trace <buffers: {    size_kb: 63488    fill_policy: DISCARD}buffers: {    size_kb: 2048    fill_policy: DISCARD}data_sources: {    config {        name: "android.packages_list"        target_buffer: 1    }}data_sources: {    config {        name: "linux.ftrace"        ftrace_config {            ftrace_events: "ftrace/print"            atrace_categories: "camera" "gfx" "input" "view" "sched"            atrace_apps: "*"        }    }}duration_ms: 10000  # 抓取时长,单位msEOF

抓取完成后,将trace文件导出,通过https://ui.perfetto.dev/网页即可可视化分析。

 

 

六、调试与问题排查:打造稳定高效的车载摄像头系统

 

 

车载摄像头开发过程中,会遇到驱动加载失败、无图像、画面异常、多开冲突等问题,以下是常用的调试技巧和常见问题的排查方案。

 

 

6.1 驱动层调试命令

 

 

1.检查驱动是否加载成功

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
# 查看内核启动日志,搜索SerDes、Sensor相关的probe日志dmesg | grep -i maximdmesg | grep -i sensor# 查看系统中加载的v4l2子设备ls /dev/v4l-subdev*# 查看系统中的视频设备节点ls /dev/video*

2.查看media拓扑链路

 

 

  •  
  •  
# 查看media设备的完整拓扑,确认解串器、Sensor、ISP、CIF的链路是否正确media-ctl -d /dev/media0 -p

3.V4L2通道测试

 

 

  •  
  •  
  •  
  •  
# 查看video设备支持的格式、分辨率v4l2-ctl -d /dev/video11 --list-formats-ext# 测试视频采集,保存为原始文件v4l2-ctl -d /dev/video11 --set-fmt-video=width=1920,height=1440,pixelformat=YUYV --stream-mmap=4 --stream-count=100 --stream-to=/data/capture.yuv

4.I2C通信调试

 

 

  •  
  •  
# 检测I2C总线上的设备,确认解串器、Sensor的I2C地址是否可访问i2cdetect -y 6  # 6为解串器挂载的I2C总线号

6.2 RVCAM与上层调试

 

 

1.查看RVCAM服务状态

 

 

  •  
  •  
  •  
  •  
# Android系统查看RVCAM服务是否正常运行ps -A | grep rvcam# 查看RVCAM服务日志logcat | grep -i rvcam

2.EVS服务调试

 

 

  •  
  •  
  •  
  •  
  •  
  •  
# 查看EVS相关进程ps -A | grep -i evs# 查看EVS日志logcat | grep -i evs# 手动重启EVS相关服务stop evs_app && start evs_app

6.3 常见问题与解决方案

 

 

常见问题

 

 

核心排查方向

 

 

解决方案

 

 

解串器驱动probe失败

 

 

1. I2C地址与硬件是否匹配;2. 电源、GPIO配置是否正确;3. 解串器硬件供电是否正常

 

 

1. 核对硬件原理图,修正DTS中的I2C地址、电源、GPIO配置;2. 用万用表测量解串器供电引脚电压是否正常

 

 

远端Sensor probe成功,但无法通信

 

 

1. 串化器与SensorDTS节点顺序是否正确;2. I2C地址映射是否正确;3. 串化器绑定是否成功

 

 

1. 确保DTS中串化器节点写在Sensor节点前面;2. 核对cam-i2c-addr-defSensor硬件默认地址是否一致;3. 查看内核日志,确认串化器绑定成功

 

 

驱动加载正常,但无图像输出

 

 

1. 解串器链路是否锁定;2. MIPI配置与Sensor输出是否匹配;3. video-pipeVC通道映射是否正确;4. Sensor是否正常输出数据

 

 

1. 查看内核日志,确认GMSL链路lock成功;2. 核对Sensor输出格式、分辨率、帧率与解串器配置是否一致;3. 检查video-pipe的寄存器配置,确保数据映射到正确的VC通道;4. 通过串化器的PCLK检测功能,确认Sensor有数据输出

 

 

上层应用找不到摄像头

 

 

1. rvcam_config.xml配置是否正确;2. 虚拟摄像头camId是否配置;3. EVSHAL3ID是否冲突;4. RVCAM服务是否正常启动

 

 

1. 核对board name与主板model是否一致;2. 确认inputMapping中配置了对应的camId3. 检查HAL3ignore配置,避免ID冲突;4. 查看RVCAM服务日志,确认配置文件加载成功

 

 

多个应用同时访问摄像头失败

 

 

1. 是否配置了一摄多开的虚拟映射;2. 每个应用是否使用不同的虚拟camId

 

 

1. rvcam_config.xmlinputMapping中,给同一个物理通道配置多个虚拟camId2. 不同应用使用不同的虚拟camId打开摄像头

 

 

图像画面花屏、卡顿

 

 

1. MIPI信号质量是否正常;2. SerDes链路速率是否匹配;3. 帧率与带宽是否匹配;4. 缓冲区数量是否足够

 

 

1. 检查硬件线缆、阻抗匹配;2. 核对GMSL链路速率配置,确保满足摄像头数据带宽需求;3. 增加streambufCnt缓冲区数量

 

 

七、总结与展望

 

 

瑞芯微的车载摄像头开发框架,为开发者提供了从底层SerDes驱动适配、中间件配置,到上层AAOS EVS/HAL3应用落地的全链路解决方案,极大降低了车载摄像头的开发门槛。

 

 

对于开发者而言,车载摄像头开发的核心要点可以总结为3步:

 

 

1.底层驱动适配:完成SerDes芯片与SensorDTS配置,RAW Sensor完成驱动适配,确保内核层能正常采集到图像数据;

 

 

2.中间件配置:通过rvcam_config.xml完成物理摄像头与虚拟摄像头的映射,实现一摄多开能力;

 

 

3.上层应用适配:根据业务场景,完成EVS倒车/环视应用配置,或基于Camera2 API开发座舱相机应用。

 

 

希望本文能帮助各位开发者快速掌握RK平台车载摄像头的开发全流程,少走弯路,打造出稳定、高效的车载视觉应用。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分