Linux ARM平台开发系列讲解(摄像头V4L2子系统) 2.12.6 OV13850 v4l2_subdev注册匹配、摄像头出图测试和工具介绍

1. 概述

上章节讲到了 V4L2 control的原理和实现,主要是设置图像处理和一些电源管理,一般不带ISP摄像头设置完这些后就可以进行sbudev的注册了,注册完基本就完成了整个驱动,具体分析如下。

2. 开启ov13850摄像头

  • 源码下载请看摄像头第一章
  • 源码路径:drivers\media\i2c\ov13850.c
static int __ov13850_power_on(struct ov13850 *ov13850)
{
	int ret;
	u32 delay_us;
	struct device *dev = &ov13850->client->dev;
	struct i2c_client *client = ov13850->client;
	unsigned short addr;

	mutex_lock(&ov13850_power_mutex);
	/* 上电 */
	ret = __ov13850_master_power_on(dev);
	if (ret) {
		dev_err(dev, "could not power on, error %d\n", ret);
		goto err_power;
	}
	/* 等待启动 */
	usleep_range(500, 1000);
	if (!IS_ERR(ov13850->pwdn_gpio))
		gpiod_set_value_cansleep(ov13850->pwdn_gpio, 1);

	/* 8192 cycles prior to first SCCB transaction */
	delay_us = ov13850_cal_delay(8192);
	usleep_range(delay_us, delay_us * 2);

        /* Change i2c address by programming SCCB_ID */
	addr = client->addr;
	if (addr != OV13850_VENDOR_I2C_ADDR) {
		client->addr = OV13850_VENDOR_I2C_ADDR;
		ret = ov13850_write_reg(client, OV13850_REG_SCCB_ID,
					OV13850_REG_VALUE_08BIT,
					addr * 2);
		if (ret) {
			dev_err(dev, "write SCCB_ID failed\n");
			goto err_i2c_addr;
		}
		client->addr = addr;
	}

	mutex_unlock(&ov13850_power_mutex);
	return 0;

err_i2c_addr:
	if (!IS_ERR(ov13850->pwdn_gpio))
		gpiod_set_value_cansleep(ov13850->pwdn_gpio, 0);
	__ov13850_master_power_off(dev);
err_power:
	mutex_unlock(&ov13850_power_mutex);
	return ret;
}

3. 校验ov13850摄像头

一般摄像头都会有一个寄存器用来存放厂家ID,用户可以用此ID区分不同的摄像头,从而进行驱动分别适配,如ov13850厂家ID如下。
在这里插入图片描述

static int ov13850_check_sensor_id(struct ov13850 *ov13850,
				   struct i2c_client *client)
{
	struct device *dev = &ov13850->client->dev;
	u32 id = 0;
	int ret;

	ret = ov13850_read_reg(client, OV13850_REG_CHIP_ID,
			       OV13850_REG_VALUE_16BIT, &id);
	if (id != CHIP_ID) {
		dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
		return -ENODEV;
	}

	ret = ov13850_read_reg(client, OV13850_CHIP_REVISION_REG,
			       OV13850_REG_VALUE_08BIT, &id);
	if (ret) {
		dev_err(dev, "Read chip revision register error\n");
		return ret;
	}

	if (id == OV13850_R2A)
		ov13850_global_regs = ov13850_global_regs_r2a;
	else
		ov13850_global_regs = ov13850_global_regs_r1a;
	dev_info(dev, "Detected OV%06x sensor, REVISION 0x%x\n", CHIP_ID, id);

	return 0;
}

4. 注册subdev进入v4l2系统

可以看到,摄像头注册的最后一步v4l2_async_register_subdev_sensor_common就是将该设备注册进入v4l2,然后与v4l2_device进行匹配。

/* 注册subdev设备 */
ret = v4l2_async_register_subdev_sensor_common(sd);
if (ret) {
	dev_err(dev, "v4l2 async register subdev failed\n");
	goto err_clean_entity;
}

pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_idle(dev);

5. 摄像头出图测试

到这里OV13850摄像头驱动基本完成,源码可以到第一章节下载查看,接下来就去测试摄像头出图。

5.1 工具介绍及其安装

