6.12. 如何调试一款新摄像头

本节旨在让用户快速调试新型号(dvp/spi接口)摄像头出图;

AC79 有两个 ISC (图像传感器控制模块)(ISC0/1),用于接收片外 Image CMOS Sensor 的图像数据,完成数据重排和处理;

其支持传统 8bit 的 DVP、BT601、BT656 接口,除此之外还支持以上接口的串行化,如 4/2/1bit 的 DVP、BT601、BT656,支持 SPI 模式;

推荐使用ISC接收,兼容DVP和SPI模式,用户不需要关心底层是如何收数据,仅需根据需求修改接口配置及摄像头寄存器配置,加快工程的开发进度。

6.12.1. 必要说明

  • 板载硬件说明

    板载摄像头型号及接口:

    camera0-gc2145-dvp

    camera1-gc0310-SPI

    AC79最大支持 96Mhz-pclk 输入(考虑稳定性,不建议pclk大于60Mhz),最大像素为1280×720

  • 调试新的摄像头驱动建议以已经适配的摄像头驱动作为参考调试,硬件电路参照AC79_DevKitBoard原理图,开源板引出了摄像头复用IO

  • 调试摄像头期间建议:准备 1 台逻辑分析仪、1 台示波器

  • 摄像头出图流程:检验摄像头(check ID)->向摄像头发送寄存器配置->主控接收数据处理->推送到屏幕显示

  • dvp和spi摄像头调试过程类似,区别在于硬件接口、接收模式上,请参考适配例程中的摄像头型号驱动进行配置

6.12.2. 环境配置方法

调试DVP-8bit、1bit、2bit及4bit摄像头建议在 apps/common/example/video/camera/dvp/main.c 环境下进行(使用ISC接收)

调试SPI-1/2bit摄像头可以在 apps/common/example/video/camera/spi/main.c 环境下进行(SPI接收)

选择 demo/demo_DevKitBoard 工程运行

apps/demo/demo_DevKitBoard/include/demo_config.h 中打开对应的宏(确保其余宏全部关闭)

//SPI:
#define CONFIG_SPI_VIDEO_ENABLE
//DVP(ISC):
#define USE_CAMERA_DVP_SHOW_TO_LCD_DEMO
//如果demo_config.h没有对应的宏,请在对应的main.c中#define以使能

即可跑对应的main.c

6.12.3. 调试步骤

第一步:摄像头引脚与芯片IO正确连接,板级配置对应IO

  • 若硬件连接与板载摄像头一致,请暂时取下板载摄像头(避免通讯冲突)

  • 板级配置文件路径: apps/demo/demo_DevKitBoard/board/wl82/DevKitBoard.c 主要配置IIC、SPI(针对SPI摄像头)及摄像头数据IO、时钟IO

//*********************************************************************************//
//                                   IIC模块配置                                    //
//*********************************************************************************//
#ifdef CONFIG_IIC_ENABLE
//板载摄像头默认使用iic0
SW_IIC_PLATFORM_DATA_BEGIN(sw_iic0_data)//软件iic
    .clk_pin = IO_PORTH_00,//SCL_IO
    .dat_pin = IO_PORTH_01,//SDA_IO
    .sw_iic_delay = 50,
SW_IIC_PLATFORM_DATA_END()
#endif
//**********************************END*******************************************//

//*********************************************************************************//
//                                   SPI模块配置                                    //
//*********************************************************************************//
#ifdef CONFIG_SPI_ENABLE
//spi/main.c默认使用spi2
SPI2_PLATFORM_DATA_BEGIN(spi2_data)
    .clk    = 40000000,
    .mode   = SPI_STD_MODE,//SPI_1WIRE_MODE(单线模式) SPI_STD_MODE(双线模式) SPI_DUAL_MODE(全双工模式) SPI_QUAD_MODE(四线模式)
    .attr   = SPI_MODE_SLAVE | SPI_SCLK_L_UPH_SMPH | SPI_UNIDIR_MODE,//从机,CLK高 更新数据高,单向模式
    .port   = 'C',
SPI2_PLATFORM_DATA_END()
#endif
//**********************************END*******************************************//

