一. 方案介绍:
二. 摄像头调试环境
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 初始化参数 :
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
评论
Joseph0831
2021年12月28日
倚天看海
2021年12月21日
Joseph0831
2021年12月10日