1. 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范围),具体数值随实际光照变化。