高通平台camera构架sensor驱动详解

1. Sensor驱动的基本概念与流程 

  • Sensor驱动的作用
    Sensor驱动是Camera硬件与CamX框架之间的桥梁,负责控制Sensor的启动、数据采集、寄存器配置以及与图像处理单元(如IFE、BPS)的交互。
    通俗理解:就像工厂的“原料采集工”,负责从摄像头传感器(如CMOS)获取原始图像数据,并将数据传递到流水线(Pipeline)中进行加工。

  • 数据流关键步骤

    1. Sensor初始化:配置电源、时钟、寄存器,确保Sensor正常工作。

    2. 数据采集:Sensor通过I2C/SPI接口传输原始图像数据(如RAW格式)。

    3. 数据处理:数据经过IFE(图像前端)进行初步处理(如降噪、去马赛克),再传递给后续节点(如IPE、BPS)。

    4. 结果输出:最终数据通过HAL层传递给Android应用层(如预览、拍照)。


2. Sensor驱动的核心配置 1112

(1) XML配置文件
  • 路径vendor/qcom/proprietary/chi-cdk/oem/qcom/sensor/
    每个Sensor需一个独立的XML文件,定义寄存器配置、电源时序、I2C地址等。
    示例

    <sensorDriver>
      <module_version major_revision="1" minor_revision="0"/>
      <slaveInfo>
        <sensorName>s5k3p9sx</sensorName>
        <slaveAddress>0x20</slaveAddress>
        <i2cFrequencyMode>FAST</i2cFrequencyMode>
      </slaveInfo>
      <powerUpSequence>
        <powerSetting>
          <configType>VANA</configType>
          <configValue>2800000</configValue>
          <delayMs>1</delayMs>
        </powerSetting>
      </powerUpSequence>
    </sensorDriver>
    
(2) 寄存器配置
  • 初始化寄存器:在XML中定义启动时需写入的寄存器值(如分辨率、帧率控制)。

  • 动态调整:运行时通过HAL接口调整参数(如曝光时间、增益)。

(3) 电源与时钟管理
  • 电源时序:需严格匹配Sensor规格,例如VANA(模拟电压)、VIO(I/O电压)的上电顺序。

  • 时钟配置:MCLK(主时钟)频率需与Sensor规格一致(如24MHz)。


3. Sensor调试与常见问题 211

(1) 调试工具
  • 日志控制:通过设置系统属性开启调试日志:

    adb shell setprop persist.vendor.camera.logInfoMask 0x3FF
  • 强制Sensor模式:在camxoverridesettings.txt中设置:

    overrideForceSensorMode=0x3  # 强制使用Sensor Mode 3
(2) 常见问题
  • 数据中断:检查I2C通信是否正常(如地址冲突、时序错误)。

  • 图像异常:验证寄存器配置(如分辨率、像素格式是否匹配)。

  • 电源问题:使用示波器测量电源时序,确保符合Sensor规格书要求。


4. Sensor与CamX架构的交互 310

  • HAL层交互
    Sensor驱动通过CamX的CSL(Camera Subsystem Layer)模块与内核驱动交互,例如调用ioctl控制V4L2设备。

  • 数据传递
    Sensor数据通过IFE Node进入Pipeline,经处理后传递给下游节点(如BPS、IPE)。
    通俗比喻:Sensor是“水源”,IFE是“净水厂”,IPE是“包装车间”,最终输出到“用户”(应用层)。


5. 推荐阅读资源

  1. 高通Camx架构学习(初篇) - 优快云博客

    • 特点:包含CamX架构图及Sensor数据流解析,适合理解Sensor在整体架构中的位置。

    • 亮点:用工厂流水线比喻Sensor与Node的协作,通俗易懂。

  2. 高通Camera驱动(1)--Camx架构介绍 - 优快云博客

    • 特点:详细分析CamX的分层架构及HAL层与Sensor的交互逻辑。

    • 亮点:提供代码目录结构及调试示例。

  3. CamX Sensor Debug指南 - 优快云博客

    • 特点:实战调试技巧,如强制Sensor模式、日志分析方法。

    • 亮点:解决实际开发中的常见问题。

  4. 高通Camx Actuator Bring up - 博客园

    • 特点:以马达驱动为例,详解Sensor相关外设的配置方法。

    • 亮点:XML配置实例及电源管理说明。


总结

  • 入门必读:优先阅读初篇架构介绍,掌握Sensor驱动的基本流程。

  • 实战调试:参考Debug指南Actuator配置,解决电源、寄存器配置问题。

  • 深入开发:结合代码目录(如chi-cdk/oem/qcom/sensor)修改XML文件并验证数据流。

