基于 NXP i.MX8QM Bumblebee 智能座舱 DMS(DS90UB933 + OV9284 )摄像头调试

一. 方案介绍:

 i.MX8QM + DS90UB964 + (DS90UB933 + OV9284 )摄像头模组,OV9284 摄像头模组是一颗支持红外功能,输出黑白图像的摄像头模组,

他的分辨率为 1280 X 800 ,采集的数据主要用来做 DMS 算法 



二. 摄像头调试环境

2.1.  软件环境 :

使用的是 IMX-Yocto_L4.14.98_0.0.0 

2.2.  硬件环境 :

Bumblebee-MB_V1.0(i.MX8QM 智能座舱 )


                                                         图1 Bumblebee-MB_V1.0

三. 实现 Serdes 数据通信

通过 i2cdetect 工具检查不到 DS90UB964 这个设备 ,通过电路图发现 :需要首先使能 CSI1_VDD_1V8 ,CSI1_VDD_1V1 这两个电平

                                                                                         图2 DS90UB964 上电引脚


CSI1_VDD_1V8 对应的  i.MX8QM 芯片引脚是 ESAI1_TX2_RX3,CSI1_VDD_1V1 对应的  i.MX8QM 芯片引脚是 ESAI1_TX1


                                             图3 i.MX8QM 芯片引脚图


在进行了以上操作后 ,通过 i2cdetect 工具 可以识别到 DS90UB964  这个设备

从下图可以知道 DS90UB964 的设备地址为 0x30


                                            图4 DS90UB964 设备地址检测

四.  驱动程序编写

4.1 摄像头驱动程序移植

关于驱动程序的移植 ,可以参考 kernel_imx8\drivers\media\platform\imx8\ov5640_v3.c  ,我把初始化 DS90UB964 和 OV9284 的参数贴出来

DS90UB964 初始化参数 :

