查看: 2344|回复: 0

基于i.mx6高清视频采集技术详解

[复制链接]

该用户从未签到

发表于 2013-11-17 20:36:53 | 显示全部楼层 |阅读模式
分享到:
 
1          概述

本文介绍基于freescale i.MX6 高清视频采集方案的技术详解,高清视频输入可以为HDMIDVI或者VGA方式。分辨率支持1600*1200@601920*1080@601280x720@60HZ等多种。视频解码芯片采用ADIADV7441A
实现低成本、高性能、高集成度的视频采集产品。
包括硬件设计详解、软件设计详解。
2         功能列表

            序号
            
            功能
            
            详细说明
            
            1
            
            处理器
            
            Freescale’s i.MX6 Dual CPUs: ARM Cortex   A9, each @ 1GHz
            
            2
            
            内存
            
            1GB DDR3 1066MHz
            
            3
            
            存储器
            
            Emmc NAND FLASH 4GB
            
            4
            
            TF
            
            TF卡,
            
            5
            
            以太网
            
            10M/100/100M以太网
            
            6
            
            USB HOST
            
            USB HOSTUSB 2.0
            
            7
            
            固态硬盘
            
            Msata硬盘
            
            8
            
            高清视频输入
            
            支持一路VGA或者HDMI或者DVI高清视频输入,分辨率为1600*1200@60或者1920*1080@60或者1280x720@60HZ
            
            9
            
            H.264或者MPEG4编码
            
            支持H.264或者MPEG4编码,分辨率至少为1600*1200@30或者1920*1080@30或者1280x720@60HZ
            
            10
            
            操作系统
            
            Linux 3.0.15
            
            11
            
            工作温度
            
            -40-70
            
3         系统框图

产品系统主要包括i.MX6 Dual处理器、以太网、高清视频解码芯片、固体硬盘、USB HOST以及调试串口。
功能见如下框图
                            

4         软件设计

4.1        CSI框图


4.2      ADV7441A I2C寄存器设置

42 03 0C ; Disable TOD
42 05 02 ; Prim_Mode =010b for automatic graphics mode
42 06 07 ; VID_STD=00111b for automatic graphics mode
42 1D 40 ; Disable TRI_LLC
42 3C A8 ; SOG Sync level for atenuated sync, PLL Qpump to default
42 37 00 ; PCLK Polarity
42 47 0A ; Enable Automatic PLL_Qpump and VCO Range
42 68 F2 ; Auto CSC, RGB Out
42 6B F2 ; Setup CPOP_SEL & DE Enable
42 7B 1D ; Turn off EAV and SAV codes
42 7C 00 ; HS/VS Positive
42 7E 03 ; HS Adjust
42 7F 88 ; VS Adjust
42 F4 3F ; Max Drive Strength
42 87 E8 ; Enable Manual PLL Divider Ratio 0x870 = 2160
42 88 70 ; Set PLL Divider Ratio
42 8C 07 ; HS adjust
42 8D 5A ; HS adjust
42 8E 87 ; VBI Adjust
42 8F 01 ; Set Free Run Line Length 0x17E = 382
42 90 7E ; Set Free Run Line Length
42 AB 4E ; Set Line Count Max 0x4E2 = 1250
42 AC 20 ; Set Line Count Max
42 B5 08 ; Deglitch Filter adjust
42 91 10 ; Progressive
4.3      引脚定义

