Maix Bit(K210) 裸机开发教程(六)摄像头使用

13 篇文章 23 订阅
9 篇文章 11 订阅

  DVP 是摄像头接口模块,支持把摄像头输入图像数据转发给 AI 模块或者内存。
在这里插入图片描述
DVP 模块具有以下功能:
• 支持 RGB565、RGB422 与单通道 Y 灰度输入模式
• 支持设置帧中断
• 支持设置传输地址
• 支持同时向两个地址写数据(输出格式分别是 RGB888 与 RGB565)
• 支持丢弃不需要处理的帧

1、代码获取

在我前面一篇博客里面简述了代码如何下载以及使用。https://blog.csdn.net/weixin_45488643/article/details/109990336如有需要自行查看。
  选择dvp_ov(摄像头):
在这里插入图片描述

2、代码修改

  和上次一样的操作,自己先创建一个新的工程文件,然后将dvp_ov文件夹下面的代码复制到:
在这里插入图片描述
安装依赖库文件:
在这里插入图片描述
比较重要的一点,开启控制:
打开board_config.h 我自己使用的是Maix bit 开发板,所以选择如下配置文件,根据需要选择自己的开发板硬件配置。
在这里插入图片描述

3、DVP 常用API

1、 DVP初始化:

void dvp_init(uint8_t reg_len)

在这里插入图片描述
2、 设置 xclk 的速率。
DVP(数字摄像头接口)的时钟频率

uint32_t dvp_set_xclk_rate(uint32_t xclk_rate)

在这里插入图片描述
返回,xclk 的实际速率。

3、禁用突发传输模式

void dvp_enable_burst(void)

4、设置输出模式使能或禁用

void dvp_set_output_enable(dvp_output_mode_t index, int enable)

在这里插入图片描述
5、设置图像接收模式

void dvp_set_image_format(uint32_t format)

6、设置图像接收模式,RGB 或 YUV
在这里插入图片描述
7、设置 DVP 图像采集尺寸

void dvp_set_image_size(uint32_t width, uint32_t height)

在这里插入图片描述

8、设置 AI 存放图像的地址
设置 AI 存放图像的地址,供 AI 模块进行算法处理

void dvp_set_ai_addr(uint32_t r_addr, uint32_t g_addr, uint32_t b_addr)

在这里插入图片描述
9、采集图像地址
设置采集图像在内存中的存放地址,可以用来显示

void dvp_set_ai_addr(uint32_t r_addr, uint32_t g_addr, uint32_t b_addr)

在这里插入图片描述
10、配置 DVP 中断类型
设置图像开始和结束中断状态,使能或禁用

void dvp_config_interrupt(uint32_t interrupt, uint8_t enable)

在这里插入图片描述
11、使能自动接收图像模式

void dvp_disable_auto(void)

12、清除中断

void dvp_clear_interrupt(uint32_t interrupt)

在这里插入图片描述

4、主函数

#include <stdio.h>
#include <string.h>

#include "board_config.h"
#include "dvp.h"
#include "fpioa.h"
#include "iomem.h"
#include "lcd.h"
#include "nt35310.h"
#include "ov2640.h"
#include "ov5640.h"
#include "plic.h"
#include "sysctl.h"
#include "uarths.h"
#include "unistd.h"

static uint32_t *g_lcd_gram0;
static uint32_t *g_lcd_gram1;

volatile uint8_t g_dvp_finish_flag;
volatile uint8_t g_ram_mux;

