跳到主要内容

Camera FAQ

串口读写 Sensor 寄存器

【读 Sensor 寄存器命令示例】

1)cd /sys/devices/gc2053_mipi(进入目标 Sensor 节点目录)
2)echo 16 > addr_width; echo 8 > data_width(输入目标 Sensor 寄存器地址/数据位宽,请查阅 datasheet 获取)
3)echo 1 > read_flag(read_flag:读写控制节点,使能为1表示后续操作为读动作,使能为0表示后续操作为写动作)
4)echo 30350021 > cci_client(“30350021”:表示读取0x3035【目标寄存器地址】,在 read_flag = 1 情况下,写入值0021为无效状态)
5)cat read_value(打印上一步操作的结果:寄存器值)

【写 Sensor 寄存器命令示例】

1)cd /sys/devices/gc2053_mipi(进入目标 Sensor 节点目录)
2)echo 16 > addr_width; echo 8 > data_width(输入目标 Sensor 寄存器地址/数据位宽,请查阅 datasheet 获取)
3)echo 0 > read_flag(read_flag:读写控制节点,使能为1表示后续操作为读动作,使能为0表示后续操作为写动作)
4)echo 36510021 > cci_client (“36510021”:0x3651【目标寄存器地址】,0x0021【将要写入的寄存器值】,在 read_flag = 0 情况下,写入值为0x0021)
5)cat read_value

TWI 通讯异常

主控读写 Sensor 寄存器都是通过 TWI 来完成的,所以在调试 Sensor 时经常会遇到 TWI 通讯异常,如下:

TWI 被占用

TWI 被占用一般是 TWI 配置有冲突导致的,需要检查当前方案 Sensor 所使用的 TWI 在 uboot.dts 和 sysconfig.fex 是否也配置上了,需要将其注释掉,如下是 TWI4 被占用的打印:

TWI被占用

sysconfig.fex 和 uboot.dts 修改如下,将 TWI4 配置注释掉:

sysconfig修改

uboot_dts修改

TWI 通讯异常

如图 TWI 通讯异常的打印,如果出现 TWI 通讯异常,建议先从几个方面进行排查:

TWI通讯异常

  • 检查 board.dts 当前方案 Sensor 所使用的 TWI 引脚配置是否正确,是否被其他模块使用。

  • 检查 board.dts 当前方案 Sensor 的 TWI 地址是否正确。

  • TWI SCK SDA 引脚硬件上是否有接上拉电阻。

  • 检查 Sensor 驱动的上电时序(sensor_power 函数)是否有问题,如果上电时序没有问题,需要用万用表量一下 Sensor 三路供电 IOVDD、DVDD 和 AVDD 是否符合 Sensor 硬件设计指南上的需求,IOVDD 一般是 1.8V, DVDD 一般是 1.2V,AVDD 一般是 2.8V。

  • 检查 board.dts 当前方案 Sensor 的 MCLK 引脚配置是否有冲突,如果配置没有问题,需要使用示波器量一下 Sensor 端 MCLK 是否有输出以及频率是否正确,是否与 Sensor 驱动配置的一样。

  • 检查 board.dts 当前方案 Sensor 的 PWDN 和 RESET 引脚配置是否有冲突,如下,当前方案 Sensor 使用的 PE11 引脚与音频模块有冲突,需要将其注释掉。

    引脚定义冲突

TWI 读出来的寄存器值异常

如果 TWI 通讯没有出现异常,但是主控端读取到 Sensor 寄存器值都为0,则需要检查一下 Sensor 驱动配置的 TWI 数据位宽和地址位宽是否与 Sensor datasheet 说明一样,见 Sensor TWI 数据位宽和地址位宽章节说明。同时,检查一下 Sensor 三路供电 IOVDDDVDD 和 AVDD 是否正常。

TWI读取的寄存器值为0

select timeout 不出图

主控将 Sensor 初始化配置写进 Sensor 之后,一般 Sensor 就会有数据输出,如果出现[ISP_ERR]video_wait_buffer, line: 488,video8 select timeout!,则表示当前 Video 节点所在的 Sensor 是没有数据给到主控端,或者是给过来数据是有问题的。

selecttimeout

出现 select timeout 的打印可以从以下几点定位问题:

检查 SOC MIPI 寄存器状态

MIPI-Parser 寄存器

在 sample_virvi 运行起来之后,连续抓取 parser 寄存器,以 V821 平台为例,检查 0x45820034 (MIPI1:0x45821034)是否有寄存器值刷新,这个寄存器值表示 SoC 收到图像的宽高信息,可以快速判断 SOC 是否收到图像数据,抓取寄存器指令如下:

MIPIA检查 0x45820034 寄存器,MIPIB检查 0x45821034 寄存器。

  • MIPIA/MIPI0:cd /sys/class/sunxi_dump && echo 0x45820000, 0x45820200 > dump; cat dump
  • MIPIB/MIPI1:cd /sys/class/sunxi_dump && echo 0x45821000, 0x45821200 > dump; cat dump