+++static struct reg_value ti964_init_setting[] = {               
+    {0x32, 0x01, 0, 0}, 
+    {0x1f, 0x02, 0, 0}, 
+    {0x33, 0x01, 0, 0}, 
+    {0x20, 0xe0, 0, 0},
+    {0x4c, 0x01, 0, 0},  // 0x01+    {0x58, 0x58, 0, 0}, 
+    {0x5c, 0xb2, 0, 0},  // 0xb4+    {0x5d, 0xc0, 0, 0},  // 0x20
+    {0x65, 0xc0, 0, 0}, // 0x20+    {0x7c, 0x01, 0, 0}, // 0x01
+    {0x70, 0x2b, 0, 0},  //{0x71, 0x2c, 0, 0}, 
+    {0x6d, 0x7f, 0, 0}, // 0x7e+ {0x20, 0xe0, 0, 0},  // enable Mipi csi 0
+    {0x23, 0x81, 0, 0},
++#ifdef TI964_PATTERN_GENERATOR
+    {0x32, 0x01, 0, 0}, {0x33, 0x01, 0, 0}, {0xb0, 0x00, 0, 0},
+    {0xb1, 0x01, 0, 0}, {0xb2, 0x01, 0, 0},
+    {0xb1, 0x02, 0, 0}, {0xb2, 0x33, 0, 0},
+    {0xb1, 0x03, 0, 0}, {0xb2, 0x24, 0, 0},
+    {0xb1, 0x04, 0, 0}, {0xb2, 0x0f, 0, 0},
+    {0xb1, 0x05, 0, 0}, {0xb2, 0x00, 0, 0},
+    {0xb1, 0x06, 0, 0}, {0xb2, 0x01, 0, 0},
+    {0xb1, 0x07, 0, 0}, {0xb2, 0xe0, 0, 0},
+    {0xb1, 0x08, 0, 0}, {0xb2, 0x02, 0, 0},
+    {0xb1, 0x09, 0, 0}, {0xb2, 0xd0, 0, 0},
+    {0xb1, 0x0a, 0, 0}, {0xb2, 0x04, 0, 0},
+    {0xb1, 0x0b, 0, 0}, {0xb2, 0x1a, 0, 0},
+    {0xb1, 0x0c, 0, 0}, {0xb2, 0x0c, 0, 0},
+    {0xb1, 0x0d, 0, 0}, {0xb2, 0x67, 0, 0},
+    {0xb1, 0x0e, 0, 0}, {0xb2, 0x21, 0, 0},
+    {0xb1, 0x0f, 0, 0}, {0xb2, 0x0a, 0, 0},
+#endif+};
+


OV9284 初始化参数 :

+static struct reg_value ov9284_init_data[] = {
+{0x0103, 0x01,0,0},
+{0x0302, 0x30,0,0},
+{0x030d, 0x60,0,0},
+{0x030e, 0x06,0,0},
+{0x3001, 0x62,0,0},
+{0x3004, 0x01,0,0},
+{0x3005, 0xff,0,0},
+{0x3006, 0xe2,0,0},
+{0x3011, 0x0a,0,0},
+{0x3013, 0x18,0,0},
+{0x301c, 0xf0,0,0},
+{0x3022, 0x07,0,0},
+{0x3030, 0x10,0,0},
+{0x3039, 0x2e,0,0},
+{0x303a, 0xf0,0,0},
+{0x3500, 0x00,0,0},
+{0x3501, 0x2a,0,0},
+{0x3502, 0x90,0,0},
+{0x3503, 0x08,0,0},
+{0x3505, 0x8c,0,0},
+{0x3507, 0x03,0,0},
+{0x3508, 0x00,0,0},
+{0x3509, 0x10,0,0},
+{0x3610, 0x80,0,0},
+{0x3611, 0xa0,0,0},
+{0x3620, 0x6e,0,0},
+{0x3632, 0x56,0,0},
+{0x3633, 0x78,0,0},
+{0x3662, 0x05,0,0},
+{0x3666, 0x5a,0,0},
+{0x366f, 0x7e,0,0},
+{0x3680, 0x84,0,0},
+{0x3712, 0x80,0,0},
+{0x372d, 0x22,0,0},
+{0x3731, 0x80,0,0},
+{0x3732, 0x30,0,0},
+{0x3778, 0x00,0,0},
+{0x377d, 0x22,0,0},
+{0x3788, 0x02,0,0},
+{0x3789, 0xa4,0,0},
+{0x378a, 0x00,0,0},
+{0x378b, 0x4a,0,0},
+{0x3799, 0x20,0,0},
+{0x3800, 0x00,0,0},
+{0x3801, 0x00,0,0},
+{0x3802, 0x00,0,0},
+{0x3803, 0x00,0,0},
+{0x3804, 0x05,0,0},
+{0x3805, 0x0f,0,0},
+{0x3806, 0x03,0,0},
+{0x3807, 0x2f,0,0},
+{0x3808, 0x05,0,0},
+{0x3809, 0x00,0,0},
+{0x380a, 0x03,0,0},
+{0x380b, 0x20,0,0},
+{0x380c, 0x03,0,0},
+{0x380d, 0x6b,0,0},
+{0x380e, 0x05,0,0},
+{0x380f, 0x5c,0,0},
+{0x3810, 0x00,0,0},
+{0x3811, 0x08,0,0},
+{0x3812, 0x00,0,0},
+{0x3813, 0x08,0,0},
+{0x3814, 0x11,0,0},
+{0x3815, 0x11,0,0},
+{0x3820, 0x40,0,0},
+{0x3821, 0x00,0,0},
+{0x382c, 0x05,0,0},
+{0x382d, 0xb0,0,0},
+{0x389d, 0x00,0,0},
+{0x3881, 0x42,0,0},
+{0x3882, 0x01,0,0},
+{0x3883, 0x00,0,0},
+{0x3885, 0x02,0,0},
+{0x38a8, 0x02,0,0},
+{0x38a9, 0x80,0,0},
+{0x38b1, 0x00,0,0},
+{0x38b3, 0x02,0,0},
+{0x38c4, 0x00,0,0},
+{0x38c5, 0xc0,0,0},
+{0x38c6, 0x04,0,0},
+{0x38c7, 0x80,0,0},
+{0x3920, 0xff,0,0},
+{0x4003, 0x40,0,0},
+{0x4008, 0x04,0,0},
+{0x4009, 0x0b,0,0},
+{0x400c, 0x00,0,0},
+{0x400d, 0x07,0,0},
+{0x4010, 0x40,0,0},
+{0x4043, 0x40,0,0},
+{0x4307, 0x30,0,0},
+{0x4317, 0x01,0,0},
+{0x4501, 0x00,0,0},
+{0x4507, 0x00,0,0},
+{0x4509, 0x00,0,0},
+{0x450a, 0x08,0,0},
+{0x4601, 0x04,0,0},
+{0x470f, 0xe0,0,0},
+{0x4f07, 0x00,0,0},
+{0x4800, 0x00,0,0},
+{0x5000, 0x9f,0,0},
+{0x5001, 0x00,0,0},
+{0x5e00, 0x00,0,0},
+{0x5d00, 0x0b,0,0},
+{0x5d01, 0x02,0,0},
+{0x4837, 0x1c,0,0},
+{0x3006, 0xea,0,0},
+{0x3210, 0x04,0,0},
+{0x3007, 0x02,0,0},
+{0x301c, 0xf0,0,0},
+{0x3020, 0x20,0,0},
+{0x3025, 0x02,0,0},
+{0x3920, 0xff,0,0},
+{0x3923, 0x00,0,0},
+{0x3924, 0x00,0,0},
+{0x3925, 0x00,0,0},
+{0x3926, 0x00,0,0},
+{0x392b, 0x00,0,0},
+{0x392c, 0x00,0,0},
+{0x392d, 0x02,0,0},
+{0x392e, 0xd8,0,0},
+{0x392f, 0xcb,0,0},
+{0x38b3, 0x07,0,0},
+{0x3885, 0x07,0,0},
+{0x382b, 0x3a,0,0},
+{0x3670, 0x68,0,0},
+{0x3208, 0x00,0,0},
+{0x3500, 0x00,0,0},

+{0x3501, 0x51,0,0},
+{0x3502, 0x40,0,0},
+{0x3509, 0x40,0,0},
+{0x380e, 0x05,0,0},
+{0x380f, 0x5c,0,0},
+{0x3927, 0x00,0,0}, // 0x00
+{0x3928, 0xf0,0,0}, // 0x96
+{0x3929, 0x00,0,0},
+{0x392a, 0x41,0,0},
+{0x3208, 0x10,0,0},
+{0x3208, 0xa0,0,0},
+{0x0100, 0x01,0,0}
+};
+
增加 /drivers/media/platform/imx8/mxc-isi-cap.c 数据格式 :

--- a/drivers/media/platform/imx8/mxc-isi-cap.c
+++ b/drivers/media/platform/imx8/mxc-isi-cap.c
@@ -106,6 +106,14 @@ struct mxc_isi_fmt mxc_isi_out_formats[] = {
  .memplanes = 1,
  .colplanes = 1,
  .mbus_code = MEDIA_BUS_FMT_RGB888_1X24,
+ }, {
+ .name = "Y10",
+ .fourcc = V4L2_PIX_FMT_Y10,
+ .depth = { 16 },
+ .color = MXC_ISI_OUT_FMT_RAW16,
+ .memplanes = 1,
+ .colplanes = 1,
+ .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
  }
};

