米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加

软件版本:VIVADO2017.4

操作系统:WIN10 64bit

硬件平台:适用米联客 ZYNQ系列开发板

米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!

25.1 概述

      本课使用MT9V034搭建两路基于VDMA的摄像头图形采集系统,并对OSD实现字幕叠加功能说明。提供的代码也包含MT9V034、OV5640摄像头双目例程,实现过程大同小异,这里不做过多讲解。

25.2 双目图像采集传输系统架构图

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第1张图片

25.3 FPGA BD工程

25.3.1 摄像头电路设计

     本课使用两个MT9V034摄像头(配套的代码也给出了2路OV5640摄像头OSD方案),每路摄像头输出分辨率640*480。摄像头部分电路设计如下所示:

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第2张图片 

25.3.2 Vid_in IP电路搭建

        MT9V034的vid_ce信号始终接电平。这里给出MT9V034部分电路设计:

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第3张图片 

25.3.3 VDMA设置

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第4张图片米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第5张图片

25.3.4 OSD设置

本章要使用OSD完成字幕的叠加功能,所以要开启AXI-lite控制接口。OSD配置如下所示:

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第6张图片米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第7张图片

LAYER2和LAYER3层设置

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第8张图片

      上面第一副图中,我们勾选了控制接口,开启了4个Layer,最大输出设置为了1280。至于为什么使用4个layer,这是因为要完成2路视频拼接和2路字幕叠加。另外最后2个layer就是字幕叠加层,所以将其设置为了Internal Graphics Controllers。第二副图是对各个层进行显示的设置,大家也可以修改这一部分的设置来完成各个图层的显示位置,功能也不仅仅局限于拼接视频,也可以完成画中画的功能,OSD是个功能很强大的IP!设置完这两部分之后,在LAYER2、3设置ASCII Offset为0,否则后面设置字符串会发生错位,其余的配置按默认即可。

25.3.5 PLL时钟设置

      PLL时钟的设置取决于分辨率大小的设置,本节采用的是720P输出,因此PLL时钟设置如下:

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第9张图片

25.3.6 VTC设置

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第10张图片

25.3.7 AXI IIC设置

     本节课要使用2路摄像头进行采集,需要两路IIC配置对摄像头寄存器进行配置。

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第11张图片

此部分的设置如下图所示:

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第12张图片

      其余选项的设置参考之前历程的设置即可。

25.4 软件部分设计

     软件部分主要可以分为三块,IIC协议实现、OSD驱动与VDMA配置。下面分别对这三个部分进行介绍。

25.4.1 IIC实现

     本课节当中要对两个摄像头进行寄存器配置,如下图所示:

 米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第13张图片

在main.c中可以看到摄像头IIC初始化配置函数。

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第14张图片  

在I2C_8bit.c文件中,找到I2C_config_init()配置函数。

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第15张图片

其中,在I2C_8bit.c中可以查找到mt9v034_config_table[]与I2C_write相关定义。

相关定义mt9v034_config_table[]

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第16张图片

       其中write_i2c是ov5640的iic配置程序,write_i2c_mt是MT9V034的iic配置程序,程序的主要设计思想就是使用一个数字来存放要配置的寄存器地址和数据。

25.4.2 OSD驱动设计

      OSD驱动部分主要由osd.c与osd.h组成。程序由官方驱动重新封装,此处重点介绍osd.c。OSD驱动如下表所示:

 

 

#include "xbasic_types.h"

#include "xparameters.h"

#include "xstatus.h"

#include "osd.h"

#include "xosd.h"

#include "stdio.h"

 

 

/*

 * Device related constants. Defined in xparameters.h

 */

#define OSD_DEVICE_ID     XPAR_OSD_0_DEVICE_ID

 

/*

 * OSD Device related data structures

 */

XOSD Osd;                    /* OSD Device driver instance */

XOSD_Config *OsdCfgPtr;      /* OSD device configuration pointer */

 

/*

 * Color table definition

 */

u32 ColorData[16] = {

    0x00000000, 0xa0a25f58, 0xa08080ff, 0xa0808010,

    0xa0ef5a51, 0x00000000, 0xa0465289, 0x00000000,

    0xa065ba6b, 0x00000000, 0xa09017c5, 0xa0a9c860,

    0xa0bc3198, 0xa010a5a9, 0xa0808080, 0xa0ada1ab

};

 

/*

 * Text table definition

 */

char __attribute__ ((aligned (4))) TextData[8][32] = {

    "OV5640", //"String #1",

    "OV7725",                       //"String #2",

    "MT9V034 CAMER TEST",

"www.osrc.cn"

    "Xilinx",

    "String #5",

    "String #6",

    "String #7"

   // "String #8"

};

 

