在rv1106上使用ov2685摄像头

本篇文档中所使用的芯片是瑞芯微的RV1106G2, 使用的SDK 是由LUCKFOX所提供

SDK环境搭建

SDK环境搭建教程

由于官方提供的摄像头是SC3336 3MP Camera (A),这个摄像头并不是一个全景摄像头,刚好手上有一个OV2685的摄像头,所以开始尝试驱动OV2685,第一次在linux玩摄像头,所以记录一下过程和问题

linux驱动

​ 一般来说linux系统源码中集成了很多的摄像头的驱动,拿luckfox的sdk来说,其所在的位置是:

luckfox-pico/sysdrv/source/kernel/drivers/media/i2c/ov2685.c

在这里插入图片描述

由于使用I2C作为控制接口,所以在I2C目录下,如果你的摄像头没有对应的驱动文件,那么就要根据摄像头的数据手册按照驱动文件的格式添加驱动

menuconfig

在知道有驱动文件后,那么只需要在内核配置里面打开,具体的配置方法luckFox教程里面有,这里只说一下要配置的一些东西,在ov2685.c的同级目录下有一个Kconfig的文件,告诉了每种摄像头需要的一些依赖,下面是ov2685的

config VIDEO_OV2685
	tristate "OmniVision OV2685 sensor support"
	depends on VIDEO_V4L2 && I2C
	select MEDIA_CONTROLLER
	select V4L2_FWNODE
	help
	  This is a Video4Linux2 sensor driver for the OmniVision
	  OV2685 camera.

	  To compile this driver as a module, choose M here: the
	  module will be called ov2685.

可以知道要打开的有OmniVision OV2685 VIDEO_V4L2 I2C MEDIA_CONTROLLER V4L2_FWNODE,依次找到使能即可,打开之后再重新编译内核,就可以得到ov2685.ko文件

有了.ko后,就可以使用insmod 加载,但在这之前要在设备数据添加节点

配置设备树

&csi2_dphy_hw {
	status = "okay";
};

&csi2_dphy0 {
	status = "okay";

	ports {
		#address-cells = <1>;
		#size-cells = <0>;

		port@0 {
			reg = <0>;
			#address-cells = <1>;
			#size-cells = <0>;

			csi_dphy_input0: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&sc3336_out>;
				data-lanes = <1 2>;
			};

			csi_dphy_input1: endpoint@1 {
				reg = <1>;
				remote-endpoint = <&sc4336_out>;
				data-lanes = <1 2>;
			};

			csi_dphy_input2: endpoint@2 {
				reg = <2>;
				remote-endpoint = <&ov2685_out>;
				data-lanes = <1>;
			};
		};

		port@1 {
			reg = <1>;
			#address-cells = <1>;
			#size-cells = <0>;

			csi_dphy_output: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&mipi_csi2_input>;
			};
		};
	};
};

&i2c4 {
	status = "okay";
	clock-frequency = <400000>;
	pinctrl-names = "default";
	pinctrl-0 = <&i2c4m2_xfer>;

	sc3336: sc3336@30 {
		compatible = "smartsens,sc3336";
		status = "okay";
		reg = <0x30>;
		clocks = <&cru MCLK_REF_MIPI0>;
		clock-names = "xvclk";
		pwdn-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>;
		pinctrl-names = "default";
		pinctrl-0 = <&mipi_refclk_out0>;
		rockchip,camera-module-index = <0>;
		rockchip,camera-module-facing = "back";
		rockchip,camera-module-name = "CMK-OT2119-PC1";
		rockchip,camera-module-lens-name = "30IRC-F16";
		port {
			sc3336_out: endpoint {
				remote-endpoint = <&csi_dphy_input0>;
				data-lanes = <1 2>;
			};
		};
	};

	sc4336: sc4336@30 {
		compatible = "smartsens,sc4336";
		status = "okay";
		reg = <0x30>;
		clocks = <&cru MCLK_REF_MIPI0>;
		clock-names = "xvclk";
		pwdn-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>;
		pinctrl-names = "default";
		pinctrl-0 = <&mipi_refclk_out0>;
		rockchip,camera-module-index = <0>;
		rockchip,camera-module-facing = "back";
		rockchip,camera-module-name = "OT01";
		rockchip,camera-module-lens-name = "40IRC_F16";
		port {
			sc4336_out: endpoint {
				remote-endpoint = <&csi_dphy_input1>;
				data-lanes = <1 2>;
			};
		};
	};
	ov2685: camera-sensor@3c {
		compatible = "ovti,ov2685";
		reg = <0x3c>;
		pinctrl-names = "default";
		pinctrl-0 = <&mipi_refclk_out0>;

		clocks = <&cru MCLK_REF_MIPI0>;
		clock-names = "xvclk";
		reset-gpios = <&gpio3 RK_PC5 GPIO_ACTIVE_LOW>;
        rockchip,camera-module-index = <1>;
        rockchip,camera-module-facing = "back";
        rockchip,camera-module-name = "YT-RV1106-2-V1";
		port {
			ov2685_out: endpoint {
				remote-endpoint = <&csi_dphy_input2>;
				data-lanes = <1>;
			};
		};
	};
};





&i2s0_8ch {
	#sound-dai-cells = <0>;
	status = "okay";
};

&mipi0_csi2 {
	status = "okay";

	ports {
		#address-cells = <1>;
		#size-cells = <0>;

		port@0 {
			reg = <0>;
			#address-cells = <1>;
			#size-cells = <0>;

			mipi_csi2_input: endpoint@1 {
				reg = <1>;
				remote-endpoint = <&csi_dphy_output>;
			};
		};

		port@1 {
			reg = <1>;
			#address-cells = <1>;
			#size-cells = <0>;

			mipi_csi2_output: endpoint@0 {
				reg = <0>;
				remote-endpoint = <&cif_mipi_in>;
			};
		};
	};
};

&rkcif {
	status = "okay";
};

&rkcif_mipi_lvds {
	status = "okay";

	pinctrl-names = "default";
	pinctrl-0 = <&mipi_pins>;
	port {
		/* MIPI CSI-2 endpoint */
		cif_mipi_in: endpoint {
			remote-endpoint = <&mipi_csi2_output>;
		};
	};
};

&rkcif_mipi_lvds_sditf {
	status = "okay";

	port {
		/* MIPI CSI-2 endpoint */
		mipi_lvds_sditf: endpoint {
			remote-endpoint = <&isp_in>;
		};
	};
};

&rkisp {
	status = "okay";
};

&rkisp_vir0 {
	status = "okay";

	port@0 {
		isp_in: endpoint {
			remote-endpoint = <&mipi_lvds_sditf>;
		};
	};
};

以上是实际设备树的一部分

数据从摄像头到实际图像需要经过的步骤

[摄像头] ——->(raw图像数据) ——->[mipi总线] ——->[图像处理芯片(如ISP)] ——-> (NV16/NV12等格式图像数据)

所以在设备树里面就要实现这个结构,

ov2685_out—>csi_dphy0_input ----> csi_dphy0_output ----> mipi_csi2_input -> mipi_csi2_output—>isp

这一个结构基本上不用自己实现,我照着之前的框架把其中一个支持的摄像头节点改为ov2685即可,还有对应的I2C地址和reset-gpios用自己的即可

添加好了之后,便可以使用,编译内核然后烧录到rv1106开发板

使用insmod加载模块
在这里插入图片描述

v4l2

​ 使用v4l2框架去获取图像,V4L2(Video for Linux 2):Linux内核中视频设备中的驱动框架,对于应用层它提供了一系列的API接口,同时对于硬件层,它适配大部分的视频设备,因此通过调用V4L2的接口函数可以适配大部分的视频设备。

​ 如果ov2685.ko加载成功那么,通过V4L2就能检测到video设备,通过命令行

v4l2-ctl --list-devices

在这里插入图片描述

能够看到正常出现vedio0到vedio10 表示注册加载正常

获取影像

使用v4l2-ctl工具去获取

v4l2-ctl -d /dev/video12 --set-fmt-video=width=800,height=800,pixelformat=NV12 --stream-mmap=3 --stream-skip=10 --stream-to=/gc5035.raw --stream-count=1 --stream-poll

在这里插入图片描述

碰到的问题

1.ISP无法正常同步

在这里插入图片描述

并且v4l2 不能够看到正常出现vedio0到vedio10,于是用dmesg打开日志,摄像头注册过程确实出现了一些问题

我查了一下原因,是因为获取frame_interval失败才导致的,看了下ov2685.c里面也确实没有相关的代码,于是我对比了一下ov2680的驱动文件,发现ov2680.c里面是注册了这个驱动函数的,于是我在ov2685.c也添加并注册了帧概率获取函数:

static int ov2685_s_g_frame_interval(struct v4l2_subdev *sd,
				     struct v4l2_subdev_frame_interval *fi)
{
    struct v4l2_fract		frame_interval;
	frame_interval.numerator = 1;
	frame_interval.denominator = 30;
	fi->interval= frame_interval;
	return 0;
}
static const struct v4l2_subdev_video_ops ov2685_video_ops = {
	.s_stream = ov2685_s_stream,
	.g_frame_interval	= ov2685_s_g_frame_interval,
	.s_frame_interval	= ov2685_s_g_frame_interval,
};

具体ov2685.c为什么不注册这个函数我没有深究,因为摄像头确实跑起来了。

2.使用MIPI 2通道无法正常获取图像

出现select timeout错误

解决方法,在设备树里面改动,当然也有可能是其它原因

	port {
		ov2685_out: endpoint {
			remote-endpoint = <&csi_dphy_input2>;
			data-lanes = <1>;
		};
	};

本来是data-lanes = <1,2>,因为我硬件上使用的是2lane ,手册上也说了可以使用2lane,但是文档里面给的示例却是1通道

在这里插入图片描述

不过确实改为1通道才能正常使用,不过我觉得2通道也能正常使用,不过需要对摄像头传感器进行配置。

参考:

https://www.ebaina.com/articles/140000017027

如果有问题可以发送到我的邮箱 qq:1074485750

  • 24
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值