前言

我们这款开发板应该是最便宜的AI开发板了吧,200RMB左右,搭载1TOPS处理能力的K210芯片,丰富的外设接口,内置超多算法,除此之外,开发板还带了屏幕和摄像头。本章我们介绍SPI接口的另一个应用,驱动LCD屏幕。需要开发板可以联系我,可以价格更低哦!
上一章写了LCD屏幕显示,这一章介绍下摄像头,最终实现摄像头的图像在LCD上显示;开发板搭载了OV2640摄像头,OV264是Omni Vision公司生产的一颗CMOS图像传感器,支持最高200万像素,支持自动曝光控制、自动增益控制、自动白平衡、自动消除灯光条纹等自动控制功能。
在这里插入图片描述
在这里插入图片描述

一、硬件介绍

ov2640摄像头模组利用透镜成像的原理,采集图像,通过感光芯片及相关电路来记录和传输图像信号,按一定的分辨率,以隔行扫描的方式采集图像上的点,当扫描到某点时,就通过图像传感芯片将该点处图像的灰度转换成灰度一一对应的电压值,然后将此电压值通过视频信号端输出。

OV2640摄像头与K210开发板通过数字摄像头接口(DVP)连接,DVP 是常用的摄像头接口模块,具有以下特性:

a.支持支持SCCB协议配置摄像头寄存器;

b.支持640×480(30万像素)及以下分辨率,每帧大小可配置;

c.支持YUV422和RGB565格式的图像输入;

d.支持图像同时输出到KPU和显示屏:

-输出到KPU的格式可选RGB888,或YUV422输入时的Y分量,

-输出到显示屏的格式为RGB565;

e.检测到一帧开始或一帧图像传输完成时可向CPU发送中断。

二、K210对硬件的支持

硬件连接图
在这里插入图片描述
在这里插入图片描述
对应的头文件 dvp.h

为用户提供以下接口:

· dvp_init :DVP初始化。

· dvp_set_output_enable:设置输出模式(内存或AI)使能或禁止。

· dvp_set_image_format:设置图像接收模式,RGB或YUV。

· dvp_set_image_size:设置DVP图像采集尺寸。

· dvp_set_ai_addr:设置AI存放图像的地址,供AI模块进行算法处理。

· dvp_set_display_addr:设置采集图像在内存中的存放地址,可以用来显示。

· dvp_config_interrupt:设置图像开始和结束中断状态,使能或禁用。

· dvp_get_interrupt:判断是否是输入的中断类型,返回值:0为否,非0为是。

· dvp_clear_interrupt:清除中断。

· dvp_start_convert:开始采集图像,在确定图像采集开始中断后调用。

· dvp_enable_burst:使能突发传输模式。

· dvp_disable_burst:禁用突发传输模式。

· dvp_enable_auto:使能自动接收图像模式。

· dvp_disable_auto:禁用自动接收图像模式。

· dvp_sccb_send_data:通过sccb协议发送数据。

· dvp_sccb_receive_data:通过SCCB接收数据。

· dvp_sccb_set_clk_rate:设置sccb的速率。

· dvp_set_xclk_rate:设置输入时钟的速率。

实验过程

