由 Tegra 处理器驱动的 Nvidia Jetson 平台已经在边缘分析市场中占据了一席之地,尤其是在视频分析、机器视觉等领域。 凭借 MIPI-CSI、USB、千兆以太网等广泛的接口,可以通过许多不同的接口获取视频数据。其中,CSI 接口仍然是机器视觉应用的首选接口。
在这篇博客中,我们将详细讨论 Jetson Tegra 平台中的相机接口和数据流以及 MIPI CSI 驱动程序的典型配置和设置。具体来说,我们将考虑 Jetson Nano 和 Onsemi OV5693 相机。
尽管 Tegra TX1、TX2、Xavier 和 Nano 平台之间存在显着的架构差异,但相机硬件子系统或多或少保持不变。下面捕获了相同的高级设计。
Nvidia Tegra 相机子系统
正如所见,主要组件及其功能是:
VI Unit 提供了一种称为 VI 同步点 (syncpts) 的硬件-软件同步机制,用于等待满足特定条件并增加计数器或希望计数器达到特定值。多个预定义索引可用,每个索引对应于一次功能,例如帧开始、行结束、ISP 处理的完成。例如,软件可以选择等待,直到通过下一个与索引对应的计数器值指示的 VI 接收到一个帧。
借助这些强大的组件,Tegra 相机子系统提供了无缝处理来自不同格式的多个来源的数据的选项。
了解了硬件子系统后,我们现在将研究 Tegra 相机接口的软件架构。Nvidia 通过其 Linux4Tegra (L4T) 软件支持 Linux 操作系统。相机驱动程序通过 CSI 总线以传感器的本机格式配置和读取来自相机传感器的数据,并可选择将它们转换为不同的格式。
Nvidia 提供两种类型的相机访问路径,可以根据相机和应用程序用例进行选择:
主要用于从相机捕获 RAW 数据,这是一条不进行任何处理且数据直接由用户应用程序使用的最小路径。
在此模型中,相机数据通过少数 Nvidia 库(例如 Camera Core、libArgus)使用。在这种情况下,可以有效地利用内核中可用的 GPU 对输入数据进行各种数据处理。
在任何一种情况下,应用程序都可以是 Gstreamer 插件或自定义插件。
为了深入了解,让我们考虑默认随 Tegra TX1 和 TX2 载板一起提供的 5MP(2592 x 1944,拜耳传感器)Omnivision CSI 摄像头模块 OV5693。高级软件架构如下:
L4T 相机驱动架构
OV5693 摄像头通过 TCA9548 I2C 扩展芯片连接到 I2C 总线 0x06(默认\I2C 地址为 0x36)。这可以通过在 SID 引脚上添加一个上拉电阻来更改为 0x40。
OV5693 驱动程序使用 I2C 总线驱动程序触发,并将自身注册到 Tegra V4L2 相机框架。这反过来又会暴露 /dev/videoX 设备,应用程序可以使用该设备来消费数据。
要启动 OV5693 驱动程序,必须处理以下内容,并在下一节中进一步说明:
在下一节中,我们将看到如何为 OV5693 摄像头设置设备树。
该 tegra194相机-e3333-a00.dtsi文件位于/硬件/ NVIDIA /平台/ t19x /普通/内核DTS / t19x常见模块/文件夹。
Tegra相机平台:
tegra-camera-platform 由一个或多个模块组成,这些模块定义了连接到 Tegra SoC 的相机/传感器的基本信息。虽然顶部的公共部分包含有关所有连接的综合信息,但每个模块子部分都单独定义了它们。在这种情况下,单个 OV5693 摄像头通过两个 MIPI 通道连接。
tegra-camera-platform {
compatible = "nvidia, tegra-camera-platform";
num_csi_lanes = <2>; //Number of lanes
max_lane_speed = <1500000>; //Maximum lane speed
min_bits_per_pixel = <12>; //bits per pixel
vi_peak_byte_per_pixel = <2>; //byte per pixel
vi_bw_margin_pct = <25>; //Don't care
max_pixel_rate = <160000>; //Don't care
isp_peak_byte_per_pixel = <5>;//Don't care
isp_bw_margin_pct = <25>; //Don't care
modules {
module0 { //OV5693 basic details
badge = "ov5693_right_iicov5693";
position = "right";
orientation = "1";
drivernode0 {
pcl_id = "v4l2_sensor";
devname = "ov5693 06-0036";
proc-device-tree = "/proc/device-tree/i2c@31c0000/tca9548@77/i2c@6/ov5693_a@36"; //Device tree node path
};
};
};
};
设备树节点
在设备树节点中,必须添加所有相机属性(输出分辨率、FPS、Mipi 时钟等)以确保设备正常运行。
I2c@31c0000 { //I2C-6 base address
tca9548@77 { //I2C expander IC
i2c@6 {
ov5693_a@36 {
compatible = nvidia,ov5693";
reg = <0x36>; //I2C slave address
devnode = "video0";//device name
/* Physical dimensions of sensor */
physical_w = "3.674"; //physical width of the sensor
physical_h = "2.738"; //physical height of the sensor
/* Enable EEPROM support */
has-eeprom = "1";
/* Define any required hw resources needed by driver */
/* ie. clocks, io pins, power sources */
avdd-reg = "vana"; //Power Regulator
iovdd-reg = "vif"; //Power Regulator
mode0 { // OV5693_MODE_2592X1944
mclk_khz = "24000"; //MIPI driving clock
num_lanes = "2"; //Number of lanes
tegra_sinterface = "serial_a"; //Serial interface
phy_mode = "DPHY"; //physical connection mode
discontinuous_clk = "yes";
dpcm_enable = "false"; //Don't care
cil_settletime = "0"; //Don't care
active_w = "2592"; //active width
active_h = "1944"; //active height
mode_type = "bayer"; //sensor type
pixel_phase = "bggr"; //output format
csi_pixel_bit_depth = "10"; //bit per pixel
readout_orientation = "0"; //Don't care
line_length = "2688"; //Total width
inherent_gain = "1"; //Don't care
mclk_multiplier = "6.67"; //pix_clk_hz/mclk_khz
pix_clk_hz = "160000000"; //Pixel clock HTotal*VTotal*FPS
gain_factor = "10"; //Don't care
min_gain_val = "10";/* 1DB*/ //Don't care
max_gain_val = "160";/* 16DB*/ //Don't care
step_gain_val = "1"; //Don't care
default_gain = "10"; //Don't care
min_hdr_ratio = "1"; //Don't care
max_hdr_ratio = "1"; //Don't care
framerate_factor = "1000000"; //Don't care
min_framerate = "1816577"; //Don't care
max_framerate = "30000000";
step_framerate = "1";
default_framerate = "30000000";
exposure_factor = "1000000"; //Don't care
min_exp_time = "34"; //Don't care
max_exp_time = "550385"; //Don't care
step_exp_time = "1"; //Don't care
default_exp_time = "33334"; //Don't care
embedded_metadata_height = "0";//Don't care
};
};
};
};
};
在本例中,像素时钟计算如下:
pix_clk_hz = HTotal*VTotal*FPS
OV5693:- 2592×1944@30fps
2592×1944 的总高度和总宽度为 2688×1984
pix_clk_hz = 2688 x 1984 x 30 = 159989760
pix_clk_hz 是 ~160000000
而 mclk 乘数是
mclk_multiplier = pix_clk_hz / mclk_khz
mclk_multiplier = 160000000 / 24000000 = 6.66
DTS绑定
如前所述,相机数据流如下:
传感器输出 | CSI输入 | CSI输出 | VI输入 |
ov5693_ov5693_out0 | ov5693_csi_in0 | ov5693_csi_out0 | ov5693_vi_in0 |
硬件 – 设备树节点数据流映射
内部端口之间的绑定是通过使用以下设置完成的。
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
ov5693_ov5693_out0: endpoint {
port-index = <0>;
bus-width = <2>;
remote-endpoint = <&ov5693_csi_in0>;
};
};
};
nvcsi@15a00000 {
num-channels = <1>;
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
channel@0 {
reg = <0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
ov5693_csi_in0: endpoint@0 {
port-index = <0>;
bus-width = <2>;
remote-endpoint = <&ov5693_ov5693_out0>;
};
};
port@1 {
reg = <1>;
ov5693_csi_out0: endpoint@1 {
remote-endpoint = <&ov5693_vi_in0>;
};
};
};
};
};
host1x {
vi@15c10000 {
num-channels = <1>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
ov5693_vi_in0: endpoint {
port-index = <0>;
bus-width = <2>;
remote-endpoint = <&ov5693_csi_out0>;
};
};
};
};
驱动程序通过 Host1x DMA 引擎模块从 VI 输出中获取数据。
覆盖
L4T 采用 DTB 覆盖机制来启用/禁用驱动程序。ov5693 驱动程序可以通过将其状态字段设置为“okay”在 DTS 中启用。
fragment-ov5693@0 {
ids = "2180-*";
override@0 {
target = <&ov5693_cam0>;
_overlay_ {
status = "okay";
};
};
};
在启动过程中,如果检测到正确的相机模块,则添加到设备树节点的覆盖层以及进一步的驱动程序和设备注册由相机驱动程序 (ov5693.c) 完成,如下一篇博客所述。
关于 Embien: Embien 是领先的产品工程服务,在 Nvidia Tegra 和 Jetson 平台上提供专业知识。我们一直在通过不同接口将各种类型的相机与 Nvidia 平台连接起来,并通过 libargus 框架以及定制的 Gstreamer 插件和应用程序启用它们。我们的客户包括国防、航空电子、工业自动化、医疗、汽车和半导体领域的财富 500 强公司。