基于avd7181c解决视频输入效果差的问题<一>---驱动移植、调试手记-阿里云开发者社区

开发者社区> 开发与运维> 正文

基于avd7181c解决视频输入效果差的问题<一>---驱动移植、调试手记

简介: 基于avd7181c解决视频输入效果差的问题---驱动移植、调试手记             做过全志A10平台的人都知道,在视频输入方面,虽然有4路TV Decoder,但是做的效果真的不敢恭维。

基于avd7181c解决视频输入效果差的问题<>---驱动移植、调试手记

 

          做过全志A10平台的人都知道,在视频输入方面,虽然有4TV Decoder,但是做的效果真的不敢恭维。笔者基于全志平台做车载互动娱乐系统以及车载导航主机,客户对视频输入效果有强烈要求,怎么办呢?

加芯片弥补平台的不足。笔者选用的是AVD7181C芯片,可以支持CVBS\S-Video\YPbPr\RGB等多种输入格式,通过该芯片可以输出YUV 4:2:2信号、656信号。YPbPr输入信号的情况下,输出YUV 4:2:2信号,CVBS视频输入的情况下,输出656信号。刚好这两种格式全志平台的CSI都可以支持。那怎么调试呢?

/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/sundesheng125原创,转载请注明出处,谢谢!

/*****************************************************************************************************/

       如果想快速的调试出图像,从下到上自己做一套会非常耗费时间,也不利于调试,那还是利用现有的资源来做。笔者就是基于android camera APK来完成前期调试的,我们就把AVD7181C芯片当着是一颗camera芯片,利用camera应用来完成yuv的数据存取以及显示,我们负责把底层打通就可以了。

         第一步:基于一个具体camera驱动移植到AVD7181C上。笔者基于gc0308驱动来做的。复制一份改个名字,把里面所有关于gc0308寄存器设置的数组都先清空,这个时候代码就会减少几百行,留着下面的驱动框架,iic操作sensor_read, sensor_write接口也留着。在其他地方都可以大刀阔斧的砍下去,留一个空函数即可。大结构代码如下:

static const struct v4l2_subdev_core_ops sensor_core_ops = {
	.g_chip_ident = sensor_g_chip_ident,
	.g_ctrl = sensor_g_ctrl,
	.s_ctrl = sensor_s_ctrl,
	.queryctrl = sensor_queryctrl,
	.reset = sensor_reset,
	.init = sensor_init,
	.s_power = sensor_power,
	.ioctl = sensor_ioctl,
};

static const struct v4l2_subdev_video_ops sensor_video_ops = {
	.enum_mbus_fmt = sensor_enum_fmt,//linux-3.0
	.try_mbus_fmt = sensor_try_fmt,//linux-3.0
	.s_mbus_fmt = sensor_s_fmt,//linux-3.0
	.s_parm = sensor_s_parm,//linux-3.0
	.g_parm = sensor_g_parm,//linux-3.0
};

static const struct v4l2_subdev_ops sensor_ops = {
	.core = &sensor_core_ops,
	.video = &sensor_video_ops,
};

/* ----------------------------------------------------------------------- */

static int sensor_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct v4l2_subdev *sd;
	struct sensor_info *info;
	struct regval_list regs;
        int ret = -1;
        int i = 0;

        avd7181c_dev_dbg("fuction=%s, line=%d\n",__FUNCTION__, __LINE__);
	info = kzalloc(sizeof(struct sensor_info), GFP_KERNEL);
	if (info == NULL)
		return -ENOMEM;
	sd = &info->sd;
	v4l2_i2c_subdev_init(sd, client, &sensor_ops);

	info->ccm_info = &ccm_info_con;
	
	info->gain = 0;
	info->wb = 0;
	info->clrfx = 0;

  avd7181c_dev_dbg("fuction=%s, line=%d\n",__FUNCTION__, __LINE__);
	init_avd7181c_proc();
	gsd = sd;

	return 0;
}

static int sensor_remove(struct i2c_client *client)
{
	struct v4l2_subdev *sd = i2c_get_clientdata(client);

	v4l2_device_unregister_subdev(sd);
	kfree(to_state(sd));
	return 0;
}

