720|3

510

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

【兆易GD32H759I-EVAL】--9.摄像头屏显 [复制链接]

 
本帖最后由 dirty 于 2024-6-1 19:56 编辑

      本篇讲述摄像头驱动,显示到LCD屏。

一.了解摄像头原理

      开发板配备有一颗OV2640摄像头,DVP接口,200W像素。开发板摄像头部分的原理如下。

图1:摄像头原理

引脚功能定义:

PIXCLK输出时钟
XCLK外部时钟输入
VSYNC场同步
HSYNC行同步
D[0:7]并口数据(8bit数据位数大小)

I2C接口:寄存器驱动配置

模块特点:

标准的SCCB接口,兼容12C接口:
RaWRGB,RGB(GRB4:2:2,RGB565/555/444),YUV(4:2:2)和YCbCr(4:2:2)输出格式。
支持UXGA、SXGA、VGA、QVGA、QQVGA、CIF、QCIF等支持自动曝光控制、自动增益控制、自动白平衡,自动消除灯光条纹、自动黑电平校准.图像质量控制包括色饱和度、色相、伽玛、锐度ANTI BLOOM等设置。
支持图像缩放、平移和窗口设置。
支持图像压缩,即可输出JPEG图像数据。

 

二.软件代码

      实现方式:使用DCI接口采集数据,使用前面用过的TLI接口显示采集图像。这里在前面LVGL工程基础上实现按键切换到摄像头图像显示到LCD屏。

1.添加sdk里关于摄像头驱动的源文件,如下图所示

图2:摄像头驱动文件添加

2.摄像头驱动初始化。这里初始化了摄像头sccb引脚,以及dci配置,包含I2C初始化,DMA初始化。之后通过写参数配置摄像头。最后定义了摄像头输出图像大小320*240。显示屏是480*272,因此后面涉及到转换。

/*!
    \brief      DCI camera initialization
    \param[in]  none
    \param[out] none
    \retval     0x00 or 0xFF
*/
uint8_t dci_ov2640_init(void)
{
    uint8_t i;
    sccb_config();
    dci_config();
    
    ckout0_init();
    delay_1ms(100);
    /* OV2640 reset */
    if(dci_byte_write(0xFF, 0x01) != 0) {
        return 0xFF;
    }
    if(dci_byte_write(0x12, 0x80) != 0) {
        return 0xFF;
    }
    delay_1ms(10);
    for(i = 0; i < sizeof(ov2640_svga_init_reg_tbl) / 2; i++) {
        if(0 != dci_byte_write(ov2640_svga_init_reg_tbl[i][0], ov2640_svga_init_reg_tbl[i][1])) {
            return 0xFF;
        }
    }

    delay_1ms(100);
    for(i = 0; i < (sizeof(ov2640_rgb565_reg_tbl) / 2); i++) {
        if(0 != dci_byte_write(ov2640_rgb565_reg_tbl[i][0], ov2640_rgb565_reg_tbl[i][1])) {
            return 0xFF;
        }
    }
    delay_1ms(100);
    ov2640_outsize_set(320, 240);
    return 0;
}

3.读出摄像头信息,包含厂商,版本和pid.

/*!
    \brief      read the ov2640 manufacturer identifier
    \param[in]  ov2640id: pointer to the ov2640 manufacturer struct
    \param[out] none
    \retval     0x00 or 0xFF
*/
uint8_t dci_ov2640_id_read(ov2640_id_struct *ov2640id)
{
    uint8_t temp;
    dci_byte_write(0xFF, 0x01);
    if(dci_byte_read(OV2640_MIDH, &temp) != 0) {
        return 0xFF;
    }
    ov2640id->manufacturer_id1 = temp;
    if(dci_byte_read(OV2640_MIDL, &temp) != 0) {
        return 0xFF;
    }
    ov2640id->manufacturer_id2 = temp;
    if(dci_byte_read(OV2640_VER, &temp) != 0) {
        return 0xFF;
    }
    ov2640id->version = temp;
    if(dci_byte_read(OV2640_PID, &temp) != 0) {
        return 0xFF;
    }
    ov2640id->pid = temp;

    return 0x00;
}

4.配置DMA和 DCI,这里LVGL显示在LAYER0,摄像头画面显示在LAYER1,故这里先将摄像头禁能。

    nvic_configuration();

    /* DMA interrupt and channel enable */
    dma_interrupt_enable(DMA1, DMA_CH7, DMA_CHXCTL_FTFIE);
    dma_channel_enable(DMA1, DMA_CH7);
    /* DCI enable */
    dci_enable();
    dci_capture_enable();
    delay_1ms(3000);

    dma_interrupt_disable(DMA1, DMA_CH7, DMA_CHXCTL_FTFIE);
    dma_channel_disable(DMA1, DMA_CH7);
    dci_capture_disable();