image-20250218140302821

MIPI-PHY 寄存器

检查 MIPIA:0x45810100(MIPIB:0x45810200)的 bit[0] 是否使能,这个 bit 表示 phy_en,检查 MIPIA:0x458101f0 (MIPIB:0x458102f0) 的 bit[19:16] 和 bit[0:3] 状态,如果状态一直处于 3(0011),则表示没有收到 Sensor 的图像数据,如果寄存器值状态处于 3-5 之间切换,则表示有收到图像数据

获取 V821 PHY 寄存器状态指令如下:

  • MIPIA/MIPI0:cd /sys/class/sunxi_dump && echo 0x45810100, 0x458101ff > dump; cat dump

  • MIPIB/MIPI1:cd /sys/class/sunxi_dump && echo 0x45810200, 0x458102fc > dump; cat dump

MIPI-PAYLOAD 寄存器

在通路运行起来之后,连续抓取 MIPI-PAYLOAD 寄存器,以 V821 平台 MIPI0 为例,检查 0x45811118 寄存器值(MIPI1检查:0x45811518 寄存器值)检查[31:07]的 ERR PD 标志位是否被置位,如果 ERR PD 被置位,需要检查 MIPI 波形是否正常,抓取寄存器指令如下:

MIPIA检查 0x45811118 寄存器,MIPIB检查 0x45811518 寄存器。

  • MIPIA/MIPI0:cd /sys/class/sunxi_dump && echo 0x45811000, 0x458111ff > dump; cat dump
  • MIPIA/MIPI1:cd /sys/class/sunxi_dump && echo 0x45811400, 0x458115ff > dump; cat dump

image-20250218140855562

image-20250218140904168

通过上述查看寄存器的方式,可以先初步判断一下是否是 Sensor 端没有发送数据过来,与此同时,可以使用示波器量一下 Sensor 端的 mipi datamipi clk 引脚是否有波形,如果没有量到波形,则需要检查一下 Sensor 驱动的初始化配置是否与 Sensor 原厂提供初始化配置一致,同时需要将问题反馈给 Sensor 原厂。如果初步检查 Sensor 有发送数据,且 SoC MIPI 状态有在轮转,那么可以尝试调节 MIPI Clk Delay 寄存器。

调节 MIPI Clk Delay 寄存器

确定 clk delay 范围

PS:需要在边跑应用出图的同时来调试,尽可能在边预览图像边调试,方便判断调整后图像是否还存在花屏、异常横/竖线等异常现象。 第一步,连续多次抓取 MIPI PAYLOAD 寄存器,检查bit【7-12】等异常中断标志位是否被置起,以此来判断 MIPI 状态是否异常。

平台MIPIAMIPIB
V8210x458111180x45811518
// MIPIA
cd /sys/class/sunxi_dump && echo 0x45811118 0xffffffff > write // 清除中断标志位
cd /sys/class/sunxi_dump && echo 0x45811000, 0x458111ff > dump; cat dump
// MIPIB
cd /sys/class/sunxi_dump && echo 0x45811518 0xffffffff > write // 清除中断标志位
cd /sys/class/sunxi_dump && echo 0x45811400, 0x458115ff > dump; cat dump

第二步,如图所示,bit【24:20】是 clk lane0 的软件设定延时值,起到延时采样的作用,适当调整这个参数可以使得 SoC 与 Sensor 的时序更加匹配。

平台MIPIAMIPIB
V8210x458101180x45810218
// MIPIA PHYA 读指令
cd /sys/class/sunxi_dump && echo 0x45810100, 0x458101ff > dump; cat dump
// PHYA 0x45810118 寄存器写指令
cd /sys/class/sunxi_dump && echo 0x45810118 0x00000000 > write
// MIPIB PHYB 读指令
cd /sys/class/sunxi_dump && echo 0x45810200, 0x458102fc > dump; cat dump
// PHYB 0x45810218 寄存器写指令
cd /sys/class/sunxi_dump && echo 0x45810218 0x00000000 > write

image-20250218140935412

第三步,保持 clk dly 为 0x0,步进递增延时值,同时检查步骤一是否出现异常状态。例如设置 clk dly 等于 0x0,步进递增至0x9 时,MIPI状态满足步骤一(即 MIPI 状态寄存器值异常),那么 clk dly 适用的的范围为【0x0,0x8】,最佳值是取这个范围的中间也就是 0x4。

Sensor 驱动配置 clk delay

将调试出来的 clk delay 值配置到 Sensor 驱动。

