rk3399调试ov2659(camera模块@dvp接口)–源码分析

rk3399调试ov2659(camera模块@dvp接口)–源码分析  之前整理的“rockchipsensorcore框架”和rkisp下的v4l2框架有点像,只不过v4l2框架有点大(而且不支持摄像头热插拔)。其实接触越多Linux子系统越发觉得这些子系统处理思想大同小异。   这种"核…

大家好,又见面了,我是你们的朋友全栈君。

版权声明:本文为博主原创文章,转载请注明出处:https://blog.csdn.net/huang_165/article/details/86217004

    之前整理的“rockchip sensor core框架”和rkisp下的v4l2框架有点像,只不过v4l2框架有点大(而且不支持摄像头热插拔)。其实接触越多Linux子系统越发觉得这些子系统处理思想大同小异。
     这种”核心思想”就是将”同类设备(soc/外设)的同种属性、内核资源管理”整理出一个”核心层”,达到求同存异、松耦合、分层管理的目的。

v4l2简单框图:


rk3399调试ov2659(camera模块@dvp接口)--源码分析

从V4L2简单框图可以看出,V4L2是一个字符设备,而V4L2的大部分功能都是通过设备文件的ioctl导出的。

一般来说,摄像头驱动需要实现与向核心层提交下面十几个ioctl接口
VIDIOC_REQBUFS:分配内存
VIDIOC_QUERYCAP:查询驱动功能
VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式
VIDIOC_S_FMT:设置当前驱动的频捕获格式
VIDIOC_G_FMT:读取当前驱动的频捕获格式
VIDIOC_TRY_FMT:验证当前驱动的显示格式
VIDIOC_CROPCAP:查询驱动的修剪能力
VIDIOC_S_CROP:设置视频信号的边框
VIDIOC_G_CROP:读取视频信号的边框
VIDIOC_QBUF:把数据放回缓存队列
VIDIOC_DQBUF:把数据从缓存中读取出来
VIDIOC_STREAMON:开始图像捕获
VIDIOC_STREAMOFF:结束图像捕获

摄像头驱动-ov2659源码分析:

rk3399调试ov2659(camera模块@dvp接口)--源码分析

      先写个断言“核心层和摄像头设备驱动是通过check_camera_id机制来确认具体摄像头driver的”,在《框架分析》证明。

我们分析下:下面的1,2,3步看看应用层、核心层、摄像头如何配合起来的。
1.应用层分配内存–VIDIOC_REQBUFS
2.应用层使能摄像头开始图像捕获–VIDIOC_STREAMON
3.应用层把捕获到的图像从缓存中读取出来–VIDIOC_DQBUF

框架分析:
     由于应用层操作的是v4l2设备(/dev/videox),这里选video0(该通道用于抓图像)。

现在,从设备树开始,分析video0是如何构建起来的。
rk3399-linux.dtsi:     compatible = "rockchip,rk3399-cif-isp";在驱动目录下查找rockchip,rk3399-cif-isp
在media/platform/rk-isp10/cif_isp10_v4l2.c-->cif_isp10_v4l2_of_match找到。所以,我这个rk3399 sdk版本下摄像头走rk-isp v4l2框架。
cif_isp10_v4l2_drv_probe
	-->match = of_match_node(cif_isp10_v4l2_of_match, node); 找到设备树上的cif_isp1: cif_isp@ff920000节点,该节点内容见附录。
	-->cif_isp10_create 构建ISP
		-->cif_isp10_pltfrm_soc_init 初始化ISP
		-->cif_isp10_img_srcs_init 初始化图像源设备(摄像头)
			-->cif_isp10_pltfrm_get_img_src_device 查找ISP10下cif接口的图像源设备
				-->phandle = of_get_property(node, "rockchip,camera-modules-attached", &size); 
			//根据该节点内容可知,这里就通过rockchip,camera-modules-attached找到camera4了
				-->client = of_find_i2c_device_by_node(camera_list_node);
				-->img_src_array[num_cameras] = cif_isp10_img_src_to_img_src(&client->dev, &(cif_isp10_dev->soc_cfg));
					-->cif_isp10_img_src_ops[i].ops.to_img_src
						-->cif_isp10_img_src_v4l2_i2c_subdev_to_img_src //至此核心层就能和摄像头设备驱动绑定了
							-->i2c_get_clientdata
							--> v4l2_subdev_call(subdev, core, ioctl, PLTFRM_CIFCAM_ATTACH, (void *)soc_cfg);
								-->ov_camera_module_ioctl-->ov_camera_module_init
												-->ov_camera_module_attach-->"custom->check_camera_id(cam_mod)"
			//将从phandle遍历出来的i2c设备中找到符合条件的client,并将client和当前ISP绑定。

	-->cif_isp10_v4l2_register_video_device
		-->vdev->ioctl_ops = ioctl_ops; 使用最后一个参数作为和上层交互的ioctl
		-->video_register_device 在这里将/dev/videox注册上
	-->g_cif_isp10_v4l2_dev[g_cif_isp10_v4l2_dev_cnt] =cif_isp10_v4l2_dev; //将设置、注册好的ISP加入核心层中。

