1. AE初始化与曝光统计

AE初始化与曝光统计 学习卡片

任务说明

本案例实现高通Spectra ISP平台上的AE(自动曝光)模块初始化流程:配置传感器曝光寄存器与ISP统计通道,并读取当前帧的亮度统计信息,为后续AE收敛算法提供输入。代码基于高通Camera Subsystem(Camera Kernel Driver)框架,适用于带Spectra ISP的骁龙平台。

核心实现

// ae_init_stats.c — AE初始化与曝光统计最小实现
#include <linux/kernel.h>
#include <linux/err.h>
#include <media/v4l2-subdev.h>
#include <cam_sensor_io.h>
#include <cam_isp_hw.h>

#define AE_STATS_WIN_NUM  4   /* 统计窗口数 */
#define AE_STATS_BIN_SIZE 256 /* 每窗口直方图bin数 */

struct ae_stats_win {
    uint32_t x_start, y_start; /* 窗口起点 */
    uint32_t width, height;    /* 窗口尺寸 */
    uint32_t hist[AE_STATS_BIN_SIZE]; /* 亮度直方图 */
};

struct ae_device {
    struct v4l2_subdev *sensor_sd;   /* 传感器subdev */
    struct cam_isp_hw *isp_hw;       /* ISP硬件句柄 */
    uint32_t sensor_exp_reg;         /* 曝光寄存器地址 */
    uint32_t isp_stats_base;         /* ISP统计基地址 */
    struct ae_stats_win wins[AE_STATS_WIN_NUM];
    uint32_t frame_brightness;       /* 整帧平均亮度 */
};

/* 配置传感器曝光寄存器(写寄存器值) */
static int ae_sensor_set_exposure(struct ae_device *dev, uint32_t exp_lines)
{
    return cam_sensor_util_write_reg(dev->sensor_sd,
                                     dev->sensor_exp_reg,
                                     exp_lines,
                                     CAM_SENSOR_REG_TYPE_32BIT);
}

/* 配置ISP统计通道:使能4个窗口并设置坐标 */
static int ae_isp_config_stats(struct ae_device *dev)
{
    struct cam_isp_stats_cfg cfg = {0};
    int i;

    cfg.stats_type = CAM_ISP_STATS_AE;
    cfg.num_windows = AE_STATS_WIN_NUM;
    for (i = 0; i < AE_STATS_WIN_NUM; i++) {
        cfg.win[i].x_start = dev->wins[i].x_start;
        cfg.win[i].y_start = dev->wins[i].y_start;
        cfg.win[i].width   = dev->wins[i].width;
        cfg.win[i].height  = dev->wins[i].height;
    }
    return cam_isp_hw_config_stats(dev->isp_hw, &cfg);
}

/* 读取ISP统计结果并计算整帧平均亮度 */
static int ae_get_frame_stats(struct ae_device *dev)
{
    uint32_t sum = 0, cnt = 0;
    int i, j, rc;

    rc = cam_isp_hw_read_stats(dev->isp_hw, CAM_ISP_STATS_AE,
                               dev->isp_stats_base,
                               (void *)dev->wins,
                               sizeof(dev->wins));
    if (rc < 0)
        return rc;

    for (i = 0; i < AE_STATS_WIN_NUM; i++) {
        for (j = 0; j < AE_STATS_BIN_SIZE; j++) {
            sum += dev->wins[i].hist[j] * j;
            cnt += dev->wins[i].hist[j];
        }
    }
    dev->frame_brightness = cnt ? sum / cnt : 0;
    return 0;
}

/* AE模块初始化入口 */
int ae_module_init(struct ae_device *dev, uint32_t exp_lines)
{
    int rc;

    /* 1. 配置传感器曝光 */
    rc = ae_sensor_set_exposure(dev, exp_lines);
    if (rc < 0)
        return rc;

    /* 2. 配置ISP统计窗口 */
    rc = ae_isp_config_stats(dev);
    if (rc < 0)
        return rc;

    /* 3. 获取当前帧统计(首次调用用于验证链路) */
    rc = ae_get_frame_stats(dev);
    if (rc < 0)
        return rc;

    dev_info(&dev->sensor_sd->dev,
             "AE init done, brightness=%u\n", dev->frame_brightness);
    return 0;
}

依赖与接入说明

  • 依赖高通Camera内核驱动头文件:cam_sensor_io.h(寄存器读写)、cam_isp_hw.h(ISP统计配置与读取)。
  • cam_sensor_util_write_reg、cam_isp_hw_config_stats、cam_isp_hw_read_stats为平台驱动提供的标准接口,直接调用即可。
  • 调用前需完成:dev->sensor_sd、dev->isp_hw已绑定;dev->wins[]已填入实际窗口坐标;dev->isp_stats_base已映射到ISP统计寄存器地址。

编译与运行

# 以模块方式编译(在kernel源码树内)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- M=$PWD/drivers/camera modules

# 将生成的ae_init_stats.ko推送到设备并加载
adb push ae_init_stats.ko /data/local/tmp/
adb shell insmod /data/local/tmp/ae_init_stats.ko

# 调用初始化(示例:曝光行数设为1000)
# 在驱动中通过ioctl或sysfs触发ae_module_init(dev, 1000)

验证方法

  • 加载模块后,在dmesg中观察日志:出现AE init done, brightness=xxx即表示初始化流程执行成功。
  • 改变环境光照(如用手遮挡镜头),再次触发初始化,brightness值应随之显著变化,说明统计链路有效。
  • 若brightness恒为0,检查:传感器曝光寄存器地址是否正确、ISP统计窗口坐标是否超出当前sensor输出尺寸、isp_stats_base映射是否有效。

预期输出示例

[  123.456] AE init done, brightness=128

该值表示当前帧4个统计窗口的平均亮度为128(0~255范围),具体数值随实际光照变化。