GD32450i-EVAL学习笔记 17 - 数字摄像头接口(DCI)

目录

1 IO初始化

2 初始化DCI

2.1 使能DCI和DMA1

2.2 配置寄存器DCI_CTL

2.2.1 快照模式SNAP

2.2.2 时钟极性选择CKS

2.2.3 水平同步极性选择HPS

2.2.4 垂直同步极性选择VPS

2.2.5 数据格式DCIF

2.2.6 帧频率FR

2.3 配置DMA

3. 使能DCI

4. 初始化OV2640

5. 设置OV2640的像素大小

6. 初始化摄像头


数字摄像头接口是一个同步并行接口,可以从数字摄像头捕获视频和图像信息。它支持不同的
颜色空间图像,例如YUV/RGB,另外支持压缩数据的JPEG格式图像。

1 IO初始化

 DCI一般选择8bit接口,另外OV2640需要I2C接口设置寄存器。

2 初始化DCI

2.1 使能DCI和DMA1

RCU_AHB2EN |= ((uint32_t)1 << 0);  //Enable DCI
RCU_AHB1EN |= ((uint32_t)1 << 22);  //Enable DMA1

一般使用DCI都会使用DMA功能,DCI对应DMA1的通道1或通道7,这里用到的是通道7.

2.2 配置寄存器DCI_CTL

2.2.1 快照模式SNAP

0:连续捕获模式 - 连续捕获摄像头数据

1:快照模式 - 只捕获单帧,收到完整的第一帧后, 将自动禁止摄像头接口

2.2.2 时钟极性选择CKS

0:下降沿捕获

1:上升沿捕获

2.2.3 水平同步极性选择HPS

0:消隐期间低电平

1:消隐期间高电平

2.2.4 垂直同步极性选择VPS

0:消隐期间低电平

1:消隐期间高电平

2.2.5 数据格式DCIF

00:每个像素时钟捕获 8 位数据

01:每个像素时钟捕获 10 位数据

10:每个像素时钟捕获 12 位数据

11:每个像素时钟捕获 14 位数据

一般设置为8位数据

2.2.6 帧频率FR

在连续捕获模式,FR 定义帧捕获频率

00:捕获所有帧

01:每隔一帧捕获一次

10:每隔三帧捕获一次

11:保留

2.3 配置DMA

有2个DMA通道可以用于DCI,即DMA1的通道1和通道7

    DMA_CHFCTL(DMA1, CAMERA_DMA_CH) = 0;
    DMA_CHCTL(DMA1, CAMERA_DMA_CH) = 0;
    
    DMA_CHFCTL(DMA1, CAMERA_DMA_CH) &= ~((uint32_t)1 << 2); //Disable Multi Data Mode
    DMA_CHPADDR(DMA1, CAMERA_DMA_CH) = (uint32_t)&DCI_DATA;
    DMA_CHM0ADDR(DMA1, CAMERA_DMA_CH) = ramAddr;
    DMA_CHCNT(DMA1, CAMERA_DMA_CH) = (uint32_t)CAMERA_SIZE_W * CAMERA_SIZE_H * stride / 4;
    
    value = DMA_CHCTL(DMA1, CAMERA_DMA_CH);
    //bit6-7: channel transfer mode
    //bit11-12: transfer data width of peripheral
    //bit13-14: transfer data width of memory
    //bit16-17: channel priority level
    value &= ~((uint32_t)0x03 << 11 | ((uint32_t)3 << 13) | ((uint32_t)3 << 16) | ((uint32_t)3 << 6));
    value |= (((uint32_t)2 << 11) | ((uint32_t)2 << 13) | ((uint32_t)2 << 16) | ((uint32_t)0 << 6));
    //bit9: next address generation algorithm of peripheral
    value &= ~((uint32_t)1 << 9); //Disable Peripheral's Address Auto Increasing.
    //bit10: next address generation algorithm of memory
    value |= ((uint32_t)1 << 10);        //Enable Memory's Address Auto Increasing.
    //bit8: DMA circular mode
    value |= ((uint32_t)1 << 8);        //Enable DMA Circular Mode
    //bit25-27: peripheral enable
    value &= ~((uint32_t)0x7 << 25);
    value |= ((uint32_t)0x1 << 25); //Peripheral 1(DCI is 1) is enable.
    
    DMA_CHCTL(DMA1, CAMERA_DMA_CH) = value;

ramAddr是MCU中分配给DCI的RAM空间,例如这里是分配一个数组

#define CAMERA_SIZE_W                   320
#define CAMERA_SIZE_H                   240
EXTERN uint16_t gCameraBuf[CAMERA_SIZE_W * CAMERA_SIZE_H];

摄像头采用RGB565格式,一个像素对应2个字节,所以这里用uint16_t定义这个数组变量,对应stride = 2(即RGB565是2个字节)。

