常见画面亮度闪烁,AE层面排查思路
常见画面亮度闪烁,AE层面排查思路Q:摄像头画面出现规律性的亮暗闪烁,自动曝光反复调节、稳定不下来,怎么快速定位?A:按 「先定性 → 查配置 → 看现成信息 → 再改源码」 四级递进。前三步用调试工具、串口和现成节点就能完成,都不用改代码。第 0 步:先确认是不是 AE 引起的用调试工具把 AE 切到 Manual 模式,固定曝光时间、模拟增益、数字增益:结果判断闪烁消失是 AE 在反复调节,继续往下查仍然闪烁大概率与 AE 无关,转查 3DNR 调试开关、ISP 其他模块或显示端这一步只点几下工具,不用改代码,先排除误判。第 1 步:查配置类原因(工具、串口可见)按现场现象直接查,多数问题在这一步就能定位:现象检查点(怎么查)处理方向开了曝光表但效果不对 / 曝光不生效工具看 AE 模式;切 Manual 或普通模式对比修正曝光表;曝光表模式不支持半行曝光,确认 sensor 是整行曝光抗频闪(flicker)不生效、滚动水波纹串口读 sensor 实际 FPS、VTS(命令见下方)修正驱动传入的 VTS/FPS,两者要匹配again/dgain 在两组值之间来回变、不收敛gain 表精度:小值达不到目标亮度、大值又超提高 gain 表精度,或增大进入稳定状态的阈值收敛越冲越亮、亮暗来回摆收敛步长 / 收敛速度上限参数/强光抑制过大限制收敛速度上限,避免步长过大或为负,降强光抑制强度双摄主/次摄闪烁隔帧生效参数、expo_fsexpo_fs 设为 0;隔帧生效按双摄配置高增益段亮度突跳驱动 again 上限是否等于 gain 表档位值again 上限改为 gain 表档位值30 fps 高分辨率下闪,降帧率后消失带宽 / 帧率降帧率复测确认,说明问题不在 AE 参数经验:先看 FPS/VTS 是否传对、曝光表模式是否配错、隔帧生效参数这三项,能覆盖相当一部分现场问题。读 sensor 实际 FPS / VTS(T33 实测可用):echo "w dbgmode 0 items 0x2 interval 0 vinum 0" > /proc/jz/isp/isp-m0 cat /proc/jz/isp/isp-m0 | grep -E "FPS|HTS|VTS"实测输出(T33 + SC4336P):Sensor OUTPUT FPS : 20 / 1 Sensor HTS : 2800 Sensor VTS : 2250第 2 步:先看现成的 AE 信息(不用改代码)T33 的 AE 算法核心在库文件(fast_ae_472.a / fast_ae_540.a)里,客户一般拿不到驱动源码。但 AE 实时信息有两个现成口子,一行代码都不用改。2.1 方式一:proc 节点(零改动,优先)核心 ISP 节点:/proc/jz/isp/isp-m0(T33 板端实测确认,ls /proc/jz/isp/ 可见 isp-m0 / isp-m1 等)# items 的 bit9(0x200)选中 AE 信息,vinum 0 = 主摄 echo "w dbgmode 0 items 0x200 interval 0 vinum 0" > /proc/jz/isp/isp-m0 cat /proc/jz/isp/isp-m0串口上全量输出太长,建议只取关键几行(注意 AeAGain : 带空格,否则会匹配到 AeAGainManualMode):cat /proc/jz/isp/isp-m0 | grep -E "AeLuma|AeAGain :|AeDGain :|AeIspDGain :|AeIntegrationTime :|AeStable"连续采样看是否跳变:for i in 1 2 3 4 5; do cat /proc/jz/isp/isp-m0 | grep -E "AeLuma|AeStable" | tr "\n" " "; echo; sleep 1; done实测输出片段:********* Ae Info ********* AeIntegrationTime : 1415 AeAGain : 1024 AeDGain : 0 AeIspDGain : 1024 ExposureValue : 1415 AeStable : 0 AeTarget : 62 AeMean : 55 AeLuma : 56输出里直接看这些字段是否来回跳:字段含义AeLuma当前统计亮度AeAGain / AeDGain / AeIspDGain模拟 / 数字 / ISP 数字增益AeIntegrationTime曝光时间AeTarget / AeMean / AeStable目标亮度 / 加权亮度 / 稳定标志ExposureValue / EVLog2曝光量2.2 方式二:应用层调 API(SDK 带库就能用)节点被裁剪时,在客户应用层直接调接口打印:tisp_ae_exprinfo_t info; tisp_g_ae_exprinfo_attr(0, &info); printf("it=%d ag=%d dg=%d ispdg=%d EV=%d\n", info.AeIntegrationTime, info.AeAGain, info.AeDGain, info.AeIspDGain, info.ExposureValue); tisp_ae_scence_attr_t sc; tisp_g_ae_scence_attr(0, &sc); printf("luma=%d\n", sc.luma);接口声明在 lib_tisp_api.h。注意实现包在 #ifdef TISP_AE_API_CTRL 里,没开这个宏时函数不填数据,先确认客户 SDK 的配置。2.3 判断:luma / 增益是否跳变观察结果下一步luma 或增益有跳变定位跳变位置,用 Manual 固定该组参数,确认画面效果没有跳变,但画面仍闪AE 算得没问题,是驱动没正确执行 → 进第 3 步对比第 3 步:还定位不了,再改驱动加打印3.1 / 3.2 需要 T33 内部 AE 固件源码(客户 SDK 一般没有,找原厂支持);3.3 改的是 sensor 驱动,客户 SDK 自带,可以自己加。只有前两步都看不出问题时才需要。3.1 打印 lumaluma 存在 AE 结果结构体 ae_context->results[index] 里:nLuma:原始统计亮度nLumaFinal:加权 / ROI 后的亮度打印点:opensource/internal/t33/t33_tiziano/src/tiziano_ae.c 的 tisp_ae_calc_process(约 413 行)——在库函数 normal_ae_calc_process / fast_ae_calc_process 调用之后、tisp_ae_set_algo_index 之前,此时 results[index] 已被本次统计填充。normal AE 和 fast AE 两种模式都覆盖。3.2 打印 it / ag / dg在同一位置打印 results[index] 的 nExpt / nAGain / nAGainReg / nDGain / nIspDGain。两个注意点:tiziano_ae.c 约 343 行有一段现成注释 printk(ag_index / again / ispd),取消注释可用,但它在 fast AE 分支,normal 模式在 306 行就提前 return 了;tisp_ae_interrupt_sync_result(约 356–409 行)整段被 #if 0 禁用,不要在那里打点。实测可用的打印代码(T33 + SC4336P 验证通过,EV 变化时逐条打印、稳定后每 50 帧心跳,避免刷屏):{ static uint64_t dbg_last_ev = ~0ULL; static uint32_t dbg_cnt = 0; uint64_t cur_ev = ae_context->results[index].nEV; if (cur_ev != dbg_last_ev || (dbg_cnt++ % 50) == 0) { dbg_last_ev = cur_ev; printk("JZ_AE: v%d it=%u ag=%u ispdg=%u luma=%u ev=%llu\n", vinum, ae_context->results[index].nExpt, ae_context->results[index].nAGain, ae_context->results[index].nIspDGain, ae_context->results[index].nLuma, (unsigned long long)cur_ev); } }为什么打 ispdg 而不打 dg:nDGain(sensor 数字增益)多数场景不用、恒为 0,AE 的实际增益调节落在 ISP 数字增益 nIspDGain 上(实测在 1024~1054 之间变化)。打 dg 会看不到调节过程。实测稳定段:JZ_AE: v0 it=896 ag=1024 ispdg=1024 luma=55 ev=917504 JZ_AE: v0 it=896 ag=1024 ispdg=1024 luma=55 ev=917504对照关系:JZ_AEm0 节点说明itAeIntegrationTime曝光行数(AeIntegrationTimeUnit : 0 时两者相等)agAeAGain模拟增益,1024 = 1xispdgAeIspDGainISP 数字增益,1024 = 1xlumaAeLuma统计亮度evExposureValueev 是 10bit 精度,ExposureValue = ev >> 10上电前几帧 luma 会剧烈波动(如 101→1),属出图瞬态,不要拿启动那几帧当判断依据,看稳定后的值。看 luma 和 ev 是否在相邻帧之间来回跳、it/ag/ispdg 是否成对反向变化,就能判断是 AE 侧振荡还是下游执行问题。3.3 对比 sensor 驱动侧输入值在 sensor 驱动里打印——这个源码客户 SDK 自带,路径 opensource/drivers/sensors/<sensor>/,不用改内部固件。以 T33 + SC4336P 为例,走的是 SENSOR_EXPO 模式(sc4336p.c 头部 #define SENSOR_EXPO),it 和 again 打包在一个 int 里传给 sc4336p_set_expo(约 2008 行):static int sc4336p_set_expo(struct tx_isp_subdev *sd, int value) { int it = value & 0xffff; /* 曝光行数 */ int again = (value >> 16) & 0xffff; /* again 寄存器值 */ printk("JZ_SENSOR: it=%d again=0x%x\n", it, again); /* again 用十六进制,和 gain 表对照 */ /* 原有写寄存器代码不动 */ }如果 sensor 驱动没开 SENSOR_EXPO(头文件里没有 #define SENSOR_EXPO),打点改在这两个函数:sc4336p_set_integration_time(约 2044 行)sc4336p_set_analog_gain(约 2076 行)WDR 短帧对应 sc4336p_set_expo_short(约 2243 行),要一起打。与第 2 步 proc 节点 / API 拿到的 AeIntegrationTime / AeAGain 对比(这条链路客户自己就能走完,不依赖内部固件源码):实测(T33 + SC4336P,收敛过程中同时抓):# sensor 驱动打印 JZ_SENSOR: it=598 again=0x80 JZ_SENSOR: it=600 again=0x80 JZ_SENSOR: it=602 again=0x80 # 同刻 proc 节点 AeIntegrationTime : 595 AeAGain : 1024对比项能否直接比说明it ↔ AeIntegrationTime✅ 直接比都是曝光行数。上例 598 vs 595 的差值是抓取时刻不同(AE 正在收敛),取同一帧或稳定态应相等again ↔ AeAGain⚠️ 需查表AeAGain 是倍数(1024 = 1x),经 sc4336p_alloc_again 查 again_lut 表得到寄存器值。上例 1024 → 0x80(表首项 {0x0080, 0},即增益下限档);增益升高时按表逐档递增,只看趋势是否跟得上,不要比数值对比结果结论一致(it 相等、again 按 AE 分配同步变化)闪烁与 AE 算法无关,查 sensor 驱动:增益表(again_lut)、增益上限、隔帧生效、寄存器写入时机不一致(sensor 收到值和 AE 分配不符)问题在 AE 算法侧或参数传递,向上排查分配逻辑避免误判先切 Manual 定性,快速定位模块;FPS/VTS 必须核对,flicker 相关几乎都和它有关;注意隔帧生效:双摄和单摄配置不同,参数照搬单摄会错;曝光表和驱动限制要对齐:表里设的值超过驱动能力时,串口会有提示,不要只看工具显示;结论先切 Manual 确认是不是 AE;再用工具和串口查模式、帧率、曝光表、隔帧生效;然后 cat proc 节点或调 API 看 AeLuma 和增益是否跳变;都不行才改驱动加打印,与 sensor 驱动输入值对比——一致查驱动,不一致查算法。