/*

 * Font definition

 */

unsigned char __attribute__ ((aligned (4))) Font[128][8] = {

    {0x00, 0x36, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00}, // NULL

    {0x18, 0x18, 0x18, 0x1F, 0x1F, 0x18, 0x18, 0x18},

    {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03},

    {0x18, 0x18, 0x18, 0xF8, 0xF8, 0x00, 0x00, 0x00},

    {0x18, 0x18, 0x18, 0xF8, 0xF8, 0x18, 0x18, 0x18},

    {0x00, 0x00, 0x00, 0xF8, 0xF8, 0x18, 0x18, 0x18},

    {0x03, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0xC0},

    {0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03},

    {0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF},

    {0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F},

    {0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF},

    {0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00},

    {0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00},

    {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},

    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF},

    {0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0},

    {0x00, 0x1C, 0x1C, 0x77, 0x77, 0x08, 0x1C, 0x00},

    {0x00, 0x00, 0x00, 0x1F, 0x1F, 0x18, 0x18, 0x18},

    {0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00},

    {0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x18, 0x18},

    {0x00, 0x00, 0x3C, 0x7E, 0x7E, 0x7E, 0x3C, 0x00},

    {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF},

    {0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0},

    {0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x18, 0x18},

    {0x18, 0x18, 0x18, 0xFF, 0xFF, 0x00, 0x00, 0x00},

    {0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0},

    {0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00},

    {0x78, 0x60, 0x78, 0x60, 0x7E, 0x18, 0x1E, 0x00},

    {0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x00},

    {0x00, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00},

    {0x00, 0x18, 0x30, 0x7E, 0x30, 0x18, 0x00, 0x00},

    {0x00, 0x18, 0x0C, 0x7E, 0x0C, 0x18, 0x00, 0x00},

 

    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Space

    {0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x00},

    {0x00, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00},

    {0x00, 0x66, 0xFF, 0x66, 0x66, 0xFF, 0x66, 0x00},

    {0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00},

    {0x00, 0x66, 0x6C, 0x18, 0x30, 0x66, 0x46, 0x00},

    {0x1C, 0x36, 0x1C, 0x38, 0x6F, 0x66, 0x3B, 0x00},

    {0x00, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00},

    {0x00, 0x0E, 0x1C, 0x18, 0x18, 0x1C, 0x0E, 0x00},

    {0x00, 0x70, 0x38, 0x18, 0x18, 0x38, 0x70, 0x00},

    {0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00},

    {0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00},

    {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30},

    {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00},

    {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00},

    {0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00},// /

    {0x00, 0x3C, 0x66, 0x6E, 0x76, 0x66, 0x3C, 0x00},// 0

    {0x00, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7E, 0x00},//1

    {0x00, 0x3C, 0x66, 0x0C, 0x18, 0x30, 0x7E, 0x00},//2

    {0x00, 0x7E, 0x0C, 0x18, 0x0C, 0x66, 0x3C, 0x00},//3

    {0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0x7E, 0x0C, 0x00},//4

    {0x00, 0x7E, 0x60, 0x7C, 0x06, 0x66, 0x3C, 0x00},//5

    {0x00, 0x3C, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00},//6

    {0x00, 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x00},//7

    {0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00},//8

    {0x00, 0x3C, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00},//9

    {0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00},

    {0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x30},

    {0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00},

    {0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00},

    {0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00},

    {0x00, 0x3C, 0x66, 0x0C, 0x18, 0x00, 0x18, 0x00},

 

    {0x00, 0x3C, 0x66, 0x6E, 0x6E, 0x60, 0x3E, 0x00}, // @

    {0x00, 0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x00}, // A

    {0x00, 0x7C, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00},

    {0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x00},

    {0x00, 0x78, 0x6C, 0x66, 0x66, 0x6C, 0x78, 0x00},

    {0x00, 0x7E, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00},

    {0x00, 0x7E, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00},

    {0x00, 0x3E, 0x60, 0x60, 0x6E, 0x66, 0x3E, 0x00},

    {0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00},

    {0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00},

    {0x00, 0x06, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00},

    {0x00, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x00},

    {0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00},

    {0x00, 0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x00},

    {0x00, 0x66, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x00},

    {0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00},

    {0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00},

    {0x00, 0x3C, 0x66, 0x66, 0x66, 0x6C, 0x36, 0x00},

    {0x00, 0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x00},

    {0x00, 0x3C, 0x60, 0x3C, 0x06, 0x06, 0x3C, 0x00},

    {0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00},

    {0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x00},

    {0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00},

    {0x00, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00},

    {0x00, 0x66, 0x66, 0x3C, 0x3C, 0x66, 0x66, 0x00},

    {0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00},

    {0x00, 0x7E, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00},//Z

    {0x00, 0x1E, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00},

    {0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00},

    {0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00},

    {0x00, 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00},

    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00},

 

    {0x40, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, // `

    {0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00}, // a

    {0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00},

    {0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x00},

    {0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00},

    {0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00},

    {0x00, 0x0E, 0x18, 0x3E, 0x18, 0x18, 0x18, 0x00},

    {0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x7C},

    {0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x00},

    {0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3C, 0x00},

    {0x00, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x3C},

    {0x00, 0x60, 0x60, 0x6C, 0x78, 0x6C, 0x66, 0x00},

    {0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00},

    {0x00, 0x00, 0x66, 0x7F, 0x7F, 0x6B, 0x63, 0x00},

    {0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00},

    {0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00},

    {0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60},

    {0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06},

    {0x00, 0x00, 0x7C, 0x66, 0x60, 0x60, 0x60, 0x00},

    {0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00},

    {0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x0E, 0x00},

    {0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00},

    {0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00},

    {0x00, 0x00, 0x63, 0x6B, 0x7F, 0x3E, 0x36, 0x00},

    {0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00},

    {0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x0C, 0x78},

    {0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00},

 

    {0x14, 0x10, 0x10, 0x40, 0x10, 0x10, 0x14, 0x00}, // {

    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},

    {0x50, 0x10, 0x10, 0x04, 0x10, 0x10, 0x50, 0x00}, // }

    {0x11, 0x11, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00}, // ~

    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 127 DEL

};

 