static iomux_v3_cfg_t mx6q_sabresd_csi1_sensor_pads[] = {
        /* IPU2 tvin */
        MX6Q_PAD_EIM_DA0__IPU2_CSI1_D_9,
        MX6Q_PAD_EIM_DA1__IPU2_CSI1_D_8,
        MX6Q_PAD_EIM_DA2__IPU2_CSI1_D_7,
        MX6Q_PAD_EIM_DA3__IPU2_CSI1_D_6,
        MX6Q_PAD_EIM_DA4__IPU2_CSI1_D_5,
        MX6Q_PAD_EIM_DA5__IPU2_CSI1_D_4,
        MX6Q_PAD_EIM_DA6__IPU2_CSI1_D_3,
        MX6Q_PAD_EIM_DA7__IPU2_CSI1_D_2,
        MX6Q_PAD_EIM_EB2__IPU2_CSI1_D_19,
        MX6Q_PAD_EIM_D16__IPU2_CSI1_D_18,
        MX6Q_PAD_EIM_D18__IPU2_CSI1_D_17,
        MX6Q_PAD_EIM_D19__IPU2_CSI1_D_16,
        MX6Q_PAD_EIM_D20__IPU2_CSI1_D_15,
        MX6Q_PAD_EIM_D26__IPU2_CSI1_D_14,
        MX6Q_PAD_EIM_D27__IPU2_CSI1_D_13,
        MX6Q_PAD_EIM_D28__IPU2_CSI1_D_12,
        MX6Q_PAD_EIM_D17__IPU2_CSI1_PIXCLK,
        MX6Q_PAD_EIM_EB3__IPU2_CSI1_HSYNC,
        MX6Q_PAD_EIM_D29__IPU2_CSI1_VSYNC,
        MX6Q_PAD_EIM_D31__GPIO_3_31,            /* tvin reset , low */
};
4.4      adv7441a复位和CPU相应寄存器初始化

       #define SABRESD_TVIN_REST       IMX_GPIO_NR(3, 31)
       static void mx6q_csi1_io_init(void)
{
        mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_csi1_sensor_pads,
                ARRAY_SIZE(mx6q_sabresd_csi1_sensor_pads));
        /* tvin reset */
        gpio_request(SABRESD_TVIN_REST, "tvin-rest");
        gpio_direction_output(SABRESD_TVIN_REST, 1);
        gpio_direction_output(SABRESD_TVIN_REST, 0);
        msleep(10);
        gpio_direction_output(SABRESD_TVIN_REST, 1);
        /* For MX6Q:
         * GPR1 bit19 and bit20 meaning:
         * Bit19:       0 - Enable mipi to IPU1 CSI0
         *                      virtual channel is fixed to 0
         *              1 - Enable parallel interface to IPU1 CSI0
         * Bit20:       0 - Enable mipi to IPU2 CSI1
         *                      virtual channel is fixed to 3
         *              1 - Enable parallel interface to IPU2 CSI1
         * IPU1 CSI1 directly connect to mipi csi2,
         *      virtual channel is fixed to 1
         * IPU2 CSI0 directly connect to mipi csi2,
         *      virtual channel is fixed to 2
         * For MX6DL:
         * GPR13 bit 0-2 IPU_CSI0_MUX
         *   000 MIPI_CSI0
         *   100 IPU CSI0
        if (cpu_is_mx6q())
                mxc_iomux_set_gpr_register(1, 20, 1, 1);
 //  CPU工作在IPU2 CSI1
        else if (cpu_is_mx6dl())
                mxc_iomux_set_gpr_register(13, 0, 3, 4);
}
 
 
 
4.5      V4L主设备驱动

 
static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm)
        if (ifparm.if_type == V4L2_IF_TYPE_BT656) {
            if (ifparm.u.bt656.clock_curr == 0) {
                csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
            } else {
                if (cam->device_type != 1)
                    csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
                else
                    csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
            }
            if (ifparm.u.bt656.mode == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT) {
                csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
            } else if (ifparm.u.bt656.mode
                    == V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT) {
                csi_param.data_width = IPU_CSI_DATA_WIDTH_10;
            } else {
                csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
            }
            csi_param.Vsync_pol = ifparm.u.bt656.nobt_vs_inv;
            csi_param.Hsync_pol = ifparm.u.bt656.nobt_hs_inv;
            csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv;
            csi_param.ext_vsync = ifparm.u.bt656.bt_sync_correct;
        } if (ifparm.if_type == V4L2_IF_TYPE_BT1120) {
            {
                if (ifparm.u.bt1120.clock_curr == 0) {
                    csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR;
                }
 else {
                    if (cam->device_type != 1)
                        csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
                    else
                        csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR;
                }
            }
            if (ifparm.u.bt1120.mode == V4L2_IF_TYPE_BT1120_MODE_BT_8BIT) {
                csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
            } else if (ifparm.u.bt1120.mode
                    == V4L2_IF_TYPE_BT1120_MODE_BT_16BIT) {
                csi_param.data_width = IPU_CSI_DATA_WIDTH_16;
            } else {
                csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
            }
            csi_param.Vsync_pol = ifparm.u.bt1120.nobt_vs_inv;
            csi_param.Hsync_pol = ifparm.u.bt1120.nobt_hs_inv;
            csi_param.pixclk_pol = ifparm.u.bt1120.latch_clk_inv;
            csi_param.ext_vsync = ifparm.u.bt1120.bt_sync_correct;
        }
 
4.6      adv7441a_probe函数

 
static int adv7441a_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
{
        int ret = 0;
        tvin_plat = client->dev.platform_data;
        if (tvin_plat->io_init)
                tvin_plat->io_init();
        if (tvin_plat->reset)
                tvin_plat->reset();
        if (tvin_plat->pwdn)
                tvin_plat->pwdn(0);
        msleep(1);
        /* Set initial values for the sensor struct. */
        memset(&adv7441a_data, 0, sizeof(adv7441a_data));
        adv7441a_data.sen.i2c_client = client;
        adv7441a_data.sen.streamcap.timeperframe.denominator = 30;
        adv7441a_data.sen.streamcap.timeperframe.numerator = 1;
        adv7441a_data.std_id = V4L2_STD_ALL;
        video_idx = ADV7441A_NOT_LOCKED;
        adv7441a_data.sen.streamcap.capability = V4L2_MODE_HIGHQUALITY | V4L2_CAP_TIMEPERFRAME;
        adv7441a_data.sen.pix.width = video_fmts[video_idx].raw_width;
        adv7441a_data.sen.pix.height = video_fmts[video_idx].raw_height;
 adv7441a_data.sen.pix.pixelformat = V4L2_PIX_FMT_YUYV; //像素格式
        adv7441a_data.sen.pix.priv = 1;  /* 1 is used to indicate TV in */
        adv7441a_data.sen.on = true;
        adv7441a_data.sen.csi = 1;
}
4.7      V4L从设备给V4L主设备的获取时序模式参数的函数

