版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_40211991/article/details/128811345
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进行通信。
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结构体。
/**
* This structure defines the board specific configurable items related to the
* camera subsystem.
*/
typedef struct
{
CameraHwBoardType boardType;
/**< Board type name */
char boardName[MAX_CAMERA_DEVICE_NAME];
/**< Camera configurations */
CameraSensorBoardType camera[MAX_NUM_CAMERA_INPUT_DEVS];
/**< I2C device configurations*/
CameraI2CDeviceType i2c[MAX_NUM_CAMERA_I2C_DEVS];
} CameraBoardType;
该结构体描述了连接到camera子系统的硬件配置信息,以及连接方式等。编译到动态库libais_config.so,通过接口GetCameraConfigInterface()返回ICameraConfig结构体给外部使用。
i2c设备跟平台芯片强相关,一般不需要我们修改。
/**
* This structure describes I2C Devices
*/
typedef struct {
//目前只支持 CAMERA_I2C_TYPE_CCI
CameraI2CType i2ctype; /**< CCI or I2C port */
//CCI Core ID
uint32 device_id; /**< CCI device number */
//master ID within a CCI Core
uint32 port_id; /**< I2C port number */
//device_id + port_id 能确定一个唯一的 CCI
CameraGPIOPinType sda_pin; /**< I2C SDA pin configuration */
CameraGPIOPinType scl_pin; /**< I2C SCL pin configuration */
char i2cDevname[MAX_I2C_DEVICE_NAME]; /**< i2c port used by sensor */
} CameraI2CDeviceType;
每个输入设备被描述为CameraSensorBoardType,包括解串器的信息,CSI、I2C、GPIO、中断的配置信息等。
/**
* This structure defines the board specific configurable items for a given
* camera sensor.
*/
typedef struct
{
/**< unique device id */
CameraDeviceIDType devId; //只要保证唯一即可,一般用定义好的枚举变量
/**< Driver config */
CameraDeviceConfigType devConfig;
/**< Driver loading info */
CameraDeviceDriverInfoType driverInfo; //需要加载的输入设备动态库信息
/**< CSI info */
CameraCsiInfo csiInfo; //CSI信息
/*GPIO config*/
CameraGPIOPinType gpioConfig[CAMERA_GPIO_MAX]; //GPIO信息,从代码上看没用,应该是被具体解串器的配置信息里取代了
/*Interrupt config*/
CameraSensorGPIO_IntrPinType intr[MAX_CAMERA_DEV_INTR_PINS]; //中断配置信息,从代码看只能配置一个GPIO为中断
/**< I2C port */
CameraI2CPortType i2cPort; //I2C信息,其中port_id指定CCI master的索引(CAMERA_I2C_TYPE_CCI),但真正决定cci master的是dtsi里的 cci-master = <1>
} CameraSensorBoardType;
/**
* This structure describes I2C port used by the camera
*/
typedef struct {
CameraI2CType i2ctype; /**< CCI or I2C port */
//device_id + port_id 会匹配到上面i2c信息里的 CCI ID
uint32 device_id; /**< CCI device number */
uint32 port_id; /**< I2C port number */
I2CSpeedType speed; /**< I2C port speed */
} CameraI2CPortType;
CameraDeviceConfigType配置 input device 信息。
/**
* This structure defines input device configuration
*/
typedef struct {
/**< sub device id in case of multiple devices sharing same driver */
uint32 subdevId; //取0-3,用以MAX9296区分输入端,一般设0
/* type = 0 will use lib default.Change type to 1 to apply config below */
uint32 type; //最终在MAX9296A的max9296a_set_default函数生效,设置位0,则用9296的default配置,设置为1,则用下面的配置
uint32 numSensors;
uint32 opMode;
//下面三个没有使用
uint32 masterSocId; /**< Master soc which control deserializer in multi SOC enviroment */
uint32 socMap; /**< Soc map for de-serializer connection with soc */
uint32 accessMode; /**< I2C access for soc with the deserializer */
int32 gpio[MAX_NUM_INPUT_DEV_INTERNAL_GPIO];
CameraPowerSaveModeType powerSaveMode;
CameraDeviceSensorConfigType sensors[MAX_NUM_INPUT_DEV_SENSORS];
} CameraDeviceConfigType;
CameraCsiInfo配置了csi的信息,需要结合硬件电路图确定de-serializer的csi输出口。
CameraChannelInfoType定义了QCarCam IDs到streams的映射。
/**
* This structure defines the mapping of unique qcarcam descriptor to
* input sources as well as the default operation mode.
*/
typedef struct
{
/**
* unique qcarcam inputId that maps to <devId, srcId>
*/
uint32 aisInputId; //映射到inputSrc的唯一ID,HAL层使用,如qcarcam_config_singleid.xml里配置的input_id
/**
* unique <devId, srcId> of input id and default operation mode
*/
struct
{
uint32 devId; //匹配CameraSensorBoardType里的devId
uint32 srcId; //匹配sensor的subchannels信息里的src_id,最终匹配到modes
}inputSrc[MAX_CHANNEL_INPUT_SRCS];
qcarcam_opmode_type opMode; //选择对应的Pproc进行post process
} CameraChannelInfoType;
qcarcam_opmode_type 可以选择具体的 Pproc。
typedef enum {
QCARCAM_OPMODE_RAW_DUMP,
QCARCAM_OPMODE_SHDR,
QCARCAM_OPMODE_INJECT,
QCARCAM_OPMODE_PAIRED_INPUT,
QCARCAM_OPMODE_DEINTERLACE,
QCARCAM_OPMODE_MAX
} qcarcam_opmode_type;
//对应的ProcChain
/**
* Proc Chain Definitions
*/
static AisProcChainDefType* g_ProcChainDefs[QCARCAM_OPMODE_MAX] =
{
[QCARCAM_OPMODE_RAW_DUMP] = &RawdumpProcChainDef,
[QCARCAM_OPMODE_SHDR] = &SHDR_ProcChainDef,
[QCARCAM_OPMODE_INJECT] = &InjectProcChainDef,
[QCARCAM_OPMODE_PAIRED_INPUT] = &PairedInput_ProcChainDef,
[QCARCAM_OPMODE_DEINTERLACE] = &DeinterlaceProcChainDef,
};
//默认是 QCARCAM_OPMODE_RAW_DUMP
/**
* RAW Dump usecase
*/
static AisBuflistDefType RawdumpBuflist[] =
{
{
.id = AIS_BUFLIST_OUTPUT_USR,
.GetBuf = GetBufferDefault,
.PutBuf = BuflistEnqIfe,
.AllocBuf = NULL,
.allocParams = {
.allocType = AIS_BUFLIST_ALLOC_NONE,
.maxBuffers = QCARCAM_MAX_NUM_BUFFERS,
.matchBuflistId = 0,
.fmt = (qcarcam_color_fmt_t)0, .width = 0, .height = 0, .stride = 0
}
},
};
// 只有一个 pProcChain
static AisProcChainTyp