Mipi: 当前主要使用的摄像头接口,速度快,抗干扰强。Lvds:个别 摄像头 mipi 接口接收不了,所以使用 lvds 接口Dvp: 相对 mipi 接口,传输的速率有限,一般 5M 或以下摄像头。
ov426: ov426@36 {
status = "okay";
compatible = "ovti,ov426";
reg = <0x36>;
clocks = <&cru CLK_CIF_OUT>;
clock-names = "xvclk";
avdd-supply = <&vcc_avdd>;
dovdd-supply = <&vcc_dovdd>;
dvdd-supply = <&vcc_dvdd>;
power-domains = <&power RV1126_PD_VI>;
pwdn-gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_LOW>;
//pwdn-gpios = <&gpio2 RK_PA6 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>;
//rockchip,grf = <&grf>;
pinctrl-names = "default";
pinctrl-0 = <&cifm0_dvp_ctl>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "default";
rockchip,camera-module-lens-name = "default";
port {
cam_para_out1: endpoint {
remote-endpoint = <&cif_para_in>;
bus-width = <10>;
hsync-active = <1>;
vsync-active = <0>;
};
};
};
调单个摄像头的时候,建议就按照这个来改,这是标准 i2c 设备,定义在 i2c 的节点下面,前面的一大串如果原理图没怎么变的话,都一样就行,当然 i2c 的地址要注意。如果摄像头 lane 数有变,在后面的 port 里面有 data-lane 这个参数,都配置成一 样的。
1.rockchip,camera-module-index: 这个定义多个摄像头时候做个区分2.rockchip,camera-module-facing : 摄像头前后置标识3.rockchip,camera-module-name :摄像头模块名4.rockchip,camera-module-lens-name :摄像头镜头名主要功能是通过关键字找对应的效果文件。比如当前 dts 找的 xml 文件为default_default.xml ,对于 yuv 摄像头不需要 xml ,可以不管这个配置。5.Ir-cut 是红外滤光片,我这里没配置,就删掉了6.Port 是根据摄像头在内部的级联关系 默认的关系是sensor0->csi_dphy0->csi2->vicap->isp0->ispp0sensor0->csi_dphy0->csi2->vicap->isp1->ispp1sensor1->csi_dphy1->isp0->ispp0
如果是DVP摄像头时
对应的数据链路
static const struct ov426_mode supported_modes[] = {
{
/* linear mode0 */
.bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10,
.width = 400,
.height = 400,
.max_fps = {
.numerator = 10000,
.denominator = 300000,
},
.exp_def = 0x01a0,
.hts_def = 0x0240,
.vts_def = 0x01ce,
.reg_list = ov426_linear10bit_400x400_regs,
.hdr_mode = NO_HDR,
},
{
/* linear mode1 */
.bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10,
.width = 400,
.height = 400,
.max_fps = {
.numerator = 10000,
.denominator = 300000,
},
.exp_def = 0x01a0,
.hts_def = 0x0240,
.vts_def = 0x01ce,
.reg_list = ov426_color_400x400_regs,
.hdr_mode = NO_HDR,
}
};
#define OV426_CHIP_ID 0x694F
#define OV426_REG_CHIP_ID 0x300A
static int probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct ov426 *ov426;
struct v4l2_subdev *sd;
char facing[2];
int ret;
dev_info(dev, " driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
ov426 = devm_kzalloc(dev, sizeof(*ov426), GFP_KERNEL);
printk("devm_kzalloc ok");
if (!ov426)
return -ENOMEM;
ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
&ov426->module_index);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
&ov426->module_facing);
ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
&ov426->module_name);
ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
&ov426->len_name);
ov426->cfg_num = ARRAY_SIZE(supported_modes);
ov426->cur_mode = &supported_modes[0];
printk("Current mode: %d\n",mode);
ov426->client = client;
ov426->xvclk = devm_clk_get(dev, "xvclk");
ov426->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
ov426->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_HIGH);
ret = ov426_configure_regulators(ov426);
mutex_init(&ov426->mutex);
sd = &ov426->subdev;
v4l2_i2c_subdev_init(sd, client, &ov426_subdev_ops);
ret = ov426_initialize_controls(ov426);
ret = __ov426_power_on(ov426);
ret = ov426_check_sensor_id(ov426, client);
printk("check id ok");
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sd->internal_ops = &ov426_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)
ov426->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &ov426->pad);
if (ret < 0)
goto err_power_off;
#endif
memset(facing, 0, sizeof(facing));
if (strcmp(ov426->module_facing, "back") == 0)
facing[0] = 'b';
else
facing[0] = 'f';
snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
ov426->module_index, facing,
OV426_NAME, dev_name(sd->dev));
printk("sd->name: %s\n", sd->name);
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);
return ret;
}
主要是进行设备的初始化设置和配置。
驱动编译好之后,烧入就可以尝试抓图了。
media-ctl 工具查看节点链路:media-ctl -p -d /dev/mediaX
1.抓原图(RAW)
通过如下命令可以实现紧凑与非紧凑格式的切换,0表示非紧凑型,1表示紧凑型;
echo 0 > /sys/devices/platform/rkcif_dvp/compact_test
echo 0 > /sys/devices/platform/rkcif_dvp/align_test
抓图命令:
v4l2-ctl -d /dev/video0 --set-fmt-video=width=400,height=400,pixelformat=BG10 --stream-mmap=4 --stream-count=1 --stream-to=/data/BG10.raw --stream-skip=2
具体含义如下:
-d /dev/video0:指定要配置和采集的视频设备为/dev/video0。
--set-fmt-video=width=400,height=400,pixelformat=BG10:设置视频格式为宽度为400,高度为400,像素格式为BG10。
--stream-mmap=4:使用mmap内存映射方式进行视频采集,缓冲区数量为4。
--stream-count=1:采集一帧视频数据。
--stream-to=/data/BG10.raw:将采集到的视频数据保存为文件/data/BG10.raw。
--stream-skip=2:跳过前两个采集缓冲区。
2.抓YUV图
抓图命令
v4l2-ctl -d /dev/video18 --set-fmt-video=width=400,height=400,pixelformat=NV12 --stream-mmap=4 --stream-count=1 --stream-to=/data/NV12.out --stream-skip=2
具体含义如下:
-d /dev/video18:指定要配置和采集的视频设备为/dev/video18。
--set-fmt-video=width=400,height=400,pixelformat=NV12:设置视频格式为宽度为400,高度为400,像素格式为NV12。
--stream-mmap=4:使用mmap内存映射方式进行视频采集,缓冲区数量为4。
--stream-count=1:采集一帧视频数据。
--stream-to=/data/NV12.out:将采集到的视频数据保存为文件/data/NV12.out。
--stream-skip=2:跳过前两个采集缓冲区。