在第一章节介绍摄像头的时候就已经介绍过media-ctl 这款v4l2出图工具了,他是v4l-utils的一个子工具,现在看看如何安装。

  • Ubuntu安装方法
sudo apt-get install v4l-utils

5.2 media-ctl查看支持的图像格式

media-ctl --known-mbus-fmts

如下图,只是截取其中一部分格式,media-ctl工具基本支持市面上所有常见的格式
Linux ARM平台开发系列讲解(摄像头V4L2子系统) 2.12.6 OV13850 v4l2_subdev注册匹配、摄像头出图测试和工具介绍_第1张图片

5.3 Media-ctl: 拓扑结构(topology)

驱动如果有支持 Media Controller, 在 CIFISP 加载成功后会创建 media 设备, 如 /dev/media0。利用 media-ctl 可以打印出当前的 pipeline 的链接情况。如下面的信息,就是rk3399ov13850的链路拓扑结构。

root@firefly:/usr/local/bin# media-ctl -p /dev/media0
Media controller API version 0.1.0

Media device information
------------------------
driver          rkisp1
model           rkisp1
serial
bus info
hw revision     0x0
driver version  0.0.0

Device topology
- entity 1: rkisp1-isp-subdev (4 pads, 6 links)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev0
        pad0: Sink
                [fmt:SBGGR10_1X10/2112x1568 field:none
                 crop.bounds:(0,0)/2112x1568
                 crop:(0,0)/2112x1568]
                <- "rkisp1_dmapath":0 []
                <- "rockchip-mipi-dphy-rx":1 [ENABLED]
        pad1: Sink
                <- "rkisp1-input-params":0 [ENABLED]
        pad2: Source
                [fmt:YUYV8_2X8/2112x1568 field:none
                 crop.bounds:(0,0)/2112x1568
                 crop:(0,0)/2112x1568]
                -> "rkisp1_selfpath":0 [ENABLED]
                -> "rkisp1_mainpath":0 [ENABLED]
        pad3: Source
                -> "rkisp1-statistics":0 [ENABLED]

