max9286+max96705摄像头调试--基于imx8qm

一.硬件原理

1.原理图

2.引脚信息

        	/* max9286 */
			SC_P_MIPI_DSI0_GPIO0_00   摄像头电源power-gpios
			SC_P_MIPI_CSI0_MCLK_OUT    摄像头信号触发,需要26HZ的pwm,gpi-gpios
			SC_P_ADC_IN0         pwn-gpios  
            /* i2c */
            SC_P_MIPI_CSI0_I2C0_SDA
            SC_P_MIPI_CSI0_I2C0_SCL

3.DTS

pinctrl_max9286: csi_pwn{
			fsl,pins = <
				SC_P_MIPI_CSI0_GPIO0_00_LSIO_GPIO1_IO27		0x18000000
				SC_P_MIPI_CSI0_MCLK_OUT_LSIO_GPIO1_IO24		0x18000000	
				SC_P_ADC_IN0_LSIO_GPIO3_IO18	0x18000000
				SC_P_SPDIF0_TX_LSIO_GPIO2_IO15	0x1C000020
				//SC_P_MIPI_DSI1_GPIO0_01_LSIO_GPIO1_IO23		0x1C000000 //Camera_PWR_EN
				SC_P_MIPI_DSI0_GPIO0_00_LSIO_GPIO1_IO18		0x1C000000
			>;
   };
  
 	i2c0_mipi_csi0: i2c@58226000 {

		compatible = "fsl,imx8qm-lpi2c";
		assigned-clocks = <&clk_post IMX8QM_CSI0_I2C0_CLK>;
		assigned-clock-rates = <24000000>;
		status = "okay";
		max9286_mipi@48	 {
			compatible = "maxim,max9286_mipi";
			reg = <0x48>;
			pinctrl-0 = <&pinctrl_max9286>;
			pinctrl-names = "default";
			clocks = <&clk IMX8QM_CLK_DUMMY>;
			clock-names = "capture_mclk";
			mclk = <81000000>;
			mclk_source = <0>;
			pwn-gpios = <&gpio3 18 GPIO_ACTIVE_HIGH>;
			power-gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
			gpi-gpios = <&gpio1 24 GPIO_ACTIVE_HIGH>;
			virtual-channel;
			port {
				max9286_0_ep: endpoint {
				remote-endpoint = <&mipi_csi0_ep>;
				data-lanes = <1 2 3 4>;
				};
			};
		};
	};
 
 &isi_0 {
	status = "okay";
};

&isi_1 {
	status = "okay";
};

&isi_2 {
	status = "okay";
};

&isi_3 {
	status = "okay";
};

4.kernel config

CONFIG_IMX8_MEDIA_DEVICE=m
CONFIG_VIDEO_V4L2_SUBDEV_API=y
# CONFIG_USB_GSPCA is not set
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_VIDEO_MXC_CAPTURE=y
CONFIG_VIDEO_MX8_CAPTURE=y
CONFIG_IMX8_CAPTURE_DRIVER=m
CONFIG_IMX8_MIPI_CSI2=m
CONFIG_MXC_CAMERA_OV5640_MIPI_V3=m
CONFIG_GMSL_MAX9286=m
CONFIG_CAMERA_ACTION=m
CONFIG_VIDEO_MXC_CSI_CAMERA=y
CONFIG_MXC_MIPI_CSI=y
CONFIG_MXC_CAMERA_OV5640_MIPI_V2=y
CONFIG_V4L_MEM2MEM_DRIVERS=y

5.驱动文件介绍

6.9286地址配置:

 

ADD0 ADD1都为low,所以地址为0x48

 

二.如何抓取摄像头视频数据

 

imx-test例程里面有v4l2将摄像头的buffer映射到drm的buffer里面。

mx8_v4l2_cap_drm_64 -cam 1 -fmt RGBP -ow 1280 -oh 720 -fr 30

