⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ov7670.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
static int ov7670_init(struct i2c_client *client){	return ov7670_write_array(client, ov7670_default_regs);}static int ov7670_detect(struct i2c_client *client){	unsigned char v;	int ret;	ret = ov7670_init(client);	if (ret < 0)		return ret;	ret = ov7670_read(client, REG_MIDH, &v);	if (ret < 0)		return ret;	if (v != 0x7f) /* OV manuf. id. */		return -ENODEV;	ret = ov7670_read(client, REG_MIDL, &v);	if (ret < 0)		return ret;	if (v != 0xa2)		return -ENODEV;	/*	 * OK, we know we have an OmniVision chip...but which one?	 */	ret = ov7670_read(client, REG_PID, &v);	if (ret < 0)		return ret;	if (v != 0x76)  /* PID + VER = 0x76 / 0x73 */		return -ENODEV;	ret = ov7670_read(client, REG_VER, &v);	if (ret < 0)		return ret;	if (v != 0x73)  /* PID + VER = 0x76 / 0x73 */		return -ENODEV;	return 0;}/* * Store information about the video data format.  The color matrix * is deeply tied into the format, so keep the relevant values here. * The magic matrix nubmers come from OmniVision. */static struct ov7670_format_struct {	__u8 *desc;	__u32 pixelformat;	struct regval_list *regs;	int cmatrix[CMATRIX_LEN];	int bpp;   /* Bytes per pixel */} ov7670_formats[] = {	{		.desc		= "YUYV 4:2:2",		.pixelformat	= V4L2_PIX_FMT_YUYV,		.regs 		= ov7670_fmt_yuv422,		.cmatrix	= { 128, -128, 0, -34, -94, 128 },		.bpp		= 2,	},	{		.desc		= "RGB 444",		.pixelformat	= V4L2_PIX_FMT_RGB444,		.regs		= ov7670_fmt_rgb444,		.cmatrix	= { 179, -179, 0, -61, -176, 228 },		.bpp		= 2,	},	{		.desc		= "RGB 565",		.pixelformat	= V4L2_PIX_FMT_RGB565,		.regs		= ov7670_fmt_rgb565,		.cmatrix	= { 179, -179, 0, -61, -176, 228 },		.bpp		= 2,	},	{		.desc		= "Raw RGB Bayer",		.pixelformat	= V4L2_PIX_FMT_SBGGR8,		.regs 		= ov7670_fmt_raw,		.cmatrix	= { 0, 0, 0, 0, 0, 0 },		.bpp		= 1	},};#define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats)/* * Then there is the issue of window sizes.  Try to capture the info here. *//* * QCIF mode is done (by OV) in a very strange way - it actually looks like * VGA with weird scaling options - they do *not* use the canned QCIF mode * which is allegedly provided by the sensor.  So here's the weird register * settings. */static struct regval_list ov7670_qcif_regs[] = {	{ REG_COM3, COM3_SCALEEN|COM3_DCWEN },	{ REG_COM3, COM3_DCWEN },	{ REG_COM14, COM14_DCWEN | 0x01},	{ 0x73, 0xf1 },	{ 0xa2, 0x52 },	{ 0x7b, 0x1c },	{ 0x7c, 0x28 },	{ 0x7d, 0x3c },	{ 0x7f, 0x69 },	{ REG_COM9, 0x38 },	{ 0xa1, 0x0b },	{ 0x74, 0x19 },	{ 0x9a, 0x80 },	{ 0x43, 0x14 },	{ REG_COM13, 0xc0 },	{ 0xff, 0xff },};static struct ov7670_win_size {	int	width;	int	height;	unsigned char com7_bit;	int	hstart;		/* Start/stop values for the camera.  Note */	int	hstop;		/* that they do not always make complete */	int	vstart;		/* sense to humans, but evidently the sensor */	int	vstop;		/* will do the right thing... */	struct regval_list *regs; /* Regs to tweak *//* h/vref stuff */} ov7670_win_sizes[] = {	/* VGA */	{		.width		= VGA_WIDTH,		.height		= VGA_HEIGHT,		.com7_bit	= COM7_FMT_VGA,		.hstart		= 158,		/* These values from */		.hstop		=  14,		/* Omnivision */		.vstart		=  10,		.vstop		= 490,		.regs 		= NULL,	},	/* CIF */	{		.width		= CIF_WIDTH,		.height		= CIF_HEIGHT,		.com7_bit	= COM7_FMT_CIF,		.hstart		= 170,		/* Empirically determined */		.hstop		=  90,		.vstart		=  14,		.vstop		= 494,		.regs 		= NULL,	},	/* QVGA */	{		.width		= QVGA_WIDTH,		.height		= QVGA_HEIGHT,		.com7_bit	= COM7_FMT_QVGA,		.hstart		= 164,		/* Empirically determined */		.hstop		=  20,		.vstart		=  14,		.vstop		= 494,		.regs 		= NULL,	},	/* QCIF */	{		.width		= QCIF_WIDTH,		.height		= QCIF_HEIGHT,		.com7_bit	= COM7_FMT_VGA, /* see comment above */		.hstart		= 456,		/* Empirically determined */		.hstop		=  24,		.vstart		=  14,		.vstop		= 494,		.regs 		= ov7670_qcif_regs,	},};#define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes))/* * Store a set of start/stop values into the camera. */static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop,		int vstart, int vstop){	int ret;	unsigned char v;/* * Horizontal: 11 bits, top 8 live in hstart and hstop.  Bottom 3 of * hstart are in href[2:0], bottom 3 of hstop in href[5:3].  There is * a mystery "edge offset" value in the top two bits of href. */	ret =  ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff);	ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff);	ret += ov7670_read(client, REG_HREF, &v);	v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);	msleep(10);	ret += ov7670_write(client, REG_HREF, v);/* * Vertical: similar arrangement, but only 10 bits. */	ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff);	ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff);	ret += ov7670_read(client, REG_VREF, &v);	v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3);	msleep(10);	ret += ov7670_write(client, REG_VREF, v);	return ret;}static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt){	struct ov7670_format_struct *ofmt;	if (fmt->index >= N_OV7670_FMTS)		return -EINVAL;	ofmt = ov7670_formats + fmt->index;	fmt->flags = 0;	strcpy(fmt->description, ofmt->desc);	fmt->pixelformat = ofmt->pixelformat;	return 0;}static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,		struct ov7670_format_struct **ret_fmt,		struct ov7670_win_size **ret_wsize){	int index;	struct ov7670_win_size *wsize;	struct v4l2_pix_format *pix = &fmt->fmt.pix;	for (index = 0; index < N_OV7670_FMTS; index++)		if (ov7670_formats[index].pixelformat == pix->pixelformat)			break;	if (index >= N_OV7670_FMTS) {		/* default to first format */		index = 0;		pix->pixelformat = ov7670_formats[0].pixelformat;	}	if (ret_fmt != NULL)		*ret_fmt = ov7670_formats + index;	/*	 * Fields: the OV devices claim to be progressive.	 */	pix->field = V4L2_FIELD_NONE;	/*	 * Round requested image size down to the nearest	 * we support, but not below the smallest.	 */	for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES;	     wsize++)		if (pix->width >= wsize->width && pix->height >= wsize->height)			break;	if (wsize >= ov7670_win_sizes + N_WIN_SIZES)		wsize--;   /* Take the smallest one */	if (ret_wsize != NULL)		*ret_wsize = wsize;	/*	 * Note the size we'll actually handle.	 */	pix->width = wsize->width;	pix->height = wsize->height;	pix->bytesperline = pix->width*ov7670_formats[index].bpp;	pix->sizeimage = pix->height*pix->bytesperline;	return 0;}/* * Set a format. */static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt){	int ret;	struct ov7670_format_struct *ovfmt;	struct ov7670_win_size *wsize;	struct ov7670_info *info = i2c_get_clientdata(c);	unsigned char com7, clkrc;	ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize);	if (ret)		return ret;	/*	 * HACK: if we're running rgb565 we need to grab then rewrite	 * CLKRC.  If we're *not*, however, then rewriting clkrc hoses	 * the colors.	 */	if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {		ret = ov7670_read(c, REG_CLKRC, &clkrc);		if (ret)			return ret;	}	/*	 * COM7 is a pain in the ass, it doesn't like to be read then	 * quickly written afterward.  But we have everything we need	 * to set it absolutely here, as long as the format-specific	 * register sets list it first.	 */	com7 = ovfmt->regs[0].value;	com7 |= wsize->com7_bit;	ov7670_write(c, REG_COM7, com7);	/*	 * Now write the rest of the array.  Also store start/stops	 */	ov7670_write_array(c, ovfmt->regs + 1);	ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart,			wsize->vstop);	ret = 0;	if (wsize->regs)		ret = ov7670_write_array(c, wsize->regs);	info->fmt = ovfmt;	if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0)		ret = ov7670_write(c, REG_CLKRC, clkrc);	return ret;}/* * Implement G/S_PARM.  There is a "high quality" mode we could try * to do someday; for now, we just do the frame rate tweak. */static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms){	struct v4l2_captureparm *cp = &parms->parm.capture;	unsigned char clkrc;	int ret;	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	ret = ov7670_read(c, REG_CLKRC, &clkrc);	if (ret < 0)		return ret;	memset(cp, 0, sizeof(struct v4l2_captureparm));	cp->capability = V4L2_CAP_TIMEPERFRAME;	cp->timeperframe.numerator = 1;	cp->timeperframe.denominator = OV7670_FRAME_RATE;	if ((clkrc & CLK_EXT) == 0 && (clkrc & CLK_SCALE) > 1)		cp->timeperframe.denominator /= (clkrc & CLK_SCALE);	return 0;}static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms){	struct v4l2_captureparm *cp = &parms->parm.capture;	struct v4l2_fract *tpf = &cp->timeperframe;	unsigned char clkrc;	int ret, div;	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)		return -EINVAL;	if (cp->extendedmode != 0)		return -EINVAL;	/*	 * CLKRC has a reserved bit, so let's preserve it.	 */	ret = ov7670_read(c, REG_CLKRC, &clkrc);	if (ret < 0)		return ret;	if (tpf->numerator == 0 || tpf->denominator == 0)		div = 1;  /* Reset to full rate */	else		div = (tpf->numerator*OV7670_FRAME_RATE)/tpf->denominator;	if (div == 0)		div = 1;	else if (div > CLK_SCALE)		div = CLK_SCALE;	clkrc = (clkrc & 0x80) | div;	tpf->numerator = 1;	tpf->denominator = OV7670_FRAME_RATE/div;	return ov7670_write(c, REG_CLKRC, clkrc);}/* * Code for dealing with controls. */#if 0  /* This seems unneeded after all, should probably come out *//* * Fetch and store the color matrix. */static int ov7670_get_cmatrix(struct i2c_client *client,	int matrix[CMATRIX_LEN]){	int i, ret;	unsigned char signbits;	ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits);	for (i = 0; i < CMATRIX_LEN; i++) {		unsigned char raw;		ret += ov7670_read(client, REG_CMATRIX_BASE + i, &raw);		matrix[i] = (int) raw;		if (signbits & (1 << i))			matrix[i] *= -1;	}	return ret;}#endifstatic int ov7670_store_cmatrix(struct i2c_client *client,		int matrix[CMATRIX_LEN]){	int i, ret;	unsigned char signbits = 0;	/*	 * Weird crap seems to exist in the upper part of	 * the sign bits register, so let's preserve it.	 */	ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits);	signbits &= 0xc0;	for (i = 0; i < CMATRIX_LEN; i++) {		unsigned char raw;		if (matrix[i] < 0) {			signbits |= (1 << i);			if (matrix[i] < -255)				raw = 0xff;			else				raw = (-1 * matrix[i]) & 0xff;		}		else {			if (matrix[i] > 255)				raw = 0xff;			else				raw = matrix[i] & 0xff;		}		ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw);	}	ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits);	return ret;}/* * Hue also requires messing with the color matrix.  It also requires * trig functions, which tend not to be well supported in the kernel. * So here is a simple table of sine values, 0-90 degrees, in steps * of five degrees.  Values are multiplied by 1000. * * The following naive approximate trig functions require an argument * carefully limited to -180 <= theta <= 180. */#define SIN_STEP 5static const int ov7670_sin_table[] = {	   0,	 87,   173,   258,   342,   422,	 499,	573,   642,   707,   766,   819,	 866,	906,   939,   965,   984,   996,	1000};static int ov7670_sine(int theta){	int chs = 1;	int sine;	if (theta < 0) {		theta = -theta;		chs = -1;	}	if (theta <= 90)		sine = ov7670_sin_table[theta/SIN_STEP];	else {		theta -= 90;		sine = 1000 - ov7670_sin_table[theta/SIN_STEP];	}	return sine*chs;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -