DM6467的OV5642 Linux驱动程序开发(三)——驱动测试
来源:互联网 发布:vba连接oracle数据库 编辑:程序博客网 时间:2024/04/30 15:17
1 编写ov5642测试例程
在编写好ov5642驱动之后,需要编写程序对其进行测试,这就是V4L2应用层程序。要编写V4L2应用层程序,首先需要理解V4L2提供的各种ioctl函数,要知道如何配置视频设备的初始化参数,特别注意的是配置是有一定顺序的,如果顺序错了那肯定会有错误。在初始化视频设备之后,需要建立缓冲区来接收视频设备传过来的帧,V4L2提供了两种模式来获取视频帧:MMAP和UserPtr。由于在vpif驱动程序中只提供了对MMAP的支持,所以我们在编写测试例程时也是使用该模式。对于V4L2的MMAP和UserPtr两种模式的理解其实有点困难,现在我也还没有完全弄清,但是这两种方法的使用却比较简单。
ov5642测试例程的编写主要包括以下几个部分,必须严格按照该顺序来编写程序。
(1) 打开视频设备。
视频设备在linux的/dev目录中,我们这里只有一个视频设备,所以是/dev/video0,使用open函数打开。
static int ov5642 = -1;
ov5642 = open ("/dev/video0", O_RDWR, 0);
(2)设置vpif channel 0的输入。
由于vpif的channel 0可以有三个输入:tvp5150、tvp7002和ov5642,所以需要选通对应的输入模式。
unsigned int input = 1; // 0: tvp5150; 1: 0v5642. defined in board-dm646x-evm.c
ioctl (ov5642, VIDIOC_S_INPUT, &input);
(3)设置视频采集格式。
现在ov5642只支持VGA格式。
vid_std_id = 0x10000000; // V4L2_STD_CAMERA_VGA
ioctl (ov5642, VIDIOC_S_STD, &vid_std_id);
(4)设置视频的像素点格式。
现在ov5642驱动程序只支持YUYV格式的像素点格式,分辨率为VGA,即640 X 480,逐行扫描,每行640 X2 X 2个字节(因为ov5642输出10-bit视频数据)。
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 640;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
fmt.fmt.pix.bytesperline = 640* 2 * 2;
fmt.fmt.pix.sizeimage = 640 * 480 * 2 * 2;
ioctl(ov5642, VIDIOC_S_FMT, &fmt);
(5)申请缓冲区。
使能视频输出之前需要申请缓冲区用来存储视频数据。
memset (&req, 0, sizeof(req));
req.count = num_bufs;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ioctl (ov5642, VIDIOC_REQBUFS, &req);
(6)查询缓冲区。
申请缓冲区之后,需要查询缓冲区,设置每个缓冲区的地址。
buf_ptr = calloc(req.count, sizeof(*buf_ptr));
assert(buf_ptr != NULL);
for (i = 0; i < req.count; i++) {
memset (&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
ioctl (ov5642, VIDIOC_QUERYBUF, &buf)) < 0);
buf_ptr[i].length = buf.length;
buf_ptr[i].start = mmap (NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, ov5642, buf.m.offset);
}
(7)将申请的缓冲区放到V4L2视频缓冲队列。
接下来需要将申请的缓冲区放到V4L2缓冲队列,让驱动程序将buffer填满。
for (i = 0; i < req.count; i++) {
memset (&qbuf, 0, sizeof(qbuf));
qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
qbuf.memory = V4L2_MEMORY_MMAP;
qbuf.index = i;
ioctl (ov5642, VIDIOC_QBUF, &qbuf);
}
(8)使能视频设备输出视频流。
在完成所有初始化配置之后,就可以使能视频设备输出视频流了。
ioctl (ov5642, VIDIOC_STREAMON, &buf_type);
(9)获取视频帧。
要获取视频帧,需要使用VIDIOC_DQBUF这个ioctl函数。获得数据之后,将其存储到文件中,方便后期处理现实图像。
if ((vid_file = fopen("test.264", "wb")) == NULL)
printf ("Open file test.264 failed.\n");
else
printf ("Open file test.264 succeed!\n");
for (i = 0; i < 1; i++) {
memset (&buf, 0 ,sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if ((err = ioctl (ov5642, VIDIOC_DQBUF, &buf)) < 0)
printf ("IOCTL dqbuf failed. error code:%d\n", err);
else
printf ("IOCTL dqbuf succeed!\n");
fwrite(buf_ptr[buf.index].start, buf.bytesused, 1, vid_file);
if ((err = ioctl (ov5642, VIDIOC_QBUF, &buf)) < 0)
printf ("IOCTL qbuf failed. error code:%d\n", err);
else
printf ("IOCTL qbuf succeed!\n");
}
fclose(vid_file);
(10)关闭视频流。
通过VIDIOC_STREAMOFF这个ioctl函数实现。
ioctl (ov5642, VIDIOC_STREAMOFF, &buf_type);
(11)释放内存。
for (i = 0; i < req.count; i++) {
if ((err = munmap(buf_ptr[i].start, buf_ptr[i].length)) < 0)
printf ("munmap[%d] failed. error code:%d\n", i, err);
else {
buf_ptr[i].start = NULL;
printf ("munmap[%d] succeed!\n", i);
}
}
free (buf_ptr);
close (ov5642);
2 调试中遇到的问题
以下是调试过程中的一些问题,由于调试时没有及时记录,很多错误都忘了怎么调好的了。
(1) 内核启动时初始化ov5642失败。
编写完驱动程序后,编译内核,下载到开发板上运行,得到下面的输出提示信息。
经过查看代码,发现在ov5642_probe()函数中对ov5642的两个ID寄存器进行了访问,而在系统上电后默认是没有使能ov5642的,所以访问肯定失败,所以,在ov5642驱动程序中注释掉相关代码就好了。
(2)运行ov5642测试例程时无法访问I2C寄存器。
在测试ov5642例程时,发现仍然无法访问其I2C寄存器。
经过检查代码,发现是在vpif_streamon()函数中还没有通过CPLD使能ov5642就对其进行了访问,这个问题和第一个类似,解决办法就是在该函数中先使能ov5642.
(3)图片纯绿色。
测试例程获得的图像为纯绿色,如下所示。
通过使用ultraedit查看文件数据,发现所有数据都为0。后来,发现是vpif寄存器配置错误,通过多次修改之后,成功获取了视频图像。
(4)图像偏绿。
在修改好vpif寄存器之后,能够成功获取图像,但是必须运行两次程序,获得的图像偏绿,很不清楚。
可以看出,图像中有轮廓,但是整体颜色不对。后来在网线发现有人说这可能是因为多次配置ov5642造成的,所以在ov5642驱动程序中添加了一个变量用以记录是否已经进行了I2C配置。当系统第一次配置ov5642,将该变量置1,如果程序要再次配置,只要该变量为1,就不会产生重复配置。修改好之后再次运行程序,图像颜色正常,如下图所示。
(5)经常无法获取视频帧。
ov5642测试例程在运行时经常是多次运行后有一次能够成功获取数据,其他都是失败。
root@dm6467t-evm:/opt/dvsdk/dm6467# ./ov5642
Open /dev/video0 succeed!
IOCTL query cap succeed!
VIDIOC_QUERYCAP Capability:0x04000001
IOCTL set input succeed!
IOCTL get input succeed!
VIDIOC_G_INPUT:1
IOCTL query standard succeed!
VIDIOC_QUERYSTD:0x100000Configure CMOS mode
00
VPIF_CH0_CTRL:0x91e05485ed!
IOCTL get standard succeed!
VIVPIF_CH1_CTRL:0x80000485
DIOC_G_STD:0x10000000
IOCTL setVPIF_CH2_CTRL:0x00000000
format succeed!
IOCTL request VPIF_CH3_CTRL:0x00000000
buf succeed!
IOCTL querybuf[0] VPIF_INTEN:0x00000013
succeed!
IOCTL querybuf[1] succVPIF_INTEN_SET:0x00000013
eed!
IOCTL querybuf[2] succeed!VPIF_INTEN_CLR:0x00000000
IOCTL qbuf[0] succeed!
IOCTL VPIF_STATUS:0x00000003
qbuf[1] succeed!
IOCTL qbuf[2] VPIF_REQ_SIZE:0x00000080
succeed!
IOCTL set stream on succeed!
Open file test.264 succeed!
IOCTL dqbuf failed. error code:-1
IOCTL qbuf failed. error code:-1
IOCTL set stream off succeed!
munmap[0] succeed!
munmap[1] succeed!
munmap[2] succeed!
经过很长时间的调试,发现其实是因为在打开ov5642设备时使用了一个O_NONBLOCK参数,该参数表示不阻塞。也就是说,在ov5642测试例程试图获取视频帧时,如果当时缓冲区里没有数据,它就直接返回了,并提供错误信息。所以,修改方法就是将该参数去掉,之后再运行测试例程就一直都不会出现上面那样的错误提示信息了。
(6)首次运行例程总是失败。
到现在为止,每次系统上点之后第一次运行ov5642测试例程都会获得错误的视频帧,但之后不管运行多少次都是正常的,这个问题还没有解决。
- DM6467的OV5642 Linux驱动程序开发(三)——驱动测试
- DM6467的OV5642 Linux驱动程序开发(二)——Linux内核修改
- DM6467的OV5642 Linux驱动程序开发(一)——V4L2框架结构
- 基于DM6467的OV5642视频采集编码程序设计(2)——Encode Demo测试
- 基于DM6467的OV5642视频采集编码程序设计(2)——Encode Demo测试
- 基于DM6467的OV5642视频采集编码程序设计(1)——Codec Engine修改
- 基于DM6467的OV5642视频采集编码程序设计(1)——Codec Engine修改
- 基于DM6467的TVP7002 Linux驱动程序开发
- 基于DM6467的OV5642视频采集编码程序设计(3)——PAL格式输入及其他调试
- 基于DM6467的OV5642视频采集编码程序设计(3)——PAL格式输入及其他调试
- Linux USB 驱动开发(三)—— 编写USB 驱动程序
- Linux USB 驱动开发(三)—— 编写USB 驱动程序
- Linux USB 驱动开发(三)—— 编写USB 驱动程序
- Linux驱动程序开发之三----按键驱动(Tiny6410)
- Linux块设备驱动(三)————块设备驱动程序的框架
- DM6467开发之U-Boot移植(3)——U-Boot移植测试
- davinci DM6467——linux开发环境搭建
- 测试驱动开发笔记(三)——测试驱动开发模式
- 常见的进程调度算法
- DM6467的OV5642 Linux驱动程序开发(二)——Linux内核修改
- Codeforces Round #207 (Div. 2) C. Knight Tournament
- 一个程序有多个选择屏幕以及一个程序调用多个程序
- 记一次CSR上线及总结
- DM6467的OV5642 Linux驱动程序开发(三)——驱动测试
- linux下通过yum安装svn及配置
- Silverlight玻璃边框样式的按钮
- HG5520A型多用表校准仪
- java学习01-基础知识与环境配置
- 篝火晚会 题解
- 中断和异常
- 使用EclipseCDT搭建Beaglebone Linux开发环境
- HG30A-1交直流标准源