//*********************************************************************************//
//                                摄像头模块配置                                   //
//*********************************************************************************//
#ifdef CONFIG_VIDEO_ENABLE
//*****************************************camera0-ISC0接收(DVP-8bit配置为例)****************************************//
static const struct camera_platform_data camera0_data = {
    .xclk_gpio      = IO_PORTH_02,//注意: 如果硬件xclk接到芯片IO,则会占用OUTPUT_CHANNEL1
    .reset_gpio     = IO_PORTH_03,//复位IO,一般该引脚可以直接接3.3V的高电平(根据数据手册),可不需要特定IO来控制
    .online_detect  = NULL,//默认NULL即可
    .pwdn_gpio      = -1,//pwdn引脚可以配合引脚写具体IO如IO_PORTC_04,一般摄像头pwdn引脚直接接地即可,具体参考摄像头数据手册
    .power_value    = 0,//pwdn引脚使用IO控制时的正常工作pwdn引脚电平
    .interface      = SEN_INTERFACE0,//SEN_INTERFACE_CSI2,//默认即可
    .dvp={                           //dvp_IO配置
        .pclk_gpio   = IO_PORTA_08,
        .hsync_gpio  = IO_PORTA_09,
        .vsync_gpio  = IO_PORTA_10,
        .group_port  = ISC_GROUPA,
        .data_gpio   = {
                IO_PORTA_07,
                IO_PORTA_06,
                IO_PORTA_05,
                IO_PORTA_04,
                IO_PORTA_03,
                IO_PORTA_02,
                IO_PORTA_01,
                IO_PORTA_00,
                -1,
                -1,
        },
    }
};
static const struct video_subdevice_data video0_subdev_data[] = {//镜头设备参数
    { VIDEO_TAG_CAMERA, (void *)&camera0_data },
};
static const struct video_platform_data video0_data = {//video0参数,设备列表参数需要该参数
    .data = video0_subdev_data,
    .num = ARRAY_SIZE(video0_subdev_data),
};

//*****************************************camera1-SPI接收****************************************//
static const struct camera_platform_data camera1_data = {
    .xclk_gpio      = -1,//IO_PORTB_02,//IO_PORTC_08,//IO_PORTC_06,//注意: 如果硬件xclk接到芯片IO,则会占用OUTPUT_CHANNEL1
    .reset_gpio     = IO_PORTH_03,
    .online_detect  = NULL,
    .pwdn_gpio      = -1,
    .power_value    = 0,
    .interface      = -1,
    .dvp={
        .group_port  = -1,
        .pclk_gpio   = -1,
        .hsync_gpio  = -1,
        .vsync_gpio  = -1,
        .data_gpio={-1},
    }
};
static const struct video_subdevice_data video1_subdev_data[] = {//镜头设备参数
    { VIDEO_TAG_CAMERA, (void *)&camera1_data },
};
static const struct video_platform_data video1_data = {//video1参数,设备列表参数需要该参数
    .data = video1_subdev_data,
    .num = ARRAY_SIZE(video1_subdev_data),
};
#endif
//**********************************END*******************************************//

第二步:摄像头驱动配置,check摄像头ID,检验是否成功与摄像头通信

  • Device Address、Sensor_ID请在相应摄像头的datasheet中查询

以gc2145为例:

//GC2145.C
#define GC2145_DVP_WRCMD 0x78//Device Address
#define GC2145_DVP_RDCMD 0x79


s32 GC2145_ID_check(void)//check摄像头ID
{
    u8 pid = 0x00;
    u8 ver = 0x00;
    u8 i ;
    for (i = 0; i < 3; i++) {
        rdGC2145Reg(0xf0, &pid);//Sensor_ID_Address
        rdGC2145Reg(0xf1, &ver);
    }
    puts("Sensor PID \n");
    puts("\n");
    if (pid != 0x21 || ver != 0x45) { //Sensor_ID_DefaultValue
        puts("\n----not GC2145_DVP-----\n");
        return -1;
    }
    puts("\n----hello GC2145_DVP-----\n");//打印此行说明成功check到摄像头ID通讯成功
    return 0;
}

第三步:根据摄像头官方驱动例程更改寄存器配置及注册配置