i.MX8QM DTS 部分 fsl-imx8qm-mek.dtsi 修改 :

--- a/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-imx8qm-mek.dtsi

@@ -1174,7 +1176,8 @@ 
port@0 {  reg = <0>; 
mipi_csi0_ep: endpoint
{
  - remote-endpoint = <&max9286_0_ep>;
  + //remote-endpoint = <&max9286_0_ep>;
  + remote-endpoint = <&ov9284_0_ep>; 
     data-lanes = <1 2 3 4>; 
}; 
};

@@ -1190,7 +1193,7 @@
port@1 {
  reg = <1>;
  mipi_csi1_ep: endpoint {
  - remote-endpoint = <&max9286_1_ep>;
  - remote-endpoint = <&max9286_1_ep>;
  + //remote-endpoint = <&max9286_1_ep>; 
  data-lanes = <1 2 3 4>;
 }; 
};  

@@ -1212,6 +1215,27 @@
clock-frequency = <100000>;
status = "okay";

+ ov9284_mipi@60 {
+ compatible = "ov9284_mipi";
+ reg = <0x60>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mipi_csi0_en_rst>;
+ clocks = <&clk IMX8QM_CLK_DUMMY>;
+ clock-names = "capture_mclk";
+ mclk = <27000000>;
+ mclk_source = <0>;
+ pwn-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>;
+     virtual-channel;
+ port {
+ ov9284_0_ep: endpoint {
+     remote-endpoint = <&mipi_csi0_ep>;
+     data-lanes = <1 2 3 4>;
+ };
+ };
+ };
+


