博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ov2656
阅读量:4075 次
发布时间:2019-05-25

本文共 16356 字,大约阅读时间需要 54 分钟。

android v2.2linux v2.6.32board DM3730sensor ov2656参考: 《Android 底层开发技术实战详解》在OMAP平台中,可以使用高级的ISP(图像信号处理)模块通过外接i2c方式连接的Camera Sensor驱动来获得视频帧的数据drivers/media/video/此目录主要由三个部分组成video for linux 2 设备:实现文件是omap34xxcam.h和omap34xxcam.cISP: 实现文件是isp目录中的isp.c isph3a.c isppreview.c ispresizer.c提供通过ISP进行3A 预览 改变大小等功能Camera Sensor 驱动:使用v4l2-int-device结果来注册1.注册i2c主设备和平台数据的设置arch/arm/mach-omap2/board-xxx//注册i2c 2 时钟为400kHzomap_register_i2c_bus(2, 400, xxx_i2c_boardinfo, ARRAY_SIZE(xxx_i2c_boardinfo));#define OV2656_I2C_ADDR		(0x61 >> 1)static struct i2c_board_info __initdata xxx_i2c_boardinfo[] = {	{		I2C_BOARD_INFO("ov2655", OV2655_I2C_ADDR),		.platform_data = &xxx_ov2656_platform_data,	},};struct ov2656_platform_data xxx_ov2656_platform_data = {	.power_set	 = ov2656_sensor_power_set,	.priv_data_set	 = ov2656_sensor_set_prv_data,	.set_xclk	 = ov2656_sensor_set_xclk,};2.sensor 电源设置DM3730		GPIO_CAM_RST------GPIO_126		GPIO_CAM_RDN------GPIO_167static int ov2656_sensor_power_set(struct v4l2_int_device *s,				   enum v4l2_power power){	----------------	switch (power) {	case V4L2_POWER_ON:		isp_configure_interface(vdev->cam->isp, &ov2656_if_config);		if (previous_power == V4L2_POWER_OFF) {			/* 打开模拟电源 */			twl_i2c_write_u8(xxx);			twl_i2c_write_u8(xxx);			gpio_direction_output(GPIO_CAM_PDN, 0);			gpio_direction_output(GPIO_CAM_RST, 0);			mdelay(1);			gpio_direction_output(GPIO_CAM_RST, 1);			mdelay(1);		}		break;	case V4L2_POWER_OFF:		/* 下电时序*/		twl_i2c_write_u8(xxx);		break;	}3. OMAP3  isp 配置设置drivers/media/video/isp/isp.cint isp_configure_interface(struct device *dev,			    struct isp_interface_config *config)根据相关的参数配置ISP 控制器 I/F选择并行或串行硬件preview 数据通道shifter像素时钟极性8到16位的CCDC输入模式isp_configure_interface(vdev->cam->isp, &ov2656_if_config);/* *@dataline_shift: Data lane shifter. *                     0 - No Shift, 1 - CAMEXT[13 to 2]->CAM[11 to 0] *                     2 - CAMEXT[13 to 4]->CAM[9 to 0] *                     3 - CAMEXT[13 to 6]->CAM[7 to 0]*/static struct isp_interface_config ov2656_if_config = {	.ccdc_par_ser		= ISP_PARLL,	.dataline_shift 	= 0x1,	.hsvs_syncdetect 	= ISPCTRL_SYNC_DETECT_VSRISE,	.strobe 		= 0x0,	.prestrobe 		= 0x0,	.shutter 		= 0x0,    	.wenlog 		= ISPCCDC_CFG_WENLOG_AND,	.wait_hs_vs             = 2,	.u.par.par_bridge       = 0x3,	.u.par.par_clk_pol      = 0x0, //0 - 不反向};4. ov2656 driver/drivers/media/video/ov2656.c1)注册,删除i2c驱动static int __init ov2656_init(void){	i2c_add_driver(&ov2656_i2c_driver);	return 0;}static void __exit ov2656_exit(void){	i2c_del_driver(&ov2656_i2c_driver);}2)定义sensor i2c驱动static struct i2_driver ov2656_i2c_driver = {	.driver = {		.name = "ov2656",		.owner = THIS_MODULE,	},	.probe = ov2656_probe,	.remove = ov2656_remove,	.id_table = ov2656_id,};static const struct i2c_device_id ov2656_id[] = {	{"ov2656", 0},	{},};3)注册sensor为i2c 客户端和V4L2设备static int ov2656_probe(struct i2c_client *client, 	const struct i2c_device_id *id){	---------------------------	i2c_get_clientdata(client);	//回调平台数据	sensor->pdata->power_set = pdata->power_set;	sensor->pdata->set_xclk = pdata->set_xclk;	sensor->pdata->priv_data_set = pdata->priv_data_set;	设置sensor的默认配置		sensor->timeperframe.numerator = 1;	sensor->timeperframe.denominator = 15;	sensor->pix.width = 640;	sensor->pix.height = 480;	sensor->pix.pixelformat =  V4L2_PIX_FMT_YUYV;   	sensor->v4l2_int_device = &ov2656_int_device;	----------------------------	i2c_set_clientdata(client, sensor);	v4l2_int_device_register(sensor->v4l2_int_device);}4)V4L2 初始化设备static struct v4l2_int_device = {	.module = THIS_MODULE,	.name = "ov2656",	.type = v4l2_int_type_slave,	.u = {		.slave = &ov2656_slave,	},};5)V4L2初始化从设备static struct v4l2_int_slave ov2656_slave = {	.ioctls = ov2656_ioctl_desc,	.num_ioctls = ARRAY_SIZE(ov2656_ioctl_desc),};提供给上层的ioctl接口static struct v4l2_int_ioctl_desc ov2656_ioctl_desc[] = {};6)加载sensor驱动的log------------ioctl_g_priv--------------                                          ------------ioctl_s_power--------------                                         ------------ioctl_dev_init--------------                                        ov2656 2-0030: Detect success (26,56)                                           ------------ioctl_g_fmt_cap--------------                                       ------------ioctl_s_power-------------- //返回sensor的私有数据地址static int ioctl_g_priv(struct v4l2_int_device *s, void *p){	struct ov2656_sensor *sensor = s->priv;	return sensor->pdata->priv_data_set(s, p);	return 0;}//电源设置static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power new_power){	-----------switch (new_power) {	case V4L2_POWER_ON:		rval = sensor->pdata->set_xclk(s, OV2656_XCLK);//24M camera时钟		if (rval == -EINVAL)			break;		rval = sensor->pdata->power_set(s, V4L2_POWER_ON);		if (rval)			break;		if (sensor->detected)			ov2656_configure(s);		else {			rval = ioctl_dev_init(s);			printk("-------ioctl_s_power--->dev_init----\n");			if (rval)				goto err_on;		}		break;	case V4L2_POWER_OFF:err_on:		rval = sensor->pdata->power_set(s, V4L2_POWER_OFF);		sensor->pdata->set_xclk(s, 0);		break;	default:		return -EINVAL;}//初始化设备当从设备和主设备相连的时候static int ioctl_dev_init(struct v4l2_int_device *s){	----------	 ov2656_detect(client);	---------}//探测i2c设备,读取i2c sensor的PIDH和PIDLstatic int ov2656_detect(struct i2c_client *client){	u32 pidh, pidl;	if (!client) 		return -ENODEV;			if (ov2656_read_reg(client, 1, OV2656_PIDH, &pidh)) 		return -ENODEV;			if (ov2656_read_reg(client, 1, OV2656_PIDL, &pidl))		return -ENODEV;	if ((pidh == OV2656_PIDH_MAGIC) && ((pidl == OV2656_PIDL_MAGIC1) )) {		dev_info(&client->dev, "Detect success (%02X,%02X)\n", pidh, pidl);		return pidl;	}	return -ENODEV;}static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f){	printk("------------%s--------------\n", __func__);	return 0;}5.打开sensor的log/ # ------------ioctl_s_power--------------                                     ----------------ov2656_configure------------                                    ------------ioctl_s_power--------------                                         ------------ioctl_g_fmt_cap--------------                                       ------------ioctl_enum_fmt_cap--------------                                    --------ioctl_enum_framesizes--frms->index=0------                              ------------ioctl_enum_frameintervals--------------                             ------------ioctl_enum_frameintervals--------------                             --------ioctl_enum_framesizes--frms->index=1------                              ------------ioctl_enum_frameintervals--------------                             ------------ioctl_enum_frameintervals--------------                             --------ioctl_enum_framesizes--frms->index=2------                              ------------ioctl_enum_fmt_cap--------------                                    ------------ioctl_g_fmt_cap--------------                                       ------------ioctl_s_fmt_cap--------------                                       ------------ioctl_s_parm--------------                                          ------------ioctl_s_power--------------                                         ----------------ov2656_configure------------  1)设置电源2)ov2656_configurestatic int ov2656_configure(struct v4l2_int_device *s){	------------------------------	//写复位寄存器	ov2656_write_reg(client, OV2656_SYS, 0x80);	mdelay(5);	/* Common registers */	err = ov2656_write_regs(client, ov2656_common[0]);	sensor->hsize = pix->width;	sensor->vsize = pix->height;		/* Store image size */	sensor->width = pix->width;	sensor->height = pix->height;	sensor->crop_rect.left = 0;	sensor->crop_rect.width = pix->width;	sensor->crop_rect.top = 0;	sensor->crop_rect.height = pix->height;	--------------------------}3)ioctl_g_fmt_cap查询出一种格式,查询驱动所支持的格式static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f){	return 0;}4)ioctl_enum_framesizes帧大小static int ioctl_enum_framesizes(struct v4l2_int_device *s,				 struct v4l2_frmsizeenum *frms){	if (frms->index >= 2)		return -EINVAL;	frms->pixel_format = V4L2_PIX_FMT_YUYV;	frms->type = V4L2_FRMSIZE_TYPE_DISCRETE;	frms->discrete.width = 640;	frms->discrete.height = 480;}5)ioctl_enum_frameintervals每秒15帧static int ioctl_enum_frameintervals(struct v4l2_int_device *s,				     struct v4l2_frmivalenum *frmi){	if (frmi->index >= 1) 			return -EINVAL;	frmi->type = V4L2_FRMIVAL_TYPE_DISCRETE;	frmi->discrete.numerator = 1 ;	frmi->discrete.denominator = 15;			return 0;}6)ioctl_s_fmt_cap设置格式static int ioctl_s_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f){		struct ov2656_sensor *sensor = s->priv;	struct v4l2_pix_format *pix = &f->fmt.pix;	sensor->pix = *pix;	return 0;}7)ioctl_s_parm设置参数static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a){	printk("------------%s--------------\n", __func__);		return 0;}8)寄存器配置列表const static struct ov2656_reg ov2656_common[2][300] = {	/* XGA_Default settings */	{	     //IO & Clock & Analog Setup  {0x308c,0x80}, //TMC12: DIS_MIPI_RW  {0x308d,0x0e}, //TMC13: MIPI disable  {0x360b,0x00},  {0x30b0,0xff}, //IO_CTRL0: Cy[7:0]  {0x30b1,0xff}, //IO_CTRL1: C_VSYNC,C_STROBE,C_PCLK,C_HREF,Cy[9:8]  {0x30b2,0x2c}, //IO_CTRL2: R_PAD[3:0]  {0x300f,0xa6},  {0x3010,0x81},  {0x3082,0x01},  {0x30f4,0x01},  {0x3091,0xc0},  {0x30ac,0x42},  {0x30d1,0x08},  {0x3015,0x02}, //AUTO_3: AGC ceiling = 4x, 5dummy frame  {0x3093,0x00},  {0x307e,0xe5}, //TMC8: AGC[7:6]=b'11  {0x3079,0x00},  {0x3017,0x40}, //AUTO_5: disable data drop, manual banding counter=0  {0x30f3,0x82},  {0x306a,0x0c}, //0x0c->0x0f Joe 0814 : BLC  {0x306d,0x00},  {0x336a,0x3c},  {0x3076,0x6a}, //TMC0: VSYNC drop option: drop  {0x30d9,0x95},  {0x3601,0x30},  {0x304e,0x88},  {0x30f1,0x82},  {0x306f,0x14},  {0x302a,0x02},  {0x302b,0x6a},  {0x3012,0x10},    {0x3018,0x80}, // jerry, 0624  {0x3019,0x70},   {0x301a,0xd4},   //Wonder 20090909  {0x3013,0xf7},   {0x30af,0x10},  {0x304a,0x00},  {0x304f,0x00},  {0x30a3,0x80}, //Wonder From OV, 20090615 0x10  {0x3013,0xf7},   {0x3014,0xa4}, //R1D bit6 always = 0 , bit[5]=1, bit[0]=1   //Wonder for AE oscillation  {0x3071,0x00},  {0x3073,0x00},  {0x304d,0x42},  {0x304a,0x00}, //Disable 50/60 auto detection function, due to ov2650 no this function  {0x304f,0x00}, //Disable 50/60 auto detection function, due to ov2650 no this function  {0x3095,0x07},  {0x3096,0x16},  {0x3097,0x1d},  {0x3020,0x01},   {0x3021,0x18},   {0x3022,0x00},  {0x3023,0x06},  {0x3024,0x06},  {0x3025,0x58},  {0x3026,0x02},  {0x3027,0x5e},    {0x3088,0x02},// ISP_XOUT 640  {0x3089,0x80},  {0x308a,0x01},// ISP_YOUT 480  {0x308b,0xe0},    {0x3316,0x64},  {0x3317,0x25},  {0x3318,0x80},  {0x3319,0x08},  {0x331a,0x64},  {0x331b,0x4b},  {0x331c,0x00},  {0x331d,0x38},  {0x3100,0x00},  {0x3320,0xfa},   //Jerry 0x9a  {0x3321,0x11},     {0x3322,0x92},     {0x3323,0x01},     {0x3324,0x97},   //Jerry 0x92     {0x3325,0x02},     {0x3326,0xff},     {0x3327,0x10},   //0x0c  {0x3328,0x11},   //Jerry 0x0f  {0x3329,0x16},   //Jerry 0x14  {0x332a,0x59},   //Jerry 0x66  {0x332b,0x60},   //5f -> 5c  //Jerry 0x5c  {0x332c,0xbe},   //a5 -> 89    //Jerry 0x89  {0x332d,0x9b},   //ac -> 96    //Jerry 0x96  {0x332e,0x34},   //35 -> 3d    //Jerry 0x3d  {0x332f,0x36},   //Jerry 0x2f  {0x3330,0x49},   //Jerry 0x57  {0x3331,0x44},   //Jerry 0x3d  {0x3332,0xf0},     {0x3333,0x00},  //0x10   {0x3334,0xf0},     {0x3335,0xf0},     {0x3336,0xf0},     {0x3337,0x40},     {0x3338,0x40},     {0x3339,0x40},     {0x333a,0x00},     {0x333b,0x00},     {0x3380,0x27},   {0x3381,0x5c},   {0x3382,0x0a},   {0x3383,0x29},  //0x2a  {0x3384,0xab},  //0xad  {0x3385,0xd3}, //d5  {0x3386,0xbf},    {0x3387,0xbc},   {0x3388,0x03},   {0x3389,0x98},   {0x338a,0x01},   {0x3340,0x0c},    {0x3341,0x18},    {0x3342,0x30},   {0x3343,0x3d},   {0x3344,0x4b},   {0x3345,0x59},  //0x60   {0x3346,0x67},  //0x6a  {0x3347,0x71},    {0x3348,0x7d},  //0x84  {0x3349,0x8e},  //0x96  {0x334a,0x9b},  //0xa2  {0x334b,0xa6},  //0xac  {0x334c,0xb9},  {0x334d,0xc6},  {0x334e,0xd9},  {0x334f,0x34},      {0x3350,0x35},  //Wonder for lens 20090909  {0x3351,0x25},  {0x3352,0x08},  {0x3353,0x23},  {0x3354,0x00},  {0x3355,0x85},  {0x3356,0x34},  {0x3357,0x25},  {0x3358,0x08},  {0x3359,0x1e},  {0x335a,0x00},  {0x335b,0x85},   {0x335c,0x35},  {0x335d,0x25},  {0x335e,0x08},  {0x335f,0x18},  {0x3360,0x00},  {0x3361,0x85},  {0x3363,0x01},  {0x3364,0x03},  {0x3365,0x02},  {0x3366,0x00},  {0x338b,0x0C}, //auto uv  //add saturation  {0x338c,0x10},  {0x338d,0x80},  //40  indoor saturation  {0x3370,0xd0},  {0x3371,0x00},  {0x3372,0x00},  {0x3374,0x10},  {0x3375,0x10},  {0x3376,0x04}, ///0624,jerry, for preview sharp  {0x3377,0x00},  {0x3378,0x04},  {0x3379,0x40},  {0x3069,0x80}, //Jerry  {0x3087,0x02},  {0x3300,0xfc},  {0x3302,0x11},  {0x3400,0x00},  {0x3606,0x20},  {0x3601,0x30},  {0x30f3,0x83},  {0x304e,0x88},  {0x3086,0x0f},   {0x3086,0x00}, //   {0x30a8,0x54}, //0x56   Wonder for Sun black  {0x30aa,0x52},  //0x42  //Wonder for Sun black  {0x30af,0x10},   {0x30b2,0x2c},   {0x30d9,0x8c},  {0x363B,0x01},  {0x363C,0xF2},  {0xFFFF,0xFF},		},};6.android HALhardware/ti/omap3/camera/V4L2Camera.cppCameraHardware.cppConverter.cpp在startPreview()的实现在,保存预览回调函数并建立预览线程,在预览线程的循环中,等待视频数据的到达视频数据到达后调用预览回调函数,将视频帧送出status_t CameraHardware::startPreview(){ 	----------	mCamera->StartStreaming();	 mPreviewThread = new PreviewThread(this);	----------}取景器预览的主要步骤1)在初始化的过程中,建立预览数据的内存队列2)在startPreview()中建立预览线程3)在预览线程的循环中,等待视频数据到达int CameraHardware::previewThread(){  ----------VIDEO_FRAME--------- yuyv422_to_yuv420sp((unsigned char *)rawFramePointer,                                (unsigned char *)mRecordingHeap->getBase(),                                PREVIEW_WIDTH, PREVIEW_HEIGHT);mDataCb(CAMERA_MSG_VIDEO_FRAME, mRecordingBuffer, mCallbackCookie);            mDataCbTimestamp(systemTime(), CAMERA_MSG_VIDEO_FRAME, mRecordingBuffer, mCallbackCookie);--------------PREVIEW FRAME------------yuyv422_to_yuv420sp((unsigned char *)rawFramePointer,                              (unsigned char *)mHeap->getBase(),                              PREVIEW_WIDTH, PREVIEW_HEIGHT);            mDataCb(CAMERA_MSG_PREVIEW_FRAME, mBuffer, mCallbackCookie);-------------------------------------------------------4)在预览到达后使用预览回调机制将视频向上传送int CameraHardware::pictureThread(){ ----------------- if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {        LOGE("Take Picture COMPRESSED IMAGE");        mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mCamera->GrabJpegFrame(), mCallbackCookie);    } ------------------}录制视频的主要步骤1)在startRecording()的实现中保存录制视频回调函数2)录制视频可以使用自己的线程,也可以使用预览线程status_t CameraHardware::startRecording(){ }3)通过录制回调函数将视频帧送出void CameraHardware::releaseRecordingFrame(const sp
& mem){}当调用releaseRecordingFrame()后,表示上层通知Camera 硬件抽象层,这一帧的内存已经用完,可以进行下一次的处理。camera 处理流程1)使用映射内核内存的方式V4L2_MEMORY_MMAP,构建预览的内存MemoryHeapBase需要从V4L2驱动程序中得到内存指针status_t CameraHardware::startPreview(){ ----------------- mPreviewFrameSize = PREVIEW_WIDTH * PREVIEW_HEIGHT * 2; mHeap = new MemoryHeapBase(mPreviewFrameSize); ----------------}2)在预览线程中,使用VIDIOC_DQBUF调用阻塞等待视频帧的到来,处理完成后使用VIDIOC_QBUF调用将帧内存再次压入队列,然后等待下一帧的到来ioctl(fd, VIDIOC_DQBUF, &videoIn->buf);ioctl(fd, VIDIOC_QBUF, &videoIn->buf);7. CameraHardware.cpp打开摄像头E/CameraHardware( 913): return Preview Heap E/CameraHardware( 913): beginAutoFocusThread E/CameraHardware( 913): Picture Thread E/CameraHardware( 913): Take Picture RAW IMAGE E/CameraHardware( 913): Take Picture COMPRESSED IMAGE E/CameraHardware( 913): pictureThread: preview started 调用sp
CameraHardware::getPreviewHeap() const{ LOGE("return Preview Heap"); return mPreviewHeap;}按下拍照按键int CameraHardware::beginAutoFocusThread(void *cookie){ CameraHardware *c = (CameraHardware *)cookie; LOGE("beginAutoFocusThread"); return c->autoFocusThread();}status_t CameraHardware::takePicture(){ pictureThread(); return NO_ERROR;}int CameraHardware::pictureThread(){ --------------------- if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) { LOGE("Take Picture COMPRESSED IMAGE"); mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mCamera->GrabJpegFrame(), mCallbackCookie); LOGE("%s: preview started", __FUNCTION__); mPreviewThread = new PreviewThread(this);}调用GrabJpegFrame()在V4L2Camera.cpp中实现

转载地址:http://qakni.baihongyu.com/

你可能感兴趣的文章
PostgreSQL查询优化器详解之逻辑优化篇
查看>>
STM32中assert_param的使用
查看>>
C语言中的 (void*)0 与 (void)0
查看>>
vu 是什么
查看>>
io口的作用
查看>>
IO口的作用
查看>>
UIView的使用setNeedsDisplay
查看>>
归档与解归档
查看>>
Window
查看>>
为什么button在设置标题时要用一个方法,而不像lable一样直接用一个属性
查看>>
字符串的截取
查看>>
2. Add Two Numbers
查看>>
17. Letter Combinations of a Phone Number (DFS, String)
查看>>
93. Restore IP Addresses (DFS, String)
查看>>
19. Remove Nth Node From End of List (双指针)
查看>>
49. Group Anagrams (String, Map)
查看>>
139. Word Break (DP)
查看>>
Tensorflow入门资料
查看>>
剑指_用两个栈实现队列
查看>>
剑指_顺时针打印矩阵
查看>>