/*

 * Function prototypes

 */

 int  OsdInit(int DeviceID);

 void external_OsdConfig(u8 layer,u16 Screen_width,u16 Screen_height,u16 Camera_width,u16 Camera_height,u16 xpos_start,u16 ypos_start);

 void internal_Graphics_setting(u8 Gcindex,u16 Screen_width,u16 Screen_height,u16 Xpos_start,u16 Ypos_start,u8 BankIndex);

 void OsdDrawText(int Gcindex,int x_pos, int y_pos, int color, int string_index, int text_size,u8 BankIndex);

 void OsdDrawBox(int Gcindex,u16 x_start, u16 y_start, u16 x_last, u16 y_last, u8 color,u8 BankIndex);

 

 

void Camera_osd_init(void)

{

    int  bOsdInitialized = 0;

 

   if ( !bOsdInitialized )

   {

      OsdInit(OSD_DEVICE_ID);

      external_OsdConfig(0,1280,720,640,480,0,140);  //外部输入图层配置

      external_OsdConfig(1,1280,720,640,480,640,140);//外部输入图层配置

     internal_Graphics_setting(2,1280,720,0,0,0); //内出输入图层配置

     internal_Graphics_setting(3,1280,720,0,0,0); //内出输入图层配置

      bOsdInitialized = 1;

   }

 

   OsdDrawText(2,30,40,8,2,8,0);  //添加文字

   OsdDrawBox(3,25,25,1255,115, 8,0);//添加框

}

 

/*****************************************************************************/

/**

*

* This function initializes the OSD device and its driver instance.

*

* @param    DeviceID is the device ID of the OSD device.

*

* @return   0 if the initialization is successful; 1 otherwise.

*

* @note     None.

*

******************************************************************************/

int OsdInit(int DeviceID)

{

int Status;

 

/* Initialize the OSD instance */

 

OsdCfgPtr = XOSD_LookupConfig(DeviceID);

Status = XOSD_CfgInitialize(&Osd, OsdCfgPtr, OsdCfgPtr->BaseAddress);

if (Status != XST_SUCCESS)

return 1;

 

/* Reset the devices */

 

XOSD_Reset(&Osd);

 

/* Enable the OSD device and tell it to pick up the register changes */

 

XOSD_Enable(&Osd);

XOSD_RegUpdateEnable(&Osd);

 

return 0;

}

 

 

void internal_Graphics_setting(u8 Gcindex,u16 Screen_width,u16 Screen_height,u16 Xpos_start,u16 Ypos_start,u8 BankIndex)

