基于 Android9.0 的 i.MX8 + TI964 + OV10635 四路摄像头显示 Hands on

一、基本介绍

1. 硬件环境介绍

  i.MX8 四路摄像头显示硬件环境主要包含如下几个部分:

  1. i.MX8QMMEK Demo Board
  2. DS90UB964 EVM
  3. OV10635 x 4
  4. HDMI 显示屏

 

 

2. 软件环境介绍

  i.MX8 四路摄像头显示软件环境主要包含如下几个部分:

  1. i. MX8 Android SDK 源码包:imx-p9.0.0_2.1.0-auto-ga
  2. TI964 驱动代码文件:ds90ub964.c
  3. 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

 

 

四、 测试环境搭建

 

搭建步骤如下:

① 连接好 i.MX8 开发板:供电、download、debug
② 将四路摄像头接入 DS90UB964 EVM Board
③ 通过转接板将 DS90UB964 EVM Board 接到 i.MX8 开发板 CSI0 口
④ 将显示屏 HDMI 线连接至 i.MX8 开发板 HDMI_TX 口
⑤ 将镜像文件烧录进 i.MX8 开发板(烧录过程可参考文档:i.MX8QM - Auto - Android hands on_Pual Lin_20190508)
⑥ 启动开发板
⑦ 通过 ADB 命令 将测试文件 mx8_v4l2_cap_drm_64 发送到开发板系统:




自此,测试环境已搭建完成。

 

 

 

五、 四路摄像头测试


① 启动开发板后,可以通过 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(显示四路)

 



★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论