iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >AIS 模块总结
  • 622
分享到

AIS 模块总结

汽车android 2023-08-17 12:08:58 622人浏览 薄情痞子
摘要

SA8155P QCOM 车载camera 模块 1. 前言 ​ 车载和手机的Camera系统是两套不一样的架构,手机Camera系统最终生成符合人眼感官的图像,需要考虑多样化的场景,如美颜、夜景提亮、降噪、虚化等;而车载Camera系统a

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结构体。

typedef struct{    CameraHwBoardType boardType;        char boardName[MAX_CAMERA_DEVICE_NAME];        CameraSensorBoardType camera[MAX_NUM_CAMERA_INPUT_DEVS];        CameraI2CDeviceType i2c[MAX_NUM_CAMERA_I2C_DEVS];} CameraBoardType;

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

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

typedef struct {    //目前只支持 CAMERA_I2C_TYPE_CCI    CameraI2CType i2ctype;          //CCI Core ID    uint32 device_id;               //master ID within a CCI Core    uint32 port_id;                 //device_id + port_id 能确定一个唯一的 CCI    CameraGPIOPinType sda_pin;      CameraGPIOPinType scl_pin;      char i2cDevname[MAX_I2C_DEVICE_NAME];    } CameraI2CDeviceType;

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

typedef struct{        CameraDeviceIDType devId; //只要保证唯一即可,一般用定义好的枚举变量        CameraDeviceConfigType      devConfig;        CameraDeviceDriverInfoType  driverInfo; //需要加载的输入设备动态库信息        CameraCsiInfo csiInfo; //CSI信息        CameraGPIOPinType gpioConfig[CAMERA_GPIO_MAX]; //GPIO信息,从代码上看没用,应该是被具体解串器的配置信息里取代了        CameraSensorGPIO_IntrPinType intr[MAX_CAMERA_DEV_INTR_PINS]; //中断配置信息,从代码看只能配置一个GPIO为中断        CameraI2CPortType i2cPort; //I2C信息,其中port_id指定CCI master的索引(CAMERA_I2C_TYPE_CCI),但真正决定cci master的是dtsi里的 cci-master = <1>} CameraSensorBoardType;typedef struct {    CameraI2CType i2ctype;     //device_id + port_id 会匹配到上面i2c信息里的 CCI ID    uint32 device_id;          uint32 port_id;            I2CSpeedType speed;    } CameraI2CPortType;

​ CameraDeviceConfigType配置 input device 信息。

typedef struct {        uint32 subdevId;  //取0-3,用以MAX9296区分输入端,一般设0        uint32 type; //最终在MAX9296A的max9296a_set_default函数生效,设置位0,则用9296的default配置,设置为1,则用下面的配置    uint32 numSensors;    uint32 opMode;//下面三个没有使用    uint32 masterSocId;     uint32 socMap;          uint32 acceSSMode;      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的映射。

typedef struct{        uint32 aisInputId; //映射到inputSrc的唯一ID,HAL层使用,如qcarcam_config_singleid.xml里配置的input_id        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;//对应的ProcChainstatic 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_DUMPstatic 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        }    },};// 只有一个 pProcChainstatic AisProcChainType RawdumpPProc[] ={    { AIS_PPROC_USR_DONE, NULL, 0, {AIS_BUFLIST_OUTPUT_USR}, {} },};static AisProcChainDefType RawdumpProcChainDef ={    .pProcChain = RawdumpPProc,    .nProc = STD_ARRAY_SIZE(RawdumpPProc),    .pBufferlistDef = RawdumpBuflist,    .nBuflist = STD_ARRAY_SIZE(RawdumpBuflist)};CameraResult AisProcChainManagerPrivate::Init(void){    CameraResult rc = CAMERA_SUCCESS;    uint32 i;//PProcId 对应到具体的实现类    m_pPProc[AIS_PPROC_USR_DONE] = AisPProcUsrDone::Create();    m_pPProc[AIS_PPROC_ISP] = AisPProcIsp::Create();    m_pPProc[AIS_PPROC_GPU] = AisPProcGpu::Create();    m_pPProc[AIS_PPROC_FRAMESYNC] = AisPprocFrameSync::Create();    for (i = 0; i < AIS_PPROC_MAX; i++)    {        if (!m_pPProc[i])        {            AIS_LOG(PPROC_MGR, FATAL, "Failed to create PPROC %d", i);            rc = CAMERA_EFAILED;            break;        }    }    return rc;}

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

                                                                                    

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

typedef struct{        void* priv_ctxt;        int (*sensor_close_lib)(void* ctxt);        img_src_channel_t channels[MAX_IMAGE_SOURCES]; //channels的输出格式,如图像格式,长宽,帧率    unsigned int num_channels;        img_src_subchannel_t subchannels[MAX_IMAGE_SOURCES];    unsigned int num_subchannels;        struct camera_sensor_slave_info sensor_slave_info;      enum camera_i2c_data_type data_type; //跟addr_type类似,I2C数据的字节数      struct sensor_id_info_t sensor_id_info;      struct camera_power_setting_array power_setting_array; //上电和下电时序      unsigned char is_init_params_valid;    };*/        sensor_output_t sensor_output; //unused        struct sensor_output_reg_addr_t output_reg_addr;        struct sensor_exp_gain_info_t exp_gain_info;        sensor_aec_data_t aec_info;        unsigned short sensor_num_frame_skip; //unused        unsigned short sensor_num_HDR_frame_skip; //unused        unsigned int sensor_max_pipeline_frame_delay;        sensor_property_t sensor_property;        sensor_imaging_pixel_array_size pixel_array_size_info;        sensor_color_level_info color_level_info;        sensor_stream_info_array_t sensor_stream_info_array;        struct camera_i2c_reg_setting start_settings;    struct camera_i2c_reg_setting stop_settings;    struct camera_i2c_reg_setting groupon_settings;    struct camera_i2c_reg_setting groupoff_settings;    struct camera_i2c_reg_setting embedded_data_enable_settings;    struct camera_i2c_reg_setting embedded_data_disable_settings;    struct camera_i2c_reg_setting aec_enable_settings;    struct camera_i2c_reg_setting aec_disable_settings;        sensor_test_info test_pattern_info;        struct sensor_effect_info effect_info;        struct sensor_lib_reg_settings_array init_settings_array;    struct sensor_lib_reg_settings_array res_settings_array;    struct sensor_lib_out_info_array     out_info_array;    struct sensor_csi_params             csi_params;    struct sensor_csid_lut_params_array  csid_lut_params_array;    struct sensor_lib_crop_params_array  crop_params_array;        sensor_exposure_table_t exposure_func_table;        struct sensor_lib_meta_data_info_array meta_data_out_info_array;                unsigned int sensor_capability;        sensor_awb_table_t awb_func_table;        sensor_RDI_parser_stats_t parse_RDI_stats;        sensor_rolloff_config rolloff_config;        long long adc_readout_time;        unsigned short sensor_num_fast_aec_frame_skip;        unsigned char app_delay[SENSOR_DELAY_MAX];        struct sensor_noise_coefficient_t noise_coeff;        unsigned char external_library;        sensor_custom_func_table_t sensor_custom_func; //客制化API    boolean use_sensor_custom_func; //是否使用客制化接口    uint32 src_id_enable_mask;    uint32 input_id;} sensor_lib_t;

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

请添加图片描述

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

CameraResult SensorPlatformLinux::SensorSetupGpioInterrupt(enum camera_gpio_type gpio_id,    sensor_intr_callback_t cb, void *data){    //1.获取中断配置信息    //....    //2.以GPIO号为id订阅V4L2消息    struct v4l2_event_subscription sub = {};    sub.type = AIS_SENSOR_EVENT_TYPE;    sub.id = m_probeCmd->gpio_intr_config[freeIdx].gpio_num;    rc = ioctl(m_sensorFd, VIDIOC_SUBSCRIBE_EVENT, &sub);    if(rc < 0)    {        AIS_LOG(SENSOR_PLATFORM, ERROR, "[%s] VIDIOC_SUBSCRIBE_EVENT [0x%x] failed %d",                m_pSensorLib->sensor_slave_info.sensor_name,                AIS_SENSOR_EVENT_TYPE, rc);        result = CAMERA_EFAILED;    }//3.通过IOCTL初始化中断信息    if (CAMERA_SUCCESS == result)    {        cam_cmd.op_code = AIS_SENSOR_INTR_INIT;        cam_cmd.size = sizeof(struct ais_sensor_gpio_intr_config);        cam_cmd.handle_type = CAM_HANDLE_USER_POINTER;        cam_cmd.reserved    = 0;        cam_cmd.handle = (uint64_t)m_probeCmd->gpio_intr_config;        rc = ioctl(m_sensorFd, VIDIOC_CAM_CONTROL, &cam_cmd, "intr_init");        if (rc < 0)        {            result = CAMERA_EFAILED;        }    }    //4.新建线程监听V4L2的消息并获取信息    if (CAMERA_SUCCESS == result)    {        pPlatformIntr->pCtxt = this;        pPlatformIntr->isUsed = TRUE;        pPlatformIntr->pCbFcn = cb;        pPlatformIntr->pData = data;        pPlatformIntr->gpio_id = gpio_id;        pPlatformIntr->gpio_num = pinInfo.pin_id;        snprintf(pPlatformIntr->tname, sizeof(pPlatformIntr->tname),                 "sensor_platform_intr_poll_thread_%d", m_eCameraInterface);        result = CameraCreateThread(CAMERA_THREAD_PRIO_DEFAULT, 0,        SensorPlatformIntrPollThread,        (void*)(pPlatformIntr),        0,        pPlatformIntr->tname,        &pPlatformIntr->hThread);        (void)CameraSetThreadPriority(pPlatformIntr->hThread,          CAMERA_THREAD_PRIO_HIGH_REALTIME);        if (result != CAMERA_SUCCESS)        {            pPlatformIntr->isUsed = FALSE;            //@todo: any cleanup...        }    }}//kernel层对应的代码int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl,void *arg){    switch (cmd->op_code):         case AIS_SENSOR_INTR_INIT: {             rc = cam_sensor_init_gpio_intr(gpio_intr_cfg,s_ctrl);         }    }}static int32_t cam_sensor_init_gpio_intr(struct ais_sensor_gpio_intr_config *gpio_intr_info,struct cam_sensor_ctrl_t *s_ctrl){int32_t rc = 0;int32_t gpio_num = 0;int32_t gpio_cfg0 = 0;int32_t idx = 0;//kernel层支持多个INTR的注册,但HAL层获取INTR的代码只允许注册一个for (idx = 0; idx < AIS_MAX_INTR_GPIO; idx++) {if (!s_ctrl->s_intr[idx].work_inited &&gpio_intr_info->gpio_num != -1) {gpio_num = gpio_intr_info->gpio_num;gpio_cfg0 = gpio_intr_info->gpio_cfg0;s_ctrl->s_intr[idx].sctrl = s_ctrl;s_ctrl->s_intr[idx].gpio_array[0].gpio = gpio_num;//初始化工作队列INIT_WORK(&s_ctrl->s_intr[idx].irq_work,bridge_irq_work);//申请一个GPIO口rc = gpio_request_one(gpio_num,GPIOF_DIR_IN, "camera_intr");if (!rc) {                //用该GPIO口申请硬件中断,中断响应函数为bridge_irqrc = request_irq(gpio_to_irq(gpio_num),bridge_irq,IRQF_ONESHOT | gpio_cfg0,"qcom,ais",&s_ctrl->s_intr[idx]);if (rc < 0)CAM_ERR(CAM_SENSOR,"gpio %d request irq failed", gpio_num);} else {gpio_free(gpio_num);CAM_ERR(CAM_SENSOR,"gpio %d request failed", gpio_num);}if (!rc)s_ctrl->s_intr[idx].work_inited = 1;break;}}return rc;}//在任务队列里生成一个id为GPIO口的V4L2事件并入队,因为native层订阅过该id的信息,所以native能触发该消息的处理函数static void bridge_irq_work(struct work_struct *work){struct cam_sensor_ctrl_t *s_ctrl;struct cam_sensor_intr_t *s_intr;struct v4l2_event event;s_intr = container_of(work, struct cam_sensor_intr_t,irq_work);s_ctrl = s_intr->sctrl;mutex_lock(&s_ctrl->cam_sensor_mutex);memset(&event, 0, sizeof(struct v4l2_event));event.id = s_intr->gpio_array[0].gpio;event.type = AIS_SENSOR_EVENT_TYPE;v4l2_event_queue(s_ctrl->v4l2_dev_str.sd.devnode, &event);mutex_unlock(&s_ctrl->cam_sensor_mutex);}//在中断响应函数里触发工作任务static irqreturn_t bridge_irq(int irq_num, void *dev){struct cam_sensor_intr_t *s_intr = dev;//将任务提交到工作队列schedule_work(&s_intr->irq_work);return IRQ_HANDLED;}

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等级控制,默认输出等级是

#if defined(__INTEGRITY)#define AIS_LOG_DEFAULT_CONF AIS_LOG_CONF_MAKE(AIS_LOG_MODE_CONSOLE, AIS_LOG_LVL_WARN)#elif defined(CAMERA_UNITTEST)#define AIS_LOG_DEFAULT_CONF AIS_LOG_CONF_MAKE(AIS_LOG_MODE_CONSOLE, AIS_LOG_LVL_WARN)#else#define AIS_LOG_DEFAULT_CONF AIS_LOG_CONF_MAKE(AIS_LOG_MODE_OS, AIS_LOG_LVL_HIGH)#endif

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

//ais_server的Log配置文件: vendor/etc/camera/ais_log_ais_server.conf//ais_client的Log配置文件: vendor/etc/camera/ais_log.conf## AIS Log Configurations## Copyright (c) 2018-2020 Qualcomm Technologies, Inc.# All Rights Reserved.# Confidential and Proprietary - Qualcomm Technologies, Inc.##memory log size#MEM_SIZE=1048576#os log size#OS_SIZE=1048576#log file#FILE_PATH=/tmp/ais_log.txt#FILE_SIZE=104857600## Module-Specified Log Configuration#   Log id:##define AIS_MOD_ID_RSRV                    0            //reserved#define AIS_MOD_ID_CAMERA_PLATFORM          1#define AIS_MOD_ID_CAMERAQ                  2#   ...##   Log Level: 1 == AIS_LOG_LVL_FATAL#              2 == AIS_LOG_LVL_CRIT#              3 == AIS_LOG_LVL_ERR#              4 == AIS_LOG_LVL_WARN#              5 == AIS_LOG_LVL_HIGH#              6 == AIS_LOG_LVL_MED#              7 == AIS_LOG_LVL_LOW#              8 == AIS_LOG_LVL_DBG#              9 == AIS_LOG_LVL_DBG1##   Log Mode:  M == log to memory#              S == log to OS logger#              F == log to file#              C == log to console##   Example:#              MODULE_xx=yMSFC#              xx means module ID, 0 is reserved, the maximum number is 255#              y means log level#              MSFC means combination of log modes, which means one message can be output to more than one destinations### Conf file path in target# Android: /vendor/etc/cameraGLOBAL=8S         #global log level set to DBG and log to OS loggerMODULE_2=8SF      #module CAMERAQ set log level to DBG and log to both os logger and file

5.2 linux

5.2.1 Kernel log

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

echo 0x20 > /sys/module/cam_debug_util/parameters/debug_mdl #enable CAM_SENSOR debug log#define CAM_CDM        (1 << 0)#define CAM_CORE       (1 << 1)#define CAM_CPAS       (1 << 2)#define CAM_ISP        (1 << 3)#define CAM_CRM        (1 << 4)#define CAM_SENSOR     (1 << 5)#define CAM_SMMU       (1 << 6)#define CAM_SYNC       (1 << 7)#define CAM_ICP        (1 << 8)#define CAM_JPEG       (1 << 9)#define CAM_FD         (1 << 10)#define CAM_LRME       (1 << 11)#define CAM_FLASH      (1 << 12)#define CAM_ACTUATOR   (1 << 13)#define CAM_CCI        (1 << 14)#define CAM_CSIPHY     (1 << 15)#define CAM_EEPROM     (1 << 16)#define CAM_UTIL       (1 << 17)#define CAM_HFI        (1 << 18)#define CAM_CTXT       (1 << 19)#define CAM_OIS        (1 << 20)#define CAM_RES        (1 << 21)#define CAM_MEM        (1 << 22)

5.2.2 I2C tool

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

# 820项目,使用的是I2C类型# 总线地址是由硬件配置决定的i2cget -f -y 8 0x6c 0x30 # 读取总线地址是8,从地址是0x6c设备的0x30寄存器

5.2.3 ccidbg

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

# 8155项目,使用的是CCI类型 i2ctype = CAMERA_I2C_TYPE_CCI,# 总线地址是由硬件配置决定的ccidbg -master=1  # master id 可以在dtsi的配置里确定 cci-master = <1>; #   CCI DBGR v1.1 #   cci power up [ok] #   MAIN MENU #           [ 0 ] - cci_read #           [ 1 ] - cci_write #           [ 2 ] - cci_write_sync_array #           [ 3 ] - cci_update #           [ 4 ] - exit3 #  , , 0x90 2 1  #根据设备实际 addr_type 和 data_type 来设置 #   MAIN MENU #          [ 0 ] - cci_read #        [ 1 ] - cci_write #        [ 2 ] - cci_write_sync_array #        [ 3 ] - cci_update #        [ 4 ] - exit0 #0x100

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的标准流程如下。
请添加图片描述

qcarcam_test -config=/vendor/bin/qcarcam_config_singleid3.xml

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

                                                        

5.3 代码调试

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

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

# 1. VS code 安装 C/C++ extension 插件;# 2. 下载最新NDK,将NDK中的gdbserver push到手机adb push .\android-arm64\gdbserver\gdbserver /data/local/adb shell chmod 777 /data/local/gdbserver# 3. VS code把ais的目录添加到工作区# 4. 配置调试信息#4.1 运行 --> 添加配置#4.2 选择 c++(GDB/LLDB)#   4.3 修改launch.JSON的配置信息# 5. 用gdb启动设备端程序# 5.1 把本地编译的ais_server和相关lib库push到设备上#5.2 ps -e |grep ais 查询获得ais_server的进行PID#5.3 gdb attach到ais_server./data/local/gdbserver --remote-debug :5555  --attach $pid#5.3.1 如果不是常驻进程,需要gdb来启动的进程,如一个test可执行文件,则命令是./data/local/gdbserver --remote-debug :5555  test [arg]# 6. window端建立端口转发。PC和设备的socket可通过5555的端口相互转发,建立设备和gdb的联系adb forward tcp:5555 tcp:5555# 7. VS code 启动调试(F5),就可以在线调试了

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

{    // 使用 IntelliSense 了解相关属性。    // 悬停以查看现有属性的描述。   // 欲了解更多信息,请访问: https://Go.microsoft.com/fwlink/?linkid=830387   "version": "0.2.0",   "configurations": [    {        "name": "(gdb) 启动",        "type": "cppdbg",        "request": "launch",        //带符号的目标调试程序        "program": "Z:\\android\\out\\target\\product\\au8155\\symbols\\vendor\\bin\\ais_server",        "args": [],        "stopAtEntry": false,        //其他的动态库路径        "additionalSOLibSearchPath": "Z:\\android\\out\\target\\product\\au8155\\symbols\\vendor\\lib64",        //本地主机的socket地址,注意需要用adb forward 把设备的地址链接到本地主机上        "miDebuggerServerAddress": "localhost:5555",        //源码路径        "cwd": "${fileDirname}",        "environment": [],        "externalConsole": false,        "MIMode": "gdb",        //gdb路径        "miDebuggerPath": "D:\\Program Files\\android-ndk-r23b\\prebuilt\\windows-x86_64\\bin\\gdb.exe",        //gdb参数        "setupCommands": [            {                "description": "为 gdb 启用整齐打印",                "text": "-enable-pretty-printing",                "ignoreFailures": true            },            {                "text": "-environment-directory Z:\\android",                "description": "gdb command: dir",                "ignoreFailures": false            },            {            "text": "-gdb-set solib-absolute-prefix Z:\\android\\out\\target\\product\\au8155\\symbols",                "description": "gdb command: set solib-absolute-prefix",                "ignoreFailures": false            },            {                "text": "-gdb-set solib-search-path Z:\\android\\out\\target\\product\\au8155\\symbols\\vendor\\lib64;Z:\\android\\out\\target\\product\\au8155\\symbols\\vendor\\lib;",                "description": "gdb command: set solib-search-path",                 "ignoreFailures": false            },            {                "description": "将反汇编风格设置为 Intel",                "text": "-gdb-set disassembly-flavor intel",                "ignoreFailures": true},                 ]    }    ]}

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

#define AIS_DISABLE_HEALTH

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

setupCommands{   "text": "handle SIGPIPE nostop noprint pass",    "description": "ignore SIGPIPE",    "ignoreFailures": true },

5.4 编译调试

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

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

# xx是具体lunch项./prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-xx.ninja ais_server

​ 需要满足条件:

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

5.4 编译调试

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

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

# xx是具体lunch项./prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-xx.ninja ais_server

​ 需要满足条件:

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

来源地址:https://blog.csdn.net/qq_40211991/article/details/128811345

--结束END--

本文标题: AIS 模块总结

本文链接: https://www.lsjlt.com/news/372842.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • AIS 模块总结
    SA8155P QCOM 车载camera 模块 1. 前言 ​ 车载和手机的Camera系统是两套不一样的架构,手机Camera系统最终生成符合人眼感官的图像,需要考虑多样化的场景,如美颜、夜景提亮、降噪、虚化等;而车载Camera系统A...
    99+
    2023-08-17
    汽车 android
  • python shutil模块总结
    shutil.copyfile(src,dst)复制文件,如果存在会覆盖copymode( src, dst)复制权限copystat(src, dst)复制访问时间和修改时间和权限copy(src, dst) 复制文件到一个目录copy2...
    99+
    2023-01-31
    模块 python shutil
  • Python日历模块总结
    calendar模块的函数都是日历相关的,提供了对日期的一些操作方法,和生成日历的方法.calendar模块中提供了三大类:    一、calendar.Calendar(firstweekday=0)  该类提供了许多生成器,如星期的生成...
    99+
    2023-01-31
    模块 日历 Python
  • Python中的time模块与datetime模块用法总结
    time模块 time模块是包含各方面对时间操作的函数. 尽管这些常常有效但不是所有方法在任意平台中有效. time用struct_time表示时间 import time # time.struct...
    99+
    2022-06-04
    模块 Python time
  • Python的functools模块使用总结
    本篇文章给大家带来了关于Python的相关知识,主要介绍了Python的functools模块使用及说明,具有很好的参考价值,下面一起来看一下,希望对大家有帮助。【相关推荐:Python3视频教程 】partial用于创建一个偏函数,将默认...
    99+
    2022-08-08
    python
  • Python错误+异常+模块总结
    目录错误和异常语法错误异常异常处理抛出异常模块前言: 本篇主要讲两方面,错误和异常以及模块。在编程时遇见错误信息在所难免,Python中会也有很多种错误信息,常见的两种就是语法错误和...
    99+
    2022-11-11
  • SD模块信贷控制总结
    原文发在微信公众号了。欢迎关注。原文链接:https://mp.weixin.qq.com/s__biz=MjM5MDE2MDQ0Ng==&mid=2649706769&idx=1&sn=98612201fe23c6...
    99+
    2023-06-05
  • JAVA中的事务,事务模块总结
    什么是事务? 简单的来说,一条SQL执行或则几条SQL一起执行时,我们希望这个SQL要么执行成功后提交,要么执行失败后回滚,这是我们最直观的理解。在上面这句话中,就包含了事务的几个必要属性:"执行成功后提交",意味着持久性;"执行失败后...
    99+
    2016-07-09
    JAVA中的事务,事务模块总结
  • Python基础之logging模块知识总结
    目录前言一、日志级别二、basicConfig三、日志写文件四、traceback记录前言 logging模块是Python内置的标准模块,主要用于输出脚本运行日志,可以设置输出日志的等级、日志保存路径等。 ...
    99+
    2022-06-02
    Python logging模块 python常用模块
  • Pyhton模块和包相关知识总结
    目录一、模块二、模块的搜索顺序三、使模块下方的测试代码在导入时不会执行四、包五、发布模块六、安装模块七、卸载模块八、pip 安装第三方模块一、模块 每一个以扩展名 py 结尾额 Py...
    99+
    2022-11-12
  • Android React Native原生模块与JS模块通信的方法总结
    Android React Native原生模块与JS模块通信的方法总结 前言: 在做React Native开发的时候避免不了的需要原生模块和JS之间进行数据传递,这篇文章将...
    99+
    2022-06-06
    模块 方法 native 通信 js React Android
  • Python基础之模块相关知识总结
    目录一、什么是模块二、导入模块三、name=‘main'四、搜索路径一、什么是模块 容器 -> 数据的封装 函数 -> 语句的封装 类 ->...
    99+
    2022-11-12
  • Python中os模块的12种用法总结
    目录一、先总结,再详谈二、详谈各种方法的使用1、getcwd() :返回当前工作目录2、chdir(path) :改变工作目录3、listdir(path) :列举指定目录中的文件名...
    99+
    2022-11-11
  • Python中re模块的常用方法总结
    前言 正则表达式作为计算机科学的一个概念,通常被用来检索、替换那些符合某个规则的文本。正则表达式是对字符串操作的一种逻辑公式,用事先定义好的规则字符串对字符串进行过滤逻辑处理。 re...
    99+
    2022-11-12
  • Node.js中的events事件模块知识点总结
    通过对Node的学习及应用,我们知道NodeJS其采用单线程、事件驱动、非阻塞I/O等架构设计,非常适用于高并发、I/O密集型应用。 1. 什么是事件驱动? 事件驱动,简单来说就是...
    99+
    2022-11-12
  • Python中几种导入模块的方式总结
    模块内部封装了很多实用的功能,有时在模块外部调用就需要将其导入。常见的方式有如下几种: 1 . import >>> import sys >>> sys.path ...
    99+
    2022-06-04
    几种 模块 方式
  • Python日志模块logging的使用方法总结
    目录导语关于开发日志关于logging基础使用关于logging进阶使用记录器处理器格式器配置记录实战生成记录器请求处理装饰器总结导语 日常开发中,定位程序异常,追溯事件发生场景都需...
    99+
    2022-11-11
  • Python中re模块常用方法总结分析
    re.findall() 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。 语法格式: re.findall(pattern, stri...
    99+
    2022-11-12
  • Python中导入模块的几种方式总结
    目录Part.I 预备知识Chap.I 几个概念的区分Chap.II 模块中的 all 变量Part.II 导入模块的几种方法Chap.I 方法Chap.II 实例补充:python...
    99+
    2022-12-09
    python导入模块的三种方法 python中模块导入的方法 python导入模块的命令
  • Python 常用内置模块超详细梳理总结
    目录time模块time.sleep()time.time()time.localtime()time.strftime()datetime()random模块random.rand...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作