以DVP-8bit为例

//GC2145.C

#define GC2145_DEVP_INPUT_W 1280//摄像头输出分辨率,需要与摄像头实际输出分辨率一致
#define GC2145_DEVP_INPUT_H 720

static const struct reginfo sensor_init_data[] = { //寄存器配置(配置重点),主要关注输出接口、输出数据格式、输出线数、输出分辨率和pclk频率等相关寄存器
    //{Address,Value}                              //sensor数据输出正确是接收正确的前提
    {0xfe, 0xf0},
    {0xfe, 0xf0},
    {0xfe, 0xf0},
    {0xfc, 0x06},
    {0xf6, 0x00},
    {0xf7, 0x1d},
//省略...
};

REGISTER_CAMERA(GC2145) = { //ISC接收摄像头注册在REGISTER_CAMERA;SPI接收摄像头注册在REGISTER_CAMERA1
    .logo                   =   "GC2145",
    .isp_dev                =   ISP_DEV_NONE, //ISP_DEV_NONE 或 ISP_DEV_0,对应”iic0”设备
    .in_format              =   SEN_IN_FORMAT_YUYV,//YUV排列顺序,与摄像头输出顺序一致
    .mbus_type              =   SEN_MBUS_PARALLEL, //数据格式配置,与摄像头输出格式一致,详见isp_dev.h
    .mbus_config            =   SEN_MBUS_DATA_WIDTH_8B | SEN_MBUS_HSYNC_ACTIVE_HIGH | \
                                SEN_MBUS_PCLK_SAMPLE_FALLING | SEN_MBUS_VSYNC_ACTIVE_HIGH, //线数配置及采样配置,详见isp_dev.h
#if CONFIG_CAMERA_H_V_EXCHANGE
    .sync_config            =   SEN_MBUS_SYNC0_VSYNC_SYNC1_HSYNC,//WL82/AC791才可以H-V SYNC互换,请留意
#endif
//省略...
    }
};

第四步:参考摄像头数据手册修改寄存器配置,根据需求调整输出效果。

  • 输出分辨率的大小:裁剪窗口相关寄存器

  • 输出帧率提高:提高pclk频率、缩小输出数据帧间距行间距

6.12.4. 适配例程

  • ISC接收

    1bit-SPI-bt656:参考byd20a6.c 1bit 配置

    2bit-SPI-bt656:参考byd20a6.c 2bit 配置

    4bit-SPI-bt656:参考byd20a6.c 4bit 配置

    8bit-DVP:参考GC2145.c 配置(上述第一、三步举例)

使用ISC接收配置举例:

1/2/4bit接收时.data_gpio的第一个IO配置必须是最低位的对应IO,以下为4bit:PA0-PA3接收配置举例:

//DevKitBoard.c
static const struct camera_platform_data camera0_data = {
            .xclk_gpio      = IO_PORTH_02,//xclk
            .reset_gpio     = IO_PORTH_03,
            .online_detect  = NULL,
            .pwdn_gpio      = -1,
            .power_value    = 0,
            .interface      = SEN_INTERFACE0,
            .dvp={
                .pclk_gpio   = IO_PORTA_08,//pclk
                .hsync_gpio  = -1,
                .vsync_gpio  = -1,
                .group_port  = ISC_GROUPA,
                .data_gpio   = {           //接收数据IO配置,按此.data_gpio配置的接收IO为PA0-PA3,对应sensor的D0-D3
                        IO_PORTA_00,//低
                        IO_PORTA_01,
                        IO_PORTA_02,
                        IO_PORTA_03,//高
                        -1,
                        -1,
                        -1,
                        -1,
                        -1,
                        -1,
                },
            }
        };