5.俘获照片数据保存到SDRAM,这里不停止视频流,如果拍照可以把屏蔽的打开

/*!
    \brief      save image to sdram
    \param[in]  none
    \param[out] none
    \retval     none
*/
void image_save(void)
{
    uint32_t i = 0;

    // dma_interrupt_disable(DMA1, DMA_CH7, DMA_CHXCTL_FTFIE);
    // dma_channel_disable(DMA1, DMA_CH7);
    // dci_capture_disable();

    /* save image to sdram */
    for(i = 0; i < 32640; i++) {
        *(uint32_t *)(0xC0800000 + 4 * i) = *(uint32_t *)(0xC1000000 + 4 * i);
    }
}

6.摄像头图片显示,这里切换图层。

/*!
    \brief      display image to lcd
    \param[in]  display_image_addr: image display address
    \param[out] none
    \retval     none
*/
void image_display(uint32_t display_image_addr)
{

    tli_layer_parameter_struct         tli_layer1_initstruct;

    /* input address configuration */
    tli_layer1_initstruct.layer_frame_bufaddr = (uint32_t)display_image_addr;

    /* layer1 windowing configuration */
    tli_layer1_initstruct.layer_window_leftpos = 162;
    tli_layer1_initstruct.layer_window_rightpos = (160 + 240 - 1);
    tli_layer1_initstruct.layer_window_toppos =  12;
    tli_layer1_initstruct.layer_window_bottompos = (12 + 272 - 1);

    /* pixel format configuration */
    tli_layer1_initstruct.layer_ppf = LAYER_PPF_RGB565;

    /* alpha constant configuration : the constant alpha for layer 1 is decreased
    to see the layer 0 in the intersection zone*/
    tli_layer1_initstruct.layer_sa = 255;

    /* default color configuration (configure A,R,G,B component values) */
    tli_layer1_initstruct.layer_default_blue = 0xFF;
    tli_layer1_initstruct.layer_default_green = 0xFF;
    tli_layer1_initstruct.layer_default_red = 0xFF;
    tli_layer1_initstruct.layer_default_alpha = 0;

    /* blending factors */
    tli_layer1_initstruct.layer_acf1 = LAYER_ACF1_PASA;
    tli_layer1_initstruct.layer_acf2 = LAYER_ACF1_PASA;

    // /* configure input address : frame buffer is located at memory */
    // tli_layer1_initstruct.layer_frame_bufaddr = (uint32_t)0xC1000000;

    tli_layer1_initstruct.layer_frame_line_length = ((240 * 2) + 3);
    tli_layer1_initstruct.layer_frame_buf_stride_offset = (240 * 2);

    tli_layer1_initstruct.layer_frame_total_line_number = 272;

    tli_layer_init(LAYER1, &tli_layer1_initstruct);
    tli_dither_config(TLI_DITHER_ENABLE);

    tli_layer_init(LAYER1, &tli_layer1_initstruct);

    /* disenable layer0 */
    tli_layer_disable(LAYER0);
    /* enable layer1 */
    tli_layer_enable(LAYER1);
    /* reload configuration */
    tli_reload_config(TLI_REQUEST_RELOAD_EN);

    /* enable TLI */
    tli_enable();
}

7.在Project\gd32h7xx_it.c添加中断处理函数。EXTI10_15_IRQHandler是Tamper按键中断,保存照片数据和使能DMA1和打开摄像头DCI俘获.DMA1_Channel7_IRQHandler处理数据将320*240摄像头数据转为240*272屏显数据。