2.4 配置时钟输出

    reg = RCU_CFG0;
    #if (PIN_DCI_XCLK == 8)
    /* reset the CKOUT0SRC, CKOUT0DIV and set according to ckout0_src and ckout0_div */
    reg &= ~(RCU_CFG0_CKOUT0SEL | RCU_CFG0_CKOUT0DIV);
    RCU_CFG0 = (reg | RCU_CKOUT0SRC_HXTAL | RCU_CKOUT0_DIV3);
    #else
    reg &= ~(RCU_CFG0_CKOUT1SEL | RCU_CFG0_CKOUT1DIV);
    RCU_CFG0 = (reg | RCU_CKOUT1SRC_HXTAL | RCU_CKOUT1_DIV3);
    #endif

3. 使能DCI

void dciEnable(void)
{
    DMA_CHCTL(DMA1, CAMERA_DMA_CH) |= ((uint32_t)1 << 0 | ((uint32_t)0x1 << 4)); //DMA_ENABLE
    DCI_CTL |= ((uint32_t)1 << 14);    //DCI enable
    DCI_CTL |= ((uint32_t)1 << 0);            //DCI capture enable
}

主要是使能DMA和DCI。

4. 初始化OV2640

void ov2640Init(void)
{
    uint8_t buf[1];
    uint16_t i;
    bool_t status = 0;
    /* OV2640 reset */
    buf[0] = 0x01;
    status = i2cWrite(I2C_CAMERA, OV2640_ADDRESS, 8, 0xff, buf, 1);
    if(status == FALSE)
    {
        OV2640_INFO(Printf("ov2640 init fail 1\n"));
    }
    buf[0] = 0x80;
    status = i2cWrite(I2C_CAMERA, OV2640_ADDRESS, 8, 0x12, buf, 1);
    if(status == FALSE)
    {
        OV2640_INFO(Printf("ov2640 init fail 2\n"));
    }
    delayms(10);
    for(i = 0; i < sizeof(ov2640_svga_init_reg_tbl) / 2; i++)
    {
        status = i2cWrite(I2C_CAMERA, OV2640_ADDRESS, 8, ov2640_svga_init_reg_tbl[i][0], (uint8_t *)&(ov2640_svga_init_reg_tbl[i][1]), 1);
        if(status == FALSE)
        {
            OV2640_INFO(Printf("ov2640 init fail 3:%d\n", i));
            break;
        }
    }
    delayms(100);
    for(i = 0; i < sizeof(ov2640_rgb565_reg_tbl)/2; i++)
    {
        status = i2cWrite(I2C_CAMERA, OV2640_ADDRESS, 8, ov2640_rgb565_reg_tbl[i][0], (uint8_t *)&(ov2640_rgb565_reg_tbl[i][1]), 1);
        if(status == FALSE)
        {
            OV2640_INFO(Printf("ov2640 init fail 4:%d\n", i));
            break;
        }
    }
    delayms(100);
}

5. 设置OV2640的像素大小

OV2640的像素大小必须是4个倍数

void ov2640SetSize(uint16_t w, uint16_t h)
{
    uint16_t outh;
    uint16_t outw;
    uint8_t buf[1];
    
    if((w % 4) > 0)
        return;
    if((h % 4) > 0)
        return;

    outw = w / 4;
    outh = h / 4;
    buf[0] = 0x00;  
    i2cWrite(I2C_CAMERA, OV2640_ADDRESS, 8, 0xff, buf, 1);
    buf[0] = 0x04;  
    i2cWrite(I2C_CAMERA, OV2640_ADDRESS, 8, 0xE0, buf, 1);
    buf[0] = outw & 0xFF;  
    i2cWrite(I2C_CAMERA, OV2640_ADDRESS, 8, 0x5A, buf, 1);
    buf[0] = outh & 0xFF;  
    i2cWrite(I2C_CAMERA, OV2640_ADDRESS, 8, 0x5B, buf, 1);

    buf[0] = (outw >> 8) & 0x03;
    buf[0] |= (outh >> 6) & 0x04;
    i2cWrite(I2C_CAMERA, OV2640_ADDRESS, 8, 0x5C, buf, 1); 
    
    buf[0] = 0x00;  
    i2cWrite(I2C_CAMERA, OV2640_ADDRESS, 8, 0xE0, buf, 1);
}

6. 初始化摄像头

最终摄像头的内容显示到TFT屏,所以这里需要把数据丢到TLI上显示出来。

    tliLayer_t layer;
    ov2640Init();
    Printf("OV2640 ID:%x\n", ov2640GetID());
    ov2640SetSize(CAMERA_SIZE_W, CAMERA_SIZE_H);
    dciEnable();
    delayms(100);
    layer.alpha = 0xFF;
    layer.bufAddr = (uint32_t)gCameraBuf;//(uint32_t)0xC0000000;
    layer.defalutColor = 0x00FFFFFF;
    layer.format = FORMAT_RGB565;
    layer.x = 0;
    layer.y = 0;
    layer.w = CAMERA_SIZE_W;
    layer.h = CAMERA_SIZE_H;
    tliLayerInit(0, layer, 1);

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值