{

u16 width   = Screen_width;

u16 height  = Screen_height;

 

int LayerAlphaValue = 0xFF;

int LayerGlobalAlphaEnable = 0;

int LayerPriority;

 

u8 ColorBankIndex=BankIndex;

u8 CharBankIndex=BankIndex;

u8 TextBankIndex=BankIndex;

u8 InstructionBankIndex=BankIndex;

 

if(Gcindex==0)

LayerPriority = XOSD_LAYER_PRIORITY_0;

else if(Gcindex==1)

LayerPriority = XOSD_LAYER_PRIORITY_1;

else if(Gcindex==2)

LayerPriority = XOSD_LAYER_PRIORITY_2;

else if(Gcindex==3)

LayerPriority = XOSD_LAYER_PRIORITY_3;

else if(Gcindex==4)

LayerPriority = XOSD_LAYER_PRIORITY_4;

else if(Gcindex==5)

LayerPriority = XOSD_LAYER_PRIORITY_5;

else if(Gcindex==6)

LayerPriority = XOSD_LAYER_PRIORITY_6;

else if(Gcindex==7)

LayerPriority = XOSD_LAYER_PRIORITY_7;

else

xil_printf("Para err!");

 

 

 

/* Set up Layer's Alpha, Priority, Dimension and enable it */

XOSD_SetLayerAlpha(&Osd, Gcindex, LayerGlobalAlphaEnable, LayerAlphaValue);

XOSD_SetLayerPriority(&Osd, Gcindex, LayerPriority);

XOSD_SetLayerDimension(&Osd, Gcindex, Xpos_start, Xpos_start, width, height);

XOSD_EnableLayer(&Osd, Gcindex);

 

    /* Load color, font and text and set the active banks */

 

XOSD_LoadColorLUTBank(&Osd, Gcindex, BankIndex, ColorData);

XOSD_LoadCharacterSetBank(&Osd, Gcindex, BankIndex, (u32 *)Font);

XOSD_LoadTextBank(&Osd, Gcindex, BankIndex, (u32 *)TextData);

XOSD_SetActiveBank(&Osd, Gcindex, ColorBankIndex, CharBankIndex,  TextBankIndex, InstructionBankIndex);

 

}

 

/*****************************************************************************/

/**

*

* This function does the general configuration on an OSD device. The

* configuration includes:

*

*   - Screen Size

*   - Background Color

*   - Layer 0 setup: Alpha, Priority, Dimension and enabling

*   - Layer 1 setup: Alpha, Priority, Dimension and enabling

*   - Loading Color/Font/Text configuration

*

* @param    None.

*

* @return   None.

*

* @note     None.

*

******************************************************************************/

void external_OsdConfig(u8 layer,u16 Screen_width,u16 Screen_height,u16 Camera_width,u16 Camera_height,u16 xpos_start,u16 ypos_start)

{

   /* Background color definition */

 

   u16 screen_width = Screen_width;

   u16 screen_height = Screen_height;

   u16 camera_width = Camera_width;

   u16 camera_height = Camera_height;

 

   u8 Red = 0x0; //0xFF;

   u8 Blue = 0x0; //0;

   u8 Green = 0x0; //0;

 

   /* Layer  property definition */

 

   int LayerAlphaValue = 0xFF;

   int LayerGlobalAlphaEnable = 1;

   int LayerPriority;

 

   if(layer==0)

    LayerPriority = XOSD_LAYER_PRIORITY_0;

    else if(layer==1)

    LayerPriority = XOSD_LAYER_PRIORITY_1;

    else if(layer==2)

    LayerPriority = XOSD_LAYER_PRIORITY_2;

    else if(layer==3)

    LayerPriority = XOSD_LAYER_PRIORITY_3;

    else if(layer==4)

    LayerPriority = XOSD_LAYER_PRIORITY_4;

    else if(layer==5)

    LayerPriority = XOSD_LAYER_PRIORITY_5;

    else if(layer==6)

    LayerPriority = XOSD_LAYER_PRIORITY_6;

    else if(layer==7)

    LayerPriority = XOSD_LAYER_PRIORITY_7;

    else

    xil_printf("Para err!");

 

 

   xil_printf("OsdConfig(%d,%d) Start\r\n", screen_width, screen_height);

 

   /* Set screen size */

   xil_printf("-- Set screen size ...\r\n" );

 

   XOSD_SetScreenSize(&Osd, screen_width, screen_height);

 

   /* Set Background color */

   xil_printf("-- Set Background color ...\r\n" );

 

   XOSD_SetBackgroundColor(&Osd, Red, Blue, Green);

 

   /* Set up Layer's Alpha, Priority, Dimension and enable it */

   xil_printf("-- Set up Layer 0's Alpha, Priority, Dimension and enable it ...\r\n" );

   XOSD_SetLayerAlpha(&Osd, layer, LayerGlobalAlphaEnable, LayerAlphaValue);

   XOSD_SetLayerPriority(&Osd, layer, LayerPriority);

   XOSD_SetLayerDimension(&Osd, layer, xpos_start, ypos_start, camera_width, camera_height);

   XOSD_EnableLayer(&Osd, layer);

 

    /* Enable the OSD device and tell it to pick up the register changes */

   xil_printf("-- Enable the OSD device ...\r\n" );

 

   //XOSD_Enable(&Osd);

 

   xil_printf("OsdConfig Done\r\n" );

   return;

}