用法如下:

 

mx8_v4l2_cap_drm_64
 -num <numbers of frame need to be captured>
 -of save to file 
 -l <device support list>
 -log <log level, 6 will show all message>
 -cam <device index> 0bxxxx,xxxx
 -d "/dev/videoX" if user use this option, -cam should be 1
 -p test performance, need to combine with "-of" option
 -m <mode> specify camera sensor capture mode(mode:0, 1, 2, 3, 4)
 -fr <frame_rate> support 15fps and 30fps
 -fmt <format> support XR24, AR24, RGBP, RGB3, BGR3, YUV4, YM24, YUYV and NV12, only XR24, AR24 and RGBP support playback
 -ow <width> specify output width
 -oh <height> specify output height
 -hflip <num> enable horizontal flip, num: 0->disable or 1->enable
 -vflip <num> enable vertical flip, num: 0->disable or 1->enable
 -alpha <num> enable and set global alpha for camera, num equal to 0~255
example:
./mx8_cap -cam 1        capture data from video0 and playback
./mx8_cap -cam 3        capture data from video0/1 and playback
./mx8_cap -cam 7 -of    capture data from video0~2 and save to 0~2.BX24
./mx8_cap -cam 255 -of  capture data from video0~7 and save to 0~7.BX24
./mx8_cap -cam 0xff -of capture data from video0~7 and save to 0~7.BX24
./mx8_cap -cam 1 -fmt NV12 -of capture data from video0 and save to 0.NV12
./mx8_cap -cam 1 -of -p test video0 performace

 

 

三.问题

目前碰到的问题:

max9286+max96705目前官方使用Automatic Mode(内同步),需要设置9286 0x06~0x08寄存器。而我们拿到的摄像头是采用外同步,只需要将max9286的gpi脚设置成26hz的pwm波即可。

目前有以下问题:

1.camera的电源需要arm这边控制。

已解决,camera有专用的电源脚,命名为power-gpio.

 

 

2.内同步就是根据9286的06, 07,08三个寄存器的值来设置帧同步的周期,而目前采用的是外同步,怎么判断是内还是外同步?

将9286 gpi引脚直接拉高,然后上电看是否有摄像头数据出来,有则表示是外同步,因为内同步需要设置帧同步时钟,以下为摄像头数据。CSI波形如下:

3.如何设置96705的线序,96705是8bit的时候,通过设置crossbar,来调整线序如:

 

目前摄像头crossbar是从那边拿到的数据才行,不然出来的图片颜色不正确,如下:

 

/* STEP 15 cross bar writes */

max9271_write_reg(max9286_data, 0, 0x20, 0x07);

max9271_write_reg(max9286_data, 0, 0x21, 0x06);

max9271_write_reg(max9286_data, 0, 0x22, 0x05);

max9271_write_reg(max9286_data, 0, 0x23, 0x04);

max9271_write_reg(max9286_data, 0, 0x24, 0x03);

max9271_write_reg(max9286_data, 0, 0x25, 0x02);

max9271_write_reg(max9286_data, 0, 0x26, 0x01);

max9271_write_reg(max9286_data, 0, 0x27, 0x00);

max9271_write_reg(max9286_data, 0, 0x30, 0x17);

max9271_write_reg(max9286_data, 0, 0x31, 0x16);

max9271_write_reg(max9286_data, 0, 0x32, 0x15);

max9271_write_reg(max9286_data, 0, 0x33, 0x14);

max9271_write_reg(max9286_data, 0, 0x34, 0x13);

max9271_write_reg(max9286_data, 0, 0x35, 0x12);

max9271_write_reg(max9286_data, 0, 0x36, 0x11);

max9271_write_reg(max9286_data, 0, 0x37, 0x10);

4.外同步需要设置行、场同步周期(VS generator configure),由以下寄存器(0x47~0x4c)设置,如果不进行设置则无法与96705进行lock,就没有信号过来,lock脚为低:

9286和96705能否进行链路还需满足以下要求,在max9286 datesheet中找到如下:

 

 

上图可知,场信号是低有效.pclk是74.25M。

V指一场高电平时间不能小于200 pclk

P1指场前肩(场无效信号)大于10PCLK

P2指场后肩大于3(A+Q)+200PCLK

A行有效信号时间

Q行无效信号

目前我们主要只需配置V F就好了,设置如下:

/* STEP 16 VS high period in terms of PCL cycles*/

max9271_write_reg(max9286_data, 0, 0x47, 0x00);

max9271_write_reg(max9286_data, 0, 0x48, 0x01);

max9271_write_reg(max9286_data, 0, 0x49, 0x90);

/* STEP 17 VS low period in terms of PCL cycles*/

max9271_write_reg(max9286_data, 0, 0x4A, 0x25);

max9271_write_reg(max9286_data, 0, 0x4B, 0xBA);

max9271_write_reg(max9286_data, 0, 0x4C, 0x4D);

算法如下:

V=400(0x190) F=2472525(0x25BA4D)

V = 400 /(74.25*1000000) = 5.39ms

F = 2472525/(74.25*1000000) = 33.3ms

FPS(帧率) = 1/(5.39+33.3) * 1000 ≈ 26HZ

5.目前max9286硬件配置是BWS=0(24bit),CX/TP=1,I2CSEL=1,HIM=1 ,MS=1,需要匹配设置摄像头96705参数。

 摄像头软件配置: uyvy格式,外同步,  YUV422 8bit,PCLK  74.25MHz

          MAX96705 摄像头硬件设置    BWS=0  CX/TP=1   I2CSEL=1     HIM=1     MS/HVEN=1

          主机端MAX9286 硬件设置       BWS=0   CX/TP=1   I2CSEL=1     HIM=1     MS=1

以上为硬件工程师修改。

 

6.多个摄像头不同步,camera传过来的图像有问题。

主要原因是帧同步时钟没设置好,应该选择GPI为帧同步输入脚,而且是26HZ图像才不会出现问题,不然会出现下面这样:

之前调试一直是把FRSYNC/GPI引脚拉高,先搞清楚内外同步模式选择和不同。

GPI定义如下:

GPI: The serializer’s GPO (or INT) outputs follow GPI (when FSYNCMODE = 11)

0x01 = 0x11000010 (C2)

 

D[7:6]是选择同步模式:

00 使用内部帧时钟同步,GPI口为高阻抗。

01 使用内部帧时钟同步,GPI口输出帧同步时钟。

10 接收另一个9286的帧同步信号,GPI口是外部的帧同步输入。

11 接收ECU的帧同步信号。

 

D[1:0]是选择同步方法:

00 手动模式,需要设置同步时钟则需设置0x06~0x08寄存器。

01 半自动模式

1x 自动模式

 

解释一下这几个模式:

● Manual Mode (FSYNCMETH = 00)

FSYNCPERIOD bits (registers 0x06 to 0x08) manu-ally set the frame sync period. Manual mode allows a frame sync period up to 2 24 PCLK cycles (~16.8million).

● Automatic Mode (FSYNCMETH = 1X)

(Figure 46)The deserializer sends frame sync after counting VSYNC pulses (determined by FSYNCPERDIV) on the slowest link (auto mode) or master link (semi-auto mode). After the last VSYNC pulse, and timing mar-gins adjustments (set by KVAL and PVAL), the dese-rializer sends frame sync. FSYNC is locked when all VSYNCs are aligned (within the margin DIFF),and FSYNC occurs within the timing margin (KVAL,PVAL) for two consecutive VSYNC cycles. PVAL is specified in PCLK cycles while KVAL is specified in absolute time units.

● Semi-Automatic Mode (FSYNCMETH = 01)