/*!
    \brief      this function handles external lines 10 to 15 interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/
void EXTI10_15_IRQHandler(void)
{

    if(RESET != exti_interrupt_flag_get(EXTI_13)) 
    {
        printf("Key Pressed\r\n");
        exti_interrupt_flag_clear(EXTI_13); 
        
        dma_interrupt_enable(DMA1, DMA_CH7, DMA_CHXCTL_FTFIE);
        dma_channel_enable(DMA1, DMA_CH7);
        dci_capture_enable();
        
        image_save();
        image_display((uint32_t)image_background1);
        delay_1ms(500);
        image_display((uint32_t)0XC1000000);
        //lv_demo_music(); 
             
    }
}


/*!
    \brief      this function handles DMA1_Channel7_IRQ interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/
void DMA1_Channel7_IRQHandler(void)
{
    /* 320*240 size image convert to 240*272 size image */
    if(dma_interrupt_flag_get(DMA1, DMA_CH7, DMA_INT_FLAG_FTF)) 
    {
        //printf("\r\nprocess image\r\n");
        int i = 0, x = 0, y = 0;
        dma_channel_disable(DMA1, DMA_CH7);
        
        for(x = 0; x < 320; x++) {
            for(y = 0; y < 240; y++) {
                if(x < 272) {
                    *(uint16_t *)(0xC1000000 + 2 * i) = *(uint16_t *)(0xC0000000 + 2 * ((320 * y) + x));
                    i++;
                }
            }
        }
        dma_interrupt_flag_clear(DMA1, DMA_CH7, DMA_INT_FLAG_FTF);
        dma_channel_enable(DMA1, DMA_CH7);
    }
}

8.main函数

int main(void)
{
    ov2640_id_struct ov2640id;
    BaseType_t ret;
    
    /* enable the CPU cache */
    cache_enable();
    /* initialize the LEDs */
    test_status_led_init();

    /* configure systick */
    systick_config();
    
   

    /* flash the LEDs for 2 time */
    led_flash(2);

    /* configure USART0 */
    usart_config();

    /* configure TAMPER key */
    gd_eval_key_init(KEY_TAMPER, KEY_MODE_EXTI);

    /* output a message on hyperterminal using printf function */
    printf("\r\n =================  LVGL =================   \r\n");

    /**********************LCD Application**********************/
    
    /* config the EXMC access mode */
    exmc_synchronous_dynamic_ram_init(EXMC_SDRAM_DEVICE0);
    printf("\r\nSDRAM Init \r\n");

    /* camera initialization */
    dci_ov2640_init();
    dci_ov2640_id_read(&ov2640id);
    printf("\r\nMF1:0x%02x,MF2:0x%02x,version:0x%02x,pid:0x%02x\r\n",ov2640id.manufacturer_id1,\
        ov2640id.manufacturer_id2,ov2640id.version,ov2640id.pid);

    nvic_configuration();

    /* DMA interrupt and channel enable */
    dma_interrupt_enable(DMA1, DMA_CH7, DMA_CHXCTL_FTFIE);
    dma_channel_enable(DMA1, DMA_CH7);
    /* DCI enable */
    dci_enable();
    dci_capture_enable();
    delay_1ms(100);

    dma_interrupt_disable(DMA1, DMA_CH7, DMA_CHXCTL_FTFIE);
    dma_channel_disable(DMA1, DMA_CH7);
    dci_capture_disable();


    timer_config();
    
    lcd_config();
    lcd_init();
    /* configure the GPIO of SPI touch panel */
    touch_panel_gpio_configure();
    #if (LVGL_DMA)
    delay_1ms(50);
    dma_config();
    delay_1ms(1000);
    #endif

    lv_init();
    lv_port_disp_init();
    lv_port_indev_init();

    // lv_demo_music();
    lv_demo_widgets();

    while(1)
    {
        delay_1ms(5);
        lv_task_handler();
    }
    
}

三.测验

      编译烧录后,可以看到LCD显示widgets,Tamper按键按下后,屏创建了一个240*272的摄像头视频显示.效果见视频。成像效果感觉一般,优化可以调整ov2640_svga_init_reg_tbl寄存器参数。

      至此,实现摄像头图像屏显。

camera_show

 

最新回复

[attach]813690[/attach]   摄像头图像屏显可以的   详情 回复 发表于 2024-6-4 07:33
点赞 关注
个人签名

保持热爱

 
 

回复
举报

510

帖子

0

TA的资源

纯净的硅(初级)

来自 4楼
 
本帖最后由 dirty 于 2024-6-24 23:38 编辑

摄像头屏显工程代码

 

FreeRTOS_LVGL_Camera.rar

36.76 MB, 下载次数: 3

摄像头屏显工程

个人签名

保持热爱

 
 
 

回复

6809

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

 

摄像头图像屏显可以的

点评

是的,实现了  详情 回复 发表于 2024-6-12 09:17
 
 
 

回复

510

帖子

0

TA的资源

纯净的硅(初级)

板凳
 
Jacktang 发表于 2024-6-4 07:33   摄像头图像屏显可以的

是的,实现了

个人签名

保持热爱

 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表