/*****************************************************************************/

/**

*

* This function draws text using the OSD device

*

* @param    None.

*

* @return   None.

*

* @note     None.

*

******************************************************************************/

void OsdDrawText(int Gcindex,int x_pos, int y_pos, int color, int string_index, int text_size,u8 BankIndex)

{

  xil_printf("OsdDrawText Start\r\n" );

 

  /* Instruction buffer */

  u32 Instruction[XOSD_INS_SIZE];

 

 

  u16 ObjType = XOSD_INS_OPCODE_TXT; /* A text string  XOSD_INS_OPCODE_TXT*/

  u8  ObjSize = (text_size<<4);      /* Text Scale factor (1x, 2x, 4x, 8x) */

  u16 XStart = x_pos;                /* Horizontal start pixel of the text */

  u16 YStart = y_pos;                /* Vertical start line of the text */

  u16 XEnd =   x_pos;                /* Horizontal end pixel of the text (not used) */

  u16 YEnd =   y_pos;                /* Vertical end line of the text (must be same as YStart) */

  u8 TextIndex = string_index;                  /* Index of Text String */

  u8 ColorIndex = color;             /* Color used to draw text */

 

  /* Create a text command instruction */

  xil_printf("-- Create a box command instruction ...\r\n" );

 

  XOSD_CreateInstruction(&Osd, Instruction, Gcindex,

                          ObjType, ObjSize,

                          XStart, YStart, XEnd, YEnd,

                          TextIndex, ColorIndex);

 

 

  /* Load the instruction to draw the box in the OSD output */

  xil_printf("-- Load the instruction to draw the box in the OSD output ...\r\n" );

 

  XOSD_LoadInstructionList(&Osd, Gcindex, BankIndex, Instruction, 1);

 

  xil_printf("OsdDrawBox Done\r\n" );

  return;

}

/*****************************************************************************/

/**

*

* This function draws a box using the OSD device

*

* @param    None.

*

* @return   None.

*

* @note     None.

*

******************************************************************************/

void OsdDrawBox(int Gcindex,u16 x_start, u16 y_start, u16 x_last, u16 y_last, u8 color,u8 BankIndex)

{

  xil_printf("OsdDrawBox Start\r\n" );

 

  /* Instruction buffer */

  u32 Instruction[XOSD_INS_SIZE];

 

  /* Instruction property definition */

  xil_printf("-- Instruction property definition ...\r\n" );

 

  u16 ObjType = XOSD_INS_OPCODE_BOX; /* A box */

  u8  ObjSize = 2;                   /* Box boarder width */

  u16 XStart = x_start;                   /* Horizontal start pixel of the box */

  u16 YStart = y_start;                   /* Vertical start line of the box */

  u16 XEnd = x_last;                /* Horizontal end pixel of the box */

  u16 YEnd =  y_last;                   /* Vertical end line of the box */

  u8 TextIndex = 0;                  /* Ignored in box instruction case */

  u8 ColorIndex = color;             /* Color used to draw the box */

 

  /* Create a box command instruction */

  xil_printf("-- Create a box command instruction ...\r\n" );

 

  XOSD_CreateInstruction(&Osd, Instruction, 2,

                          ObjType, ObjSize,

                          XStart, YStart, XEnd, YEnd,

                          TextIndex, ColorIndex);

 

  /* Load the instruction to draw the box in the OSD output */

  xil_printf("-- Load the instruction to draw the box in the OSD output ...\r\n" );

 

  XOSD_LoadInstructionList(&Osd,Gcindex, BankIndex, Instruction, 1);

 

  xil_printf("OsdDrawBox Done\r\n" );

  return;

}

 

 

 

 

       Camera_osd_init是OSD驱动程序中的主程序。程序首先开始检测OSD是否初始化,如果是首次进行就跳转到Osd_Init()程序当中,Osd_Init()函数原型如下图所示:

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第17张图片

      程序当中,已经给出了相应的注释,这段程序和往常的初始化程序大体是一致的,这里我们不需要深层次去剖析这段程序,只要会用就好,在今后的设计中,完全可以照搬过来使用。

      回到Camera_Osd_Init()的分析当中,看到Osd_config()子函数,程序一开始是一些必要的变量设置,我们直接看到下面这个子函数:

cb14bc3ac2af96c4b9e98fc8a01c7f6cbed.jpg

      由其命名,可以猜出这是一个设置屏幕分辨率的子函数,其函数原型如下图所示:

8fae95ee1201a1fa9faa5347a833adc22ab.jpg

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第18张图片

      由函数开头注释了解到此函数如我们猜测,是一个设置OSD输出的功能函数,三个参数分别是OSD的实例模型、输出宽和高。

      之后再看到下面这个子函数:

f3596d4cebdac062f9bf8a3bb7692ba0dc0.jpg

     与之前分析一致,这个函数实现的功能为设置OSD的输出背景颜色。

     接下来看到下面这段程序:

46c3863e4ff462ea08018b205df8f95a9ea.jpg

   这段程序分别对Layer的alpha通道值,优先级,显示信息做了设置,最后使用XOSD_EnableLayer()函数允许Layer输出。然后再看看XOSD_SetLayerAlpha()函数,此函数用于设置指定层(Layer)的通道值与是否使用此通道。此函数的第二个参数即为层的标识,第三个参数决定了是否使用Alpha通道,最后一个参数是设置的Alpha值。

    XOSD_SetLayerPriority()函数用于设置层的优先级,这个函数比较简单,此处就不多加以解释这里重点注意XOSD_SetLayerDimension()函数,它关系到各个层的显示的分辨率,显示的位置。它带的第二个参数是层的标识号,第三和第四个参数分别是横向和纵向的开始位置,最后两个是显示的宽和高。

    XOSD_EnableLayer()函数也不用多说了,它实现的是允许层输出的功能。

    再看到Camera_osd_init函数中的internal_Graphics_setting()这一个函数:

这是一个字幕层设置程序,函数原型如下图所示:

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第19张图片米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第20张图片

      这里面的程序相信大家经过之前的讲解,已经能大致的看懂了,此处只看到最后四个函数。这四个函数分别载入了字幕的颜色查找表、字符块、文本块与活动块。这部分其实大家也不必过多的去了解,参照此部分设计就行,深层次实现原理太过的繁琐,不是一时半会儿就能了解。此处的程序需要注意Gcindex是字幕层的标识号,设置的宽和高与输出分辨率一致。

      再次回到主程序的分析当中,看到最后一个函数OsdDrawText()函数其函数原型如下图所示:

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第21张图片

     此函数完成了字符的显示和定位,从程序中可以看到,这个函数的核心组成是由两个官方函数组成的,因此我们对这两个函数进行分析,首先看到XOSD_CreateInstruction这个函数,定位一下其函数的原型,最后查找到如下图所示:

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第22张图片

       其实现方式我们暂且不研究,先研究其用法,函数开头注释足以够我们了解其用法。将英文注释翻译到中文,可知此函数完成了为OSD创建一个指令的功能,具体这个指令是什么,我们先往后看,然后再回头来看。这个函数带了十一个参数,第一个是OSD的实例,第二个是指向要用于创建指令的指令缓冲区的指针。 上级应用程序负责分配该指令缓冲区。第三个参数是字幕层的标识号,第四个参数是表示要绘制的对象的类型, 使用xosd_hw.h中定义的XOSD_INS_OPCODE_ *常数之一。第五个参数是显示字符的尺寸大小。第6-9个参数是显示的位置。第十个参数是要显示哪个字符串。第十一个参数是显示的颜色的定义。这里要注意的是要显示的字符串和颜色已经在OsdConfig中进行了定义,如下图圈出的部分:

1133a861e0a0f45d212e27c24f836ab0085.jpg

      因此上面函数的指令就是创建一个显示字符的指令,告知系统要以何种方式,显示何种字符。然后再看到XOSD_LoadInstructionList函数,函数的原型如下图所示:

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第23张图片

      此函数的分析方法与上一个函数类似,这个函数也是搭配上一个函数来使用的。这个函数用于加载OSD的字符控制器中的指令。此函数的参数中第三个和第五个是使用的默认的最小值,这是一种普遍的用法,这里需要注意的是第四个参数,应该与上一个函数中的第二个参数保持一致。

     OsdDrawBox()用于画框,分析方法与OsdDrawText()相同。

