Bài viết này tập trung vào việc phân tích driver cho các cảm biến hình ảnh IMX297 và IMX296, bao gồm so sánh hai model, phân tích mã nguồn driver Linux và cấu hình thanh ghi.
1. Giới thiệu
Các điểm chính của bài viết bao gồm:
- So sánh chi tiết giữa IMX297 và IMX296.
- Phân tích cấu trúc và hoạt động của driver Linux cho các cảm biến này.
- Khám phá cách cấu hình các thanh ghi của cảm biến.
1.1 Giải thích các khái niệm
Cảm biến hình ảnh Global Shutter
Cảm biến hình ảnh CMOS có hai loại chính:
- Rolling Shutter: Quét từng dòng để thu nhận hình ảnh. Loại này có thể gây ra hiện tượng méo hình, "hiệu ứng jelly" hoặc đường kẻ dọc bị nghiêng khi chụp các vật thể chuyển động nhanh.
- Global Shutter: Chụp toàn bộ hình ảnh cùng một lúc trên mặt phẳng tiêu cự. Loại này đảm bảo tất cả các pixel được phơi sáng đồng thời, loại bỏ hiện tượng méo hình khi chụp vật thể chuyển động nhanh.
Cảm biến Global Shutter lý tưởng cho các ứng dụng yêu cầu độ chính xác cao và hình ảnh không bị biến dạng, như kiểm tra công nghiệp, ghi lại chuyển động và các cảnh quay có độ động cao.
Dòng 3.4 Series
Thuật ngữ "3.4 Series" đề cập đến các cảm biến có kích thước pixel là 3.4μm. Đây là tiêu chuẩn cho các cảm biến hình ảnh công nghiệp, phù hợp với nhiều ứng dụng.
So sánh chi tiết IMX297 và IMX296
Cả IMX297 và IMX296 đều thuộc dòng 3.4 Series với cùng kích thước cảm biến quang học. Tuy nhiên, chúng khác nhau về độ phân giải tối đa và tốc độ khung hình.
- Đều thuộc 3.4 Series.
- Đều hướng tới ứng dụng nhúng với giao diện MIPI.
- Kích thước vật lý giống nhau.
- Tốc độ khung hình và độ phân giải tối đa khác nhau.
| Model | H x V | Kích thước | Tốc độ khung hình (fps) | Tỷ lệ khung hình |
|---|---|---|---|---|
| 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.2 Pregius vs Pregius S
Pregius là công nghệ pixel Global Shutter của Sony, kết hợp cấu trúc CCD giảm nhiễu để cho ra hình ảnh chất lượng cao. Tên gọi "Pregius" bắt nguồn từ "Precision GS", thể hiện sự kết hợp giữa hiệu suất giảm nhiễu của CCD và tốc độ, độ chính xác của Global Shutter (GS).
Pregius S là sự nâng cấp của Pregius, sử dụng cấu trúc BSI (Back-Side Illuminated) giúp tăng tốc độ khung hình và cấu trúc xếp chồng (stacked structure) cho phép thu nhỏ kích thước cảm biến, lắp đặt linh hoạt và mở rộng chức năng.
Tóm tắt đơn giản:
- Pregius = Cấu trúc CCD + CMOS Active Pixel + Global Shutter
- Pregius S = Pregius + Cấu trúc BSI + Cấu trúc xếp chồng
Cấu trúc BSI cải thiện góc chiếu sáng tới, nhưng thường đối mặt với các vấn đề về triệt tiêu nhiễu và dòng tối. Trong công nghệ Pregius S, Sony đã phát triển cấu trúc diode quang và cấu trúc che chắn ánh sáng tối ưu hóa cho BSI, giúp tăng độ nhạy, đặc tính bão hòa và giảm nhiễu.
2. Phân tích mã nguồn
2.1 Cấu trúc dữ liệu imx296
Cấu trúc này đại diện cho thiết bị cảm biến, chứa các con trỏ tới thiết bị, clock, bộ điều chỉnh nguồn, mô tả GPIO, ánh xạ thanh ghi, sub-device V4L2, bộ xử lý điều khiển, v.v.
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; // Cờ báo hiệu cảm biến đơn sắc hay màu
bool streaming; // Cờ báo hiệu trạng thái streaming
struct v4l2_subdev subdev; // Sub-device V4L2
struct media_pad pad; // Pad của media controller
struct v4l2_ctrl_handler ctrls; // Bộ xử lý các điều khiển V4L2
struct v4l2_ctrl *hblank; // Điều khiển Horizontal Blanking
struct v4l2_ctrl *vblank; // Điều khiển Vertical Blanking
struct v4l2_ctrl *vflip; // Điều khiển lật dọc
struct v4l2_ctrl *hflip; // Điều khiển lật ngang
};
2.2 Hàm đọc/ghi I2C
Các hàm này được sử dụng để đọc và ghi dữ liệu vào các thanh ghi của cảm biến thông qua giao diện I2C.
/**
* imx296_read - Đọc dữ liệu từ thanh ghi I2C của cảm biến
* @sensor: Con trỏ tới cấu trúc imx296
* @addr: Địa chỉ thanh ghi cần đọc
*
* Trả về giá trị đọc được hoặc mã lỗi âm.
*/
static int imx296_read(struct imx296 *sensor, u32 addr)
{
u8 data_buffer[3] = { 0, 0, 0 }; // Đệm lưu trữ dữ liệu đọc được
int ret_code;
// Sử dụng regmap_raw_read để đọc dữ liệu
// addr & IMX296_REG_ADDR_MASK: Lấy địa chỉ thanh ghi
// (addr >> IMX296_REG_SIZE_SHIFT) & 3: Xác định số byte cần đọc
ret_code = regmap_raw_read(sensor->regmap, addr & IMX296_REG_ADDR_MASK, data_buffer,
(addr >> IMX296_REG_SIZE_SHIFT) & 3);
if (ret_code < 0) {
// Xử lý lỗi đọc
return ret_code;
}
// Ghép các byte đọc được thành giá trị 32-bit
return (data_buffer[2] << 16) | (data_buffer[1] << 8) | data_buffer[0];
}
/**
* imx296_write - Ghi dữ liệu vào thanh ghi I2C của cảm biến
* @sensor: Con trỏ tới cấu trúc imx296
* @addr: Địa chỉ thanh ghi cần ghi
* @value: Giá trị cần ghi
* @err: Con trỏ để lưu mã lỗi (tùy chọn)
*
* Trả về 0 nếu thành công, hoặc mã lỗi âm nếu thất bại.
*/
static int imx296_write(struct imx296 *sensor, u32 addr, u32 value, int *err)
{
// Chuẩn bị dữ liệu ghi theo định dạng byte
u8 data_to_write[3] = { value & 0xff, (value >> 8) & 0xff, value >> 16 };
int ret_code;
// Kiểm tra lỗi đã được báo hiệu trước đó (nếu có)
if (err && *err)
return *err;
// Sử dụng regmap_raw_write để ghi dữ liệu
// addr & IMX296_REG_ADDR_MASK: Địa chỉ thanh ghi
// (addr >> IMX296_REG_SIZE_SHIFT) & 3: Số byte cần ghi
ret_code = regmap_raw_write(sensor->regmap, addr & IMX296_REG_ADDR_MASK,
data_to_write, (addr >> IMX296_REG_SIZE_SHIFT) & 3);
if (ret_code < 0) {
// Ghi thông báo lỗi chi tiết
dev_err(sensor->dev, "%u-bit write to 0x%04x failed: %d\n",
((addr >> IMX296_REG_SIZE_SHIFT) & 3) * 8, // Số bit được ghi
addr & IMX296_REG_ADDR_MASK, // Địa chỉ thanh ghi
ret_code); // Mã lỗi
if (err)
*err = ret_code; // Lưu lỗi nếu có con trỏ err
}
return ret_code; // Trả về mã trạng thái
}
2.3 Quản lý nguồn điện
Các hàm imx296_power_on và imx296_power_off chịu trách nhiệm quản lý trạng thái nguồn của cảm biến, bao gồm cung cấp điện áp, điều khiển tín hiệu reset và bật/tắt clock.
Driver cũng hỗ trợ quản lý nguồn theo thời gian thực (runtime PM) thông qua các hàm imx296_runtime_resume và imx296_runtime_suspend.
/**
* imx296_power_on - Bật nguồn cho cảm biến IMX296
* @sensor: Con trỏ tới cấu trúc imx296
*
* Cung cấp nguồn, kích hoạt reset và bật clock cho cảm biến.
* Trả về 0 nếu thành công, mã lỗi âm nếu thất bại.
*/
static int imx296_power_on(struct imx296 *sensor)
{
int ret_status;
// Kích hoạt các nguồn cung cấp (regulators)
ret_status = regulator_bulk_enable(ARRAY_SIZE(sensor->supplies),
sensor->supplies);
if (ret_status < 0) {
dev_err(sensor->dev, "Failed to enable supplies: %d\n", ret_status);
return ret_status;
}
// Chờ một khoảng thời gian ngắn sau khi cấp nguồn
udelay(1);
// Thiết lập chân RESET ở trạng thái đầu ra và kéo xuống (reset)
ret_status = gpiod_direction_output(sensor->reset, 0);
if (ret_status < 0) {
dev_err(sensor->dev, "Failed to set reset pin as output: %d\n", ret_status);
goto power_off_supplies; // Quay lại tắt nguồn cung cấp nếu lỗi
}
// Chờ một khoảng thời gian ngắn sau khi reset
udelay(1);
// Chuẩn bị và kích hoạt clock cho cảm biến
ret_status = clk_prepare_enable(sensor->clk);
if (ret_status < 0) {
dev_err(sensor->dev, "Failed to enable clock: %d\n", ret_status);
goto release_reset_pin; // Quay lại giải phóng chân reset nếu lỗi
}
/*
* Tài liệu không nêu rõ khoảng thời gian cần thiết sau khi cung cấp
* clock và trước khi bắt đầu giao tiếp I2C. Tài liệu đề cập đến độ trễ
* 20µs ở chế độ 4-wire, nhưng thử nghiệm cho thấy độ trễ 100µs có thể
* gây lỗi giao tiếp I2C, trong khi 500µs dường như đủ. Chọn giá trị an toàn.
*/
usleep_range(1000, 2000); // Độ trễ từ 1ms đến 2ms
return 0; // Trả về thành công
power_off_supplies:
regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies);
release_reset_pin:
gpiod_direction_output(sensor->reset, 1); // Đặt chân reset về trạng thái không reset (output 1)
return ret_status;
}
// imx296_power_off sẽ thực hiện các hành động ngược lại
// static int imx296_power_off(struct imx296 *sensor) { ... }
2.4 Giao diện điều khiển
Driver quản lý các điều khiển của cảm biến thông qua V4L2 (Video for Linux Two) API. Các điều khiển này bao gồm các tham số như Horizontal Blanking (hblank), Vertical Blanking (vblank), lật ảnh dọc (vflip) và lật ảnh ngang (hflip).
2.5 Thao tác V4L2 Sub-device
Driver triển khai các thao tác (operations) cần thiết cho một V4L2 sub-device, cho phép nó tích hợp vào framework media controller của Linux. Điều này bao gồm các hàm để query, set format, stream on/off, v.v.
2.6 Khởi tạo và Dọn dẹp
Hàm khởi tạo (probe) sẽ thực hiện việc đăng ký sub-device, thiết lập các kết nối media, khởi tạo các điều khiển và cấu hình ban đầu cho cảm biến. Hàm dọn dẹp (remove) sẽ giải phóng tài nguyên, hủy đăng ký sub-device và tắt nguồn cảm biến.
2.7 Hỗ trợ Device Tree
Driver sử dụng Device Tree để mô tả phần cứng, bao gồm các kết nối I2C, GPIO, clock và các thông số cấu hình khác của cảm biến. Điều này giúp driver trở nên linh hoạt và có thể chạy trên nhiều cấu hình phần cứng khác nhau mà không cần sửa đổi mã nguồn.
3. Cấu hình thanh ghi
Phần này sẽ đi sâu vào các thanh ghi cụ thể của IMX297/296, giải thích chức năng của từng thanh ghi và cách chúng được cấu hình để điều khiển các chế độ hoạt động của cảm biến, như độ phân giải, tốc độ khung hình, phơi sáng, gain, v.v. Việc phân tích này thường dựa trên datasheet của nhà sản xuất.