SA8155P QCOM 车载camera 模块

1. 前言

车载和手机的Camera系统是两套不一样的架构,手机Camera系统最终生成符合人眼感官的图像,需要考虑多样化的场景,如美颜、夜景提亮、降噪、虚化等;而车载Camera系统AIS(Automotive Imaging System)的图像大部分是给自动驾驶等机器识别使用,更多考虑的是远距离传输、多摄像头图像处理等场景。因此两套系统不管是从硬件结构还是从软件框架上差异都很大。

2. 简介

车载Camera的基本组成如下,黄色的箭头代表数据的传输,蓝色的箭头代表控制信号的传输。

ISP图像处理芯片有的会放置在摄像头这边,把处理后的信号传输给到主机,有的是不放置ISP芯片,由主机那边的内置ISP芯片进行图像处理,这样摄像头端的散热会好很多,辐射也小。

这里跟手机Camera最大的差别是多了一个串行器和解串器。我们知道相机传感器或ISP的图像数据输出总线是MIPI CSI标准,其特点是高速穿行,但是传输总线距离较短,否则容易受到干扰无法保证信号的完整性,所以在车辆上,我们需要将其转换成例如GMSL等适合在车上长距离传输的高速总线标准进行传输,所以相机模组内部通常会通过串行板进行总线的转换。另外同轴电缆既可以用来为模组提供电源,也可以传输图像数据。如一些项目,串行器使用MAX92745,解串器是MAX9296A。

总的来说,手机系统上,SOC对接camera硬件,可以直接操作摄像头;而车载系统上,SOC对接的是解串器,camera的配置、上下电需要摄像头模组内的串行器来控制,另外摄像头的供电和信号传输是通过同轴电缆完成的。

车载Camera最经典的使用场景是360°全景图像系统(AVM:Around View Monitor),其硬件拓扑图如下。

原理是利用最少4个广角摄像头的数据合成一幅360°图像的画面。

高清摄像头项目有2种配置方式,分为泊车摄像头(前、后、左、有)和倒车后视摄像头。泊车摄像头和倒车后视摄像头除了Lens其他硬件方案一样。

泊车摄像头系统由安装于车身前、后、左、右四路高清摄像头和智能域控制器组成,域控制器通过同轴线(POC)给摄像头供电,摄像头经过LVDS串行器将视频信号传输给域控制器。摄像头进行图像采集,域控制器对图像进行裁剪、畸变校正、图像拼接、2D/3D视角切换、轨迹线生成等处理,XPU处理完后送入中央控制域进行显示。如下图高清全景系统连接示意图。

倒车后视摄像头系统由安装于车身后部高清摄像头和中央域控制器组成,摄像头进行图像采集,中央域控制器对图像进行裁减、轨迹线生成、显示屏显示等处理。如下图倒车后视摄像头系统连接示意图。

3. AIS系统简介

qcom AIS软件框架图如下。

AIS Server作为一个守护进程运行在Native层,该服务通过封装好的平台相关库最终使用IOCTL和Kernel进行交互,使用中断产生事件,并以V4L2视频框架进行驱动;

同时AIS Server通过Socket和AIS Client交互,经过封装的Socket实现了向对端发送指令并取回对端返回的数据,其实就是实现了IPC。

最新的软件框架图如下。

其实变化不大,主要在Configurer管理的硬件模块,这个跟芯片平台是强相关的。

4. 车载Camera模块

车载Camera模块从上到下涉及Camera APP、Framework、CameraService、CameraProvider、AISService。因车载Camera使用场景比较单一简单,不需要复杂的逐帧控制等需求,当前使用的是Camera1 API。其中APP、Framework层是Android通用接口,这里不予介绍。

关键流程的软件架构图如下。

4.1 CameraService

CameraService注册在Native ServiceManager,使用binder和Framework进行通信。



手机aiservedemo是什么 手机上显示ais是什么意思4.2 CameraProvider

CameraProvider注册在hwServiceManager,使用hwbinder和CameraService进行通信(HwBinder机制可以跨System和Vendor分区使用,使用HIDL接口)。同时使用Socket和ais_service进行通信。

这里涉及到厂商对camera device的具体实现,脑图就不贴上来了。

4.3 ais_service

ais_service是高通针对车载系统的Camera HAL实现,作为后台服务程序运行在native层。

在手机系统里,这部分代码是运行在camera.provider进程的。车载系统把这部分代码独立成一个服务的原因,我猜测是为了适配快速倒车的场景。快速倒车是指Android系统还没有完全起来,用户切换到倒车模式时把倒车影像显示出来。Android启动完成(显示桌面)需要比较长的时间(10s以上),而倒车影像不必等framework启动完成,就可以通过native进程完成图像显示。实现原理是native层的client拉通display和ais_service,把图像数据显示到大屏。native层测试用例可参考qcarcam_test。


ais_server作为camera HAL层的核心,内部有跟平台和硬件强相关的配置信息。可参考高通文档(80-pg469-93_e_sa6155_sa8155_sa8195_automotive_camera_ais_customization_guide.pdf)。

首先是跟平台强相关的CameraBoardType结构体。