// DVP 中断回调
static int on_irq_dvp(void *ctx) {
  if (dvp_get_interrupt(DVP_STS_FRAME_FINISH)) {
    /* switch gram */
    dvp_set_display_addr(g_ram_mux ? (uint32_t)g_lcd_gram0
                                   : (uint32_t)g_lcd_gram1);

    dvp_clear_interrupt(DVP_STS_FRAME_FINISH);
    g_dvp_finish_flag = 1;
  } else {
    if (g_dvp_finish_flag == 0) dvp_start_convert();
    dvp_clear_interrupt(DVP_STS_FRAME_START);
  }

  return 0;
}
//初始化设备,使用宏定义区分board,详情修改 board_config.h
static void io_mux_init(void) {
#if BOARD_LICHEEDAN
  /* Init DVP IO map and function settings */ /*初始化DVP输入输出映射和功能设置*/
  fpioa_set_function(42, FUNC_CMOS_RST);
  fpioa_set_function(44, FUNC_CMOS_PWDN);
  fpioa_set_function(46, FUNC_CMOS_XCLK);
  fpioa_set_function(43, FUNC_CMOS_VSYNC);
  fpioa_set_function(45, FUNC_CMOS_HREF);
  fpioa_set_function(47, FUNC_CMOS_PCLK);
  fpioa_set_function(41, FUNC_SCCB_SCLK);
  fpioa_set_function(40, FUNC_SCCB_SDA);

  /* Init SPI IO map and function settings */ /*初始化串行接口输入输出映射和功能设置*/
  fpioa_set_function(38, FUNC_GPIOHS0 + DCX_GPIONUM);
  fpioa_set_function(36, FUNC_SPI0_SS3);
  fpioa_set_function(39, FUNC_SPI0_SCLK);
  fpioa_set_function(37, FUNC_GPIOHS0 + RST_GPIONUM);

  sysctl_set_spi0_dvp_data(1);
#else
  /* Init DVP IO map and function settings */ /*初始化DVP输入输出映射和功能设置*/
  fpioa_set_function(11, FUNC_CMOS_RST);
  fpioa_set_function(13, FUNC_CMOS_PWDN);
  fpioa_set_function(14, FUNC_CMOS_XCLK);
  fpioa_set_function(12, FUNC_CMOS_VSYNC);
  fpioa_set_function(17, FUNC_CMOS_HREF);
  fpioa_set_function(15, FUNC_CMOS_PCLK);
  fpioa_set_function(10, FUNC_SCCB_SCLK);
  fpioa_set_function(9, FUNC_SCCB_SDA);

  /* Init SPI IO map and function settings */ /*初始化串行接口输入输出映射和功能设置*/
  fpioa_set_function(8, FUNC_GPIOHS0 + DCX_GPIONUM);
  fpioa_set_function(6, FUNC_SPI0_SS3);
  fpioa_set_function(7, FUNC_SPI0_SCLK);

  sysctl_set_spi0_dvp_data(1);

#endif
}
//初始化DVP PWOER
static void io_set_power(void) {
#if BOARD_LICHEEDAN
  /* Set dvp and spi pin to 1.8V */ /*将dvp和spi引脚设为1.8V */
  sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
  sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V18);

#else
  /* Set dvp and spi pin to 1.8V */ /*将dvp和spi引脚设为1.8V */
  sysctl_set_power_mode(SYSCTL_POWER_BANK1, SYSCTL_POWER_V18);
  sysctl_set_power_mode(SYSCTL_POWER_BANK2, SYSCTL_POWER_V18);
#endif
}