cif_isp10_v4l2_register_video_device最后一个参数:cif_isp10_v4l2_sp_ioctlops,是提供给上层用的,我们等下要分析的1,2,3点将用到。cif_isp10_v4l2_sp_ioctlops原型见附录

看到cif_isp10_v4l2_sp_ioctlops原型一系列ioctl函数,我们对上层的调用就很清晰了:

第1步的VIDIOC_REQBUFS就调用.vidioc_reqbufs
第2步的VIDIOC_STREAMON就调用.vidioc_streamon
第3步的VIDIOC_DQBUF就调用.vidioc_dqbuf
      1,3步和摄像头的设备驱动没什么关系,有兴趣的读者自行分析。
      我分析第2步,看.vidioc_streamon如何调用到设备驱动的,也就是ov2659_custom_config.start_streaming
要解决这个问题,其实是要知道核心层是如何寻找到摄像头设备驱动的。

“框架分析”我们知道,rkisp组织的v4l2框架通过设备树rockchip,camera-modules-attached属性绑定具体摄像头硬件,通过check_camera_id机制来确认具体摄像头driver。


    关于第2步顺序跟踪下cif_isp10_v4l2_sp_ioctlops.vidioc_streamon

cif_isp10_v4l2_streamon
	-->cif_isp10_v4l2_streamon
		-->cif_isp10_start
			-->cif_isp10_img_src_ioctl
				-->img_src->ops->ioctl(img_src->img_src, cmd, arg); 
			而img_src:cif_isp10_img_src_ops[]是一个全局常量数组,其ops.ioctl字段为cif_isp10_img_src_v4l2_subdev_ioctl
					-->cif_isp10_img_src_v4l2_subdev_ioctl
						-->v4l2_subdev_call(subdev,core,ioctl,cmd,arg);//v4l2_subdev_call原型见附录

可以看出,cif_isp10_v4l2_streamon最终会调用subdev下的ioctl.ioctl这里的subdev就是摄像头驱动ov2659.sd

     总结:因为摄像头(subdev)和核心层(rkisp)是通过设备树cif_isp1节点下的rockchip,camera-modules-attached属性、check_camera_id机制绑定。所以,摄像头是不支持“严格意义热插拔”的。其实,分析的难点也是知道核心层(rkisp)、摄像头(subdev)是如何绑定。
     最后,分享一个调试经验。在对源码调用关系把握不好时,可以故意做一个编译错误、运行错误、运行打印等信息来帮助调试分析。看别人分析源码有时候会有点接不上,这时候最好是自己也分析一遍,分析多了就有一些想法,对一些关键组件看名字也能猜到一些调用关系。


附录:

v4l2_subdev_call原型:

