BananaPi上ov5640摄像头自动对焦功能的实现
2014-10-23 17:52
423 查看
经过一段时间的学习,找了很多ov5640的资料,终于把自动对焦功能实现了。
ov5640是一款用在平板和手机上的摄像头,像素为500W,这个像素在目前来讲不算高,中低端手机的像素都比这个高,但是对于学习摄像头驱动开发已经足够了。这次主要的开发和使用平台式BananaPi----基于全志A20双核处理器的平台。使用的软件是linux-sunxi社区的Linux系统。
sunxi的系统中有ov5640的驱动代码,但是这个驱动把ov540的很多功能都阉割了,自动对焦(AutoFocus)功能就在被阉割的功能之列。从ov5640的数据手册和其他的应用手册上来看,自动对焦功能实现需要以下几个步骤:
1、 上电初始化,写入自动对焦固件(firmware)
2、 向控制寄存器写入指定值,开始一次自动对焦过程
3、 等待自动对焦结束,让镜头固定,等待下一次对焦
4、 断电之前让镜头固定在最远处
这里还有一个问题需要注意下,新的摄像头模组上都有一个保护胶膜,把里面的马达粘住了,需要把这个胶膜去掉才能调整焦距。
ov5640和主板连接的方式有很多种,BananaPi上的接口是CSI接口,CSI接口是挂在I2C总线上的,所以,ov5640上寄存器的读写都是通过I2C命令进行的。有关驱动的分析和开发详细信息见全志的说明文档:http://download.csdn.net/detail/longhui173/8074173
驱动的路径为:drivers/media/video/sun4i_csi/device/ov5640.c
根据上面的分析得知,主要修改的地方是初始化部分和sensor_s_ctrl函数部分。在初始化函数中,需要向摄像头模块写入4K的寄存器值,寄存器的值见固件文档:http://download.csdn.net/detail/longhui173/8074193。
初始化部分修改为:
static int sensor_init(struct v4l2_subdev *sd, u32 val) { int ret; csi_dev_dbg("sensor_init\n"); /*Make sure it is a target sensor*/ ret = sensor_detect(sd); if (ret) { csi_dev_err("chip found is not an target chip.\n"); return ret; } <pre name="code" class="cpp"> ret = sensor_write_array(sd, afc_firmware,ARRAY_SIZE( afc_firmware)); //Simon edit 2014/10/13 if(ret < 0) { csi_dev_err("write afc reg error!!\n"); return ret; }ret = sensor_write_array(sd, sensor_default_regs , ARRAY_SIZE(sensor_default_regs));if(ret < 0){csi_dev_err("write def array error!!\n");return ret;}csi_dev_print("start write auto focus register\n");return ret;}
其中的afc_firmware就是自动对焦固件的寄存器的值。
sensor_s_ctrl函数修改为:
static int sensor_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: return sensor_s_brightness(sd, ctrl->value); case V4L2_CID_CONTRAST: return sensor_s_contrast(sd, ctrl->value); case V4L2_CID_SATURATION: return sensor_s_saturation(sd, ctrl->value); case V4L2_CID_HUE: return sensor_s_hue(sd, ctrl->value); case V4L2_CID_VFLIP: return sensor_s_vflip(sd, ctrl->value); case V4L2_CID_HFLIP: return sensor_s_hflip(sd, ctrl->value); case V4L2_CID_GAIN: return sensor_s_gain(sd, ctrl->value); case V4L2_CID_AUTOGAIN: return sensor_s_autogain(sd, ctrl->value); case V4L2_CID_EXPOSURE: return sensor_s_exp(sd, ctrl->value); case V4L2_CID_EXPOSURE_AUTO: return sensor_s_autoexp(sd, (enum v4l2_exposure_auto_type) ctrl->value); case V4L2_CID_DO_WHITE_BALANCE: return sensor_s_wb(sd, (enum v4l2_whiteblance) ctrl->value); case V4L2_CID_AUTO_WHITE_BALANCE: return sensor_s_autowb(sd, ctrl->value); case V4L2_CID_COLORFX: return sensor_s_colorfx(sd, (enum v4l2_colorfx) ctrl->value); case V4L2_CID_CAMERA_FLASH_MODE: return sensor_s_flash_mode(sd, (enum v4l2_flash_mode) ctrl->value); case V4L2_CID_FOCUS_AUTO: return sensor_s_single_af(sd,ctrl->value); } return -EINVAL; }还需要加入新的函数:sensor_s_single_af();
static int sensor_s_single_af(struct v4l2_subdev *sd, int value) { unsigned char i=0; int ret; struct sensor_info *info = to_state(sd); struct regval_list regs; csi_dev_print("sensor_s_single_af\n"); regs.reg_num[0] = 0x30; //Write 0x00 to 0x3000, enable the mcu regs.reg_num[1] = 0x0; regs.value[0] = 0x00; ret = sensor_write(sd,regs.reg_num,regs.value); if(ret < 0) { csi_dev_err("sensor_write err at start a single af\n"); return ret; } regs.reg_num[0] = 0x30; //set 0x3004 BIT6=1,BIT5=1 regs.reg_num[1] = 0x04; ret = sensor_read(sd,regs.reg_num,regs.value); if(ret < 0) { csi_dev_err("sensor_read err at register 0x%x%x\n",regs.reg_num[0],regs.reg_num[1]); return ret; } csi_dev_print("register 0x3004 = 0x%x\n",regs.value[0]); regs.value[0] |= 0x01 <<5; regs.value[0] |= 0x01 <<6; ret = sensor_write(sd,regs.reg_num,regs.value); if(ret < 0) { csi_dev_err("sensor_write err at register 0x%x%x\n",regs.reg_num[0],regs.reg_num[1]); return ret; } regs.reg_num[0] = 0x30; //set 0x3001 BIT6=0 regs.reg_num[1] = 0x01; ret = sensor_read(sd,regs.reg_num,regs.value); if(ret < 0) { csi_dev_err("sensor_read err at register 0x%x%x\n",regs.reg_num[0],regs.reg_num[1]); return ret; } csi_dev_print("register 0x%x%x = 0x%2x\n",regs.reg_num[0],regs.reg_num[1],regs.value[0]); regs.value[0] &= ~(0x01 <<6); ret = sensor_write(sd,regs.reg_num,regs.value); if(ret < 0) { csi_dev_err("sensor_write err at register 0x%x%x\n",regs.reg_num[0],regs.reg_num[1]); return ret; } regs.reg_num[0] = 0x30; //set 0x3005 BIT6=1 regs.reg_num[1] = 0x05; ret = sensor_read(sd,regs.reg_num,regs.value); if(ret < 0) { csi_dev_err("sensor_read err at register 0x%x%x\n",regs.reg_num[0],regs.reg_num[1]); return ret; } csi_dev_print("register 0x%x%x = 0x%x\n",regs.reg_num[0],regs.reg_num[1],regs.value[0]); regs.value[0] |= 0x01 <<6; ret = sensor_write(sd,regs.reg_num,regs.value); if(ret < 0) { csi_dev_err("sensor_write err at register 0x%x%x\n",regs.reg_num[0],regs.reg_num[1]); return ret; } regs.reg_num[0] = 0x30; //Write 0x03 to 0x3022, start singal af regs.reg_num[1] = 0x22; regs.value[0] = 0x03; ret = sensor_write(sd,regs.reg_num,regs.value); if(ret < 0) { csi_dev_err("sensor_write err at start a single af\n"); return ret; } while(regs.value[0] !=0 && i < 50) { i++; msleep(100); ret = sensor_read(sd, regs.reg_num, regs.value); if (ret < 0) { csi_dev_err("sensor_read err at sensor_s_single_af!\n"); return ret; } csi_dev_print("register 0x3022=0x%x\n",regs.value[0]); } if( i >= 50) { csi_dev_print("write 0x03 to 0x3022 timeout!!\n"); return -1; } i = 0; regs.reg_num[0] = 0x30; regs.reg_num[1] = 0x29; //regs.value[0] = 0x10; while(regs.value[0] != 0x10 && i < 200) { msleep(500); ret = sensor_read(sd,regs.reg_num,regs.value); if(ret < 0) { csi_dev_err("sensor_read err at sensor_s_single_af!\n"); return -1; } csi_dev_print("register 0x3029=0x%x\n",regs.value[0]); i++; } if(i >= 200) { csi_dev_err("sensor_s_single_af failed\n"); return -1; } csi_dev_print("Single AF ok ,value = 0x10\n"); regs.reg_num[0] = 0x30; regs.reg_num[1] = 0x22; regs.value[0] = 0x06; ret = sensor_write(sd,regs.reg_num,regs.value); if(ret < 0) { csi_dev_err("sensor_write err at pause af\n"); return ret; } return 0; }这个函数中间很多代码都是为了调试所用。
在应用程序中,在需要自动对焦的地方调用函数:
struct v4l2_ext_control control; CLEAR(control); control.id = V4L2_CID_FOCUS_AUTO;//V4L2_CID_EXPOSURE_AUTO; if (-1 == ioctl(fd, VIDIOC_S_CTRL, &control)) { perror("VIDIOC_S_CTRL"); exit(EXIT_FAILURE); }
这样就可以实现ov5640的自动对焦了。
相关文章推荐
- android手动实现相机功能,自动对焦+手动对焦
- 如何实现android手机摄像头的的自动对焦
- Android照相功能驱动层中HAL的实现(基于OK6410开发板+OV9650摄像头)
- Android照相功能驱动层中HAL的实现(基于OK6410开发板+OV9650摄像头)
- Android实现手机摄像头的自动对焦
- Android实现手机摄像头的自动对焦
- Android照相功能驱动层中HAL的实现(基于OK6410开发板+OV9650摄像头)
- 如何实现android手机摄像头的的自动对焦
- -01-OV7251摄像头与设计规划【Xilinx-LVDS读写功能实现】
- 如何实现android手机摄像头的的自动对焦
- Android照相功能驱动层中HAL的实现(基于OK6410开发板+OV9650摄像头)
- 2005中ClickOnce实现程序的自动升级功能。
- 使用ASP.NET Atlas AutoComplete Behavior或AutoComplete Extender实现自动完成功能(上)
- SOS,用客户端实现自动比对功能
- Atlas学习手记(4):使用AutoComplete Extender实现自动完成功能
- 实现ISA2004的WPAD(自动发现功能)
- 求助:怎么样用VB实现对网页表格的自动填写功能?
- 实现Flash的TextInput输入框自动填写功能
- IFS's ERP刷新后自动选择某行的功能实现
- VB6 实现文本框的自动完成功能