以上文章均基于实际开发经验,涵盖理论、配置与调试,适合不同层次的学习需求。

在高通CamX架构中,通过XML配置的Sensor寄存器值最终写入硬件传感器的过程涉及分层解析硬件接口调用,以下是详细的分步说明:


1. XML配置的解析流程

(1) 文件定位与加载
  • XML路径
    Sensor配置文件位于vendor/qcom/proprietary/chi-cdk/oem/qcom/sensor/目录下,文件名通常为sensor_<sensor_name>.xml(如sensor_imx586.xml)。

  • 加载时机
    Camera服务启动时,CamX框架解析XML文件,生成寄存器配置列表和电源时序。

(2) 解析寄存器配置

XML中的寄存器定义示例:

<registerConfiguration>
    <writeOperation>
        <registerAddress>0x0100</registerAddress>
        <registerData>0x01</registerData>
        <delayMs>5</delayMs>
    </writeOperation>
</registerConfiguration>
  • 解析逻辑
    CamX框架读取registerAddress(寄存器地址)和registerData(写入值),生成一个RegisterSetting结构体数组,记录地址、值、延迟等参数。


2. 寄存器写入硬件的底层机制

(1) 通过I2C/SPI总线通信
  • 通信协议
    Sensor通常通过I2CSPI总线与SoC连接,CamX通过内核的I2C驱动与Sensor通信。

  • 数据传输
    每个寄存器写入操作对应一次I2C写操作,格式为:
    I2C_Write(Sensor_Slave_Address, Register_Address, Register_Value)

(2) CSL(Camera Subsystem Layer)调用
  • 流程代码示例

    // CamX代码中的寄存器写入逻辑(伪代码)
    CSLWriteRequest request;
    request.slotId = sensorSlot;        // Sensor硬件槽位
    request.regSetting = registerList;  // 解析后的寄存器配置列表
    request.count = registerCount;      // 寄存器数量
    
    // 调用内核驱动执行I2C写入
    CSLResult result = CSLWrite(sensorHandle, &request);
  • 内核交互
    CSLWrite最终调用Linux内核的I2C驱动接口(如i2c_transfer),将数据发送到Sensor的I2C从机地址。

(3) 电源与时钟协同
  • 电源管理
    在写入寄存器前,需确保Sensor已正确上电(XML中定义的powerUpSequence会通过PMIC控制电源)。

  • 时钟同步
    MCLK(主时钟)在Sensor启动前由时钟驱动模块配置,确保Sensor工作频率正确。


3. 实际写入流程示例

以Sensor初始化为例:

  1. 加载XML配置
    CamX解析sensor_imx586.xml,提取寄存器列表和电源时序。

  2. 上电Sensor
    按XML中的powerUpSequence依次开启VANA、VDIG、VIO等电源,并等待指定延迟。

  3. 写入初始化寄存器
    通过I2C总线依次写入0x0100=0x01(启动Sensor)、0x0300=0x02(设置MIPI通道数)等寄存器。

  4. 验证Sensor状态
    读取状态寄存器(如0x0002),确认Sensor已进入工作模式。


4. 调试与验证方法

(1) 日志验证
  • 启用I2C日志:

    adb shell setprop persist.vendor.camera.logInfoMask 0x100  # 启用I2C日志
  • 日志示例:

    CamX: [INFO][SENSOR] I2C Write: Slave=0x20, Addr=0x0100, Data=0x01
    CamX: [INFO][SENSOR] I2C Write: Slave=0x20, Addr=0x0300, Data=0x02
(2) 硬件信号抓取
  • 工具
    使用示波器或逻辑分析仪捕获I2C总线上的SCL(时钟)和SDA(数据)信号,验证实际写入的地址和值。

  • 信号解析

(3) 寄存器回读校验
  • 代码示例

    UINT32 readValue = 0;
    CSLReadRegister(sensorHandle, 0x0100, &readValue); // 回读寄存器0x0100
    if (readValue != 0x01) {
        CAMX_LOG_ERROR("Register 0x0100 write failed!");
    }

5. 常见问题与解决

问题现象可能原因解决方案
寄存器写入后Sensor无响应I2C从机地址错误或电源未正确开启检查XML中的slaveAddress和电源时序
图像数据格式异常像素格式寄存器配置错误(如RAW10 vs YUV)核对XML中outputFormat相关寄存器配置
部分寄存器写入失败寄存器地址受保护或需特定解锁序列参考Sensor数据手册补充解锁命令