#define v4l2_subdev_call(sd, o, f, args...)				\
	(!(sd) ? -ENODEV : (((sd)->ops->o && (sd)->ops->o->f) ?	\
		(sd)->ops->o->f((sd) , ##args) : -ENOIOCTLCMD))

cif_isp10_v4l2_sp_ioctlops原型:

const struct v4l2_ioctl_ops cif_isp10_v4l2_sp_ioctlops = {
	.vidioc_reqbufs = cif_isp10_v4l2_reqbufs,
	.vidioc_querybuf = cif_isp10_v4l2_querybuf,
	.vidioc_create_bufs = vb2_ioctl_create_bufs,
	.vidioc_qbuf = cif_isp10_v4l2_qbuf,
	.vidioc_dqbuf = cif_isp10_v4l2_dqbuf,
	.vidioc_streamon = cif_isp10_v4l2_streamon,
	.vidioc_streamoff = cif_isp10_v4l2_streamoff,
	...
	.vidioc_enum_input = v4l2_enum_input,
	.vidioc_g_ctrl = v4l2_g_ctrl,
	.vidioc_s_ctrl = cif_isp10_v4l2_s_ctrl,
	.vidioc_s_fmt_vid_cap = cif_isp10_v4l2_s_fmt,
	.vidioc_g_fmt_vid_cap = cif_isp10_v4l2_g_fmt,
	...
	.vidioc_s_ext_ctrls = v4l2_s_ext_ctrls,
	.vidioc_enum_fmt_vid_cap = v4l2_enum_fmt_cap,
	.vidioc_enum_framesizes = cif_isp10_v4l2_enum_framesizes,
	...
};

设备树:

cif_isp1: cif_isp@ff920000 {
		compatible = "rockchip,rk3399-cif-isp";
		rockchip,grf = <&grf>;
		reg = <0x0 0xff920000 0x0 0x4000>, <0x0 0xff968000 0x0 0x8000>;
		reg-names = "register", "dsihost-register";
		clocks =
			<&cru ACLK_ISP1_NOC>, <&cru ACLK_ISP1_WRAPPER>,
			<&cru HCLK_ISP1_NOC>, <&cru HCLK_ISP1_WRAPPER>,
			<&cru SCLK_ISP1>, <&cru PCLK_ISP1_WRAPPER>,
			<&cru SCLK_DPHY_TX1RX1_CFG>,
			<&cru PCLK_MIPI_DSI1>, <&cru SCLK_MIPIDPHY_CFG>,
			<&cru SCLK_CIF_OUT>, <&cru SCLK_CIF_OUT>,
			<&cru SCLK_MIPIDPHY_REF>;
		clock-names =
			"aclk_isp1_noc", "aclk_isp1_wrapper",
			"hclk_isp1_noc", "hclk_isp1_wrapper",
			"clk_isp1", "pclkin_isp1",
			"pclk_dphytxrx",
			"pclk_mipi_dsi","mipi_dphy_cfg",
			"clk_cif_out", "clk_cif_pll",
			"pclk_dphy_ref";
		interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH 0>;
		interrupt-names = "cif_isp10_irq";
		power-domains = <&power RK3399_PD_ISP1>;
		rockchip,isp,iommu-enable = <1>;
		iommus = <&isp1_mmu>;
		status = "okay";
};
&cif_isp1 {		//cif_isp1指定了和camera4绑定(在上一篇《rk3399调试ov2659(camera模块@dvp接口)--移植过程》有介绍)
	rockchip,camera-modules-attached = <&camera4>;
	status = "okay";
};

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/133443.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(1)
blank

相关推荐

  • Oracle sqlplus 查询结果显示优化

    Oracle sqlplus 查询结果显示优化使用Oraclesqlplus进行查询时经常会碰到查询结果显示问题,字段和查询结果难以直接对应显示。这个是因为sqlplus的设置问题,在Windows环境下,可直接在查询窗口“右键-环境”,修改屏幕显示的缓冲区设置,将设置值调整到合适的值,确定即可。Linux环境下可直接设置环境变量setpagesizexxx;setlinesizexxx;修改显示的方式有很多…

  • activation code激活码【2021.10最新】「建议收藏」

    (activation code激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html…

  • 非主流免费播放器|免费QQ空间播放器代码|非主流播放器

    非主流免费播放器|免费QQ空间播放器代码|非主流播放器 script type=”text/javascript”>…google_ad_client = “pub-2372065995666058”;/**//* btttttttttttt */google_ad_slot = “7097305745”;google_ad_width = 468;google_ad_height = 15;//–>script>script type

  • JRebel插件使用详解

    JRebel插件使用详解简介JRebel是一套JavaEE开发工具。Jrebel可快速实现热部署,节省了大量重启时间,提高了个人开发效率。JRebel是一款JAVA虚拟机插件,它使得JAVA程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。JRebel使你能即时分别看到代码、类和资源的变化,你可以一个个地上传而不是一次性全部部署。当程序员在开发环境中对任何一个类或者资源作出修改的时候,这…

  • cutoff激活成功教程版下载_cutout

    cutoff激活成功教程版下载_cutout000000013F67F64|E831680500         |callcutout.13F6D5E80                  |000000013F67F64|4C8D0DCAF33C00   |lear9,qwordptrds:[13FA4EA20]        |;13FA4EA20:L”menuicon.png”

  • 矩阵特征值和特征向量详细计算过程(转载)_矩阵特征值的详细求法

    矩阵特征值和特征向量详细计算过程(转载)_矩阵特征值的详细求法1.矩阵特征值和特征向量定义        A为n阶矩阵,若数λ和n维非0列向量x满足Ax=λx,那么数λ称为A的特征值,x称为A的对应于特征值λ的特征向量。式Ax=λx也可写成(A-λE)x=0,并且|λE-A|叫做A的特征多项式。当特征多项式等于0的时候,称为A的特征方程,特征方程是一个齐次线性方程组,求解特征值的过程其实就是求解特征方程的解。 计算:A的特征值和特征向量。计算行列式得化简…

    2022年10月22日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号