+/* 
max9286_mipi@6A

compatible = "maxim,max9286_mipi"; 
reg = <0x6A>;@@ -1230,6 +1254,7 @@ 
}; 
}; 
};
+*/


&i2c0_mipi_csi1 {
@@ -1260,6 +1285,7 @@  
&isi_0 { 
status = "okay";
+ dma-coherent; 
};





五. 应用程序编译

5.1 测试应用程序下载

完成驱动程序的移植后,还需要通过应用程序进行测试 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


                                                                                                         图5 mxc_v4l2_test 应用程序下载

5.2 Debayer 运算

由于从摄像头出来的数据是 RAW Data ,需要对数据进行 Debayer 处理

在 mx8_v4l2_cap_drm.c   display_on_screen 函数里面加入 format_change_single 函数做 Debayer 运算

static int display_on_screen(int ch, struct media_dev *media)
{
 。。。。。。。。。。。。。。。。。。。。。。
format_change_single(video_ch[ch].buffers[buf_id].planes[0].start, cscbuf, DEBAY_BUF_WIDTH, DEBAY_BUF_HIGH);
}

format_change_single() 函数把 RAW12 转换为 RAW8 ,然后对 RAW8 进行 Debayer 

int format_change_single(unsigned char raw12_data[], unsigned char RGB_data[], int width, int height)
{
 unsigned char *bayer_data = NULL;
 unsigned char *display_buff = NULL;

 bayer_data = malloc(width * height);
 memset(bayer_data, 0, width * height);

 display_buff = malloc(width * height * BYTE_PER_PIXEL);
 memset(display_buff, 0, width * height * BYTE_PER_PIXEL);

 raw_12_to_8(bayer_data, raw12_data, width, height);
 bayer2rgb_simplify(RGB_data, bayer_data, width, height);

 free(bayer_data);
 free(display_buff);

 return 0;
}


对 OV9284 RAW8 数据做 Debayer 运算 :

int bayer2rgb_simplify(unsigned char RGB_data[], unsigned char bayer_data[], int width, int height)
{
 int pixel;
 int i, j;
 unsigned char R, G, B;

 for(j = 0; j < width; j += 2)
 {
  for(i = 0; i < height; i += 1)
  {
   R = G = B = bayer_data[ j + i *width];

   pixel = j+width*i;
   RGB_data[pixel * BYTE_PER_PIXEL + 0] = R;//OVERFLOW((R<<1), 255, 0);
   RGB_data[pixel * BYTE_PER_PIXEL + 1] = G;//OVERFLOW( G, 255, 0);
   RGB_data[pixel * BYTE_PER_PIXEL + 2] = B;//OVERFLOW((B<<1), 255, 0);
   RGB_data[pixel * BYTE_PER_PIXEL + 3] = 0;
  }
}

return 0;
}​


由于 OV9284  输出的图像是黑白的,他的 RGB 的值作相同处理


5.3 程序编译

进入到 imx-test\test 目录 ,打开 Makefile ,指定编译器路径

DIR :=
BUILD :=
COPY :=
CFLAGS :=-I/opt/fsl-imx-wayland/4.14-sumo/sysroots/aarch64-poky-linux/usr/include/imx
LDFLAGS :=
SRCDIR := $(patsubst %/Makefile,%,$(1))

输入编译命令 make all 后 ,会在 test/mxc_v4l2_test/ 目录下生成  mx8_v4l2_cap_drm.out 文件


                                                              图6 mx8_v4l2_cap_drm 编译结果

六. 摄像头效果
运行命令 : ./mx8_v4l2_cap_drm.out -cam 1  ,将会看到以下图像


                                                    图7 设想头效果演示

七. 参考文档

【1】 OV9284-Product-Specification-a-CSP_Version-2-0.pdf   January 2019



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

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

评论

Joseph0831

Joseph0831

2021年12月28日
joseph083182@gmail.com
倚天看海

倚天看海

2021年12月21日
可以提供 ,请把您的邮箱发出来
Joseph0831

Joseph0831

2021年12月10日
您好,因為近期也在做imx8的dms開發,看到此篇受益良多。 但想與您更細節的請教關於 mx8_v4l2_cap_drm.c的修改,照著您分享的修正補丁,會缺失BYTE_PER_PIXEL、DEBAY_BUF_WIDTH、DEBAY_BUF_HIGH,以及raw_12_to_8 的function實做。 請問方便提供嗎,感恩不盡。