目录
前言:
调试准备工作:
修改内核默认打印等级
一、imx415驱动开发
1、硬件接线
2、设备树修改
2.1 创建 tegra234-p3767-camera-p3768-imx415-C-4lane.dtsi 文件
2.2 tegra234-p3767-camera-p3768-imx415-C-4lane.dtsi 添加到设备树
2.3 编译设备树
3、imx415驱动开发
3.1 imx415寄存器
1)mclk 时钟
2)lane数量
3)lane速率
4)分辨率
5)像素深度
6)Master/Slave模式
7)启流、停流相关
8)增益
编辑
9)曝光
编辑
10)All pixel模式 4lane 配置表
3.2 imx415驱动
1)Linux_for_Tegra/source/nvidia-oot/drivers/media/i2c/imx415_mode_tbls.h 源码
2)Linux_for_Tegra/source/nvidia-oot/include/media/imx415.h 源码
3)Linux_for_Tegra/source/nvidia-oot/drivers/media/i2c/nv_imx415.c 驱动文件
4)将 nv_imx415 添加到Makefile
二、编译调试
1、编译imx415驱动
2、安装 v4l-utils 并查看 /dev/video0信息
2.1 安装 v4l-utils
2.2 查看 /dev/video0 信息
3、抓拍
3.1 v4l2-ctl 命令验证vi抓拍
3.2 gstreamer英伟达命令抓拍
1)gst-launch-1.0 自动曝光、自动增益抓拍
2)gst-launch-1.0 设置曝光、增益抓拍
三、imx415驱动开发遇到的问题及解决方法
1、Jetson orin nano开发板的CAM0不支持4lane模式
2、使用 CSI0/1 时,需要将lane_polarity改为 6
3、v4l2-ctl 抓图命令报错
4、v4l2-ctl 抓图不成功,vi能收到数据,但数据不对
5、gstreamer抓图偏红色
四、曝光、增益、格式、焦距对拍照效果的影响
前言:
nvidia相机开发参考链接:相机软件开发解决方案 — NVIDIA Jetson Linux 开发者指南
可加载内核模块 (LKM)其实就是就是编译成ko模块。nvidia将所有模块都放在 nvidia-oot 目录下。参考链接:传感器软件驱动程序编程 — NVIDIA Jetson Linux 开发者指南
说明:博主使用野火的imx415摄像头模块,在 Jetson Orin Nano开发板上开发imx415驱动
调试准备工作:
修改内核默认打印等级
$ vi /etc/sysctl.conf
#
# /etc/sysctl.conf - Configuration file for setting system variables
# See /etc/sysctl.d/ for additional system variables.
# See sysctl.conf (5) for information.
#
#kernel.domainname = example.com
# Uncomment the following to stop low-level messages on console
kernel.printk = 8 8 8 8 #打印等级
###################################################################
# Functions previously found in netbase
#
# Uncomment the next two lines to enable Spoof protection (reverse-path filter)
# Turn on Source Address Verification in all interfaces to
# prevent some spoofing attacks
#net.ipv4.conf.default.rp_filter=1
#net.ipv4.conf.all.rp_filter=1
# Uncomment the next line to enable TCP/IP SYN cookies
# See http://lwn.net/Articles/277146/
一、imx415驱动开发
1、硬件接线
imx415模块和 Jetson orin nano开发板的csi接口中间有转接板。2 lane模式下,仅 CSI_D0 P/N 和 CSI_D1 P/N 有数据。我使用的是 4 lane 模式。
硬件接上后,用 i2cdetect 工具探测 I2C通不通。cam_i2cmux挂在i2c3下,因此命令如下:
$ i2cdetect -r -y 2
可以看到 imx415 的设备地址为 0x1a
问题:如何知道 CAM1_I2C 挂在 i2c3下?
查看 Linux_for_Tegra/source/hardware/nvidia/t23x/nv-public/tegra234.dtsi
cam_i2c 为I2C3节点, 因此cam_i2cmux在I2C3节点下
2、设备树修改
设备树增加sensor参考文档:Sensor Software Driver Programming — NVIDIA Jetson Linux Developer Guide
2.1 创建 tegra234-p3767-camera-p3768-imx415-C-4lane.dtsi 文件
1)将 Linux_for_Tegra/source/hardware/nvidia/t23x/nv-public/overlay 目录下的 tegra234-p3767-camera-p3768-imx477-C.dts 作为模板拷贝一份 tegra234-p3767-camera-p3768-imx415-C-4lane.dtsi
imx415 模块 4 lane差分线接在CSI2上,CSI2对应”serial_c”(CSI0对应serial_a,依此类推),因此命名 “tegra234-p3767-camera-p3768-imx415-C-4lane.dtsi”
2)修改 tegra234-p3767-camera-p3768-imx415-C-4lane.dtsi
关键参数计算过程:
compatible = “ridgerun,imx415” 要和imx415驱动对应上
mclk_khz:imx415模块外接 37.125M晶振,因此 mclk_khz = “37125”
4 lane模式:因此 num_lanes = “4”, bus-width = <4>;
CSI2:因此 tegra_sinterface = “serial_c”,port-index = <2>
分辨率:根据 imx415分辨率设置 “active_w = 3864″,active_h = “2192”
pixel_phase:像素格式,pixel_phase = “gbrg”,调试时设置为 “rggb” 导致图像偏红色
csi_pixel_bit_depth:像素深度,imx415使用RAW12模式,因此 csi_pixel_bit_depth = “12”
pix_clk_hz:imx415 配置 lane频率为 891 Mbps,4lane,像素深度为12bit,pix_clk_hz = 891 Mbps × 4 / 12 = 297000000,我理解只要不小于此值即可。
mclk_multiplier :mclk_multiplier ≥ pix_clk_hz / mclk = 297000000 / 37125000 = 8,因此mclk_multiplier = “8”。从nvidia官方手册可知,mclk_multiplier 必须大于等于pix_clk_hz / mclk,以确保ISP运行得足够快,能够处理来自传感器的数据。

增益,查看imx415手册
GAIN_PCG_0计算公式:GAIN_PCG_0 = Gain[dB] x 10 /3

GAIN_PCG_0 范围为 0 – 240d,因此 Gain范围为 0 – 72 [dB],我这里增益因子配置为 gain_factor = “10” ,Gain范围 0 – 72 [dB] 乘上增益因子,得到 min_gain_val = “0”, max_gain_val = “720”,step为 0.3dB 乘增益因子,因此 step_gain_val = “3”
曝光:
曝光参数单位为us,需要根据帧率(30fps)、VMAX(2250)、 SHR0 值范围(8 到 Number oflines per frame – 4),按照下面公式倒推 exposure 最小值、最大值、step,我算得结果图下:
min_exp_time = "15"; /* 单位:us */
max_exp_time = "33214"; /* 单位:us */
step_exp_time = "15"; /* 单位:us */