//byd20a6.c
        REGISTER_CAMERA(BYD20a6) = {
        .isp_dev                        =       ISP_DEV_NONE,
        .in_format                      =       SEN_IN_FORMAT_YVYU,//与摄像头输出格式一致
        .mbus_type          =   SEN_MBUS_BT656,//与摄像头输出数据格式一致(此例程1/2/4bit帧协议均为:帧头:ff0000ab,帧尾:ff0000b6,行头:ff000080, 行尾:ff00009d)
      //.mbus_config        =   SEN_MBUS_DATA_WIDTH_1B | SEN_MBUS_PCLK_SAMPLE_FALLING,//1bit接收|下降沿采样
      //.mbus_config        =   SEN_MBUS_DATA_WIDTH_2B | SEN_MBUS_PCLK_SAMPLE_FALLING,//2bit接收|下降沿采样
        .mbus_config        =   SEN_MBUS_DATA_WIDTH_4B | SEN_MBUS_PCLK_SAMPLE_FALLING,//4bit接收|下降沿采样

      //省略...
    };
  • SPI接收

    SPI-1bit:参考GC0310.c 1bit 配置

    SPI-2bit:参考GC0310.c 2bit 配置

    板级配置参考上述第一步配置

6.12.5. IO反转接收功能配置说明

.data_gpio按照正常正序配置,在摄像头驱动中的.mbus_config添加 SEN_MBUS_DATA_WIDTH_REVERSE 即可

以下配置为4bit:PA4-PA7、IO反转接收举例,即D0-PA7,D1-PA6,D2-PA5,D3-PA4对应

//DevKitBoard.c

.data_gpio   = {
        IO_PORTA_04,       //按照正常正序配置
        IO_PORTA_05,
        IO_PORTA_06,
        IO_PORTA_07,
        -1,
        -1,
        -1,
        -1,
        -1,
        -1,
},
//byd20a6.c

.mbus_config        =   SEN_MBUS_DATA_WIDTH_4B | SEN_MBUS_PCLK_SAMPLE_FALLING | SEN_MBUS_DATA_WIDTH_REVERSE ,//4bit接收|下降沿采样|反转接收

6.12.6. 报错总结

  • IIC读取ID不匹配:

    驱动里面的 iic 设备不对应(“iic0”还是“iic1”),原因为:.isp_dev = xx 不对;

    board.c 的 iic 的 IO 不对;

    摄像头的 xmclk 引脚没有时钟输入,检查 board.c 的 xclk 时钟引脚;

    摄像头的 power_down 引脚的电平没接对,一般正常工作低电平(要看数据手册,看看是低电平还是高电平);

    摄像头的 reset 引脚的电平是否正确;

    检查Device Address、Sensor_ID配置是否正确。

  • 出现 video_ioct: err = 11 或 yuv recv timeout:

    硬件没有收到时钟,检查 pclk 的有没有时钟输出(示波器看下有没有时钟);

    pclk频率配置过高,镜头输出时钟不稳定,尝试降低频率;

    接线问题:确定 PCLK 和 DATA 数据正确接对在对应 IO,连接没有断线可能;

    VDDIO电压错误;

    协议不正确:逻辑分析仪 100M 采样率抓数据进行解析帧头帧尾、行头行尾;

    ISC 接收情况下检查帧协议是否正确:帧头:ff0000ab,帧尾:ff0000b6,行头:ff000080, 行尾:ff00009d。

  • 报错 isc line err 行出错,原因可能有:

    初始化 bt656 分辨率和实际摄像头输出的分辨率不一致;

    在 2/4/8bit 模式下,可能因为数据位 IO 反接(isc line err 打印很猛下大部分因为这个原因);

    协议不符合。

  • 报错 isc bandwith err,带宽不够,原因可能有:

    数据瑕疵;

    性能带宽不足,如果能正常出图可忽略。

  • 使用 SPI 接收,出现—->SPI_FSTART = 0x%x , 0x%x ,recv data err , reinit spi camera :

    数据头出现问题,用逻辑分析仪解析spi数据是否正确。若数据不正确,检查接线及数据格式配置;若数据正确,spi接收不正确,则大部分原因为:配置的边沿采样不符合,尝试更换边沿采样配置。

  • 图像显示异常:

    数据瑕疵;

    出现大片绿色:YUV格式顺序错误,在摄像头驱动.c中配置YUV格式顺序;

    出现图像条纹、显示分格:采样边沿出错、分辨率设置与镜头实际输出分辨率不一致;

    出现蓝色条纹、噪点:检查电源供电

  • 以上报错可能来源于电压不稳定、数据线时钟线毛刺,请确保硬件的稳定性。