// 请配置在 sensor_init 函数中
static int sensor_init(struct v4l2_subdev *sd, u32 val)
{
int ret;
struct sensor_info *info = to_state(sd);

sensor_dbg("sensor_init\n");

/*Make sure it is a target Sensor */
ret = sensor_detect(sd);
if (ret) {
sensor_err("chip found is not an target chip.\n");
return ret;
}

info->focus_status = 0;
info->low_speed = 0;
info->width = 1280;
info->height = 720;
info->hflip = 0;
info->vflip = 0;
info->gain = 0;
info->exp = 0;
info->deskew = 0x4; // 配置 clk delay 参数

info->tpf.numerator = 1;
info->tpf.denominator = 20; /* 30fps */
return 0;
}

翻转失效或图像异常

翻转失效

在调用水平或垂直方向进行翻转,API 已返回成功后,画面延迟生效或者概率性失效,大部分 Sensor 在设置翻转寄存器到生效需要一小段时间,可以在设置寄存器后加一点点小延时来规避,也可以通过回读寄存器来大致估摸需要的延时时长,或者在代码中添加回读机制,保证翻转寄存器被更新到后才执行其它操作,如下:

// gc2083垂直翻转示例
data_type sensor_flip_status; //定义私有全局变量,用于记录当前翻转状态
static int sensor_s_vflip(struct v4l2_subdev *sd, int enable)
{
unsigned int iic_addr;
data_type get_value;
data_type set_value;
data_type value_0015;
data_type value_0d15;
int times_out = 3;
int eRet;

if (!(enable == 0 || enable == 1)) {
sensor_err("Invalid parameter!!!\n");
return -1;
}

sensor_i2c_addr_get(sd, &iic_addr);
get_value = sensor_flip_status & 0x03;
if (enable)
set_value = get_value | 0x02;
else
set_value = get_value & 0xFD;

sensor_write(sd, 0x0015, set_value);
sensor_write(sd, 0x0d15, set_value);
do {
/* write repeatly */
sensor_write(sd, 0x0015, set_value); //覆写寄存器
sensor_write(sd, 0x0d15, set_value);
eRet = sensor_read(sd, 0x0015, &value_0015); //回读寄存器
eRet = sensor_read(sd, 0x0d15, &value_0d15);
sensor_print("[V] eRet:%d, value_0015 = 0x%x, value_0d15 = 0x%x, times_out:%d\n", eRet, value_0015, value_0d15, times_out);
usleep_range(10000, 30000);
times_out--;
} while ((value_0015 != set_value) && (value_0d15 != set_value) && (times_out >= 0)); //通过覆写和回读,确认寄存器已被更新

if ((times_out < 0) && ((value_0d15 != set_value) || (value_0015 != set_value))) {
sensor_err("set vflip failed, please set more times!!!\n"); //寄存器未能被更新到,上报异常
return -1;
} else {
sensor_flip_status = set_value;
}
sensor_print("vflip current_switch_choice : 0x%x, set_value : 0x%x, sensor_flip_status = 0x%x, , value_0015 = 0x%x, value_0d15 = 0x%x\n",iic_addr, set_value, sensor_flip_status, value_0015, value_0d15);

return 0;
}

如果寄存器未被正常更新,则上报异常,具体问题也可以咨询 Sensor 原厂翻转寄存器设置时,是否有其它相关联寄存器需要同步设置(如切页、组写等),同时,检查驱动中是否有其它操作翻转寄存器的代码,是否存在同时使用的冲突。

自动降帧常见问题

调整的帧率与预期不符

有以下几种可能性:

1.sensor_win_sizes 中的 VTS、HTS、PCLK 信息填写不正确,VTS、HTS 需要按照 Sensor 初始化寄存器列表里的值来进行填写,PCLK 可以通过 Sensor 原厂获取(或自行计算)后填写,注意三者要满足公式,这三个关键信息是会交由 ISP 计算实际的曝光时间的,如果填写不准确会间接导致曝光时间有误差,进而导致降帧时帧率产生误差。

 PCLK = HTS * VTS * FPS

2.更新 VTS、HTS 寄存器的方法有误,寄存器的读写方式需要严格按照规格书描述来操作(也可以直接询问 Sensor 原厂),注意大部分寄存器会区分高低位信息分别更新两个寄存器,需要留意写入的值是否符合预期,可以在更新寄存器后,使用 sensor_read 函数回读打印确认,并实时查看 VI 结点信息来检查。

3.检查 ISP 效果的最大曝光时间设置是否与预期不符,如目标是自动降帧至 10fps,但最大曝光时间又限制在 1/20s,那么不会触发自动降帧策略,当然也存在当前照度可能还未到要降帧延长曝光时间的时候;

设置帧率之后,Sensor 不出图

有以下几种可能性:

  1. 回退驱动中帧率调整的相关代码,检查出图稳定性,是否真的是帧率改动导致的不出图。

  2. 确保 VTS、HTS 寄存器更新成功,设置的值也符合预期;如果确定寄存器值符合预期,那么可以咨询 Sensor 原厂该 Sensor 在调整帧率时是否有其它注意事项,如 VTS 偏移量限制等。