int main(void) {
  /* Set CPU and dvp clk */ /*设置CPU  DVP时钟*/
  sysctl_pll_set_freq(SYSCTL_PLL0, 800000000UL);
  sysctl_pll_set_freq(SYSCTL_PLL1, 160000000UL);
  sysctl_pll_set_freq(SYSCTL_PLL2, 45158400UL);
  uarths_init();

  io_mux_init();   //初始化DVP输入输出映射和功能设置
  io_set_power();  //初始化DVP POWER
  plic_init();     //初始化为外部中断

  /* LCD init */
  printf("LCD init\n");
  /* LCD 初始化 */
  lcd_init();
  lcd_clear(BLACK);
  lcd_draw_string(136, 70, "QingYeMuRong",
                  WHITE);  //初始化LCD液晶显示屏,并显示黑底白字:QingYeMuRong
#if BOARD_LICHEEDAN
  /*设置LCD显示方向*/
  lcd_set_direction(DIR_YX_RLDU); //DIR_YX_LRDU 摄像头LCD方向自行调整
#else
  lcd_set_direction(DIR_YX_RLUD);
#endif

  lcd_clear(BLACK);

  g_lcd_gram0 = (uint32_t *)iomem_malloc(320 * 240 * 2);
  g_lcd_gram1 = (uint32_t *)iomem_malloc(320 * 240 * 2);
  /* DVP init */
  printf("DVP init\n");
#if OV5640
  dvp_init(16);
  dvp_set_xclk_rate(50000000);
  dvp_enable_burst();
  dvp_set_output_enable(0, 1);
  dvp_set_output_enable(1, 1);
  dvp_set_image_format(DVP_CFG_RGB_FORMAT);
  dvp_set_image_size(320, 240);
  ov5640_init();

#if 0
//    OV5640_Focus_Init();
    OV5640_Light_Mode(2);      //set auto
    OV5640_Color_Saturation(6); //default
    OV5640_Brightness(8);   //default
    OV5640_Contrast(3);     //default
//    OV5640_Sharpness(33);   //set auto
//    OV5640_Auto_Focus();
#endif

// 初始化摄像头
#else
  dvp_init(8);                  //初始化DVP,设置sccb寄存器长度为8
  dvp_set_xclk_rate(24000000);  //摄像头时钟频率
  dvp_enable_burst();           //使能突发传输模式
  dvp_set_output_enable(0, 1);  //使能输出模式,并设置图像输出至内存
  dvp_set_output_enable(1, 1);  //使能输出模式,并设置图像输出至AI
  dvp_set_image_format(DVP_CFG_RGB_FORMAT);  //设置接收图像模式模式为RGB

  dvp_set_image_size(320, 240);  //设置DVP 图像采集尺寸为320*240
  ov2640_init();                 //初始化摄像头
#endif
  //设置AI 存放图像的地址,供AI 模块进行算法处理。
  //分别是红色分量地址、绿色分量地址、蓝色分量地址
  dvp_set_ai_addr((uint32_t)0x40600000, (uint32_t)0x40612C00,
                  (uint32_t)0x40625800);
  //设置采集图像在内存中的存放地址,可以用来显示。
  dvp_set_display_addr((uint32_t)g_lcd_gram0);
  //禁止图像开始采集中断、结束采集中断
  dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 0);
  dvp_disable_auto();  //禁用自动接收图像模式

  /* DVP interrupt config */ /*DVP中断控制 */
  printf("DVP interrupt config\n");
  // 设置摄像头的中断  IRQN_DVP_INTERRUPT是数字摄像头(DVP)中断号
  plic_set_priority(IRQN_DVP_INTERRUPT, 1);
  plic_irq_register(
      IRQN_DVP_INTERRUPT, on_irq_dvp,
      NULL);  // plic_irq_register注册外部中断函数,on_irq_dvp是中断回调函数
  plic_irq_enable(IRQN_DVP_INTERRUPT);

  /* enable global interrupt */ /*使能全局中断*/
  sysctl_enable_irq();

  /* system start */
  printf("system start\n");
  g_ram_mux = 0;
  g_dvp_finish_flag = 0;
  dvp_clear_interrupt(DVP_STS_FRAME_START | DVP_STS_FRAME_FINISH);
  dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 1);

  while (1) {
    /* ai cal finish*/
    while (g_dvp_finish_flag == 0)
      ;
    g_dvp_finish_flag = 0;
    /* display pic*/
    g_ram_mux ^= 0x01;
    lcd_draw_picture(0, 0, 320, 240, g_ram_mux ? g_lcd_gram0 : g_lcd_gram1);
  }
  iomem_free(g_lcd_gram0);
  iomem_free(g_lcd_gram1);
  return 0;
}

5、效果展示

LCD显示屏的方向自行调整。
在这里插入图片描述

  • 6
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值