static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
{
        if (s == NULL) {
                pr_err("   ERROR!! no slave device set!\n");
                return -1;
        }
        /* Initialize structure to 0s then set any non-0 values. */
        memset(p, 0, sizeof(*p));
        p->if_type = V4L2_IF_TYPE_BT1120;/* This is the only possibility. */
        p->u.bt656.mode = V4L2_IF_TYPE_BT1120_MODE_BT_8BIT;
        p->u.bt656.clock_curr = 1;
        return 0;
}

4.8      V4L从设备给V4L主设备的获取分辨率的函数

 
static int ioctl_enum_framesizes(struct v4l2_int_device *s,

                struct v4l2_frmsizeenum *fsize)

{

        if (fsize->index >= 1)

                return -EINVAL;

                fsize->discrete.width = (hdmi_read(0x07) & 0x0f) * 256 + hdmi_read(0x08);

                fsize->discrete.height = (hdmi_read(0x09) & 0x0f) * 256 + hdmi_read(0x0a);

                adv7441a_autoset(fsize->discrete.width, fsize->discrete.height);

                fsize->discrete.height -= (fsize->discrete.height) % 8;

        return 0;

}

更多详细技术信息请参看成都嵌智捷科技网站或咨询公司技术支持,http://www.nidetech.com
clip_image002.gif
clip_image002.jpg
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条



手机版|小黑屋|与非网

GMT+8, 2025-1-11 13:00 , Processed in 0.122040 second(s), 17 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.