embedded_metadata_height:根据imx415手册来配置为 “1”,如下图
最终 tegra234-p3767-camera-p3768-imx415-C-4lane.dtsi 文件内容如下:
设备树描述了 VI(视频输入)、NvCSI 、传感器模块 的端口绑定关系
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
///dts-v1/;
///plugin/;
#define CAM0_RST TEGRA234_MAIN_GPIO(Q, 6) /* add */
#define CAM0_PWDN TEGRA234_MAIN_GPIO(H, 6)
#define CAM1_PWDN TEGRA234_MAIN_GPIO(AC, 0)
#define CAM_I2C_MUX TEGRA234_AON_GPIO(CC, 3)
#include <dt-bindings/tegra234-p3767-0000-common.h>
/ {
overlay-name = "Camera IMX415-C 4 lane";
jetson-header-name = "Jetson 24pin CSI Connector";
compatible = JETSON_COMPATIBLE_P3768;
/*IMX415 connected on cam0 port */
fragment@0 {
target-path = "/";
__overlay__ {
tegra-capture-vi {
num-channels = <1>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
rbpcv3_imx415_vi_in1: endpoint {
port-index = <2>;
bus-width = <4>;
remote-endpoint = <&rbpcv3_imx415_csi_out1>;
};
};
};
};
tegra-camera-platform {
compatible = "nvidia, tegra-camera-platform";
/**
* Physical settings to calculate max ISO BW
*
* num_csi_lanes = <>;
* Total number of CSI lanes when all cameras are active
*
* max_lane_speed = <>;
* Max lane speed in Kbit/s
*
* min_bits_per_pixel = <>;
* Min bits per pixel
*
* vi_peak_byte_per_pixel = <>;
* Max byte per pixel for the VI ISO case
*
* vi_bw_margin_pct = <>;
* Vi bandwidth margin in percentage
*
* max_pixel_rate = <>;
* Max pixel rate in Kpixel/s for the ISP ISO case
*
* isp_peak_byte_per_pixel = <>;
* Max byte per pixel for the ISP ISO case
*
* isp_bw_margin_pct = <>;
* Isp bandwidth margin in percentage
*/
num_csi_lanes = <4>;
max_lane_speed = <1500000>;
min_bits_per_pixel = <10>;
vi_peak_byte_per_pixel = <2>;
vi_bw_margin_pct = <25>;
max_pixel_rate = <7500000>;
isp_peak_byte_per_pixel = <5>;
isp_bw_margin_pct = <25>;
/**
* The general guideline for naming badge_info contains 3 parts, and is as follows,
* The first part is the camera_board_id for the module; if the module is in a FFD
* platform, then use the platform name for this part.
* The second part contains the position of the module, ex. "rear" or "front".
* The third part contains the last 6 characters of a part number which is found
* in the module's specsheet from the vendor.
*/
modules {
module1 {
badge = "jakku_rear_RBPCV3";
position = "rear";
orientation = "1";
drivernode0 {
pcl_id = "v4l2_sensor";
sysfs-device-tree = "/sys/firmware/devicetree/base/bus@0/cam_i2cmux/i2c@1/rbpcv3_imx415_c@1a";
};
};
};
};
bus@0 {
host1x@13e00000 {
nvcsi@15a00000 {
num-channels = <1>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
rbpcv3_imx415_csi_in1: endpoint@0 {
port-index = <2>;
bus-width = <4>;
remote-endpoint = <&rbpcv3_imx415_out1>;
};
};
port@1 {
reg = <1>;
rbpcv3_imx415_csi_out1: endpoint@1 {
remote-endpoint = <&rbpcv3_imx415_vi_in1>;
};
};
};
};
};
};
cam_i2cmux {
status = "okay";
compatible = "i2c-mux-gpio";
#address-cells = <1>;
#size-cells = <0>;
mux-gpios = <&gpio_aon CAM_I2C_MUX GPIO_ACTIVE_HIGH>;
i2c-parent = <&cam_i2c>;
i2c@0 {
rbpcv2_imx219_a@10 {
status = "disabled";
};
};
i2c@1 {
status = "okay";
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
rbpcv2_imx219_c@10 {
status = "disabled";
};
rbpcv3_imx415_c@1a {
reset-gpios = <&gpio CAM1_PWDN GPIO_ACTIVE_HIGH>;
compatible = "ridgerun,imx415";
/* I2C device address */
reg = <0x1a>;
/* V4L2 device node location */
devnode = "video0";
/* Physical dimensions of sensor */
physical_w = "9.3";
physical_h = "4.65";
sensor_model = "imx415";
use_sensor_mode_id = "true";
mode0 { /* IMX415_MODE_3864x2192 */
mclk_khz = "37125"; //"24000";
num_lanes = "4";
tegra_sinterface = "serial_c";
phy_mode = "DPHY";
discontinuous_clk = "no";
dpcm_enable = "false";
cil_settletime = "0"; // 0表示自动校准
lane_polarity = "0";
active_w = "3864";
active_h = "2192";
mode_type = "bayer";
pixel_phase = "gbrg"; //"rggb";
csi_pixel_bit_depth = "12"; //12
readout_orientation = "0"; //90
line_length = "4400"; //0x08CA "11200";
inherent_gain = "1";
mclk_multiplier = "8"; //pix_clk_hz / mclk_khz = 297000000 / 37125000 = 8
pix_clk_hz = "297000000"; //891 Mbps × 4 / 12
gain_factor = "10";
framerate_factor = "1000000";
exposure_factor = "1000000";
min_gain_val = "0"; /* 0dB */
max_gain_val = "720"; /* 72dB */
step_gain_val = "3"; /* 0.3dB step */
default_gain = "10"; /* 1dB */
min_hdr_ratio = "1";
max_hdr_ratio = "1";
min_framerate = "2000000"; /* 2.0 fps */
max_framerate = "60000000"; //"30000000"; /* 30.0 fps */
step_framerate = "1";
default_framerate = "30000000"; /* 30.0 fps */
min_exp_time = "15"; /* us, 1H时间 = line_length / pix_clk_hz */
max_exp_time = "33214"; //"33334"; /* us */
step_exp_time = "15";
default_exp_time = "5000"; /* us */
embedded_metadata_height = "1";
set_mode_delay_ms = "500"; //dongao 等待8帧
};
mode1 { /* IMX415_MODE_3864x2192 */
mclk_khz = "37125"; //"24000";
num_lanes = "4";
tegra_sinterface = "serial_c";
phy_mode = "DPHY";
discontinuous_clk = "no";
dpcm_enable = "false";
cil_settletime = "0"; // 0表示自动校准
lane_polarity = "0";
active_w = "3864";
active_h = "2192";
mode_type = "bayer";
pixel_phase = "gbrg"; //"rggb";
csi_pixel_bit_depth = "12"; //10
readout_orientation = "0"; //90
line_length = "4400"; //0x08CA "11200";
inherent_gain = "1";
mclk_multiplier = "8";
pix_clk_hz = "297000000"; //"356400000";
gain_factor = "10";
framerate_factor = "1000000";
exposure_factor = "1000000";
min_gain_val = "0"; /* 0dB */
max_gain_val = "720"; /* 72dB */
step_gain_val = "3"; /* 0.3dB step */
default_gain = "10"; /* 1dB */
min_hdr_ratio = "1";
max_hdr_ratio = "1";
min_framerate = "2000000"; /* 2.0 fps */
max_framerate = "60000000"; /* 60.0 fps */
step_framerate = "1";
default_framerate = "30000000"; /* 60.0 fps */
min_exp_time = "15"; /* us */
max_exp_time = "33214"; /* us */
step_exp_time = "15";
default_exp_time = "5000"; /* us */
embedded_metadata_height = "1";
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
rbpcv3_imx415_out1: endpoint {
port-index = <2>;
bus-width = <4>;
remote-endpoint = <&rbpcv3_imx415_csi_in1>;
};
};
};
};
};
};
gpio@2200000 { //add
camera-control-output-low {
gpio-hog;
output-low;
gpios = <CAM0_RST 0>;
label = "cam0-rst";
};
};
gpio@6000d000 {
camera-control-output-low {
gpio-hog;
output-low;
gpios = <CAM1_PWDN 0 CAM0_PWDN 0>;
label = "cam1-pwdn", "cam0-pwdn";
};
};
};
};
};
};
2.2 tegra234-p3767-camera-p3768-imx415-C-4lane.dtsi 添加到设备树
在 tegra234-p3768-0000+p3767-0000-dynamic.dts 中新增 “#include “tegra234-p3767-camera-p3768-imx415-C-4lane.dtsi””,如下:
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/dts-v1/;
/plugin/;
/ {
overlay-name = "Tegra234 p3768-0000+p3767-xxxx Dynamic Overlay";
};
/*
* Include this file last in the device tree. It manages run-time
* pruning of peripherals that are not available across the various
* SKUs of p3767. For example PVA can be enabled in the device tree
* and it will automatically be disabled for SKUs without PVA support.
*/
#include "tegra234-p3767-sku-handling.dtsi"
#include "tegra234-p3767-camera-p3768-imx415-C-4lane.dtsi" //设备树新增imx415内容
问题:为什么在 tegra234-p3768-0000+p3767-0000-dynamic.dts 中添加?
我们刷机命令的配置文件为 jetson-orin-nano-devkit-nvme.conf
$ sudo ./flash.sh jetson-orin-nano-devkit-nvme internal
看下 jetson-orin-nano-devkit-nvme.conf 文件相关内容,设置了 OVERLAY_DTB_FILE 的缺省值
2.3 编译设备树
1)编译
Linux_for_Tegra/source 目录下执行:
设置交叉编译工具 CROSS_COMPILE 环境变量
$ export CROSS_COMPILE=$HOME/l4t-gcc/aarch64–glibc–stable-2022.08-1/bin/aarch64-buildroot-linux-gnu-
设置环境变量
$ export KERNEL_HEADERS=$PWD/kernel/kernel-jammy-src
编译dtbs
$ make dtbs
编译报错:
解决方法:
编译成功打印结果:
2)编译完成后,fdtdump命令查看是否生效
$ fdtdump kernel-devicetree/generic-dts/dtbs/tegra234-p3768-0000+p3767-0000-dynamic.dtbo
3)拷贝编译结果
$ cp kernel-devicetree/generic-dts/dtbs/* /Linux_for_Tegra/kernel/dtb/
4)刷机
$ sudo ./flash.sh jetson-orin-nano-devkit-nvme internal
设备树查看路径:
/sys/firmware/devicetree/base/bus@0/cam_i2cmux/i2c@1/rbpcv3_imx415_c@1a/mode0
3、imx415驱动开发
3.1 imx415寄存器
重点已关注下列几个相关寄存器,其他寄存器看imx415手册
mclk时钟
lane数量
lane速率
分辨率
像素深度
Master/Slave模式
启流、停流
增益
曝光
1)mclk 时钟
野火imx415相机模块接了37.125M的晶振,以 891Mbps/lane 为例:

将INCK相关寄存器设置成对应值
2)lane数量
默认值是 3h:表示 CSI-2 4lane
3)lane速率
我用的 891 Mbps / lane,因此需将 3033h 寄存器配置成 0x05
4)分辨率
imx415寄存器只有设置 VMAX(垂直方向时钟数,包括blanking等区域)、HMAX(水平方向时钟数,包括blanking等区域)。我理解imx415缺省输出 3864×2192 分辨率,如下图:
寄存器如下:
VMAX表示每帧的行数
HMAX表示每行的时钟数,单位:像素时钟周期(pixel clocks)
帧率 = 像素时钟频率 / (VMAX * HMAX)
5)像素深度
我配置的像素深度为12,因此 3032h 寄存器设置成 1h
6)Master/Slave模式
默认是 0 : Master模式
7)启流、停流相关
8)增益
GAIN_PCG_0计算公式:GAIN_PCG_0 = Gain[dB] x 10 /3
GAIN_PCG_0 范围为 0 – 240d,因此 Gain范围为 0 – 72 [dB]
9)曝光
imx415的曝光与SHR0寄存器相关。具体计算方式查看手册,也可以查看imx415驱动设置曝光函数
曝光时间计算公式:
10)All pixel模式 4lane 配置表
imx415手册提供了寄存器配置表,我们只需根据需求配置即可,我这里用的 4lane 30fps 891Mbps/lane
3.2 imx415驱动
驱动源码下载链接:https://download.csdn.net/download/hinewcc/90933767
思路:
Jetson orin nano平台内核没有 imx415 驱动,我用 imx477 驱动作为模板去修改(imx477 和 imx415 寄存器区别很大)
瑞芯微 rv1126 或 rv3588 自带 imx415 驱动,下载一份作为参考,kernel链接:GitHub – LubanCat/kernel: LubanCat-RK BSP kernel source
阅读驱动代码发现,由于nvidia平台v4l2驱动封装了一层,因此 rv3588 自带 imx415 驱动无法直接使用。驱动修改主要参考rv3588 自带 imx415 驱动的寄存器部分。
需要修改的文件
Linux_for_Tegra/source/nvidia-oot/include/media/imx415.h
Linux_for_Tegra/source/nvidia-oot/drivers/media/i2c/nv_imx415.c
Linux_for_Tegra/source/nvidia-oot/drivers/media/i2c/imx415_mode_tbls.h
imx415 Master 模式流程:
1)Linux_for_Tegra/source/nvidia-oot/drivers/media/i2c/imx415_mode_tbls.h 源码
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
*/
#ifndef __IMX415_I2C_TABLES__
#define __IMX415_I2C_TABLES__
#include <media/camera_common.h>
#define IMX415_TABLE_WAIT_MS 0
#define IMX415_TABLE_END 1
#define IMX415_WAIT_MS 24
#define IMX415_STANDBY_REG 0x3000
#define IMX415_XMSTA_REG 0x3002
#define imx415_reg struct reg_8
static const imx415_reg imx415_start[] = {
{IMX415_STANDBY_REG, 0x0},
{IMX415_TABLE_WAIT_MS, IMX415_WAIT_MS*3},
{IMX415_TABLE_END, 0x00}
};
static const imx415_reg imx415_stop[] = {
{IMX415_STANDBY_REG, 0x1},
{IMX415_TABLE_END, 0x00}
};
static const imx415_reg imx415_global_10bit_3864x2192_regs[] = {
// {0x3002, 0x00},
{0x3008, 0x7F},
{0x300A, 0x5B},
{0x3031, 0x00},
{0x3032, 0x01},
{0x30C1, 0x00},
{0x30D9, 0x06},
{0x3116, 0x24},
{0x311E, 0x24},
{0x32D4, 0x21},
{0x32EC, 0xA1},
{0x3452, 0x7F},
{0x3453, 0x03},
{0x358A, 0x04},
{0x35A1, 0x02},
{0x36BC, 0x0C},
{0x36CC, 0x53},
{0x36CD, 0x00},
{0x36CE, 0x3C},
{0x36D0, 0x8C},
{0x36D1, 0x00},
{0x36D2, 0x71},
{0x36D4, 0x3C},
{0x36D6, 0x53},
{0x36D7, 0x00},
{0x36D8, 0x71},
{0x36DA, 0x8C},
{0x36DB, 0x00},
{0x3701, 0x00},
{0x3724, 0x02},
{0x3726, 0x02},
{0x3732, 0x02},
{0x3734, 0x03},
{0x3736, 0x03},
{0x3742, 0x03},
{0x3862, 0xE0},
{0x38CC, 0x30},
{0x38CD, 0x2F},
{0x395C, 0x0C},
{0x3A42, 0xD1},
{0x3A4C, 0x77},
{0x3AE0, 0x02},
{0x3AEC, 0x0C},
{0x3B00, 0x2E},
{0x3B06, 0x29},
{0x3B98, 0x25},
{0x3B99, 0x21},
{0x3B9B, 0x13},
{0x3B9C, 0x13},
{0x3B9D, 0x13},
{0x3B9E, 0x13},
{0x3BA1, 0x00},
{0x3BA2, 0x06},
{0x3BA3, 0x0B},
{0x3BA4, 0x10},
{0x3BA5, 0x14},
{0x3BA6, 0x18},
{0x3BA7, 0x1A},
{0x3BA8, 0x1A},
{0x3BA9, 0x1A},
{0x3BAC, 0xED},
{0x3BAD, 0x01},
{0x3BAE, 0xF6},
{0x3BAF, 0x02},
{0x3BB0, 0xA2},
{0x3BB1, 0x03},
{0x3BB2, 0xE0},
{0x3BB3, 0x03},
{0x3BB4, 0xE0},
{0x3BB5, 0x03},
{0x3BB6, 0xE0},
{0x3BB7, 0x03},
{0x3BB8, 0xE0},
{0x3BBA, 0xE0},
{0x3BBC, 0xDA},
{0x3BBE, 0x88},
{0x3BC0, 0x44},
{0x3BC2, 0x7B},
{0x3BC4, 0xA2},
{0x3BC8, 0xBD},
{0x3BCA, 0xBD},
{0x4004, 0x48},
{0x4005, 0x09},
{IMX415_TABLE_WAIT_MS, IMX415_WAIT_MS},
{IMX415_TABLE_END, 0x0000}
};
static const imx415_reg imx415_linear_12bit_3864x2192_891M_regs[] = {
{0x3020, 0x00},
{0x3021, 0x00},
{0x3022, 0x00},
{0x3024, 0xCA},
{0x3025, 0x08},
{0x3028, 0x4C}, //每行指定的时钟数(水平视场范围) 0x0044C - 1100 (* 4lane) *2
{0x3029, 0x04},
{0x302C, 0x00},
{0x302D, 0x00},
{0x3033, 0x05},
{0x3050, 0x08},
{0x3051, 0x00},
{0x3054, 0x19},
{0x3058, 0x3E},
{0x3060, 0x25},
{0x3064, 0x4a},
{0x30CF, 0x00},
{0x3118, 0xC0},
{0x3260, 0x01},
{0x400C, 0x00},
{0x4018, 0x7F},
{0x401A, 0x37},
{0x401C, 0x37},
{0x401E, 0xF7},
{0x401F, 0x00},
{0x4020, 0x3F},
{0x4022, 0x6F},
{0x4024, 0x3F},
{0x4026, 0x5F},
{0x4028, 0x2F},
{0x4074, 0x01},
{IMX415_TABLE_WAIT_MS, IMX415_WAIT_MS},
{IMX415_TABLE_END, 0x0000}
};
enum {
IMX415_MODE_3864x2192_30FPS_2LANE,
// IMX415_MODE_1920x1080_60FPS,
IMX415_MODE_3864x2192_30FPS_4LANE,
// IMX415_MODE_1920x1080_60FPS_4LANE,
IMX415_MODE_COMMON,
IMX415_START_STREAM,
IMX415_STOP_STREAM,
};
static const imx415_reg *mode_table[] = {
[IMX415_MODE_3864x2192_30FPS_2LANE] = imx415_linear_12bit_3864x2192_891M_regs,
// [IMX415_MODE_1920x1080_60FPS] = imx415_linear_10bit_3864x2192_891M_regs,
[IMX415_MODE_3864x2192_30FPS_4LANE] = imx415_linear_12bit_3864x2192_891M_regs,
// [IMX415_MODE_1920x1080_60FPS_4LANE] = imx415_linear_10bit_3864x2192_891M_regs,
[IMX415_MODE_COMMON] = imx415_global_10bit_3864x2192_regs,
[IMX415_START_STREAM] = imx415_start,
[IMX415_STOP_STREAM] = imx415_stop,
};
static const int imx415_15_fr[] = {
15,
};
static const int imx415_30_fr[] = {
30,
};
#if 0
static const int imx415_60_fr[] = {
60,
};
#endif
static const struct camera_common_frmfmt imx415_frmfmt[] = {
{
{3864, 2192}, imx415_30_fr, 1, 0, IMX415_MODE_3864x2192_30FPS_2LANE},
// {
{1920, 1080}, imx415_60_fr, 1, 0, IMX415_MODE_1920x1080_60FPS},
};
#endif /* __IMX415_I2C_TABLES__ */
2)Linux_for_Tegra/source/nvidia-oot/include/media/imx415.h 源码
/* SPDX-License-Identifier: GPL-2.0 */
/*
* IMX415_.h - IMX415 sensor header
*
* Copyright (c) 2020, RidgeRun. All rights reserved.
*
* Contact us: support@ridgerun.com
*
*/
#ifndef __IMX415_H__
#define __IMX415_H__
/* IMX415 - sensor parameters */
#define IMX415_GAIN_PCG_0_MIN (0)
#define IMX415_GAIN_PCG_0_MAX (240)
#define IMX415_SHIFT_8_BITS (8)
#define IMX415_MASK_LSB_1_BITS 0x0001
#define IMX415_MASK_LSB_8_BITS 0x00ff
/* IMX415 sensor register address */
#define IMX415_MODEL_ID_ADDR_MSB 0x311B
#define IMX415_MODEL_ID_ADDR_LSB 0x311A
#define IMX415_ANALOG_GAIN_ADDR_MSB 0x3091
#define IMX415_ANALOG_GAIN_ADDR_LSB 0x3090
#define IMX415_GROUP_HOLD_ADDR 0x3001
#define IMX415_LF_EXPO_REG_H 0x3052
#define IMX415_LF_EXPO_REG_M 0x3051
#define IMX415_LF_EXPO_REG_L 0x3050
#define IMX415_VTS_REG_L 0x3024 //VMAX
#define IMX415_VTS_REG_M 0x3025
#define IMX415_VTS_REG_H 0x3026
#define IMX415_ADBIT_ADDR 0x3031
#define IMX415_ADBIT_10BIT 0x00
#define IMX415_ADBIT_12BIT 0x01
#endif /* __IMX415_H__ */
3)Linux_for_Tegra/source/nvidia-oot/drivers/media/i2c/nv_imx415.c 驱动文件
修改 compatible 与 设备树匹配
static const struct of_device_id imx415_of_match[] = {
{.compatible = "ridgerun,imx415",},
{},
};
static struct i2c_driver imx415_i2c_driver = {
.driver = {
.name = "imx415",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(imx415_of_match),
},
.probe = imx415_probe,
.remove = imx415_remove,
.id_table = imx415_id,
};
主要修改 ops 结构体中的函数,主要有:
imx415_set_mode – 设置模式(配置寄存器)
imx415_start_streaming – 启流
imx415_stop_streaming – 停流
imx415_set_gain – 设置增益
imx415_set_exposure – 设置曝光
nv_imx415.c 驱动源码:
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2021-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Copyright (c) 2020, RidgeRun. All rights reserved.
*
* Contact us: support@ridgerun.com
*
* nv_imx415.c - imx415 sensor driver
*/
#include <nvidia/conftest.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <media/tegra_v4l2_camera.h>
#include <media/tegracam_core.h>
#include <media/imx415.h>
#include "../platform/tegra/camera/camera_gpio.h"
#include "imx415_mode_tbls.h"
//#define IMX415_SENSOR_INTERNAL_CLK_FREQ 840000000
static const struct of_device_id imx415_of_match[] = {
{.compatible = "ridgerun,imx415",},
{},
};
MODULE_DEVICE_TABLE(of, imx415_of_match);
static const u32 ctrl_cid_list[] = {
TEGRA_CAMERA_CID_GAIN,
TEGRA_CAMERA_CID_EXPOSURE,
TEGRA_CAMERA_CID_FRAME_RATE, //imx415帧率跟很多寄存器相关
TEGRA_CAMERA_CID_SENSOR_MODE_ID,
};
enum imx415_Config {
TWO_LANE_CONFIG,
FOUR_LANE_CONFIG,
};
struct imx415 {
struct i2c_client *i2c_client;
struct v4l2_subdev *subdev;
u16 fine_integ_time;
u32 frame_length;
struct camera_common_data *s_data;
struct tegracam_device *tc_dev;
enum imx415_Config config;
};
static const struct regmap_config sensor_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
.use_single_read = true,
.use_single_write = true,
};
static inline void imx415_get_shr0_regs(imx415_reg *regs, u32 val)
{
regs->addr = IMX415_LF_EXPO_REG_H;
regs->val = (val >> 16) & 0x0f;
(regs + 1)->addr = IMX415_LF_EXPO_REG_M;
(regs + 1)->val = (val >> 8) & 0xff;
(regs + 2)->addr = IMX415_LF_EXPO_REG_L;
(regs + 2)->val = val & 0xff;
}
static inline void imx415_get_gain_reg(imx415_reg *reg, u16 gain)
{
reg->addr = IMX415_ANALOG_GAIN_ADDR_MSB;
reg->val = (gain >> IMX415_SHIFT_8_BITS) & IMX415_MASK_LSB_1_BITS;
(reg + 1)->addr = IMX415_ANALOG_GAIN_ADDR_LSB;
(reg + 1)->val = (gain) & IMX415_MASK_LSB_8_BITS;
}
static inline int imx415_read_reg(struct camera_common_data *s_data,
u16 addr, u8 *val)
{
int err = 0;
u32 reg_val = 0;
err = regmap_read(s_data->regmap, addr, ®_val);
*val = reg_val & 0xff;
return err;
}
static inline int imx415_write_reg(struct camera_common_data *s_data,
u16 addr, u8 val)
{
int err = 0;
err = regmap_write(s_data->regmap, addr, val);
if (err)
dev_err(s_data->dev, "%s: i2c write failed, 0x%x = %x",
__func__, addr, val);
return err;
}
static int imx415_write_table(struct imx415 *priv, const imx415_reg table[])
{
return regmap_util_write_table_8(priv->s_data->regmap, table, NULL, 0,
IMX415_TABLE_WAIT_MS,
IMX415_TABLE_END);
}
static int imx415_set_group_hold(struct tegracam_device *tc_dev, bool val)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
int err;
dev_dbg(dev, "%s: Setting group hold control to: %u
", __func__, val);
err = imx415_write_reg(s_data, IMX415_GROUP_HOLD_ADDR, val);
if (err) {
dev_err(dev, "%s: Group hold control error
", __func__);
return err;
}
return 0;
}
//val = gain[dB] * gain_factor
static int imx415_set_gain(struct tegracam_device *tc_dev, s64 val)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = s_data->dev;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
int err = 0, i = 0;
imx415_reg gain_reg[2];
// s16 gain;
s16 gain_pcg_0 = 0;
dev_info(dev, "%s: mode index: %d
", __func__, s_data->mode_prop_idx);
dev_info(dev, "%s: Setting gain control to: %lld
", __func__, val);
dev_info(dev, "%s: min_gain_val: %d
", __func__, mode->control_properties.min_gain_val);
dev_info(dev, "%s: max_gain_val: %d
", __func__, mode->control_properties.max_gain_val);
dev_info(dev, "%s: gain_factor: %d
", __func__, mode->control_properties.gain_factor);
//增益
if (val < mode->control_properties.min_gain_val)
val = mode->control_properties.min_gain_val;
else if (val > mode->control_properties.max_gain_val)
val = mode->control_properties.max_gain_val;
if (val == 0)
return -EINVAL;
/* gain_pcg_0 = gain[dB] * 10 / 3 */
gain_pcg_0 = val * 10 / mode->control_properties.gain_factor / 3;
dev_info(dev, "%s: gain_pcg_0: %d
", __func__, gain_pcg_0);
if (gain_pcg_0 < IMX415_GAIN_PCG_0_MIN)
gain_pcg_0 = IMX415_GAIN_PCG_0_MIN;
else if (gain_pcg_0 > IMX415_GAIN_PCG_0_MAX)
gain_pcg_0 = IMX415_GAIN_PCG_0_MAX;
dev_info(dev, "%s: gain_pcg_0 result: %d
", __func__, gain_pcg_0);
imx415_get_gain_reg(gain_reg, (u16) gain_pcg_0);
for (i = 0; i < ARRAY_SIZE(gain_reg); i++) {
dev_info(dev, "%s: set gain: Addr: 0x%x Value: %d
", __func__, gain_reg[i].addr, gain_reg[i].val);
err = imx415_write_reg(s_data, gain_reg[i].addr,
gain_reg[i].val);
if (err) {
dev_err(dev, "%s: gain control error
", __func__);
break;
}
}
return err;
}
static int imx415_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
{
return 0;
}
//val: 曝光时间,单位:us
static int imx415_set_exposure(struct tegracam_device *tc_dev, s64 val)
{
struct camera_common_data *s_data = tc_dev->s_data;
// struct imx415 *priv = (struct imx415 *)tc_dev->priv;
struct device *dev = tc_dev->dev;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
int err = 0;
imx415_reg shr0_regs[3] = {0};
u8 vmax_array[3] = {0};
int vmax_value = 0;
int shr0 = 0;
u8 reg_adbit = 0;
int Toffset = 0;
int Toffset_LineNum = 0, Val_LineNum = 0;
int line_length = 0;
int i;
dev_info(dev, "%s: mode index: %d
", __func__, s_data->mode_prop_idx);
dev_info(dev, "%s: pixel_clock: %lld
", __func__, mode->signal_properties.pixel_clock.val);
dev_info(dev, "%s: exposure_factor: %d
", __func__, mode->control_properties.exposure_factor);
dev_info(dev, "%s: line_length: %d
", __func__, mode->image_properties.line_length);
if (mode->signal_properties.pixel_clock.val == 0 ||
mode->control_properties.exposure_factor == 0 ||
mode->image_properties.line_length == 0)
return -EINVAL;
err = imx415_read_reg(s_data, IMX415_VTS_REG_L, &vmax_array[0]);
if (err) {
dev_info(dev, "%s: imx415_read_reg IMX415_VTS_REG_L failed
", __func__);
return err;
}
err = imx415_read_reg(s_data, IMX415_VTS_REG_M, &vmax_array[1]);
if (err) {
dev_info(dev, "%s: imx415_read_reg IMX415_VTS_REG_M failed
", __func__);
return err;
}
err = imx415_read_reg(s_data, IMX415_VTS_REG_H, &vmax_array[2]);
if (err) {
dev_info(dev, "%s: imx415_read_reg IMX415_VTS_REG_M failed
", __func__);
return err;
}
vmax_value = ((vmax_array[2] << 16) & 0x0f0000) + ((vmax_array[1] << 8) & 0xff00) + vmax_array[0];
dev_info(dev, "%s: vmax_value: %d, val: %lld
", __func__, vmax_value, val);
/*
Integration time(曝光时间) = 1 frame period - SHR0 x (1H period) + Toffset
AD 10bit: Toffset = 1.79 us
AD 12bit: Toffset = 2.68us
*/
/*
val / mode->control_properties.exposure_factor = 曝光时间(us)
曝光时间 * mode->signal_properties.pixel_clock.val = 像素数量
像素数量 / mode->image_properties.line_length = 行数,即:shr0
*/
err = imx415_read_reg(s_data, IMX415_ADBIT_ADDR, ®_adbit);
if (err) {
dev_info(dev, "%s: imx415_read_reg IMX415_ADBIT_ADDR failed
", __func__);
return err;
}
if (reg_adbit == IMX415_ADBIT_10BIT) {
Toffset = 1790; //单位:ns
} else {
Toffset = 2680; //单位:ns
}
/*
Integration time(曝光时间) = 1 frame period - SHR0 x (1H period) + Toffset
SHR0 = height + Toffset_LineNum - Val_LineNum;
Toffset_LineNum(Toffset的行数) = Toffset * mode->signal_properties.pixel_clock.val / 1000 / line_length / mode->control_properties.exposure_factor;
Val_LineNum(val的行数) = val * mode->signal_properties.pixel_clock.val / line_length / mode->control_properties.exposure_factor;
*/
line_length = mode->image_properties.line_length;
Toffset_LineNum = Toffset * mode->signal_properties.pixel_clock.val / 1000 / line_length / mode->control_properties.exposure_factor;
Val_LineNum = val * mode->signal_properties.pixel_clock.val / line_length / mode->control_properties.exposure_factor;
dev_info(dev, "%s: line_length: %d, vmax_value : %d
", __func__, line_length, vmax_value);
dev_info(dev, "%s: Toffset_LineNum: %d, Val_LineNum : %d
", __func__, Toffset_LineNum, Val_LineNum);
shr0 = vmax_value + Toffset_LineNum - Val_LineNum;
/* shr0值:8 - (VMAX - 4)之间 */
if (shr0 < 8) {
shr0 = 8;
} else if (shr0 >= vmax_value - 4) {
shr0 = vmax_value - 4;
}
//shr0 = vmax_value - 500;
dev_info(dev, "%s: shr0_val: %d
", __func__, shr0);
imx415_get_shr0_regs(shr0_regs, shr0);
for (i = 0; i < ARRAY_SIZE(shr0_regs); i++) {
dev_info(dev, "%s: set shr0 Addr: 0x%x Value: %d
", __func__, shr0_regs[i].addr, shr0_regs[i].val);
err = imx415_write_reg(s_data, shr0_regs[i].addr, shr0_regs[i].val);
if (err) {
dev_dbg(dev,
"%s: shr0 control error
", __func__);
return err;
}
}
return err;
}
//用于更新传感器参数
static struct tegracam_ctrl_ops imx415_ctrl_ops = {
.numctrls = ARRAY_SIZE(ctrl_cid_list),
.ctrl_cid_list = ctrl_cid_list,
.set_gain = imx415_set_gain,
.set_exposure = imx415_set_exposure,
.set_frame_rate = imx415_set_frame_rate, //返回0
.set_group_hold = imx415_set_group_hold,
};
static int imx415_power_on(struct camera_common_data *s_data)
{
int err = 0;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
dev_info(dev, "%s: power on
", __func__);
if (pdata && pdata->power_on) {
err = pdata->power_on(pw);
if (err)
dev_err(dev, "%s failed.
", __func__);
else
pw->state = SWITCH_ON;
return err;
}
#if 0 //dongao
if (pw->reset_gpio) {
if (gpiod_cansleep(gpio_to_desc(pw->reset_gpio)))
gpio_set_value_cansleep(pw->reset_gpio, 0);
else
gpio_set_value(pw->reset_gpio, 0);
}
#else
if (pw->reset_gpio) {
dev_info(dev, "dongao: reset_gpio hi
");
gpiod_direction_output(gpio_to_desc(pw->reset_gpio), 0); //复位无效
}
#endif
if (unlikely(!(pw->avdd || pw->iovdd || pw->dvdd)))
goto skip_power_seqn;
usleep_range(10, 20);
if (pw->avdd) {
err = regulator_enable(pw->avdd);
if (err)
goto imx415_avdd_fail;
}
if (pw->iovdd) {
err = regulator_enable(pw->iovdd);
if (err)
goto imx415_iovdd_fail;
}
if (pw->dvdd) {
err = regulator_enable(pw->dvdd);
if (err)
goto imx415_dvdd_fail;
}
usleep_range(10, 20);
skip_power_seqn:
#if 0 //dongao
if (pw->reset_gpio) {
if (gpiod_cansleep(gpio_to_desc(pw->reset_gpio)))
gpio_set_value_cansleep(pw->reset_gpio, 1);
else
gpio_set_value(pw->reset_gpio, 1);
}
#endif
/* Need to wait for t4 + t5 + t9 + t10 time as per the data sheet */
/* t4 - 200us, t5 - 21.2ms, t9 - 1.2ms t10 - 270 ms */
usleep_range(300000, 300100);
pw->state = SWITCH_ON;
return 0;
imx415_dvdd_fail:
regulator_disable(pw->iovdd);
imx415_iovdd_fail:
regulator_disable(pw->avdd);
imx415_avdd_fail:
dev_err(dev, "%s failed.
", __func__);
return -ENODEV;
}
static int imx415_power_off(struct camera_common_data *s_data)
{
int err = 0;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
dev_info(dev, "%s: power off
", __func__);
if (pdata && pdata->power_off) {
err = pdata->power_off(pw);
if (err) {
dev_err(dev, "%s failed.
", __func__);
return err;
}
} else {
#if 0 //dongao
if (pw->reset_gpio) {
if (gpiod_cansleep(gpio_to_desc(pw->reset_gpio)))
gpio_set_value_cansleep(pw->reset_gpio, 0);
else
gpio_set_value(pw->reset_gpio, 0);
}
#else
if (pw->reset_gpio) {
dev_info(dev, "dongao: reset_gpio low
");
gpiod_direction_output(gpio_to_desc(pw->reset_gpio), 1); //复位有效
}
#endif
usleep_range(10, 10);
if (pw->dvdd)
regulator_disable(pw->dvdd);
if (pw->iovdd)
regulator_disable(pw->iovdd);
if (pw->avdd)
regulator_disable(pw->avdd);
}
pw->state = SWITCH_OFF;
return 0;
}
static int imx415_power_put(struct tegracam_device *tc_dev)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct camera_common_power_rail *pw = s_data->power;
if (unlikely(!pw))
return -EFAULT;
if (likely(pw->dvdd))
devm_regulator_put(pw->dvdd);
if (likely(pw->avdd))
devm_regulator_put(pw->avdd);
if (likely(pw->iovdd))
devm_regulator_put(pw->iovdd);
pw->dvdd = NULL;
pw->avdd = NULL;
pw->iovdd = NULL;
if (likely(pw->reset_gpio))
gpio_free(pw->reset_gpio);
return 0;
}
static int imx415_power_get(struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
struct camera_common_data *s_data = tc_dev->s_data;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct clk *parent;
int err = 0;
if (!pdata) {
dev_err(dev, "pdata missing
");
return -EFAULT;
}
dev_info(tc_dev->dev, "dongao:%s, mclk_name:%s
", __func__, pdata->mclk_name);
/* Sensor MCLK (aka. INCK) */
if (pdata->mclk_name) {
pw->mclk = devm_clk_get(dev, pdata->mclk_name);
if (IS_ERR(pw->mclk)) {
dev_err(dev, "unable to get clock %s
",
pdata->mclk_name);
return PTR_ERR(pw->mclk);
}
if (pdata->parentclk_name) {
parent = devm_clk_get(dev, pdata->parentclk_name);
if (IS_ERR(parent)) {
dev_err(dev, "unable to get parent clock %s",
pdata->parentclk_name);
} else
clk_set_parent(pw->mclk, parent);
}
}
/* analog 2.8v */
if (pdata->regulators.avdd)
err |= camera_common_regulator_get(dev,
&pw->avdd,
pdata->regulators.avdd);
/* IO 1.8v */
if (pdata->regulators.iovdd)
err |= camera_common_regulator_get(dev,
&pw->iovdd,
pdata->regulators.iovdd);
/* dig 1.2v */
if (pdata->regulators.dvdd)
err |= camera_common_regulator_get(dev,
&pw->dvdd,
pdata->regulators.dvdd);
if (err) {
dev_err(dev, "%s: unable to get regulator(s)
", __func__);
goto done;
}
/* Reset or ENABLE GPIO */
pw->reset_gpio = pdata->reset_gpio;
err = gpio_request(pw->reset_gpio, "cam_reset_gpio");
if (err < 0) {
dev_err(dev, "%s: unable to request reset_gpio (%d)
",
__func__, err);
goto done;
}
done:
pw->state = SWITCH_OFF;
return err;
}
static struct camera_common_pdata *imx415_parse_dt(struct tegracam_device
*tc_dev)
{
struct device *dev = tc_dev->dev;
struct device_node *np = dev->of_node;
struct camera_common_pdata *board_priv_pdata;
const struct of_device_id *match;
struct camera_common_pdata *ret = NULL;
int err = 0;
int gpio;
if (!np)
return NULL;
match = of_match_device(imx415_of_match, dev);
if (!match) {
dev_err(dev, "Failed to find matching dt id
");
return NULL;
}
board_priv_pdata = devm_kzalloc(dev,
sizeof(*board_priv_pdata), GFP_KERNEL);
if (!board_priv_pdata)
return NULL;
gpio = of_get_named_gpio(np, "reset-gpios", 0);
if (gpio < 0) {
if (gpio == -EPROBE_DEFER)
ret = ERR_PTR(-EPROBE_DEFER);
dev_err(dev, "reset-gpios not found
");
goto error;
}
board_priv_pdata->reset_gpio = (unsigned int)gpio;
err = of_property_read_string(np, "mclk", &board_priv_pdata->mclk_name);
if (err)
dev_dbg(dev,
"mclk name not present, assume sensor driven externally
");
err = of_property_read_string(np, "avdd-reg",
&board_priv_pdata->regulators.avdd);
err |= of_property_read_string(np, "iovdd-reg",
&board_priv_pdata->regulators.iovdd);
err |= of_property_read_string(np, "dvdd-reg",
&board_priv_pdata->regulators.dvdd);
if (err)
dev_dbg(dev,
"avdd, iovdd and/or dvdd reglrs. not present, assume sensor powered independently
");
board_priv_pdata->has_eeprom = of_property_read_bool(np, "has-eeprom");
return board_priv_pdata;
error:
devm_kfree(dev, board_priv_pdata);
return ret;
}
static int imx415_set_mode(struct tegracam_device *tc_dev)
{
struct imx415 *priv = (struct imx415 *)tegracam_get_privdata(tc_dev);
struct camera_common_data *s_data = tc_dev->s_data;
unsigned int mode_index = 0;
int err = 0;
const char *config;
struct device_node *mode;
uint offset = ARRAY_SIZE(imx415_frmfmt);
usleep_range(1000000, 1000100);
dev_dbg(tc_dev->dev, "%s:
", __func__);
mode = of_get_child_by_name(tc_dev->dev->of_node, "mode0");
err = of_property_read_string(mode, "num_lanes", &config);
if (config[0] == '4')
priv->config = FOUR_LANE_CONFIG;
else if (config[0] == '2')
priv->config = TWO_LANE_CONFIG;
else
dev_err(tc_dev->dev, "Unsupported config
");
dev_info(tc_dev->dev, "dongao: %s:
", __func__);
if (mode_table[IMX415_MODE_COMMON] != NULL) {
err = imx415_write_table(priv, mode_table[IMX415_MODE_COMMON]);
if (err)
return err;
}
#if 0 //dongao
err = imx415_write_table(priv, mode_table[IMX415_MODE_3864x2192_30FPS_4LANE]);
#else
mode_index = s_data->mode;
dev_info(tc_dev->dev, "%s, mode_index = %d, offset = %d
", __func__, mode_index, offset);
if (priv->config == FOUR_LANE_CONFIG)
err = imx415_write_table(priv, mode_table[mode_index + offset]);
else
err = imx415_write_table(priv, mode_table[mode_index]);
#endif
if (err)
return err;
return 0;
}
static int imx415_start_streaming(struct tegracam_device *tc_dev)
{
struct imx415 *priv = (struct imx415 *)tegracam_get_privdata(tc_dev);
struct camera_common_data *s_data = priv->s_data;
u8 regdata = 0;
u16 regaddr = 0;
int i = 0;
int err = -1;
/* dongao 读寄存器并打印 */
for (i = 0; i < ARRAY_SIZE(imx415_linear_12bit_3864x2192_891M_regs); i++) {
regaddr = imx415_linear_12bit_3864x2192_891M_regs[i].addr;
if (regaddr == IMX415_TABLE_WAIT_MS || regaddr == IMX415_TABLE_END) {
continue;
}
err = imx415_read_reg(s_data, regaddr, ®data);
if (err) {
dev_info(tc_dev->dev, "%s: read 0x%04x failed
", __func__, regaddr);
}else {
dev_info(tc_dev->dev, "%s dongao read: 0x%04x - 0x%x
", __func__, regaddr, regdata);
}
if (regdata != imx415_linear_12bit_3864x2192_891M_regs[i].val) {
dev_info(tc_dev->dev, "%s: !!!!!!! read 0x%x != 0x%x
", __func__, regdata, imx415_linear_12bit_3864x2192_891M_regs[i].val);
}
}
dev_dbg(tc_dev->dev, "%s:
", __func__);
err = imx415_write_table(priv, mode_table[IMX415_START_STREAM]);
usleep_range(24000, 30000);
err = imx415_write_reg(priv->s_data, IMX415_XMSTA_REG, 0); //XMSTA start
usleep_range(500000, 500100);
return 0;
}
static int imx415_stop_streaming(struct tegracam_device *tc_dev)
{
int err;
struct imx415 *priv = (struct imx415 *)tegracam_get_privdata(tc_dev);
dev_info(tc_dev->dev, "dongao:%s
", __func__);
dev_dbg(tc_dev->dev, "%s:
", __func__);
err = imx415_write_table(priv, mode_table[IMX415_STOP_STREAM]);
imx415_write_reg(priv->s_data, IMX415_XMSTA_REG, 1); //XMSTA stop
return err;
}
//sensor驱动程序使用的基本功能
static struct camera_common_sensor_ops imx415_common_ops = {
.numfrmfmts = ARRAY_SIZE(imx415_frmfmt),
.frmfmt_table = imx415_frmfmt,
.power_on = imx415_power_on,
.power_off = imx415_power_off,
.write_reg = imx415_write_reg,
.read_reg = imx415_read_reg,
.parse_dt = imx415_parse_dt,
.power_get = imx415_power_get,
.power_put = imx415_power_put,
.set_mode = imx415_set_mode,
.start_streaming = imx415_start_streaming,
.stop_streaming = imx415_stop_streaming,
};
static int imx415_board_setup(struct imx415 *priv)
{
struct camera_common_data *s_data = priv->s_data;
struct device *dev = s_data->dev;
u8 reg_val[2];
int err = 0;
/* Skip mclk enable as this camera has an internal oscillator */
err = imx415_power_on(s_data);
if (err) {
dev_err(dev, "error during power on sensor (%d)
", err);
goto done;
}
/* Probe sensor model id registers */
err = imx415_read_reg(s_data, IMX415_MODEL_ID_ADDR_MSB, ®_val[0]);
if (err) {
dev_err(dev, "%s: error during i2c read probe (%d)
",
__func__, err);
goto err_reg_probe;
}
err = imx415_read_reg(s_data, IMX415_MODEL_ID_ADDR_LSB, ®_val[1]);
if (err) {
dev_err(dev, "%s: error during i2c read probe (%d)
",
__func__, err);
goto err_reg_probe;
}
//dongao
dev_info(dev, "dongao: sensor model id: %x-%x
", IMX415_MODEL_ID_ADDR_MSB, reg_val[0]);
dev_info(dev, "dongao: sensor model id: %x-%x
", IMX415_MODEL_ID_ADDR_LSB, reg_val[1]);
#if 0 //dongao
/* Sensor fine integration time */
err = imx415_get_fine_integ_time(priv, &priv->fine_integ_time);
if (err)
dev_err(dev, "%s: error querying sensor fine integ. time
",
__func__);
#endif
err_reg_probe:
imx415_power_off(s_data);
done:
return err;
}
static int imx415_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
dev_info(&client->dev, "%s:
", __func__);
return 0;
}
//V4L2 框架使用 V4L2 子设备 op 来启动驱动程序
static const struct v4l2_subdev_internal_ops imx415_subdev_internal_ops = {
.open = imx415_open,
};
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
static int imx415_probe(struct i2c_client *client)
#else
static int imx415_probe(struct i2c_client *client,
const struct i2c_device_id *id)
#endif
{
struct device *dev = &client->dev;
struct tegracam_device *tc_dev;
struct imx415 *priv;
int err;
dev_info(dev, "dongao: imx415_probe_V1.0
");
dev_dbg(dev, "probing v4l2 sensor at addr 0x%0x
", client->addr);
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return -EINVAL;
priv = devm_kzalloc(dev, sizeof(struct imx415), GFP_KERNEL);
if (!priv)
return -ENOMEM;
tc_dev = devm_kzalloc(dev, sizeof(struct tegracam_device), GFP_KERNEL);
if (!tc_dev)
return -ENOMEM;
priv->i2c_client = tc_dev->client = client;
tc_dev->dev = dev;
strncpy(tc_dev->name, "imx415", sizeof(tc_dev->name));
tc_dev->dev_regmap_config = &sensor_regmap_config;
tc_dev->sensor_ops = &imx415_common_ops; //通用操作集
tc_dev->v4l2sd_internal_ops = &imx415_subdev_internal_ops; //提供 open
tc_dev->tcctrl_ops = &imx415_ctrl_ops;
err = tegracam_device_register(tc_dev); //解析设备树,参数保存到 tegracam_device
if (err) {
dev_err(dev, "tegra camera driver registration failed
");
return err;
}
priv->tc_dev = tc_dev;
priv->s_data = tc_dev->s_data;
priv->subdev = &tc_dev->s_data->subdev;
tegracam_set_privdata(tc_dev, (void *)priv);
err = imx415_board_setup(priv);
if (err) {
dev_err(dev, "board setup failed
");
return err;
}
err = tegracam_v4l2subdev_register(tc_dev, true); //v4l2_i2c_subdev_init 等
if (err) {
tegracam_device_unregister(tc_dev);
dev_err(dev, "tegra camera subdev registration failed
");
return err;
}
dev_info(dev, "detected imx415 sensor
");
return 0;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
static int imx415_remove(struct i2c_client *client)
#else
static void imx415_remove(struct i2c_client *client)
#endif
{
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
struct imx415 *priv;
if (!s_data) {
dev_err(&client->dev, "camera common data is NULL
");
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
return -EINVAL;
#else
return;
#endif
}
priv = (struct imx415 *)s_data->priv;
tegracam_v4l2subdev_unregister(priv->tc_dev);
tegracam_device_unregister(priv->tc_dev);
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
return 0;
#endif
}
static const struct i2c_device_id imx415_id[] = {
{"imx415", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, imx415_id);
static struct i2c_driver imx415_i2c_driver = {
.driver = {
.name = "imx415",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(imx415_of_match),
},
.probe = imx415_probe,
.remove = imx415_remove,
.id_table = imx415_id,
};
module_i2c_driver(imx415_i2c_driver);
MODULE_DESCRIPTION("Media Controller driver for Sony IMX415");
MODULE_AUTHOR("DONGAO");
MODULE_LICENSE("GPL v2");
4)将 nv_imx415 添加到Makefile
Linux_for_Tegra/source/nvidia-oot/drivers/media/i2c/Makefile
源码链接:基于英伟达Jetsonorinnano平台开发的imx415驱动资源-CSDN文库
二、编译调试
1、编译imx415驱动
我们修改的 nvidia-oot/ 目录下的驱动, 需编译可加载内核模块 (LKM):
Linux_for_Tegra/source 目录下执行:
$ export CROSS_COMPILE=$HOME/l4t-gcc/aarch64--glibc--stable-2022.08-1/bin/aarch64-buildroot-linux-gnu-
$ export KERNEL_HEADERS=$PWD/kernel/kernel-jammy-src
$ make modules
方法一:安装后,整体刷机
$ export INSTALL_MOD_PATH=<install-path>/Linux_for_Tegra/rootfs/
$ sudo -E make modules_install
安装完成后,刷机即可
方法二:使用scp 将 .ko 驱动直接拷贝到开发板
编译生成 nv_imx415.ko 传入开发板:
$ scp nvidia-oot/drivers/media/i2c/nv_imx415.ko nvidia@192.168.7.75:/tmp
开发板上重新加载 nv_imx415.ko
$ sudo insmod nv_imx415.ko
驱动加载成功后,生成 /dev/video0 节点
2、安装 v4l-utils 并查看 /dev/video0信息
2.1 安装 v4l-utils
先连上网线,确保板子能访问外网
$ sudo apt-get update
$ sudo apt-get install v4l-utils
运行过程:
2.2 查看 /dev/video0 信息
1)查看摄像头支持的图像格式和分辨率
$ v4l2-ctl -d /dev/video0 –list-formats-ext
2) 列出设备信息
$ v4l2-ctl –list-devices
/dev/video0:视频捕获设备节点
/dev/media0:media子系统设备节点
3)获取video0格式
$ v4l2-ctl -d /dev/video0 –get-fmt-video
4)查看 vi、csi、imx415 端口绑定结果
$ sudo media-ctl -p -d /dev/media0
$ v4l2-ctl -d /dev/video0 –list-ctrls 查看各种参数
root@localhost:/tmp# v4l2-ctl -d /dev/video0 --list-ctrls
Camera Controls
group_hold 0x009a2003 (bool) : default=0 value=0 flags=execute-on-write
sensor_mode 0x009a2008 (int64) : min=0 max=2 step=1 default=0 value=0 flags=slider
gain 0x009a2009 (int64) : min=0 max=241 step=1 default=0 value=100 flags=slider
exposure 0x009a200a (int64) : min=13 max=683710 step=1 default=3000 value=13 flags=slider
frame_rate 0x009a200b (int64) : min=2000000 max=30000000 step=1 default=15000000 value=2000000 flags=slider
sensor_configuration 0x009a2032 (u32) : min=0 max=4294967295 step=1 default=0 dims=[22] flags=read-only, volatile, has-payload
sensor_mode_i2c_packet 0x009a2033 (u32) : min=0 max=4294967295 step=1 default=0 dims=[1026] flags=read-only, volatile, has-payload
sensor_control_i2c_packet 0x009a2034 (u32) : min=0 max=4294967295 step=1 default=0 dims=[1026] flags=read-only, volatile, has-payload
bypass_mode 0x009a2064 (intmenu): min=0 max=1 default=0 value=0 (0 0x0)
override_enable 0x009a2065 (intmenu): min=0 max=1 default=0 value=0 (0 0x0)
height_align 0x009a2066 (int) : min=1 max=16 step=1 default=1 value=1
size_align 0x009a2067 (intmenu): min=0 max=2 default=0 value=0 (1 0x1)
write_isp_format 0x009a2068 (int) : min=1 max=1 step=1 default=1 value=1
sensor_signal_properties 0x009a2069 (u32) : min=0 max=4294967295 step=1 default=0 dims=[30][18] flags=read-only, has-payload
sensor_image_properties 0x009a206a (u32) : min=0 max=4294967295 step=1 default=0 dims=[30][16] flags=read-only, has-payload
sensor_control_properties 0x009a206b (u32) : min=0 max=4294967295 step=1 default=0 dims=[30][36] flags=read-only, has-payload
sensor_dv_timings 0x009a206c (u32) : min=0 max=4294967295 step=1 default=0 dims=[30][16] flags=read-only, has-payload
low_latency_mode 0x009a206d (bool) : default=0 value=0
preferred_stride 0x009a206e (int) : min=0 max=65535 step=1 default=0 value=0
override_capture_timeout_ms 0x009a206f (int) : min=-1 max=2147483647 step=1 default=15000 value=15000
sensor_modes 0x009a2082 (int) : min=0 max=30 step=1 default=30 value=2 flags=read-only
//获取单个参数
nvidia@localhost:~$ v4l2-ctl -d /dev/video0 --get-ctrl=exposure
exposure: 13
3、抓拍
3.1 v4l2-ctl 命令验证vi抓拍
$ sudo v4l2-ctl –set-fmt-video=width=3864,height=2192,pixelformat=GB12 –stream-skip=8 –stream-mmap –stream-count=100 -d /dev/video0 –stream-to=imx415.raw
命令执行结果:
问题:明明配置的帧率为30帧/s,为什么这里只 15fps左右???
原因:采集数据写到 imx415.raw 文件花费了时间
不写文件验证,确实为30fps
$ v4l2-ctl –stream-mmap –stream-count=500 -d /dev/video0

博主遇到v4l2-ctl抓拍的几个问题(没有深究):(Bayer/Packed)
v4l2-ctl命令抓 RAW10/RAW12 (Bayer/Packed)图片的大小有问题。1帧图片 packed RAW12 大小理论上为 3864 * 2192 * 1.5,但实际为 3864 * 2192 * 2
v4l2-ctl -d /dev/video0 –get-fmt-video 命令查看 Bytes per Line 为什么为 7728(3864 * 2)?
抓到的raw12图片放大后,就是这种gbrg的小方格

3.2 gstreamer英伟达命令抓拍
先安装SDK组件,然后再执行英伟达抓拍命令,否则会报错
$ sudo apt-get update -y
$ sudo apt-get install nvidia-jetpack -y //安装SDK
1)gst-launch-1.0 自动曝光、自动增益抓拍
$ gst-launch-1.0 nvarguscamerasrc sensor-id=0 num-buffers=15 ! 'video/x-raw(memory:NVMM), width=(int)3864,height=(int)2192, framerate=15/1' ! nvvidconv flip-method=2 ! 'video/x-raw, format=(string)I420' ! jpegenc ! multifilesink location=camera0.jpg -e
正常打印(帧率要比实际帧率小,否则命令可能报错):
正常照片:
2)gst-launch-1.0 设置曝光、增益抓拍
$ gst-launch-1.0 nvarguscamerasrc exposuretimerange=”200000 200000″ gainrange=”8 8″ sensor-id=0 num-buffers=15 ! 'video/x-raw(memory:NVMM), width=(int)3864,height=(int)2192, framerate=15/1' ! nvvidconv flip-method=2 ! 'video/x-raw, format=(string)I420' ! jpegenc ! multifilesink location=camera5.jpg -e
exposuretimerange=”200000 200000″ 表示固定曝光200us
gainrange=”8 8″ 表示固定增益8x
当曝光设为200us、增益8x 拍照结果:
三、imx415驱动开发遇到的问题及解决方法
Nvidia平台trace查看方法:
$ sudo su
$ modprobe rtcpu_debug
$ echo 1 > /sys/kernel/debug/tracing/tracing_on
$ echo 30720 > /sys/kernel/debug/tracing/buffer_size_kb
$ echo 1 > /sys/kernel/debug/tracing/events/tegra_rtcpu/enable
$ echo 1 > /sys/kernel/debug/tracing/events/freertos/enable
$ echo 3 > /sys/kernel/debug/camrtc/log-level
$ echo 1 > /sys/kernel/debug/tracing/events/camera_common/enable
$ echo > /sys/kernel/debug/tracing/trace
$ cat /sys/kernel/debug/tracing/trace //运行 v4l2-ctl 抓图后,调用此命令可以看到 nvidia的 trace日志
1、Jetson orin nano开发板的CAM0不支持4lane模式
原因:CS1_CLK 仅支持2lane
分析过程:
Orin Nano Devkit 的摄像头 #0 连接器 (J20) 上的 CSI0_D0_N/P 和 CSI0_D1_N/P 的设计目的是什么?- Jetson & Embedded Systems / Jetson Orin Nano – NVIDIA开发者论坛
2、使用 CSI0/1 时,需要将lane_polarity改为 6
说明:因为我用的 CSI2,因此lane_polarity为0
设备树中提到 lane_polarity
3、v4l2-ctl 抓图命令报错
$ sudo v4l2-ctl –set-fmt-video=width=3864,height=2192,pixelformat=GB12 –stream-mmap –stream-count=1 -d /dev/video0 –stream-to=imx415.raw
报错 2500ms超时:
tegra-camrtc-capture-vi tegra-capture-vi: uncorr_err: request timed out after 2500 ms
trace日志:
kworker/3:2-160 [003] .... 72.586960: rtcpu_string: tstamp:3691891507 id:0x04010000 str:"VM0 activating."
kworker/3:2-160 [003] .... 72.642962: rtcpu_vinotify_event: tstamp:3692561650 cch:0 vi:0 tag:VIFALC_TDSTATE channel:0x23 frame:0 vi_tstamp:118146060768 data:0x759d580010000000
kworker/3:2-160 [003] .... 72.642964: rtcpu_vinotify_event: tstamp:3692561788 cch:0 vi:0 tag:VIFALC_TDSTATE channel:0x23 frame:0 vi_tstamp:118146067232 data:0x0000000031000001
kworker/3:2-160 [003] .... 72.642965: rtcpu_vinotify_event: tstamp:3692561941 cch:0 vi:0 tag:VIFALC_TDSTATE channel:0x23 frame:0 vi_tstamp:118146127648 data:0x759d550010000000
kworker/3:2-160 [003] .... 72.642965: rtcpu_vinotify_event: tstamp:3692562072 cch:0 vi:0 tag:VIFALC_TDSTATE channel:0x23 frame:0 vi_tstamp:118146134176 data:0x0000000031000002
vi-output, ov42-2565 [002] .... 75.279729: tegra_channel_capture_setup: vnc_id 0 W 1500 H 1500 fmt c4
kworker/3:2-160 [003] .... 75.338965: rtcpu_vinotify_event: tstamp:3777198043 cch:0 vi:0 tag:VIFALC_TDSTATE channel:0x23 frame:0 vi_tstamp:120853141696 data:0x759d580010000000
kworker/3:2-160 [003] .... 75.338967: rtcpu_vinotify_event: tstamp:3777198180 cch:0 vi:0 tag:VIFALC_TDSTATE channel:0x23 frame:0 vi_tstamp:120853184384 data:0x0000000031000001
kworker/3:2-160 [003] .... 75.338968: rtcpu_vinotify_event: tstamp:3777198333 cch:0 vi:0 tag:VIFALC_TDSTATE channel:0x23 frame:0 vi_tstamp:120853202016 data:0x759d550010000000
kworker/3:2-160 [003] .... 75.338969: rtcpu_vinotify_event: tstamp:3777198464 cch:0 vi:0 tag:VIFALC_TDSTATE channel:0x23 frame:0 vi_tstamp:120853262400 data:0x0000000031000002
vi-output, ov42-2565 [001] .... 78.867978: tegra_channel_capture_setup: vnc_id 0 W 1500 H 1500 fmt c4
kworker/3:2-160 [003] .... 86.154100: rtcpu_string: tstamp:4114987402 id:0x04010000 str:"VM0 deactivating."
原因:1)csi引脚没收到 mipi 信号,可能是sensor驱动问题(没有mipi信号输出),也有可能是硬件问题; 2)可能设备树pix_clk_hz值有问题
解决方法:1)可以用示波器看mipi引脚是否有输出; 2)mipi输出是否连到对应的CSI上
相似问题:Ov428 drives tegra-capture-vi timeout (jetpack 5.1.3-b29) – Jetson & Embedded Systems / Jetson Orin Nano – NVIDIA Developer Forums
4、v4l2-ctl 抓图不成功,vi能收到数据,但数据不对

trach信息
vi-output, imx4-3067 [001] ....... 904.941756: tegra_channel_capture_frame: sof:926.921297600
vi-output, imx4-3067 [001] ....... 904.941758: tegra_channel_capture_frame: eof:926.921328256
vi-output, imx4-3066 [001] ....... 904.942394: vi_task_submit: class_id:48 ch:0 syncpt_id:26 syncpt_thresh:964 pid:3066 tid:3066
kworker/5:1-49 [005] ....... 904.945896: rtcpu_vinotify_event: tstamp:28966226634 cch:0 vi:1 tag:CHANSEL_FAULT channel:0x23 frame:53 vi_tstamp:926918622816 data:0x00000000086f0182
kworker/5:1-49 [005] ....... 904.945897: rtcpu_vinotify_event: tstamp:28966226927 cch:0 vi:1 tag:ATOMP_FRAME_DONE channel:0x23 frame:53 vi_tstamp:926918623776 data:0x0000000000000000
kworker/5:1-49 [005] ....... 904.945897: rtcpu_vinotify_event: tstamp:28966227183 cch:0 vi:1 tag:CHANSEL_FAULT channel:0x23 frame:53 vi_tstamp:926918631008 data:0x00000000087001c0
kworker/5:1-49 [005] ....... 904.945898: rtcpu_vinotify_event: tstamp:28966297792 cch:0 vi:1 tag:FE channel:0x00 frame:53 vi_tstamp:926919571552 data:0x0000003500000022
kworker/5:1-49 [005] ....... 904.945898: rtcpu_vinotify_event: tstamp:28966298051 cch:0 vi:1 tag:CHANSEL_SHORT_FRAME channel:0x04 frame:53 vi_tstamp:926919571552 data:0x0001200000000000
kworker/5:1-49 [005] ....... 904.945898: rtcpu_vinotify_event: tstamp:28966298346 cch:0 vi:1 tag:ATOMP_FE channel:0x00 frame:53 vi_tstamp:926919571584 data:0x0000000800000000
kworker/5:1-49 [005] ....... 904.945899: rtcpu_vinotify_event: tstamp:28966298600 cch:0 vi:1 tag:VIFALC_ACTIONLST channel:0x23 frame:0 vi_tstamp:926919590752 data:0x0000000007020036
kworker/5:1-49 [005] ....... 904.945899: rtcpu_vinotify_event: tstamp:28966298885 cch:0 vi:1 tag:VIFALC_TDSTATE channel:0x23 frame:0 vi_tstamp:926919605216 data:0x799e300010000000
kworker/5:1-49 [005] ....... 904.945899: rtcpu_vinotify_event: tstamp:28966299137 cch:0 vi:1 tag:VIFALC_TDSTATE channel:0x23 frame:0 vi_tstamp:926919615040 data:0x0000000031000037
kworker/5:1-49 [005] ....... 904.945900: rtcpu_vinotify_event: tstamp:28966299418 cch:0 vi:1 tag:FS channel:0x00 frame:54 vi_tstamp:926920171200 data:0x0000003600000012
kworker/5:1-49 [005] ....... 904.945900: rtcpu_vinotify_event: tstamp:28966299672 cch:0 vi:1 tag:ATOMP_FS channel:0x00 frame:54 vi_tstamp:926920171200 data:0x0000000800000000
kworker/5:1-49 [005] ....... 904.945901: rtcpu_vinotify_event: tstamp:28966299954 cch:0 vi:1 tag:CHANSEL_EMBED_SOF channel:0x23 frame:54 vi_tstamp:926920201312 data:0x0000000000000004
kworker/5:1-49 [005] ....... 904.945901: rtcpu_vinotify_event: tstamp:28966300206 cch:0 vi:1 tag:CHANSEL_NOMATCH channel:0x04 frame:54 vi_tstamp:926920230912 data:0x00000000000006e9
kworker/5:1-49 [005] ....... 904.945901: rtcpu_vinotify_event: tstamp:28966300485 cch:0 vi:1 tag:CHANSEL_PXL_SOF channel:0x23 frame:54 vi_tstamp:926921297600 data:0x0000000000000001
kworker/5:1-49 [005] ....... 904.945902: rtcpu_vinotify_event: tstamp:28966300734 cch:0 vi:1 tag:VIFALC_ACTIONLST channel:0x23 frame:54 vi_tstamp:926921299648 data:0x0000000008020036
kworker/5:1-49 [005] ....... 905.001899: rtcpu_vinotify_event: tstamp:28966601541 cch:0 vi:1 tag:CHANSEL_FAULT channel:0x23 frame:54 vi_tstamp:926921319072 data:0x0000000000000100
kworker/5:1-49 [005] ....... 905.001900: rtcpu_vinotify_event: tstamp:28966601808 cch:0 vi:1 tag:VIFALC_ACTIONLST channel:0x23 frame:54 vi_tstamp:926921328640 data:0x0000000001020036
vi-output, imx4-3067 [001] ....... 905.008662: tegra_channel_capture_frame: sof:926.987963488
vi-output, imx4-3067 [001] ....... 905.008664: tegra_channel_capture_frame: eof:926.987994144
问题原因:imx415分辨率配置成了 3840×2160
分析过程:
论坛帖子:IMX-678 on Jetson Orin Nano Devkit – Jetson & Embedded Systems / Jetson Orin Nano – NVIDIA Developer Forums
解决方法:
1)将驱动文件中的分辨率改为 3864×2192
2)设备树中的分辨率改为3864×2192
5、gstreamer抓图偏红色
英伟达抓图命令:
$ gst-launch-1.0 nvarguscamerasrc sensor-id=0 num-buffers=15 ! 'video/x-raw(memory:NVMM), width=(int)3864,height=(int)2192, framerate=15/1' ! nvvidconv flip-method=2 ! 'video/x-raw, format=(string)I420' ! jpegenc ! multifilesink location=camera0.jpg -e
抓拍是红色的
问题原因:修改设备树 “rggb” 改为 “gbrg”,正常出图,修改方法如下图
最终正常抓拍结果:
四、曝光、增益、格式、焦距对拍照效果的影响
帧率:30fps
正常拍照:exposure(曝光):33210 us、gain(增益):8.1dB

1、曝光时间设很低:exposure(曝光):300 us、gain(增益):8.1dB

2、曝光很低、自动增益:exposure(曝光):300 us、gain(自动增益):34.2dB
可以看到很多噪点

3、格式不对:”gbrg” 改为 “rggb”格式,图像变红

4、调整焦距后





















暂无评论内容