该结构体描述了连接到camera子系统的硬件配置信息,以及连接方式等。编译到动态库libais_config.so,通过接口GetCameraConfigInterface()返回ICameraConfig结构体给外部使用。

i2c设备跟平台芯片强相关,一般不需要我们修改。

每个输入设备被描述为CameraSensorBoardType,包括解串器的信息,CSI、I2C、GPIO、中断的配置信息等。

CameraDeviceConfigType配置 input device 信息。

CameraCsiInfo配置了csi的信息,需要结合硬件电路图确定de-serializer的csi输出口。

CameraChannelInfoType定义了QCarCam IDs到streams的映射。

qcarcam_opmode_type 可以选择具体的 Pproc。

其中aisInputId是给native层使用的,和framework传下来的cameraId的对应关系在文件/vendor/bin/input_mapping_id.xml中。

然后是具体解串器的配置信息,如MAX9296A。最重要的是结构体sensor_lib_t。

ais调用sensor接口的时序图如下。

AIS使用了大量IOCTL和V4L2结合的实例,来完成ais_server和kernel的通信。以解串器的中断诊断为例。

4.4 MAX9296A

有些项目使用的是美信的MAX9296A解串器,该解串器有GMSL1和GMSL2两种工作模式。默认工作模式由硬件电路决定:

MAX9296A 有两个输入 LINKA/B 和两个输出 Port A/B,内部有4个 Pipeline。同个 Port 口可以支持多路输出,通过 VC 来区分。
以下是当前GMSL2模式下默认数据流,配置0x51 -> 0x00,表示 streamId 为0的数据流会 remap 到 Pipeline Y 上,在 GMSL2 模式下,Pipeline 和 streamId 绑定,streamId 由出入信号的串行器设置,此时跟输入流接 LINKA 或 B 没有关系,但是硬件上输入流具体接入的是 LINKA 还是 LINKB,需要配置寄存器 0x0010 来选择。具体拓扑图就不贴上来了,需要可以自行联系美信对接人。

5. 调试

这个章节描述如何进行debug。

5.1 ais debug

ais的log由log等级控制,默认输出等级是

可以通过文件来修改输出等级。

5.2 Linux

5.2.1 Kernel log

Camera Kernel drivers模块的Log可通过文件节点设置。

5.2.2 I2C tool

I2C tool是集成到toolbox里的,操作I2C设备的协助工具。

5.2.3 ccidbg

ccidbg是用于读写CCI设备的工具,只有使用CCI的设备才能使用。

5.2.4 qcarcam_test

camera.provider里包含了ais_client的实现,而qcarcam_test也包含了ais_client的实现,所以qcarcam_test能直接跟ais_server通信实现native层的camera功能,通常该可执行文件用来测试ais_server和摄像头是否正常,因为它没有经过定制化的图像数据处理(裁剪、缩放等)。

qcarcam_test使用ais_server的标准流程如下。

xml配置文件的内容要跟项目匹配。

5.3 代码调试

这里推荐使用 VS code来进行代码级别的在线调试。在线调试对于跟踪代码流程、debug问题有很大的帮助。

下面的在window PC上的设置步骤,在Ubuntu上会简单很多。

其中,launch.json的配置信息参考如下。

需要特别注意的是,调试camera.provider的时候,会遇到PIPE信号导致gdb无法调试的问题,该问题是因为ais health thread心跳监测导致的,可以通过宏

来关闭心跳机制,或者在config配置项里配置忽略SIGPIPE信号。

5.4 编译调试

修改源码后,要编译模块,可以选择mmm命令或者make单编模块,熟悉编译流程的同学都知道这种编译命令会先收集遍历makefile,重新生成Ninja配置文件,然后再执行具体模块的编译,遇到服务器有其他编译任务的时候,单编也会消耗很长的时间(短则几分钟,长则几十分钟)。

其实在满足某些条件下,我们是可以跳过前面的步骤,直接用Ninja编译。

需要满足条件:

  1. 当前out目录已经生成完整的Ninja配置文件,执行过全编或者用make进行过单编的情况下,就会生成完整的Ninja配置文件;
  2. 当前改动没有涉及到编译规则,即没有改动Android.mk和Android.bp以及相关的makefile。通俗的说只是C/C++/JAVA源码的改动,就满足该条件。

5.4 编译调试

修改源码后,要编译模块,可以选择mmm命令或者make单编模块,熟悉编译流程的同学都知道这种编译命令会先收集遍历makefile,重新生成Ninja配置文件,然后再执行具体模块的编译,遇到服务器有其他编译任务的时候,单编也会消耗很长的时间(短则几分钟,长则几十分钟)。

其实在满足某些条件下,我们是可以跳过前面的步骤,直接用Ninja编译。

需要满足条件:

  1. 当前out目录已经生成完整的Ninja配置文件,执行过全编或者用make进行过单编的情况下,就会生成完整的Ninja配置文件;
  2. 当前改动没有涉及到编译规则,即没有改动Android.mk和Android.bp以及相关的makefile。通俗的说只是C/C++/JAVA源码的改动,就满足该条件。