25.4.3 VDMA配置

     VDMA的配置与第一课基本一致,只是增加了一路VDMA的配置,此部分的程序代码如下表所示:

//Xil_Out32((VDMA_BASEADDR + 0x030), 0x108B);// enable circular mode

Xil_Out32((VDMA_BASEADDR0 + 0x030), 0x108B);// enable circular mode

Xil_Out32((VDMA_BASEADDR0 + 0x0AC), VIDEO_BASEADDR0); // start address

Xil_Out32((VDMA_BASEADDR0 + 0x0B0), VIDEO_BASEADDR1); // start address

Xil_Out32((VDMA_BASEADDR0 + 0x0B4), VIDEO_BASEADDR2); // start address

Xil_Out32((VDMA_BASEADDR0 + 0x0A8), (H_STRIDE*4)); // h offset (640 * 4) bytes

Xil_Out32((VDMA_BASEADDR0 + 0x0A4), (H_ACTIVE)); // h size (640 * 4) bytes

Xil_Out32((VDMA_BASEADDR0 + 0x0A0), V_ACTIVE); // v size (480)

/*****************从DDR读数据设置**********************/

Xil_Out32((VDMA_BASEADDR0 + 0x000), 0x8B); // enable circular mode

Xil_Out32((VDMA_BASEADDR0 + 0x05c), VIDEO_BASEADDR0); // start address

Xil_Out32((VDMA_BASEADDR0 + 0x060), VIDEO_BASEADDR1); // start address

Xil_Out32((VDMA_BASEADDR0 + 0x064), VIDEO_BASEADDR2); // start address

Xil_Out32((VDMA_BASEADDR0 + 0x058), (H_STRIDE*4)); // h offset (640 * 4) bytes

Xil_Out32((VDMA_BASEADDR0 + 0x054), (H_ACTIVE)); // h size (640 * 4) bytes

Xil_Out32((VDMA_BASEADDR0 + 0x050), V_ACTIVE); // v size (480)

 

//Xil_Out32((VDMA_BASEADDR + 0x030), 0x108B);// enable circular mode

Xil_Out32((VDMA_BASEADDR1 + 0x030), 0x108B);// enable circular mode

Xil_Out32((VDMA_BASEADDR1 + 0x0AC), VIDEO_BASEADDR3); // start address

Xil_Out32((VDMA_BASEADDR1 + 0x0B0), VIDEO_BASEADDR4); // start address

Xil_Out32((VDMA_BASEADDR1 + 0x0B4), VIDEO_BASEADDR5); // start address

Xil_Out32((VDMA_BASEADDR1 + 0x0A8), (H_STRIDE*4)); // h offset (640 * 4) bytes

Xil_Out32((VDMA_BASEADDR1 + 0x0A4), (H_ACTIVE)); // h size (640 * 4) bytes

Xil_Out32((VDMA_BASEADDR1 + 0x0A0), V_ACTIVE); // v size (480)

/*****************从DDR读数据设置**********************/

Xil_Out32((VDMA_BASEADDR1 + 0x000), 0x8B); // enable circular mode

Xil_Out32((VDMA_BASEADDR1 + 0x05c), VIDEO_BASEADDR3); // start address

Xil_Out32((VDMA_BASEADDR1 + 0x060), VIDEO_BASEADDR4); // start address

Xil_Out32((VDMA_BASEADDR1 + 0x064), VIDEO_BASEADDR5); // start address

Xil_Out32((VDMA_BASEADDR1 + 0x058), (H_STRIDE*4)); // h offset (640 * 4) bytes

Xil_Out32((VDMA_BASEADDR1 + 0x054), (H_ACTIVE)); // h size (640 * 4) bytes

Xil_Out32((VDMA_BASEADDR1 + 0x050), V_ACTIVE); // v size (480)

 

25.4.4 主程序设计

#include "I2C_8bit.h"

#include "xil_io.h"

#include "osd.h"

#include "xparameters.h"

 

#define VDMA_BASEADDR0 XPAR_AXI_VDMA_0_BASEADDR

#define VDMA_BASEADDR1 XPAR_AXI_VDMA_1_BASEADDR

 

 

#define VIDEO_BASEADDR0 0x01000000

#define VIDEO_BASEADDR1 0x02000000

#define VIDEO_BASEADDR2 0x03000000

 

#define VIDEO_BASEADDR3 0x04000000

#define VIDEO_BASEADDR4 0x05000000

#define VIDEO_BASEADDR5 0x06000000

 

 

 

#define H_ACTIVE 640*3

#define V_ACTIVE 480

#define H_STRIDE 640*3

 

 