static const struct i2c_device_id sensor_id[] = {
	{ "7181c", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, sensor_id);

static struct i2c_driver sensor_driver = {
	.driver = {
		.owner = THIS_MODULE,
	  .name = "7181c",
	},
	.probe = sensor_probe,
	.remove = sensor_remove,
	.id_table = sensor_id,
};

 

         第二步:根据需要的视频输入格式写好对应寄存器设置。如果需要支持CVBS就加一个cvbs格式的一长串寄存器,ypbpr也一样。笔者以ypbpr为例,列出部分寄存器设置:

 static const struct regval_list reg_ypbpr[]=
{
{{0x05},{0x01}},// ; PRIM_MODE = 001b COMP
{{0x06},{0x06}},// ; VID_STD for 525P 2x1
{{0x03},{0x08}},
{{0xC3},{0x46}},// ; ADC1 to Ain4, ADC0 to Ain6, 
{{0xC4},{0xB5}},// ; ADC2 to Ain5 and enables manual override of mux
{{0x1D},{0x47}},// ; Enable 28.63636MHz crystal
{{0x3A},{0x11}},// ; Set Latch Clock 01b. Power down ADC3.
{{0x3B},{0x81}},// ; Enable Internal Bias 

{{0x3C},{0x3d}},// ; PLL QPUMP to 011b 
{{0x6B},{0x83}}, //0xc3,//0x83,// ; 422 8bit out 
{{0xC9},{0x00}},// ; SDR mode
#if 1
{{0x73},{0xD0}},// ; Enable Manual Gain and set CH_A gain
{{0x74},{0xE6}},// ; Set CH_A and CH_B Gain - 0FAh
{{0x75},{0x81}},// ; Set CH_B and CH_C Gain
{{0x76},{0xa0}},// ; Set CH_C Gain
{{0x77},{0x06}},

{{0x78},{0x08}},
{{0x79},{0x02}},
{{0x7A},{0x00}},
#endif
...........
}

         第三部:在设置fmt的接口中去控制输入格式。在sensor_s_fmt函数中可以去控制是选择CVBS还是ypbpr,当然是通过这个接口中传递下来的参数来控制。这部分完全可以自定义,笔者介绍一下ypbpr 480P情况下的设置:

	info->fmt = sensor_fmt;
	info->width = 720;
	info->height = 480;
	
       /*write reg_ypbpr  setting*/
	ret = sensor_write_array(sd, reg_ypbpr , ARRAY_SIZE(reg_ypbpr)); //reg_ypbpr
	avd7181c_dev_dbg("==========sensor_write at wirte reg_ypbpr ret=%d\n", ret); 

         第四步:为了调试方便增加便捷调试功能。怎么才能在运行的时候,可以很便利的去修改寄存器,读出当前设置的寄存器值呢?可以通过proc来完成。通过串口来输入控制命令,这样想读哪个寄存器就读哪个寄存器,想怎么调试方便,就可以按需要很方便的去调试。

static void init_avd7181c_proc(void)
{
	struct proc_dir_entry *read_r, *write_r;

	avd7181c_dev_dbg("%s\n", __func__);

	dir = proc_mkdir("avd7181ctest", NULL);
	read_r = create_proc_entry("read_r", 0666, dir);
	if (read_r)
		read_r->write_proc = avd7181cTest_proc_read;
	write_r  = create_proc_entry("write_r", 0666, dir);
	if (write_r)
		write_r->write_proc = avd7181cTest_proc_write;

}

         第五步:在system_config1.fex中添加配置。主要是打开csi,设置名称、iic地址等,还有就是复位、standby供电的gpio设置。

csi_used                 = 1
csi_mname                = "7181c"
csi_twi_id               = 1
csi_twi_addr             = 0x42
csi_if                   = 0

csi_d15                  = 
csi_reset                = port:PH13<1><default><default><0>
csi_power_en             = port:PI11<1><default><default><0>
csi_stby                 = port:PH18<1><default><default><0>
csi_reset_b              = 

          通过以上几步,我们已经搭建好一个初步的AVD7181C驱动框架,编译通过就可以跑测试了。笔者使用DVD输出ypbpr信号给AVD7181C,在camera apk中查看图像。先贴一副截屏图像: 

 

 

        在这个调试过程中,笔者遇到了很多的问题,多问问,多试试,一步步解决,总能解决好。笔者将在后续文章中介绍遇到的AVD7181C iic读寄存器兼容性问题、CVBS输入情况下CSI驱动的修改等。敬请期待!

版权声明:本文首发在云栖社区,遵循云栖社区版权声明:本文内容由互联网用户自发贡献,版权归用户作者所有,云栖社区不为本文内容承担相关法律责任。云栖社区已升级为阿里云开发者社区。如果您发现本文中有涉嫌抄袭的内容,欢迎发送邮件至:developer2020@service.aliyun.com 进行举报,并提供相关证据,一经查实,阿里云开发者社区将协助删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章