摄像头驱动
前言
摄像头有很多种,比如常见的USB摄像头,网络摄像头,lvds摄像头,mipi摄像头等。最常见的摄像头是usb摄像头,通常此款摄像头是免驱的,将摄像头插入USB接口即可使用。网络摄像头可以访问相应的ip地址即可获取画面。然而lvds、mipi摄像头则需要驱动,不可以将摄像头插入接口即可使用。
本篇文章主要介绍如何在rk3588上使用mipi摄像头。将从硬件设计和软件驱动两方面进行讲解。
MIPI摄像头硬件设计
电源
通常需要多组电压(如2.8V模拟电源、1.5V数字电源、1.2V核心电源)
信号
信号线包含MIPI CSI-2接口、I2C接口、时钟输入。
数据通常采用1~4对差分信号线进行传输,时钟通道使用1对差分时钟信号同步数据传输,I2C用于传感器配置。
摄像头驱动相关文件路径
在rk3588上添加摄像头驱动主要包含几步操作。
驱动文件:/rk3588/ELF2-linux-source/kernel/drivers/media/i2c
.
设备树:rk3588/ELF2-linux-source/kernel/arch/arm64/boot/dts/rockchip
驱动Makefile:/zkb/rk3588/ELF2-linux-source/kernel/drivers/media/i2c
使用./build.sh kconfig
修改内核配置。
设备树配置 elf2-3588-Camera.dtsi
c
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2022 Forlinx Co., Ltd.
*
* rkisp0 --> rkisp0_vir0/rkisp0_vir1/rkisp0_vir2/rkisp0_vir3
* rkisp1 --> rkisp1_vir0/rkisp1_vir1/rkisp1_vir2/rkisp1_vir3
* rkcif_mipi_lvds --> rkcif_mipi_lvds[0-4]_sditf
* mipicamera0 --> csi2_dcphy0 --> mipi0_csi2 -->rkcif_mipi_lvds --> rkcif_mipi_lvds_sditf --> rkisp0_vir0
* mipicamera1 --> csi2_dcphy1 --> mipi1_csi2 -->rkcif_mipi_lvds1 --> rkcif_mipi_lvds1_sditf --> rkisp0_vir1
* csi2_dphy0 or (csi2_dphy1、csi2_dphy2) dphy0
* csi2_dphy3 or (csi2_dphy4、csi2_dphy5) dphy1
* mipicamera2 --> csi2_dphy1 --> mipi2_csi2 -->rkcif_mipi_lvds2 -->rkcif_mipi_lvds2_sditf --> rkisp0_vir2
* mipicamera3 --> csi2_dphy2 --> mipi3_csi2 -->rkcif_mipi_lvds3 -->rkcif_mipi_lvds3_sditf --> rkisp1_vir0
* mipicamera4 --> csi2_dphy4 --> mipi4_csi2 -->rkcif_mipi_lvds4 -->rkcif_mipi_lvds4_sditf --> rkisp1_vir1
* mipicamera5 --> csi2_dphy5 --> mipi5_csi2 -->rkcif_mipi_lvds5 -->rkcif_mipi_lvds5_sditf --> rkisp1_vir2
* mipicamera6 --> rkcif_dvp ---> rkcif_dvp_sditf
*/
/ {
ext_cam_clk: external-camera-clock {
compatible = "fixed-clock";
clock-frequency = <24000000>;
clock-output-names = "CLK_CAMERA_24MHZ";
#clock-cells = <0>;
};
};
&rkcif {
status = "okay";
};
&rkcif_mmu {
status = "okay";
};
//************************************************
//*** CAM1 OV13850 Configuration description ***
//************************************************
&mipi_dcphy0 {
status = "okay";
};
&rkisp0 {
status = "okay";
};
&isp0_mmu {
status = "okay";
};
&i2c3 {
status = "okay";
clock-frequency = <400000>;
cam1_dw9763: cam1-dw9763@c {
compatible = "dongwoon,dw9763";
status = "okay";
reg = <0x0c>;
rockchip,vcm-max-current = <120>;
rockchip,vcm-start-current = <20>;
rockchip,vcm-rated-current = <90>;
rockchip,vcm-step-mode = <3>;
rockchip,vcm-t-src = <0x20>;
rockchip,vcm-t-div = <1>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
};
cam1_ov13850: cam1-ov13850@10 {
compatible = "ovti,ov13850";
status = "okay";
reg = <0x10>;
clocks = <&ext_cam_clk>;
clock-names = "xvclk";
pinctrl-names = "default";
pinctrl-0 = <&cam1_reset_gpio
&cam1_pwren_gpio>;
pwdn-gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "ZC-OV13850R2A-V1";
rockchip,camera-module-lens-name = "Largan-50064B31";
lens-focus = <&cam1_dw9763>;
port {
cam1_ov13850_out: endpoint {
remote-endpoint = <&mipi_in_0_ucam1>;
data-lanes = <1 2 3 4>;
};
};
};
};
&csi2_dcphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_in_0_ucam1: endpoint@1 {
reg = <1>;
remote-endpoint = <&cam1_ov13850_out>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidcphy0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi0_csi2_input>;
};
};
};
};
&mipi0_csi2 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi0_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csidcphy0_out>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi0_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi_lvds0>;
};
};
};
};
&rkcif_mipi_lvds {
status = "okay";
port {
cif_mipi_lvds0: endpoint {
remote-endpoint = <&mipi0_csi2_output>;
};
};
};
&rkcif_mipi_lvds_sditf {
status = "okay";
port {
mipi_lvds_sditf: endpoint {
remote-endpoint = <&isp0_vir0>;
};
};
};
&rkisp0_vir0 {
status = "okay";
port {
#address-cells = <1>;
#size-cells = <0>;
isp0_vir0: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi_lvds_sditf>;
};
};
};
c
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2022 Forlinx Co., Ltd.
*
* rkisp0 --> rkisp0_vir0/rkisp0_vir1/rkisp0_vir2/rkisp0_vir3
* rkisp1 --> rkisp1_vir0/rkisp1_vir1/rkisp1_vir2/rkisp1_vir3
* rkcif_mipi_lvds --> rkcif_mipi_lvds[0-4]_sditf
* mipicamera0 --> csi2_dcphy0 --> mipi0_csi2 -->rkcif_mipi_lvds --> rkcif_mipi_lvds_sditf --> rkisp0_vir0
* mipicamera1 --> csi2_dcphy1 --> mipi1_csi2 -->rkcif_mipi_lvds1 --> rkcif_mipi_lvds1_sditf --> rkisp0_vir1
* csi2_dphy0 or (csi2_dphy1、csi2_dphy2) dphy0
* csi2_dphy3 or (csi2_dphy4、csi2_dphy5) dphy1
* mipicamera2 --> csi2_dphy1 --> mipi2_csi2 -->rkcif_mipi_lvds2 -->rkcif_mipi_lvds2_sditf --> rkisp0_vir2
* mipicamera3 --> csi2_dphy2 --> mipi3_csi2 -->rkcif_mipi_lvds3 -->rkcif_mipi_lvds3_sditf --> rkisp1_vir0
* mipicamera4 --> csi2_dphy4 --> mipi4_csi2 -->rkcif_mipi_lvds4 -->rkcif_mipi_lvds4_sditf --> rkisp1_vir1
* mipicamera5 --> csi2_dphy5 --> mipi5_csi2 -->rkcif_mipi_lvds5 -->rkcif_mipi_lvds5_sditf --> rkisp1_vir2
* mipicamera6 --> rkcif_dvp ---> rkcif_dvp_sditf
*/
/ {
ext_cam_clk: external-camera-clock {
compatible = "fixed-clock";
clock-frequency = <24000000>;
clock-output-names = "CLK_CAMERA_24MHZ";
#clock-cells = <0>;
};
};
&rkcif {
status = "okay";
};
&rkcif_mmu {
status = "okay";
};
//************************************************
//*** CAM1 sc200ai Configuration description ***
//************************************************
&mipi_dcphy0 {
status = "okay";
};
&rkisp0 {
status = "okay";
};
&isp0_mmu {
status = "okay";
};
&i2c3 {
status = "okay";
clock-frequency = <400000>;
cam1_dw9763: cam1-dw9763@c {
compatible = "dongwoon,dw9763";
status = "okay";
reg = <0x0c>;
rockchip,vcm-max-current = <120>;
rockchip,vcm-start-current = <20>;
rockchip,vcm-rated-current = <90>;
rockchip,vcm-step-mode = <3>;
rockchip,vcm-t-src = <0x20>;
rockchip,vcm-t-div = <1>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
};
cam1_sc200ai: cam1-sc200ai@30 {
compatible = "smartsens,sc200ai";
status = "okay";
reg = <0x30>;
clocks = <&ext_cam_clk>;
clock-names = "xvclk";
pinctrl-names = "default";
pinctrl-0 = <&cam1_reset_gpio
&cam1_pwren_gpio>;
pwdn-gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "C7234A-400";
rockchip,camera-module-lens-name = "30IRC-2MP-F20";
rockchip,camera-hdr-mode = <5>;
port {
cam1_sc200ai_out: endpoint {
remote-endpoint = <&mipi_in_0_ucam1>;
data-lanes = <1 2>;
};
};
};
};
&csi2_dcphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_in_0_ucam1: endpoint@1 {
reg = <1>;
remote-endpoint = <&cam1_sc200ai_out>;
data-lanes = <1 2>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidcphy0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi0_csi2_input>;
};
};
};
};
&mipi0_csi2 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi0_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csidcphy0_out>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi0_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi_lvds0>;
};
};
};
};
&rkcif_mipi_lvds {
status = "okay";
port {
cif_mipi_lvds0: endpoint {
remote-endpoint = <&mipi0_csi2_output>;
};
};
};
&rkcif_mipi_lvds_sditf {
status = "okay";
port {
mipi_lvds_sditf: endpoint {
remote-endpoint = <&isp0_vir0>;
};
};
};
&rkisp0_vir0 {
status = "okay";
port {
#address-cells = <1>;
#size-cells = <0>;
isp0_vir0: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi_lvds_sditf>;
};
};
};
测试
检查驱动是否成功加载
shell
dmesg | grep -i camera
检查ov13850是否加载
shell
dmesg | grep -i ov13850
检查sc200ai是否加载
shell
dmesg | grep -i sc200ai
查找摄像头节点
grep '' /sys/class/video4linux/video*/name
查看设备
shell
v4l2-ctl --list-devices
shell
elf@elf2-desktop:~$ v4l2-ctl --list-devices
rk_hdmirx (fdee0000.hdmirx-controller):
/dev/video20
rkisp-statistics (platform: rkisp):
/dev/video18
/dev/video19
rkcif-mipi-lvds (platform:rkcif):
/dev/media0
rkcif (platform:rkcif-mipi-lvds):
/dev/video0
/dev/video1
/dev/video2
/dev/video3
/dev/video4
/dev/video5
/dev/video6
/dev/video7
/dev/video8
/dev/video9
/dev/video10
rkisp_mainpath (platform:rkisp0-vir0):
/dev/video11
/dev/video12
/dev/video13
/dev/video14
/dev/video15
/dev/video16
/dev/video17
/dev/media1
检查/dev下的视频设备节点
shell
ls /dev/video*
查看拓扑结构
查看media节点
shell
ls /dev/media*
查看拓扑结构命令
shell
media-ctl –d /dev/mediaX –p
查看支持的格式
shell
v4l2-ctl -d /dev/video0 --list-formats-ext
输出的结果为:
shell
elf@elf2-desktop:~$ v4l2-ctl -d /dev/video0 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
Type: Video Capture Multiplanar
[0]: 'RG10' (10-bit Bayer RGRG/GBGB)
Size: Stepwise 64x64 - 2112x1568 with step 8/8
[1]: 'BA10' (10-bit Bayer GRGR/BGBG)
Size: Stepwise 64x64 - 2112x1568 with step 8/8
[2]: 'GB10' (10-bit Bayer GBGB/RGRG)
Size: Stepwise 64x64 - 2112x1568 with step 8/8
[3]: 'BG10' (10-bit Bayer BGBG/GRGR)
Size: Stepwise 64x64 - 2112x1568 with step 8/8
[4]: 'Y10 ' (10-bit Greyscale)
Size: Stepwise 64x64 - 2112x1568 with step 8/8
抓图
从main节点抓取raw图
v4l2-ctl -d /dev/video0 \
--set-fmt-video=width=1920,height=1080,pixelformat=BG10 \
--stream-mmap --stream-count=1 --stream-to=output.raw
结果
elf@elf2-desktop:~$ v4l2-ctl -d /dev/video0 \
--set-fmt-video=width=1920,height=1080,pixelformat=BG10 \
--stream-mmap --stream-count=1 --stream-to=output.raw
[ 1823.115580] rockchip-mipi-csi2 mipi0-csi2: stream on, src_sd: 00000000f4ff90c6, sd_name:rockchip-csi2-dphy0
[ 1823.115604] rockchip-mipi-csi2 mipi0-csi2: stream ON
<[ 1823.210107] rockchip-mipi-csi2 mipi0-csi2: stream off, src_sd: 00000000f4ff90c6, sd_name:rockchip-csi2-dphy0
[ 1823.210128] rockchip-mipi-csi2 mipi0-csi2: stream OFF
从isp节点拍摄一张图片
gst-launch-1.0 v4l2src device=/dev/video11 num-buffers=1 ! videoconvert ! jpegenc ! filesink location=capture.jpg
用GStreamer显示图像
gst-launch-1.0 v4l2src device=/dev/video11 ! autovideosink
问题排查
- 获取 I2C 访问权限
sudo i2cdetect -y 3