代码比较多,demo会统一放到gitCode上(https://gitcode.com/bin_zhangg0n/K210/tree/main)。

首先根据上面的硬件连接引脚图,完成硬件引脚和软件功能的映射关系

#include "fpioa.h"

/*****************************HARDWARE-PIN*********************************/
// 硬件IO口,与原理图对应
#define PIN_LCD_CS             (36)
#define PIN_LCD_RST            (37)
#define PIN_LCD_RS             (38)
#define PIN_LCD_WR             (39)

// camera
#define PIN_DVP_PCLK           (47)
#define PIN_DVP_XCLK           (46)
#define PIN_DVP_HSYNC          (45)
#define PIN_DVP_PWDN           (44)
#define PIN_DVP_VSYNC          (43)
#define PIN_DVP_RST            (42)
#define PIN_DVP_SCL            (41)
#define PIN_DVP_SDA            (40)

/*****************************SOFTWARE-GPIO********************************/
// 软件GPIO口,与程序对应
#define LCD_RST_GPIONUM        (0)
#define LCD_RS_GPIONUM         (1)


/*****************************FUNC-GPIO************************************/
// GPIO口的功能,绑定到硬件IO口
#define FUNC_LCD_CS             (FUNC_SPI0_SS3)
#define FUNC_LCD_RST            (FUNC_GPIOHS0 + LCD_RST_GPIONUM)
#define FUNC_LCD_RS             (FUNC_GPIOHS0 + LCD_RS_GPIONUM)
#define FUNC_LCD_WR             (FUNC_SPI0_SCLK)

void hardware_init(void)
{
    /* lcd */
    fpioa_set_function(PIN_LCD_CS,  FUNC_LCD_CS);
    fpioa_set_function(PIN_LCD_RST, FUNC_LCD_RST);
    fpioa_set_function(PIN_LCD_RS,  FUNC_LCD_RS);
    fpioa_set_function(PIN_LCD_WR,  FUNC_LCD_WR);

    /* DVP camera */
    fpioa_set_function(PIN_DVP_RST,   FUNC_CMOS_RST);
    fpioa_set_function(PIN_DVP_PWDN,  FUNC_CMOS_PWDN);
    fpioa_set_function(PIN_DVP_XCLK,  FUNC_CMOS_XCLK);
    fpioa_set_function(PIN_DVP_VSYNC, FUNC_CMOS_VSYNC);
    fpioa_set_function(PIN_DVP_HSYNC, FUNC_CMOS_HREF);
    fpioa_set_function(PIN_DVP_PCLK,  FUNC_CMOS_PCLK);
    fpioa_set_function(PIN_DVP_SCL,   FUNC_SCCB_SCLK);
    fpioa_set_function(PIN_DVP_SDA,   FUNC_SCCB_SDA);
    
    /* 使能SPI0和DVP */
    sysctl_set_spi0_dvp_data(1);
}
//初始化电源域电压,摄像头和显示器都需要1.8V电平信号,根据所在电源域设置bank6和bank7的电压为1.8V
void io_set_power(void)
{
    sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
    sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V18);
}

int main(void)
{
    int OV_type;
    /* 硬件引脚初始化 */
    hardware_init();
    /* 设置IO口电压 */
    io_set_power();

    /* 设置系统时钟和DVP时钟 */
    sysctl_pll_set_freq(SYSCTL_PLL0, 800000000UL);
    sysctl_pll_set_freq(SYSCTL_PLL1, 300000000UL); 
    sysctl_pll_set_freq(SYSCTL_PLL2, 45158400UL);
    uarths_init();

    /* 系统中断初始化,使能全局中断*/
    plic_init();
    sysctl_enable_irq();
    
    /* 初始化LCD */
    lcd_init();
    
    /* LCD显示图片 */
    uint16_t *img = &gImage_logo;
    lcd_draw_picture_half(0, 0, 320, 240, img);
    lcd_draw_string(16, 40, "Hello Yahboom!", RED);
    lcd_draw_string(16, 60, "Nice to meet you!", BLUE);
    sleep(1);

    OV_type=OVxxxx_read_id();
    /* 初始化摄像头 */
    if(OV_type == OV_9655)
    {
        ov9655_init();
    }   
    else if(OV_type == OV_2640) 
    {
        ov2640_init();
    }
    else 
    {
       return 0;//打不开摄像头,结束
    }

    while (1)
    {  
        /* 等待摄像头采集结束,然后清除结束标志 */
        while (g_dvp_finish_flag == 0)
            ;
        g_dvp_finish_flag = 0;

        /* 显示画面 */
       lcd_draw_picture(0, 0, 320, 240, display_buf_addr);
    }

    return 0;
}

在编译过程中有部分同学可能因为SDK版本问题,找不到iomem.h和iomem.c可以到github上下载,放到lib/drivers下

把代码中的camera复制到SDK中的src目录下,

然后进入build目录,运行以下命令编译。

cd build

cmake .. -DPROJ=camera -G "MinGW Makefiles"

make

编译完成后,在build文件夹下会生成camera.bin文件,

打开kflash将camera.bin文件烧录到K210开发板上。
在这里插入图片描述
实验结果
在这里插入图片描述


总结

K210开发板板载dvp接口可以与兼容dvp接口的ov2640摄像头连接使用,画面显示整体来说比较流畅;

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