The device operates similar to automatic mode with the following differences: The deserializer does not check the skew between different serial links (DIFF). Timing margins adjustments (KVAL, PVAL) are measured from the master link (as opposed to the slowest link).

 

网友问题点:

1.用v4l2_cap获取视频时,色彩不对,如下:

发现他们camera输入格式设置如下:

也就是说CSC的src_fmt是上面这种。

查看支持表,根据函数:

mxc-isi-cap.c

struct mxc_isi_fmt *mxc_isi_get_src_fmt(struct v4l2_subdev_format *sd_fmt)
{
	u32 index;

	/* two fmt RGB32 and YUV444 from pixellink */
	if (sd_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16 ||
		sd_fmt->format.code == MEDIA_BUS_FMT_YVYU8_2X8 ||
		sd_fmt->format.code == MEDIA_BUS_FMT_AYUV8_1X32 ||
		sd_fmt->format.code == MEDIA_BUS_FMT_UYVY8_2X8)
		index = 1;
	else
		index = 0;
	return &mxc_isi_src_formats[index];
}

其中UYVY格式应该设置成MEDIA_BUS_FMT_UYVY8_2X8才能被认为是YUV格式的,所以修改成MEDIA_BUS_FMT_UYVY8_2X8格式就好了。

 

三.代码

指出几个重要寄存器:

96705:

max9271_write_reg(max9286_data, 0, 0x07, 0x94);

max9271_write_reg(max9286_data, 0, 0x04, 0x43);

max9271_write_reg(max9286_data, 0, 0x42, 0x5F);

 

9286:

max9286_write_reg(max9286_data, 0x12, 0xF3);

 

max9286_write_reg(max9286_data, 0x01, 0xE2);

 

驱动代码在我的下载列表里,如下:

https://download.csdn.net/download/u011784994/13773582

有不懂的可以留言。

 

 

 

 

 

  • 19
    点赞
  • 108
    收藏
    觉得还不错? 一键收藏
  • 34
    评论