6. 关键代码与配置文件参考

  1. XML配置文件

    • 路径:chi-cdk/oem/qcom/sensor/sensor_imx586.xml

    • 内容:定义电源时序、I2C参数、初始化寄存器列表。

  2. 寄存器操作代码

    • 文件:camxsensorsubmodule.cpp

    • 函数:SensorSubModule::ExecuteSensorConfiguration()

  3. I2C驱动接口

    • 内核驱动:kernel/drivers/i2c/i2c-core.c

    • 关键函数:i2c_transfer()


通过以上流程,XML中配置的寄存器值最终通过I2C总线写入Sensor硬件,完成摄像头传感器的初始化与控制。实际开发中需结合Sensor数据手册和调试工具验证配置的正确性。

以下是 CSLWrite 调用到 i2c_transfer 的详细过程,以及 sensorHandle 的来源解析,结合 CamX 架构和 Linux 内核驱动机制:


一、CSLWrite 到 i2c_transfer 的调用过程

1. 整体调用链
CamX应用层(HAL)
  │
  ├── SensorSubModule::ExecuteSensorConfiguration()  // 解析XML生成寄存器配置
  │
  ├── CSLWrite()                                     // CamX子系统层接口
  │   │
  │   └── ioctl(CAM_IOC_WRITE)                      // 用户态到内核态的桥接
  │
  └── 内核驱动
      ├── cam_ioctl()                               // 内核入口
      │
      └── i2c_transfer()                           // 实际I2C总线操作

2. 详细过程分解

**(1) CamX应用层:触发寄存器配置
  • 代码路径camxsensorsubmodule.cpp

  • 关键函数SensorSubModule::ExecuteSensorConfiguration()

    void SensorSubModule::ExecuteSensorConfiguration() {
        // 解析XML生成寄存器列表
        RegisterSettings regSettings = ParseSensorXML("sensor_imx586.xml");
        
        // 构建CSLWrite请求
        CSLWriteRequest request;
        request.slotId        = m_sensorSlot;        // 传感器槽位(如0)
        request.regSetting    = regSettings.data();  // 寄存器配置数组
        request.count         = regSettings.size();
        
        // 调用CSLWrite,传递sensorHandle和请求
        CSLResult result = CSLWrite(m_sensorHandle, &request);
        if (result != CSLResultSuccess) {
            CAMX_LOG_ERROR("Sensor config failed: %d", result);
        }
    }
**(2) CSL层:处理用户态请求
  • 代码路径camxcsllink.cpp

  • 关键函数CSLWrite()

    CSLResult CSLWrite(CSLHandle handle, CSLWriteRequest* pRequest) {
        // 1. 验证句柄和请求有效性
        if (!IsValidHandle(handle) || !pRequest) {
            return CSLResultEInvalidArg;
        }
        
        // 2. 将用户态请求转换为内核兼容格式
        struct cam_control iocontrol;
        iocontrol.opcode     = CAM_REG_WRITE;
        iocontrol.handle     = handle;          // sensorHandle传递到内核
        iocontrol.u.write    = *pRequest;       // 寄存器配置数据
        
        // 3. 通过ioctl调用内核驱动
        int ret = ioctl(g_camFD, CAM_IOC_WRITE, &iocontrol);
        if (ret < 0) {
            return CSLResultEHardware;
        }
        return CSLResultSuccess;
    }
**(3) 内核驱动:执行I2C操作
  • 代码路径drivers/media/platform/msm/camera/cam_sensor/cam_sensor_dev.c

  • 关键函数cam_sensor_subdev_ioctl()

    long cam_sensor_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) {
        switch (cmd) {
            case CAM_IOC_WRITE: {
                struct cam_write_req *req = (struct cam_write_req *)arg;
                struct cam_sensor_ctrl_t *s_ctrl = (struct cam_sensor_ctrl_t *)sd->dev_priv;
                
                // 1. 获取I2C适配器(与Sensor关联的I2C总线)
                struct i2c_adapter *adap = s_ctrl->io_master_info.client->adapter;
                
                // 2. 遍历寄存器列表,逐个写入
                for (int i = 0; i < req->count; i++) {
                    struct i2c_msg msg = {
                        .addr  = s_ctrl->io_master_info.client->addr, // I2C从机地址(如0x20)
                        .flags = 0,                                   // 写操作
                        .len   = req->regSetting[i].size,
                        .buf   = req->regSetting[i].data,
                    };
                    // 3. 调用i2c_transfer发送数据
                    int ret = i2c_transfer(adap, &msg, 1);
                    if (ret < 0) {
                        pr_err("I2C write failed: reg=0x%x, val=0x%x\n", 
                               req->regSetting[i].regAddr, 
                               req->regSetting[i].regData);
                        return -EIO;
                    }
                }
                break;
            }
        }
        return 0;
    }

