目录
1. 简介
1.1 文章要点
- IMX297 与 IMX296 对比
- Linux 驱动代码分析
- 寄存器配置分析
1.2 概念解释
- 全局快门图像传感器(Global Shutter Image Sensor)
CMOS图像传感器大致可分为两种类型:
- 一种使用滚动快门(Rolling Shutter),通过逐行扫描来捕捉图像。
- 另一种采用全局快门,在焦平面上一次性拍摄图像。
全局快门能够在同一时间捕捉整幅图像的所有像素,在拍摄快速移动的物体时,全局快门可以避免图像产生失真或扭曲,因为所有像素都同时曝光。
在滚动快门模式下,图像传感器逐行曝光,图像的不同部分在不同时间被捕捉。可能导致在拍摄快速移动的物体或进行快速移动的拍摄时出现失真,例如“果冻效应”或倾斜的垂直线条。
全局快门特别适用于需要高精度和无失真图像的应用场景,如工业检测、运动捕捉和高动态场景拍摄等。
- 3.4 系列
3.4 系列,是指具有 3.45μm 像素的 Sensor,它是工业图像传感器的标准型号,适用于多种用途。
- 详细对比
IMX297 与 IMX296 都是 3.4 系列,且具有相同的感光尺寸,区别在于最大分辨率、刷新率不同。
要点:
- 同属3.4系列
- 同属嵌入式应用方向,MIPI接口
- 尺寸相同
- 最高帧率和分辨率不同
型号 | H x V | 尺寸 | 帧率 | 长宽比 |
IMX296 | 1456 x 1088 | 1/2.9(6.3mm) | 60 | 4:3 |
IMX297 | 728 x 544 | 1/2.9(6.3mm) | 120 | 4:3 |
1.3 Pregius vs Pregius S
按照 sony 的说法,Pregius 是一种用于 CMOS 图像传感器的全局快门像素技术,它结合了低噪声 CCD 结构,实现高质量成像。Pregius 这个名字来源于 “Precision GS”,代表CCD的低噪声性能与全局快门(GS)的高速和高精度特性相结合。
而 Pregius S 是 Pregius 技术的进一步升级,采用背照式结构使得实现更快的帧速率成为可能,而堆叠结构的应用则实现了图像传感器的小型化、多功能安装以及功能扩展。
简易总结:
1)Pregius = CCD 结构 + 有源像素型 CMOS + 全局快门
2)Pregius S = Pregius + 背照结构 + 堆栈式结构
背照式结构的第一个优点是允许更大的入射角,如上图所示。通常,这种结构面临的问题包括噪声抑制和暗电流的处理。在 Pregius S 技术中,sony 开发了一种原始的光电二极管结构和光遮蔽结构,这些结构经过优化,适用于背照式结构。这大大提高了灵敏度和饱和特性,同时抑制了噪声的产生。
2. 代码分析
2.1 imx296 结构体
用于表示传感器设备的主要数据结构,包含设备指针、时钟、调节器、GPIO描述符、寄存器映射、V4L2子设备、控制处理程序等。
struct imx296 {
struct device *dev;
struct clk *clk;
struct regulator_bulk_data supplies[ARRAY_SIZE(imx296_supply_names)];
struct gpio_desc *reset;
struct regmap *regmap;
const struct imx296_clk_params *clk_params;
bool mono;
bool streaming;
struct v4l2_subdev subdev;
struct media_pad pad;
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *vflip;
struct v4l2_ctrl *hflip;
};
2.2 I2C读写函数
用于通过 I2C 总线与传感器进行寄存器读写操作。
static int imx296_read(struct imx296 *sensor, u32 addr)
{
u8 data[3] = { 0, 0, 0 };
int ret;
ret = regmap_raw_read(sensor->regmap, addr & IMX296_REG_ADDR_MASK, data,
(addr >> IMX296_REG_SIZE_SHIFT) & 3);
if (ret < 0)
return ret;
return (data[2] << 16) | (data[1] << 8) | data[0];
}
static int imx296_write(struct imx296 *sensor, u32 addr, u32 value, int *err)
{
u8 data[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 };
int ret;
if (err && *err)
return *err;
ret = regmap_raw_write(sensor->regmap, addr & IMX296_REG_ADDR_MASK,
data, (addr >> IMX296_REG_SIZE_SHIFT) & 3);
if (ret < 0) {
dev_err(sensor->dev, "%u-bit write to 0x%04x failed: %d\n",
((addr >> IMX296_REG_SIZE_SHIFT) & 3) * 8,
addr & IMX296_REG_ADDR_MASK, ret);
if (err)
*err = ret;
}
return ret;
}
2.3 电源管理
函数 imx296_power_on 和 imx296_power_off:用于管理传感器的电源状态,提供电源、复位和时钟的控制。
支持运行时电源管理(runtime PM),通过imx296_runtime_resume 和 imx296_runtime_suspend实现。
static int imx296_power_on(struct imx296 *sensor)
{
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies),
sensor->supplies);
if (ret < 0)
return ret;
udelay(1);
ret = gpiod_direction_output(sensor->reset, 0);
if (ret < 0)
goto err_supply;
udelay(1);
ret = clk_prepare_enable(sensor->clk);
if (ret < 0)
goto err_reset;
/*
* The documentation doesn't explicitly say how much time is required
* after providing a clock and before starting I2C communication. It
* mentions a delay of 20µs in 4-wire mode, but tests showed that a
* delay of 100µs resulted in I2C communication failures, while 500µs
* seems to be enough. Be conservative.
*/
usleep_range(1000, 2000);
retu