硬件环境:友善之臂mini2440开发板+中星微zc301b摄像头
软件环境:linux2.6.29内核+上位机Ubuntu8.04
日 期:2012-12-19 于广州日顺电子科技有限公司
作 者:行者无疆 or 蜗牛
提示:感谢网友的倾情付出,我也是在网友的基础上整理,归类,然后通过实验验证罢了。
关于如何移植驱动,可以在google上搜索,
移植完驱动后,启动开发板,挂载NFS进入系统后,插上USB摄像头,串口出现如下信息:
usb 1-1: new full speed USB device using s3c2410-ohci and address 4
usb 1-1: device descriptor read/64, error -62
usb 1-1: device descriptor read/64, error -62
usb 1-1: new full speed USB device using s3c2410-ohci and address 5
usb 1-1: New USB device found, idVendor=0ac8, idProduct=301b
usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-1: Product: PC Camera
usb 1-1: Manufacturer: Vimicro Corp.
usb 1-1: configuration #1 chosen from 1 choice
gspca: probing 0ac8:301b
zc3xx: probe 2wr ov vga 0x0000
zc3xx: probe 3wr vga 1 0xe400
zc3xx: probe 3wr vga 2 0x0000
zc3xx: Sensor UNKNOW_0 force Tas5130
gspca: probe ok
# ./server_arm fastspeed.txt
start 2.0...
Device name:PC Camera
Width:640 ~ 48
Height:480 ~ 32
Frames:4
Buffer size:475136
Offset:0
encoded:38016, 4228 bytes.
encoded:38016, 152 bytes.
encoded:38016, 12 bytes.
encoded:38016, 12 bytes.
encoded:38016, 12 bytes.
gspca: ISOC data error: [10] len=38, status=-84
encoded:38016, 12 bytes.
encoded:38016, 12 bytes.
encoded:38016, 12 bytes.
encoded:38016, 12 bytes.
encoded:38016, 12 bytes.
encoded:38016, 12 bytes.
encoded:38016, 12 bytes.
encoded:38016, 12 bytes.
encoded:38016, 12 bytes.
encoded:38016, 12 bytes.
encoded:38016, 12 bytes.
//-------------------------------------------------------------------------------------------------------------------
仔细查看,我们不难发现有两个问题:
其一:zc3xx: Sensor UNKNOW_0 force Tas5130,提示没有找到摄像头感光芯片,强制为Tas5130,其实中星微zc3xx摄像头感光芯片Tas5130CK,ID号为14。有些网友用的不是linux2.6.29内核版本,ID号为16,其实我们可以从内核中找到答案:
摘自
////////////////////////////////////
从内核zc3xx..c中copy
5, /* SENSOR_CS2102 0 */
5, /* SENSOR_CS2102K 1 */
4, /* SENSOR_GC0305 2 */
4, /* SENSOR_HDCS2020b 3 */
4, /* SENSOR_HV7131B 4 */
4, /* SENSOR_HV7131C 5 */
4, /* SENSOR_ICM105A 6 */
4, /* SENSOR_MC501CB 7 */
3, /* SENSOR_OV7620 8 */
4, /* SENSOR_OV7630C 9 */
4, /* SENSOR_PAS106 10 */
4, /* SENSOR_PAS202B 11 */
4, /* SENSOR_PB0330 12 */
4, /* SENSOR_PO2030 13 */
4, /* SENSOR_TAS5130CK 14 */
4, /* SENSOR_TAS5130CXX 15 */
3, /* SENSOR_TAS5130C_VF0250 16 */
既然找到问题,那就好办了,使用root权限,输入下列命令
# echo 14 > /sys/module/gspca_zc3xx/parameters/force_sensor
或者直接修改/sys/module/gspca_zc3xx/parameters/force_sensor文件,将文件清空然后输入14保存
重新插上你的摄像头就可以用了
当然,如果想一劳永逸呢,就编辑/etc/modprobe.conf加入这行
options gspca_zc3xx force_sensor=16
保存就OK! 但是这个一劳永逸的解决方法在此版本上不能用,没有modprobe.conf这个配置文件。
其二:
gspca: ISOC data error: [10] len=38, status=-84
解决USB摄像头出现ISOC data error的问题gspcav1-20071224/gspca_core.c: [spca50x_move_data:1611] ISOC data e
rror: [XX] len=XX, status=-84 XX代表一些不定的数字
这个问题在我用VIDCAT的时候遇到了,这个主要是USB-host的问题。
下面是解决的办法:
修改drivers/usb/host/ohci-s3c2410.c文件中的s3c2410_start_hc函数,开始部分添加以下内容:
unsigned long s3c2410_upllcon=(unsigned long)ioremap(0x4C000008, 4);
unsigned long upllvalue=(0x38<<12)|(0x02<<4)|(0x02);
while(upllvalue!=__raw_readl(s3c2410_upllcon)){
__raw_writel(upllvalue,s3c2410_upllcon);
mdelay(1);
}
然后重新编译内核,即可解决。
好了,我们可以开始走上正途了:
重新拔了usb摄像头,再插上,弹出如下信息:
# echo 14 > /sys/module/gspca_zc3xx/parameters/force_sensor
# usb 1-1: USB disconnect, address 3
gspca: disconnect complete
usb 1-1: new full speed USB device using s3c2410-ohci and address 4
usb 1-1: New USB device found, idVendor=0ac8, idProduct=301b
usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 1-1: Product: PC Camera
usb 1-1: Manufacturer: Vimicro Corp.
usb 1-1: configuration #1 chosen from 1 choice
gspca: probing 0ac8:301b
zc3xx: probe 2wr ov vga 0x0000
zc3xx: probe 3wr vga 1 0xe400
zc3xx: probe 3wr vga 2 0x0000
zc3xx: sensor forced to 14
gspca: probe ok
激动人心的时刻到了,摄像头终于找到自己的家了,zc3xx: sensor forced to 14
运行我们的单帧采集测试程序,马上在同一目录下抓拍到图片。
# ./v4l
open success!
set_norm success
init success!
size=475136
memory map success!
get picture success!
img address 0x40001000
#
测试程序源代码如下:
/*********************************************************
中星微摄像头zc301b感光芯片是Tas5130CK,在linux2.6.29版本中,
ID号14
# echo 14 > /sys/module/gspca_zc3xx/parameters/force_sensor
**********************************************************/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <error.h>
#include <fcntl.h>
#include <sys/types.h>
#include <linux/videodev.h>
//#include "v4l.h"
#include <linux/videodev.h>
#include <sys/types.h>
#define DEFAULT_DEVICE "/dev/video0"
#include <string.h>
#define norm VIDEO_MODE_NTSC
#define DEFAULT_FILE_NAME "picture"
//PAL CIF NTSC tuner mode
#define PAL_WIDTH 768
#define PAL_HEIGHT 576
#define CIF_WIDTH 352
#define CIF_HEIGHT 288
#define NTSC_WIDTH 80 //
#define NTSC_HEIGHT 60
#define DEFAULT_PALETTE VIDEO_PALETTE_RGB32
struct _v4l_device
{
int fd;
struct video_capability capability;
struct video_picture picture;
struct video_window window;
struct video_channel channel[8];
struct video_mbuf mbuf;
struct video_capture capture;
struct video_buffer vbuffer;
struct video_mmap mmap;
unsigned char *map;
int frame;
int framestat[2];
};
typedef struct _v4l_device v4ldevice;
int v4l_open(char *dev,v4ldevice *vd)
{
if (!dev){dev = DEFAULT_DEVICE;} ;
if((vd->fd=open(dev,O_RDWR,10705))<0)
{
return -1;
};
if(v4l_get_capability(vd)<0)
return -1;
if(v4l_get_picture(vd)<0)
return -1;
return 0;
}
int v4l_get_capability(v4ldevice *vd)
{
if(ioctl(vd->fd,VIDIOCGCAP,&(vd->capability))<0)
{
perror("v4l_get_capability:");
return -1;
};
return 0;
}
int v4l_get_picture(v4ldevice *vd)
{
if(ioctl(vd->fd,VIDIOCGPICT,&(vd->picture))<0)
{
perror("v4l_get_picture");
return -1;
};
return 0;
}
int v4l_set_norm(v4ldevice *vd, int nrm)
{
int i;
for(i=0;i< vd->capability.channels ; i++){
// vd->channel[i]=nrm ;
};
return 0;
}
int v4l_grab_init(v4ldevice *vd,int width,int height)
{
vd->mmap.width=width;
vd->mmap.height=height;
vd->mmap.format=vd->picture.palette;
vd->frame=0;
vd->framestat[0]=0;
vd->framestat[1]=0;
return 0;
}
int v4l_mmap_init(v4ldevice *vd)
{
if(v4l_get_mbuf(vd)<0)
return -1;
if((vd->map=mmap(0,vd->mbuf.size,PROT_READ|PROT_WRITE,MAP_SHARED,vd->fd,0) )<0)
{
return -1;
}
return 0;
}
int v4l_get_mbuf(v4ldevice *vd)
{
if(ioctl(vd->fd,VIDIOCGMBUF,&(vd->mbuf))<0)
{
perror("v4l_get_mbuf:");
return -1;
}
printf("size=%d\n",vd->mbuf.size);
return 0;
}
int v4l_grab_start(v4ldevice *vd,int frame)
{
vd->mmap.frame=frame;
if(ioctl(vd->fd,VIDIOCMCAPTURE,&(vd->mmap))<0)
{
exit(-1);
return -1;
}
vd->framestat[frame]=1;
return 0;
}
int v4l_grab_sync(v4ldevice *vd,int frame)
{
if(ioctl(vd->fd,VIDIOCSYNC,&frame)<0)
{
return -1;
}
vd->framestat[frame]=0;
return 0;
}
unsigned char * v4l_get_address(v4ldevice *vd)
{
return (vd->map+vd->mbuf.offsets[vd->frame]);
// return (vd->map+vd->mbuf.offsets[0]);
}
int v4l_close(v4ldevice *vd)
{
close(vd->fd);
return 0;
}
/*************************************************************/
/******************main.c************************/
/*name :main.c
date:2009-5-20
author:kevin
copyright:all is reserved
************************************/
char *buffer=NULL;
int main()
{
v4ldevice VD;
v4ldevice *vd=&VD;
int frame=0;
int f_d;
int NUM, write_number = 0;
f_d=open(DEFAULT_FILE_NAME,O_RDWR|O_CREAT,0666);
printf("f_d = %d \n",f_d);
if(0==v4l_open("/dev/video0",vd))
printf("open success!\n");
else
printf("open failure\n");
if(0==v4l_set_norm(vd,norm))
printf("set_norm success\n");
else
printf("set_norm failure\n");
if(0==v4l_grab_init(vd,NTSC_WIDTH,NTSC_HEIGHT))
printf("init success!\n");
else
printf("init failure\n");
if(0==v4l_mmap_init(vd))
printf("memory map success!\n");
else
printf("memory map failure\n");
if(0==v4l_grab_start(vd,frame))
printf("get picture success!\n");
else
printf("get picture failure\n");
v4l_grab_sync(vd,frame);
buffer=(char *)v4l_get_address(vd);
printf("img address %p\n",buffer);
write_number = write(f_d,buffer,NTSC_WIDTH*3*NTSC_HEIGHT); //每一帧的字节数 80*60*3=14400byte
printf("write_number = %d bytes\n",write_number);
v4l_close(vd);
return 0;
}
Copy这段代码,注意查看驱动文件,在mini2440运行即可。