获取海康威视摄像头的源码,需要先了解一下摄像头的型号和接口类型。如果是USB接口的摄像头,可以使用V4L2(UVC)驱动来进行操作。如果是CSI接口的摄像头,需要根据具体的型号和规格书来开发对应的驱动程序。以下是一个使用V4L2驱动的示例程序: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/ioctl.h> #include <linux/videodev2.h> #define CAMERA_DEVICE "/dev/video0" #define CAPTURE_FILE "frame.raw" #define IMAGE_WIDTH 640 #define IMAGE_HEIGHT 480 struct buffer { void *start; size_t length; }; static void errno_exit(const char *s) { fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno)); exit(EXIT_FAILURE); } static int xioctl(int fd, int request, void *arg) { int r; do { r = ioctl(fd, request, arg); } while (-1 == r && EINTR == errno); return r; } static void process_image(const void *p, int size) { FILE *fp; fp = fopen(CAPTURE_FILE, "wb"); if (fp) { fwrite(p, size, 1, fp); fclose(fp); } } static int read_frame(int fd, struct buffer *buffers) { struct v4l2_buffer buf; CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { switch (errno) { case EAGAIN: return 0; case EIO: default: errno_exit("VIDIOC_DQBUF"); } } process_image(buffers[buf.index].start, buf.bytesused); if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) errno_exit("VIDIOC_QBUF"); return 1; } static void mainloop(int fd, struct buffer *buffers) { unsigned int count; count = 100; while (count-- > 0) { for (;;) { fd_set fds; struct timeval tv; int r; FD_ZERO(&fds); FD_SET(fd, &fds); tv.tv_sec = 2; tv.tv_usec = 0; r = select(fd + 1, &fds, NULL, NULL, &tv); if (-1 == r) { if (EINTR == errno) continue; errno_exit("select"); } if (0 == r) { fprintf(stderr, "select timeout\n"); exit(EXIT_FAILURE); } if (read_frame(fd, buffers)) break; } } } static void stop_capturing(int fd) { enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) errno_exit("VIDIOC_STREAMOFF"); } static void start_capturing(int fd, struct buffer *buffers) { unsigned int i; enum v4l2_buf_type type; for (i = 0; i < 4; ++i) { struct v4l2_buffer buf; CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) errno_exit("VIDIOC_QUERYBUF"); buffers[i].length = buf.length; buffers[i].start = mmap(NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, fd, buf.m.offset); if (MAP_FAILED == buffers[i].start) errno_exit("mmap"); } for (i = 0; i < 4; ++i) { struct v4l2_buffer buf; CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) errno_exit("VIDIOC_QBUF"); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) errno_exit("VIDIOC_STREAMON"); } static void uninit_device(struct buffer *buffers) { unsigned int i; for (i = 0; i < 4; ++i) if (-1 == munmap(buffers[i].start, buffers[i].length)) errno_exit("munmap"); } static void init_mmap(int fd, struct buffer **buffers, unsigned int *n_buffers) { struct v4l2_requestbuffers req; CLEAR(req); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { if (EINVAL == errno) { fprintf(stderr, "%s does not support " "memory mapping\n", CAMERA_DEVICE); exit(EXIT_FAILURE); } else { errno_exit("VIDIOC_REQBUFS"); } } if (req.count < 2) { fprintf(stderr, "Insufficient buffer memory on %s\n", CAMERA_DEVICE); exit(EXIT_FAILURE); } *buffers = calloc(req.count, sizeof(**buffers)); if (!*buffers) { fprintf(stderr, "Out of memory\n"); exit(EXIT_FAILURE); } for (*n_buffers = 0; *n_buffers < req.count; ++*n_buffers) { struct v4l2_buffer buf; CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = *n_buffers; if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) errno_exit("VIDIOC_QUERYBUF"); (*buffers)[*n_buffers].length = buf.length; (*buffers)[*n_buffers].start = mmap(NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, fd, buf.m.offset); if (MAP_FAILED == (*buffers)[*n_buffers].start) errno_exit("mmap"); } } static void init_device(int fd) { struct v4l2_capability cap; struct v4l2_format fmt; if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) { if (EINVAL == errno) { fprintf(stderr, "%s is no V4L2 device\n", CAMERA_DEVICE); exit(EXIT_FAILURE); } else { errno_exit("VIDIOC_QUERYCAP"); } } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { fprintf(stderr, "%s is no video capture device\n", CAMERA_DEVICE); exit(EXIT_FAILURE); } if (!(cap.capabilities & V4L2_CAP_STREAMING)) { fprintf(stderr, "%s does not support streaming i/o\n", CAMERA_DEVICE); exit(EXIT_FAILURE); } CLEAR(fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = IMAGE_WIDTH; fmt.fmt.pix.height = IMAGE_HEIGHT; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) errno_exit("VIDIOC_S_FMT"); if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV) { fprintf(stderr, "Libv4l only supports V4L2_PIX_FMT_YUYV format\n"); exit(EXIT_FAILURE); } } int main(int argc, char *argv[]) { struct buffer *buffers; unsigned int n_buffers; int fd = open(CAMERA_DEVICE, O_RDWR | O_NONBLOCK, 0); if (-1 == fd) { fprintf(stderr, "Cannot open %s\n", CAMERA_DEVICE); exit(EXIT_FAILURE); } init_device(fd); init_mmap(fd, &buffers, &n_buffers); start_capturing(fd, buffers); mainloop(fd, buffers); stop_capturing(fd); uninit_device(buffers); close(fd); return 0; } ``` 这个程序会从摄像头中获取视频流,并将每一帧保存到文件中。您需要根据自己的需求进行修改。需要注意的是,这个程序只适用于使用V4L2驱动的摄像头,如果您使用的是CSI接口的摄像头,需要开发对应的驱动程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值