您的位置:首页 > 其它

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

2013-02-02 19:35 567 查看
基于avd7181c解决视频输入效果差的问题<一>---驱动移植、调试手记
 
          做过全志A10平台的人都知道,在视频输入方面,虽然有4路TV 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驱动的修改等。敬请期待!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