一、基本介绍
1. 硬件环境介绍
i.MX8 四路摄像头显示硬件环境主要包含如下几个部分:
- i.MX8QMMEK Demo Board
- DS90UB964 EVM
- OV10635 x 4
- HDMI 显示屏
2. 软件环境介绍
i.MX8 四路摄像头显示软件环境主要包含如下几个部分:- i. MX8 Android SDK 源码包:imx-p9.0.0_2.1.0-auto-ga
- TI964 驱动代码文件:ds90ub964.c
- MX V4L2 应用程序测试代码文件:mx8_v4l2_cap_drm.c、Makefile、Android.mk
注:i.MX8 Android 软件环境搭建可参考文档 i.MX8QM - Auto - Android hands on_Pual Lin_20190508,这里不再赘述。
二、 驱动代码移植
i.MX8 Android SDK 中使用的 Camera 为 Max9286,我们可以在此基础上进行驱动代码的移植。首先找到 max9286.c 所在目录为:kernel_imx\drivers\media\platform\imx8 ,然后将代码中所有关于 max9286 的命名替换为 ds90ub964。找到 probe 函数 ds90ub964_probe,修改初始化配置代码,将所有 I2C 读写函数注释,修改 ds90ub964_hardware_preinit 函数如下:
static int ds90ub964_hardware_preinit(struct sensor_data *ds90ub964_data)
{
//u8 reg;
printk("ds90ub964_hardware_preinit\r\n");
dev_info(&ds90ub964_data->i2c_client->dev, "In %s()\n", __func__);
/*i.MX8 ov10635 四路摄像头*/
ds90ub964_write_reg(ds90ub964_data, 0x32, 0x01);//CSI0 select
ds90ub964_write_reg(ds90ub964_data, 0x1f, 0x02);//CSI_TX_SPEED 800M
ds90ub964_write_reg(ds90ub964_data, 0x33, 0x01);//Enable CSI output & 4 lanes
ds90ub964_write_reg(ds90ub964_data, 0x20, 0xe0);// RX Port 0 Forwarding enabled
ds90ub964_write_reg(ds90ub964_data, 0x4c, 0x01);// RX port 0 Write Enable
ds90ub964_write_reg(ds90ub964_data, 0x58, 0x58);//Enabled Pass-Through to Serializer & enabled Back channel
ds90ub964_write_reg(ds90ub964_data, 0x5c, 0xb0);//7-bit Remote Serializer Alias ID (0x58) 913 虚拟地址
ds90ub964_write_reg(ds90ub964_data, 0x5d, 0x60);//7-bit Remote Slave Device ID 0 (0x30) 10635 物理地址
ds90ub964_write_reg(ds90ub964_data, 0x65, 0x60);//7-bit Remote Slave Device Alias ID 0 (0x30) 10635 虚拟地址
ds90ub964_write_reg(ds90ub964_data, 0x7c, 0x01);//Normal Raw10 Mode & FrameValid Polarity is low
ds90ub964_write_reg(ds90ub964_data, 0x70, 0x1f);//RAW10_datatype_yuv422b10_VC0
ds90ub964_write_reg(ds90ub964_data, 0x6d, 0x7f);//Discard truncated 1st video line & Coax mode & RAW10 Mode
ds90ub964_write_reg(ds90ub964_data, 0x32, 0x01);
ds90ub964_write_reg(ds90ub964_data, 0x1f, 0x02);
ds90ub964_write_reg(ds90ub964_data, 0x33, 0x01);
ds90ub964_write_reg(ds90ub964_data, 0x20, 0xd0);//0xd0
ds90ub964_write_reg(ds90ub964_data, 0x4c, 0x12);//0x12
ds90ub964_write_reg(ds90ub964_data, 0x58, 0x58);
ds90ub964_write_reg(ds90ub964_data, 0x5c, 0xb0);
ds90ub964_write_reg(ds90ub964_data, 0x5d, 0x60);
ds90ub964_write_reg(ds90ub964_data, 0x65, 0x60);
ds90ub964_write_reg(ds90ub964_data, 0x7c, 0x01);
ds90ub964_write_reg(ds90ub964_data, 0x70, 0x5f);//0x5f
ds90ub964_write_reg(ds90ub964_data, 0x6d, 0x7f);
ds90ub964_write_reg(ds90ub964_data, 0x32, 0x01);
ds90ub964_write_reg(ds90ub964_data, 0x1f, 0x02);
ds90ub964_write_reg(ds90ub964_data, 0x33, 0x01);
ds90ub964_write_reg(ds90ub964_data, 0x20, 0xb0);//0xb0
ds90ub964_write_reg(ds90ub964_data, 0x4c, 0x24);//0x24
ds90ub964_write_reg(ds90ub964_data, 0x58, 0x58);
ds90ub964_write_reg(ds90ub964_data, 0x5c, 0xb0);
ds90ub964_write_reg(ds90ub964_data, 0x5d, 0x60);
ds90ub964_write_reg(ds90ub964_data, 0x65, 0x60);
ds90ub964_write_reg(ds90ub964_data, 0x7c, 0x01);
ds90ub964_write_reg(ds90ub964_data, 0x70, 0x9f);//0x9f
ds90ub964_write_reg(ds90ub964_data, 0x6d, 0x7f);
ds90ub964_write_reg(ds90ub964_data, 0x32, 0x01);
ds90ub964_write_reg(ds90ub964_data, 0x1f, 0x02);
ds90ub964_write_reg(ds90ub964_data, 0x33, 0x01);
ds90ub964_write_reg(ds90ub964_data, 0x20, 0x70);//0x70
ds90ub964_write_reg(ds90ub964_data, 0x4c, 0x38);//0x38
ds90ub964_write_reg(ds90ub964_data, 0x58, 0x58);
ds90ub964_write_reg(ds90ub964_data, 0x5c, 0xb0);
ds90ub964_write_reg(ds90ub964_data, 0x5d, 0x60);
ds90ub964_write_reg(ds90ub964_data, 0x65, 0x60);
ds90ub964_write_reg(ds90ub964_data, 0x7c, 0x01);
ds90ub964_write_reg(ds90ub964_data, 0x70, 0xdf);//0xdf
ds90ub964_write_reg(ds90ub964_data, 0x6d, 0x7f);
ds90ub964_write_reg(ds90ub964_data, 0x21, 0x01);// Synchronized Basic_FWD *0x14
ds90ub964_write_reg(ds90ub964_data, 0x20, 0x00);//RX Port 0~4 Forwarding enabled *0x00
ds90ub964_write_reg(ds90ub964_data, 0x4c, 0x01);//RX0
ds90ub964_write_reg(ds90ub964_data, 0x6e, 0xa0);//BC_GPIO_CTL0: FrameSync signal to GPIO1
ds90ub964_write_reg(ds90ub964_data, 0x4c, 0x12);//RX1
ds90ub964_write_reg(ds90ub964_data, 0x6e, 0xa0);//BC_GPIO_CTL0: FrameSync signal to GPIO1
ds90ub964_write_reg(ds90ub964_data, 0x4c, 0x24);//RX2
ds90ub964_write_reg(ds90ub964_data, 0x6e, 0xa0);//BC_GPIO_CTL0: FrameSync signal to GPIO1
ds90ub964_write_reg(ds90ub964_data, 0x4c, 0x38);//RX3
ds90ub964_write_reg(ds90ub964_data, 0x6e, 0xa0);//BC_GPIO_CTL0: FrameSync signal to GPIO1
ds90ub964_write_reg(ds90ub964_data, 0x19, 0x02);//FS_HIGH_TIME_1 : 02
ds90ub964_write_reg(ds90ub964_data, 0x1a, 0x2c);//FS_HIGH_TIME_0 : 15
ds90ub964_write_reg(ds90ub964_data, 0x1b, 0x08);//FS_LOW_TIME_1 : 08
ds90ub964_write_reg(ds90ub964_data, 0x1c, 0xae);//FS_LOW_TIME_0 : c4
ds90ub964_write_reg(ds90ub964_data, 0x18, 0x01);//Enable FrameSync
msleep(100);
return 0;
}
修改 ov10635_initialize 函数如下:
static int ov10635_initialize (struct sensor_data *ds90ub964_data, int index)
{
int i, array_size;
int retval;
uint16_t l16bReg = 0x0000;
printk("ov9716_initialize\r\n");
dev_info(&ds90ub964_data->i2c_client->dev, "%s: index = %d.\n", __func__, index);
array_size = ARRAY_SIZE(ov9716_init_data);
for (i = 0; i < array_size; i++) {
l16bReg = ( ov9716_init_data[i].reg_addr_h<< 8 ) + ov9716_init_data[i].reg_addr_l;
retval = ov9716_write_reg(ds90ub964_data, index,
l16bReg, ov9716_init_data[i].val);
if (retval < 0)
break;
if (ov9716_init_data[i].delay_ms != 0)
msleep(ov9716_init_data[i].delay_ms);
}
return 0;
}
修改 sensor 配置表如下(参考 ds90ub964.c):
static struct reg_value ov10635_init_data[] = {
{0x30,0x0C, 0x61,0},
{0x30,0x0C, 0x61,0},
{0x30,0x0C, 0x61,0},
{0x30,0x0C, 0x61,0},
{0x30,0x0C, 0x61,0},
{0x30,0x0C, 0x61,0},
{0x30,0x0C, 0x61,0},
{0x30,0x0C, 0x61,0},
{0x30,0x0C, 0x61,0},
{0x30,0x0C, 0x61,0},
{0x30,0x0C, 0x61,0},
/*省略部分代码*/
{0xC4,0xB1, 0x02,0},
{0xC4,0xB2, 0x01,0},
{0xC4,0xB3, 0x03,0},
{0x6F,0x00, 0x03,0},
{0x6F,0x00, 0x43,0},
{0x38,0x32, 0x01,0},
{0x38,0x33, 0x1a,0},
{0x38,0x34, 0x03,0},
{0x38,0x35, 0x48,0},
{0x30,0x2E, 0x01,0},
};
完成 TI964 及 OV10635 的寄存器配置之后,还需要修改同一级目录下的 Makefile 及 Kconfig 文件,添加内容如下 ;
Makefile:
ds90ub964_ti-objs := ds90ub964.o
obj-$(CONFIG_TI_DS90UB964) += ds90ub964_ti.o
Kconfig:
config TI_DS90UB964
tristate "DS90UB964 Versatile Camera Hub Driver Input support"
select SENSOR_OV9716
depends on I2C
---help---
If you plan to use the DS90UB964 Versatile Camera Hub with your capture system, say Y here.
DTS 文件配置,打开文件 fsl-imx8qm-mek.dtsi,所在目录为:kernel_imx\arch\arm64\boot\dts\freescale
修改 mipi_csi_0 节点内容如下:
&mipi_csi_0 {
#address-cells = <1>;
#size-cells = <0>;
virtual-channel;
status = "okay";
/* Camera 0 MIPI CSI-2 (CSIS0) */
port@0 {
reg = <0>;
mipi_csi0_ep: endpoint {
remote-endpoint = <&ds90ub964_0_ep>;
data-lanes = <1 2 3 4>;
};
};
};
修改 i2c0_mipi_csi0 节点内容如下:
&i2c0_mipi_csi0 {
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <100000>;
status = "okay";
ds90ub964_mipi@3d {
compatible = "ti,ds90ub964_mipi";
reg = <0x3d>;
clocks = <&clk IMX8QM_CLK_DUMMY>;
clock-names = "capture_mclk";
mclk = <27000000>;
mclk_source = <0>;
pwn-gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>;
virtual-channel;
status = "okay";
port {
ds90ub964_0_ep: endpoint {
remote-endpoint = <&mipi_csi0_ep>;
data-lanes = <1 2 3 4>;
};
};
};
};
三、 应用程序编译
完成驱动程序的移植后,还需要通过应用程序进行测试,NXP 官方有提供一份专门用于 i.MX Camera 测试的代码,下载链接如下:https://source.codeaurora.org/external/imx/imx-test/tree/test/mxc_v4l2_test?h=imx_4.14.98_2.0.0_ga
我们这里只需要用到 mx8_v4l2_cap_drm.c、Makefile、Android.mk,
将这三个文件移入 SDK 文件目录(新建): imx-p9.0.0_2.1.0-auto-ga/android_build/external/mxc_v4l2_test,
进入到该目录,执行 mm 命令编译(编译前需要先在 android_build 目录下执行 source build/envsetup.sh 设置好编译环境),编译后生成可执行文件 mx8_v4l2_cap_drm_64,
所在目录为:imx-p9.0.0_2.1.0-auto-ga/android_build/out/target/product/mek_8q/vendor/bin
四、 测试环境搭建
搭建步骤如下:
自此,测试环境已搭建完成。
五、 四路摄像头测试
① 启动开发板后,可以通过 debug 口接收串口信息,执行 su 命令开启权限:su
② 关闭 kernel log 输出,只输出 应用层 信息:echo 0 >/proc/sys/kernel/printk
③ 进入测试程序所在目录:cd data/pual
④ 修改 mx8_v4l2_cap_drm_64 测试程序执行权限: chmod 777 mx8_v4l2_cap_drm_64
⑤ 查看帮助信息,执行命令:./mx8_v4l2_cap_drm_64
⑥ 显示第一路摄像头,执行命令:./mx8_v4l2_cap_drm_64 -cam 1 -d /dev/video0。出现如下提示,当前显示屏线程被 Android 系统占用,无法打开
⑦ 使用 kill 命令关闭Android 系统显示屏线程:kill -s 9 3329
⑧ 再次执行命令:./mx8_v4l2_cap_drm_64 -cam 1 -d /dev/video0
⑨ 显示画面如下:
⑩ 修改 video 编号可以分别切换四路摄像头单独显示,可选为 0 1 2 3
测试多路摄像头同时显示,执行命令:./mx8_v4l2_cap_drm_64 -cam 3(显示两路)
./mx8_v4l2_cap_drm_64 -cam 7(显示三路)
./mx8_v4l2_cap_drm_64 -cam 15(显示四路)
评论