static XIic Iic_1;

static XIic Iic_2;

 

int init_camer(void)

{

//initial iic

iic_init(&Iic_1,XPAR_AXI_IIC_0_DEVICE_ID);

iic_init(&Iic_2,XPAR_AXI_IIC_1_DEVICE_ID);

// Initialize camera regesiter

I2C_config_init(&Iic_1);

I2C_config_init(&Iic_2);

 

}

 

void main()

{

 

init_camer();

 

Camera_osd_init();

 

//Xil_Out32((VDMA_BASEADDR + 0x030), 0x108B);// enable circular mode

Xil_Out32((VDMA_BASEADDR0 + 0x030), 0x108B);// enable circular mode

Xil_Out32((VDMA_BASEADDR0 + 0x0AC), VIDEO_BASEADDR0); // start address

Xil_Out32((VDMA_BASEADDR0 + 0x0B0), VIDEO_BASEADDR1); // start address

Xil_Out32((VDMA_BASEADDR0 + 0x0B4), VIDEO_BASEADDR2); // start address

Xil_Out32((VDMA_BASEADDR0 + 0x0A8), (H_STRIDE)); // h offset (640 * 3) bytes

Xil_Out32((VDMA_BASEADDR0 + 0x0A4), (H_ACTIVE)); // h size (640 * 3) bytes

Xil_Out32((VDMA_BASEADDR0 + 0x0A0), V_ACTIVE); // v size (480)

/*****************从DDR读数据设置**********************/

Xil_Out32((VDMA_BASEADDR0 + 0x000), 0x8B); // enable circular mode

Xil_Out32((VDMA_BASEADDR0 + 0x05c), VIDEO_BASEADDR0); // start address

Xil_Out32((VDMA_BASEADDR0 + 0x060), VIDEO_BASEADDR1); // start address

Xil_Out32((VDMA_BASEADDR0 + 0x064), VIDEO_BASEADDR2); // start address

Xil_Out32((VDMA_BASEADDR0 + 0x058), (H_STRIDE)); // h offset (640 * 3) bytes

Xil_Out32((VDMA_BASEADDR0 + 0x054), (H_ACTIVE)); // h size (640 * 3) bytes

Xil_Out32((VDMA_BASEADDR0 + 0x050), V_ACTIVE); // v size (480)

 

//Xil_Out32((VDMA_BASEADDR + 0x030), 0x108B);// enable circular mode

Xil_Out32((VDMA_BASEADDR1 + 0x030), 0x108B);// enable circular mode

Xil_Out32((VDMA_BASEADDR1 + 0x0AC), VIDEO_BASEADDR3); // start address

Xil_Out32((VDMA_BASEADDR1 + 0x0B0), VIDEO_BASEADDR4); // start address

Xil_Out32((VDMA_BASEADDR1 + 0x0B4), VIDEO_BASEADDR5); // start address

Xil_Out32((VDMA_BASEADDR1 + 0x0A8), (H_STRIDE)); // h offset (640 * 3) bytes

Xil_Out32((VDMA_BASEADDR1 + 0x0A4), (H_ACTIVE)); // h size (640 * 3) bytes

Xil_Out32((VDMA_BASEADDR1 + 0x0A0), V_ACTIVE); // v size (480)

/*****************从DDR读数据设置**********************/

Xil_Out32((VDMA_BASEADDR1 + 0x000), 0x8B); // enable circular mode

Xil_Out32((VDMA_BASEADDR1 + 0x05c), VIDEO_BASEADDR3); // start address

Xil_Out32((VDMA_BASEADDR1 + 0x060), VIDEO_BASEADDR4); // start address

Xil_Out32((VDMA_BASEADDR1 + 0x064), VIDEO_BASEADDR5); // start address

Xil_Out32((VDMA_BASEADDR1 + 0x058), (H_STRIDE)); // h offset (640 * 3) bytes

Xil_Out32((VDMA_BASEADDR1 + 0x054), (H_ACTIVE)); // h size (640 * 3) bytes

Xil_Out32((VDMA_BASEADDR1 + 0x050), V_ACTIVE); // v size (480)

 

 

while (1) ;

 

 

}

25.5 验证测试

25.5.1 测试连接

开发板测试连接(MZ7XA、MZ7XB),如图所示:

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第24张图片

25.5.2 测试结果

程序编写完成之后,根据程序的约束接好摄像头,然后下载程序,得到测试结果如下:

米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加_第25张图片

转载于:https://my.oschina.net/msxbo/blog/3102445

你可能感兴趣的:(米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加)