- entity 2: rkisp1_mainpath (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video0
        pad0: Sink
                <- "rkisp1-isp-subdev":2 [ENABLED]

- entity 3: rkisp1_selfpath (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video1
        pad0: Sink
                <- "rkisp1-isp-subdev":2 [ENABLED]

- entity 4: rkisp1_dmapath (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video2
        pad0: Source
                -> "rkisp1-isp-subdev":0 []

- entity 5: rkisp1-statistics (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video3
        pad0: Sink
                <- "rkisp1-isp-subdev":3 [ENABLED]

- entity 6: rkisp1-input-params (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video4
        pad0: Source
                -> "rkisp1-isp-subdev":1 [ENABLED]

- entity 7: rockchip-mipi-dphy-rx (2 pads, 2 links)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev1
        pad0: Sink
                [fmt:SBGGR10_1X10/2112x1568@10000/300000 field:none]
                <- "m00_b_ov13850 1-0036":0 [ENABLED]
        pad1: Source
                [fmt:SBGGR10_1X10/2112x1568@10000/300000 field:none]
                -> "rkisp1-isp-subdev":0 [ENABLED]

- entity 8: m00_b_ov13850 1-0036 (1 pad, 1 link)
            type V4L2 subdev subtype Sensor flags 0
            device node name /dev/v4l-subdev2
        pad0: Source
                [fmt:SBGGR10_1X10/2112x1568@10000/300000 field:none]
                -> "rockchip-mipi-dphy-rx":0 [ENABLED]

5.4 Media-ctl: entity、pad 及 link

EntityMedia Controller 中,表示一个节点。它包含一个或多个的输入输出 padsLink 表示一条链接,它连接多个不同的 pad。多个 Link 组成了一条完整的 pipeline

Entity 的名称可以从拓扑结构中查看,比如以下都是 entity 的名称:

  • ov2685 7-003c
  • rkisp1-isp-subdev
  • rkisp1_mainpath

Pad 由数字表示,一个 Entity 中可以包含多个 pad,既可以有 Source, 也可以有 SinkLink 连接两个”entity:pad,比如以下表示的链接,

  • rkisp1-isp-subdev:2->“rkisp1_mainpath:0
  • rkisp1-isp-subdev:3->“rkisp1-statistics:0
  • 链接的状态可以是 Active, 也可以是 In-Active

Media Controller 提供了灵活配置 pipeline 的功能, 在 CIFISP 驱动初始化过程中,会根 据配置,将 Link 完整建立起来,如果有多个 Sensor 会激活其中的一个。 用户可以使用 media-ctl 命令修改 LinkActive 状态,也可以修改 Padformatsize

5.5 Media-ctl:In-/Active Link

如图2 ISPCamera 拓扑结构,有多个 Sensor 连接到同一个 Mipi D-Phy, 同时只能有 一个是 Active 状态。以下示例设置 ov2659Active
Linux ARM平台开发系列讲解(摄像头V4L2子系统) 2.12.6 OV13850 v4l2_subdev注册匹配、摄像头出图测试和工具介绍_第2张图片

#首先将 ov5695 设置为 In-Active
media-ctl -l '"ov5695 7-0036":0->"rockchip-sy-mipi-dphy":0[0]' 
#再将 ov2685 设置为 Active 
media-ctl -l '"ov2685 7-003c":0->"rockchip-sy-mipi-dphy":0[1]'

注意:

  • 格式为:
media-ctl -l '"entity name":pad->"entity name":pad[Status]' 
  • 整个 link 需要用单引号,因为有特殊字符,如 > [ ]
  • Entity name 需要用双引号,因为中间有空格
  • Status01 表示 ActiveIn-Active,需要用中括号

5.6 Media-ctl:修改 fmt/size

如图 2 ISPCamera 拓扑结构,以下示例如何修改 fmt/size。 示例一,修改 ov5695 输出的 size640x480(前提是 ov5695 驱动中已经有支持 640x480 输出,否则设置不会成功),并设置整个 pipeline 的输入输出分辨率都为 640x480,同时 isp entityformatYUYV

  • 设置 Sensor 输出 640x480
media-ctl -d /dev/media0  --set-v4l2 '"ov5695 7-0036":0[fmt:SBGGR10_1X10/640x480]'
  • 设置 isp 的接收(从 mipi dphy)格式及大小,格式要求要与 Sensor 输出相同
media-ctl -d /dev/media0  --set-v4l2 '"rkisp1-isp-subdev":0[fmt:SBGGR10_1X10/640x480]'
  • isp 接收的大小可以 crop(裁剪),但这里还保持 640x480
media-ctl -d /dev/media0  --set-v4l2 '"rkisp1-isp-subdev":0[crop:(0,0)/640x480]'
  • 设置 isp 输出的,YUV 格式只能是 YUYV2X8
media-ctl -d /dev/media0  --set-v4l2 '"rkisp1-isp-subdev":2[fmt:YUYV8_2X8/640x480]'
  • isp 输出也有 crop 功能,但也保持 640x480
media-ctl -d /dev/media0  --set-v4l2 '"rkisp1-isp-subdev":2[crop:(0,0)/640x480]'

注意:

  • 不同版本的 v4l-utils 其对应的 fmt 代码可能不同,最好用 media-ctl 查看
  media-ctl --known-mbus-fmts
  • 注意特殊字符,需要使用单引号或双引号
  • 注意引号中不要少掉空格,也不要多出空格
  • 请使用 media-ctl --help,查看更详细的使用帮助

5.7 v4l2-ctl 设置 fmt、controls 及抓帧

Media-ctl 工具的操作是通过/dev/medio0media 设备,它所管理是 Media 的拓扑结构中 各个节点的 format,大小,链接。V4l2-ctl 工具则是针对/dev/video0/dev/video1video 设备,它在 video 设备上进行 set_fmtreqbufqbufdqbufstream_onstream_off 等一 系列操作。

本文中主要用 v4l2-ctl 进行采集帧数据,设置曝光、gainVTSv4l2_control
首先还是要建议先查看 v4l2-ctl 的帮助文档。帮助文档内容比较多,分成很多个部分,我们比 较关心,streamingvidcap

  • 查看v4l2-ctl 帮助介绍
v4l2-ctl --help
  • 查看完整的帮助文档如下,内容很多。
v4l2-ctl --help-all
  • 查看与 streaming 相关的参数如下
v4l2-ctl --help-streaming
  • 查看与 vidcap 相关的参数如下。它主要包括 get-fmtset-fmt
v4l2-ctl --help-vidcap

5.7.1 设置 fmt 并抓帧

示例一,在 px3se-evb 板上,抓取 1nv12 数据保存到/tmp/cif.out,分辨率为 720x480; 在抓帧保存数据前,先丢弃前面 3 帧(即前面 3 帧虽然返回给 userspace,但不保存到文件)。

v4l2-ctl -d /dev/video0 \
--set-fmt-video=width=720,height=480,pixelformat=NV12 \
--stream-mmap=3 \ 
--stream-skip=3 \
--stream-to=/tmp/cif.out \ 
--stream-count=1 \ 
--stream-poll
v4l2-ctl -d /dev/video0 --set-fmt-video=width=720,height=480,pixelformat=NV12 --stream-mmap=3  --stream-skip=3 --stream-to=/tmp/cif.out --stream-count=1 --stream-poll

参数的说明:

  • -d,指定操作对象为/dev/video0 设备。

  • --set-fmt-video,指定了宽高及 pxielformat

  • NV12,即用 FourCC 表示的 pixelformatFourCC 编码详见上文 FourCC

  • --stream-mmap,指定 buffer 的类型为 mmap,即由 kernel 分配的物理连续的或经过iommu 映射的 buffer

  • --stream-skip,指定丢弃(不保存到文件)前 3

  • --stream-to,指定帧数据保存的文件路径

  • --stream-count,指定抓取的帧数, 不包括--stream-skip 丢弃的数量

  • --stream-poll,该选项指示 v4l2-ctl 采用异步 IO,即在 dqbuf 前先用 select 等等帧数据完 成,从而保证 dqbuf 不阻塞。否则 dqbuf 将会阻塞直到有数据帧到来。

  • 实际操作 如下图<<<<<就是输出的帧
    在这里插入图片描述

5.7.1 设置曝光、gain 等 control

如果 sensor 驱动有实现 v4l2 control,在采集图像前, 可以通过 v4l2-ctl 设置如曝光、gainv4l2 controlCIFISP 会继承 sub device 的 control,因此这里通过/dev/video0 可以看到 Sensorv4l2 control。如下是 RK3399 机子上查看到的 OV13850 的相关设置,包括 exposuregainblankingtest_pattern 等。

v4l2-ctl -d /dev/video0 -l
root@firefly:/home/firefly/driver_module# v4l2-ctl -d /dev/video0 -l

User Controls

                       exposure 0x00980911 (int)    : min=4 max=1660 step=1 default=1536 value=1536

Image Source Controls

              vertical_blanking 0x009e0901 (int)    : min=96 max=31199 step=1 default=96 value=96
            horizontal_blanking 0x009e0902 (int)    : min=2688 max=2688 step=1 default=2688 value=2688 flags=read-only
                  analogue_gain 0x009e0903 (int)    : min=16 max=248 step=1 default=16 value=16

Image Processing Controls

                 link_frequency 0x009f0901 (intmenu): min=0 max=0 default=0 value=0 flags=read-only
                     pixel_rate 0x009f0902 (int64)  : min=0 max=120000000 step=1 default=120000000 value=120000000 flags=read-only
                   test_pattern 0x009f0903 (menu)   : min=0 max=4 default=0 value=0

  • v4l2-ctl 可以修改这些 control。如修改 exposureanalogue_gain 如下。
v4l2-ctl -d /dev/video0 --set-ctrl 'exposure=1216,analogue_gain=10'

注意:

  • 有特殊字符需要用单引号
  • V4l2-ctl 存在 bug,如多个 Camera 连到同一个 ISP,只有查看、修改第一个 sensorcontrol

至此,关于摄像头OV13850 驱动已经讲解完毕,后续还会深入v4l2专题,这专题只需要大概了解摄像头的一些开发流程和框架,再后续可能会继续深入。

返回总目录

你可能感兴趣的