二、sensorHandle 的来源

1. sensorHandle 的本质
  • 定义sensorHandle 是一个 句柄(Handle),本质是内核中为每个 Sensor 实例分配的 唯一标识符,用于在用户态(CamX HAL)与内核态(驱动)之间引用特定的 Sensor 设备。

  • 作用
    通过 sensorHandle,CamX 可以区分多摄像头系统中的不同 Sensor(如前置、后置、广角等)。

2. sensorHandle 的创建流程
**(1) 探测阶段:内核枚举 Sensor 设备
  • 代码路径drivers/media/platform/msm/camera/cam_sensor/cam_sensor_dev.c

  • 关键函数cam_sensor_driver_probe()

    static int cam_sensor_driver_probe(struct platform_device *pdev) {
        // 1. 解析设备树(DTS)中的Sensor配置
        struct cam_sensor_ctrl_t *s_ctrl = devm_kzalloc(&pdev->dev, sizeof(*s_ctrl), GFP_KERNEL);
        
        // 2. 初始化I2C客户端
        s_ctrl->io_master_info.client = i2c_new_device(adapter, &sensor_i2c_info);
        
        // 3. 注册为V4L2子设备
        v4l2_subdev_init(&s_ctrl->v4l2_dev, &cam_sensor_subdev_ops);
        platform_set_drvdata(pdev, s_ctrl);
        
        // 4. 生成唯一的sensorHandle(基于设备实例地址或ID)
        s_ctrl->sensorHandle = (uintptr_t)s_ctrl; // 示例:直接使用指针值
    }
**(2) CamX初始化:打开Sensor设备
  • 代码路径camxsensormodule.cpp

  • 关键函数SensorModule::Initialize()

    CamxResult SensorModule::Initialize() {
        // 1. 打开内核Sensor设备节点(如/dev/v4l-subdev0)
        int fd = open("/dev/v4l-subdev0", O_RDWR);
        
        // 2. 通过ioctl获取sensorHandle
        struct v4l2_subdev_info info;
        ioctl(fd, VIDIOC_SUBDEV_QUERY, &info);
        m_sensorHandle = info.handle; // 从内核获取已注册的handle
        
        // 3. 保存句柄供后续使用
        g_camFD = fd; // 全局文件描述符
    }
**(3) 句柄传递:从HAL到CSL
  • 代码路径camxsensorsubmodule.cpp

    SensorSubModule::SensorSubModule() {
        // 从SensorModule获取全局sensorHandle
        m_sensorHandle = SensorModule::GetInstance()->GetHandle();
    }

三、关键数据结构

**1. CSLHandle(用户态)
  • 定义typedef uintptr_t CSLHandle;

  • 赋值:通过 ioctl(VIDIOC_SUBDEV_QUERY) 从内核获取。

**2. cam_sensor_ctrl_t(内核态)
  • 定义:内核中管理 Sensor 设备的核心结构体。

    struct cam_sensor_ctrl_t {
        struct v4l2_subdev v4l2_dev;     // V4L2子设备
        struct camera_io_master io_master_info; // I2C/SPI总线信息
        uintptr_t sensorHandle;          // 关联的句柄
    };

四、调试与验证

1. 查看sensorHandle的值
  • 用户态日志

    adb logcat | grep "sensorHandle"
    # 输出示例:CamX: [INFO][SENSOR] sensorHandle=0x7f8a3c00
  • 内核态日志

    dmesg | grep "cam_sensor"
    # 输出示例:cam_sensor_driver_probe: sensorHandle=0xffffffc0f3d4a000
2. 验证I2C传输
  • 逻辑分析仪抓取波形
    检查I2C总线的SCL/SDA信号,确认地址和数据与XML配置一致。

  • 内核日志

    dmesg | grep "i2c_transfer"
    # 输出示例:i2c_write: slave=0x20, addr=0x0100, data=0x01

五、常见问题

问题原因解决方案
sensorHandle 为0或无效值设备未正确初始化或探测失败检查内核日志,确认Sensor驱动加载成功
I2C写入返回权限错误用户态未正确打开设备节点确保CamX进程有/dev/v4l-subdev*的访问权限
多Sensor场景句柄混淆未正确区分不同Sensor的句柄在XML中明确指定每个Sensor的slotId

通过上述流程,sensorHandle 在 CamX 初始化阶段从内核获取,并在后续通过 CSLWrite 传递到驱动层,最终由 i2c_transfer 完成对 Sensor 寄存器的写入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值