米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加
软件版本:VIVADO2017.4
操作系统:WIN10 64bit
硬件平台:适用米联客 ZYNQ系列开发板
米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!
25.1 概述
本课使用MT9V034搭建两路基于VDMA的摄像头图形采集系统,并对OSD实现字幕叠加功能说明。提供的代码也包含MT9V034、OV5640摄像头双目例程,实现过程大同小异,这里不做过多讲解。
25.2 双目图像采集传输系统架构图
25.3 FPGA BD工程
25.3.1 摄像头电路设计
本课使用两个MT9V034摄像头(配套的代码也给出了2路OV5640摄像头OSD方案),每路摄像头输出分辨率640*480。摄像头部分电路设计如下所示:
25.3.2 Vid_in IP电路搭建
MT9V034的vid_ce信号始终接电平。这里给出MT9V034部分电路设计:
25.3.3 VDMA设置
25.3.4 OSD设置
本章要使用OSD完成字幕的叠加功能,所以要开启AXI-lite控制接口。OSD配置如下所示:
LAYER2和LAYER3层设置
上面第一副图中,我们勾选了控制接口,开启了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时钟设置如下:
25.3.6 VTC设置
25.3.7 AXI IIC设置
本节课要使用2路摄像头进行采集,需要两路IIC配置对摄像头寄存器进行配置。
此部分的设置如下图所示:
其余选项的设置参考之前历程的设置即可。
25.4 软件部分设计
软件部分主要可以分为三块,IIC协议实现、OSD驱动与VDMA配置。下面分别对这三个部分进行介绍。
25.4.1 IIC实现
本课节当中要对两个摄像头进行寄存器配置,如下图所示:
在main.c中可以看到摄像头IIC初始化配置函数。
在I2C_8bit.c文件中,找到I2C_config_init()配置函数。
其中,在I2C_8bit.c中可以查找到mt9v034_config_table[]与I2C_write相关定义。
相关定义mt9v034_config_table[]
其中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()函数原型如下图所示:
程序当中,已经给出了相应的注释,这段程序和往常的初始化程序大体是一致的,这里我们不需要深层次去剖析这段程序,只要会用就好,在今后的设计中,完全可以照搬过来使用。
回到Camera_Osd_Init()的分析当中,看到Osd_config()子函数,程序一开始是一些必要的变量设置,我们直接看到下面这个子函数:
由其命名,可以猜出这是一个设置屏幕分辨率的子函数,其函数原型如下图所示:
由函数开头注释了解到此函数如我们猜测,是一个设置OSD输出的功能函数,三个参数分别是OSD的实例模型、输出宽和高。
之后再看到下面这个子函数:
与之前分析一致,这个函数实现的功能为设置OSD的输出背景颜色。
接下来看到下面这段程序:
这段程序分别对Layer的alpha通道值,优先级,显示信息做了设置,最后使用XOSD_EnableLayer()函数允许Layer输出。然后再看看XOSD_SetLayerAlpha()函数,此函数用于设置指定层(Layer)的通道值与是否使用此通道。此函数的第二个参数即为层的标识,第三个参数决定了是否使用Alpha通道,最后一个参数是设置的Alpha值。
XOSD_SetLayerPriority()函数用于设置层的优先级,这个函数比较简单,此处就不多加以解释这里重点注意XOSD_SetLayerDimension()函数,它关系到各个层的显示的分辨率,显示的位置。它带的第二个参数是层的标识号,第三和第四个参数分别是横向和纵向的开始位置,最后两个是显示的宽和高。
XOSD_EnableLayer()函数也不用多说了,它实现的是允许层输出的功能。
再看到Camera_osd_init函数中的internal_Graphics_setting()这一个函数:
这是一个字幕层设置程序,函数原型如下图所示:
这里面的程序相信大家经过之前的讲解,已经能大致的看懂了,此处只看到最后四个函数。这四个函数分别载入了字幕的颜色查找表、字符块、文本块与活动块。这部分其实大家也不必过多的去了解,参照此部分设计就行,深层次实现原理太过的繁琐,不是一时半会儿就能了解。此处的程序需要注意Gcindex是字幕层的标识号,设置的宽和高与输出分辨率一致。
再次回到主程序的分析当中,看到最后一个函数OsdDrawText()函数其函数原型如下图所示:
此函数完成了字符的显示和定位,从程序中可以看到,这个函数的核心组成是由两个官方函数组成的,因此我们对这两个函数进行分析,首先看到XOSD_CreateInstruction这个函数,定位一下其函数的原型,最后查找到如下图所示:
其实现方式我们暂且不研究,先研究其用法,函数开头注释足以够我们了解其用法。将英文注释翻译到中文,可知此函数完成了为OSD创建一个指令的功能,具体这个指令是什么,我们先往后看,然后再回头来看。这个函数带了十一个参数,第一个是OSD的实例,第二个是指向要用于创建指令的指令缓冲区的指针。 上级应用程序负责分配该指令缓冲区。第三个参数是字幕层的标识号,第四个参数是表示要绘制的对象的类型, 使用xosd_hw.h中定义的XOSD_INS_OPCODE_ *常数之一。第五个参数是显示字符的尺寸大小。第6-9个参数是显示的位置。第十个参数是要显示哪个字符串。第十一个参数是显示的颜色的定义。这里要注意的是要显示的字符串和颜色已经在OsdConfig中进行了定义,如下图圈出的部分:
因此上面函数的指令就是创建一个显示字符的指令,告知系统要以何种方式,显示何种字符。然后再看到XOSD_LoadInstructionList函数,函数的原型如下图所示:
此函数的分析方法与上一个函数类似,这个函数也是搭配上一个函数来使用的。这个函数用于加载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),如图所示:
25.5.2 测试结果
程序编写完成之后,根据程序的约束接好摄像头,然后下载程序,得到测试结果如下:
转载于:https://my.oschina.net/msxbo/blog/3102445
米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加相关推荐
- 米联客 ZYNQ/SOC精品教程 S01-CH05 FPGA程序的固化和下载
软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...
- 基于zynq的千兆网udp项目_米联客 ZYNQ/SOC 精品教程 S05-CH05 PS 千兆 UDP 加速
软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...
- 米联客 ZYNQ/SOC精品教程 S02-CH13 CAN总线通信实验
软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...
- fast角点检测 java_米联客 ZYNQ/SOC 精品教程 S04-CH11 快速角点检测之硬件实现
软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...
- 米联客 ZYNQ/SOC精品教程 S01-CH04 VIVADO创建工程之流水灯
软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...
- 米联客 ZYNQ/SOC 精品教程 S02-CH15 AXI_Lite 总线详解
软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...
- 米联客 ZYNQ/SOC 精品教程 S02-CH24 利用AXI VDMA 实现MT9V034摄像头采集
软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...
- 米联客 ZYNQ/SOC精品教程 S01-CH06 FPGA按钮去抖实验
软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...
- 米联客 ZYNQ/SOC精品教程 S01-CH07 FPGA多路分频器实验
软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...
最新文章
- 深度学习在计算机视觉中的应用长篇综述
- 数据库-ADONET-使用强类型DataSet
- 数据结构源码笔记(C语言):链接栈
- 使用Unity引擎打造赛博朋克之城!CIGA Game Jam 2019 48小时独立游戏开发挑战
- Java性能调优调查结果(第二部分)
- 同一台机器上安装2个SDE服务
- 2017.10.23 硬币购物 失败总结
- 家用计算机的使用说明,AWIND奇机家用无线投屏器使用说明
- linux ftp prompt off,FTP命令详解及使用技巧
- PHP架构师必备技术视频合集
- 完全平方数-动态规划
- unity游戏开发毕设_毕设分享:用Unity探究2D游戏的打击感
- 如果你不释放MogaFX外汇,你将无法获得交易或投资
- WebView 加载微信公众号文章加载失败或图片不显示
- Flutter 自定义组件实战
- Android DRM框架分析
- 负数 mysql 时间戳_【mysql】负数时间戳日期转换问题
- 注册ActiveX控件简单方法及控件未被正确授权解决方案
- ECharts修改坐标轴,坐标轴字体,坐标轴网格样式以及控制坐标轴是否显示
- 2050热身赛 1001 1004
热门文章
- 绝地求生竞赛服务器没有响应,绝地求生比赛莫名掉线,一个小时都没解决,这是专业性?...
- 用一个程序员的角度来遐想第五代或第六代计算机
- 【大数据哔哔集20210108】Spark Shuffle 和 Hadoop Shuffle有什么异同?
- Mac电脑安装Python
- ImportError: attempted relative import beyond top-level package
- 加油站-贪心134-python
- 1.3「Motoko——Actors and async data」
- 脑梗如何康复治疗?明确病因,针对性康复治疗是关键!
- kotlin ..与 until 区别
- Js字符串数据处理方法汇总