欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

miniGUI 3.0.2 在Hi3535平台上的移植

程序员文章站 2022-05-30 14:18:03
...

miniGUI是一个*软件项目。其目标是提供一个快速、稳定、跨操作系统的图形用户界面(GUI)支持系统,尤其是基于 Linux/uClinux、eCos 以及其他传统 RTOS(如 VxWorks、ThreadX、uC/OS-II、Nucleus 等)的实时嵌入式操作系统。最近在Hi3535的平台上移植miniGUI3.0,并完成Helloworld的用例测试。这里将移植的过程记录如下。

准备工作

  1. Hi3535SDK和开发板一套,并构建Hi3535的嵌入式开发环境(包括linux编译主机、安装交叉编译工具以及在宿主机上安装NFS调试环境等)。

  2. 从官网下载miniGUI源码以及资源包和示例包。点击打开链接

  3. 熟悉海思Hi3535的Framebuffer模块。包括海思Hi3535提供Framebuffer的标准接口以及Hi3535提供的扩展接口(包括设置colorkey,Alpha等),Hi3535的Framebuffer提供的几种工作模式(None Buffer,One Buffer,Double Buffer等)。此外要仔细研读海思Hi3535的SDK中提供关于Framebufer的指导文档以及参考代码。熟悉Hi3535初始化流程以及Framebuffer的使用流程(包括初始化以及绘制Framebuffer)。

初次编译

解压下载的源代码后,先在源代码的根路径下创建_install目录用于保存编译生成文件。运行以下命令进行配置:

./configure --prefix=[mg_path]/libminigui-3.0.12-linux/_install CC=arm-hisiv100nptl-linux-gcc --host=arm-hisiv100nptl-linux --disable-pcxvfb --disable-screensaver --disable-splash --disable-jpgsupport --enable-videoqvfb=no --enable-rtosxvfb=no --enable-pcxvfb=no

注意:[mg_path]为miniGUI 3.0源代码的存储路径,在具体运行时根据实际保存的源代码路径重新写入。

运行以下命令进行编译:

make
make install

编译成功后可在_install目录下看到编译生成的文件。包括四个文件夹,简要说明如下:

  • etc   文件夹下保存运行配置文件miniGUI.cfg,在实际调试过程中需要修改其内容,详见后续章节描述;
  • include 集成miniGUI库时需要使用到的头文件;
  • lib 包括链接库和运行库;
  • share 暂未使用;

加入Hi3535的framebuffer接口文件

miniGUI中Framebuffer部分的接口主要需要完成两个结构体的初始化,即VideoBootStrap和GAL_VideoDevice。可查到上述两个结构体的定义如下:

typedef struct VideoBootStrap {
	const char *name;
	const char *desc;
	int (*available)(void);
	GAL_VideoDevice *(*create)(int devindex);
} VideoBootStrap;

结构体成员简要说明如下:

  • name为字符串变量,改字符串用于区分运行的平台,因此尽量保持唯一性。这里使用hi3535作为name。此字符串需要跟运行配置文件MiniGUI.cfg中的名称保持一致。
  • desc 描述,目前没有查到有什么限制,本例使用HI3535 Framebuffer Console。
  • available为需要填充的函数,检查framebuffer是否可用。即尝试打开设备,如果打开成功即验证可用。
  • create为需要填充的函数,函数主要完成GAL_VideoDevice变量的初始化。

GAL_VideoDevice的定义详见src/newgal/sysvideo.h文件。

主要说两点:

  • name仍然保持和VideoBootStrap中定义的一致;
  • hidden 成员变量,主要保存Hi3535在后续Framebuffer中操作需要的信息,可根据需要进行定制。本例中暂定义为:
struct GAL_PrivateVideoData 
{
	Uint32 			fd;
	HIFB_BUFFER_S	stCanvasBuf;
	Uint32			memLen;
};

其中:

        • fd为open Framebuffer设备后的句柄;
        • stCanvasBuf为framebuffer的画布信息(请参考海思文档);
        • memLen为Framebuffer分配的内存长度;

其他为需要填充的函数。

miniGUI3.0.2中的src/newgal中包含hisi文件夹,目前有实现Hi3510/Hi3560/Hi3560a等芯片的接口。本例中添加Hi3535芯片的接口,将海思hi3535的接口文件命名为:hi3535_fbvideo.c和hi3535_fbvideo.h,完成上述两个结构体变量的初始化。首先可使用空函数完成代码。接下来修改配置文件(包括configure和makefile)来编译新增加的Hi3535的接口文件。

修改configure.in文件,增加编译Hi3535

增加如下代码:

dnl Check HI3535 video driver
CheckHI3535Video()
{
    AC_ARG_ENABLE(videohi3535,
[  --enable-videohi3535     include Hi3535 Video  NEWGAL engine <default=no>],
    enable_video_hi3535=$enableval)

    if test "x$enable_video_hi3535" = "xyes"; then
        AC_DEFINE(_MGGAL_HI3535, 1,
                [Define if include Hi3535 Video NEWGAL engine])
        VIDEO_SUBDIRS="$VIDEO_SUBDIRS hisi"
        VIDEO_DRIVERS="$VIDEO_DRIVERS hisi/libvideo_hisifbcon.la"
    fi
}

增加调用上述代码:

dnl Checks NewGAL Engine.
{
  CheckDummyVideo
  CheckFBCON
  CheckQVFB
  CheckXVFB
  CheckWVFB
  CheckCOMMLCD
  CheckShadowVideo
  CheckMLShadowVideo
  CheckEM85xxOSD
  CheckEM85xxYUV
  CheckEM86GFX
  CheckSvpxxosdVideo
  CheckBF533Video
  CheckMB93493Video
  CheckUTPMCVideo
  CheckDirectFBVideo
  CheckSTGFBVideo
  CheckHI35XXVideo
  CheckHI3560AVideo
  CheckHI3535Video
  CheckGDLVideo
  CheckNexusVideo
  CheckS3C6410Video
  CheckCustomVideo
  CheckSigmaVideo
  CheckMStarVideo
}

修改makefile相关文件

修改src/newgal/hisi目录下的make.in文件

am__objects_1 = hi3510_fbvideo.lo gal_hi3560a.lo hi3560_fbvideo.lo hi3535_fbvideo.lo \
	pix_array.lo tde.lo

上述属于修改,找到am__objects_1的变量,增加hi3535_fbvideo.lo

SRC_FILES = hi3510_fbvideo.c gal_hi3560a.c hi3560_fbvideo.c hi3535_fbvideo.c pix_array.c tde.c
HDR_FILES = hi3510_fb.h hi3560_fb.h hi3510_fbvideo.h hi3560_fbvideo.h hi3535_fbvideo.h \
			hi_tde.h tde_reg.h gal_hi3560a.h

上述属于修改,找到SRC_FILES和HDR_FILES变量,分别添加hi3535_fbvideo.c和hi3535_fbvideo.h

@aaa@qq.com@aaa@qq.com @aaa@qq.com/$(DEPDIR)/aaa@qq.comaaa@qq.com

上述属于增加的行,参考现有海思芯片的类型进行添加。

修改src/newgal/hisi目录下的makefile.am

SRC_FILES = hi3510_fbvideo.c gal_hi3560a.c hi3560_fbvideo.c hi3535_fbvideo.c pix_array.c tde.c
HDR_FILES = hi3510_fb.h hi3560_fb.h hi3510_fbvideo.h hi3560_fbvideo.h hi3535_fbvideo.h \
			hi_tde.h tde_reg.h gal_hi3560a.h

完成四个基础函数的填充。

static int HI3535_Available(void)
{
	const char *GAL_fbdev;
    	int fd;
		
	GAL_fbdev = getenv("FRAMEBUFFER");
	if ( GAL_fbdev == NULL ) 
	{
		GAL_fbdev = "/dev/fb0";
	}

	fd = open(GAL_fbdev, O_RDWR, 0);

	if ( fd < 0 ) 
	{
		fprintf(stderr, "failed to open file :%s!\n", GAL_fbdev);
		return 0;
	}
	else
	{
		close(fd);
		return 1;
	}
}

Hi3535默认加载Framebuffer,因此可以在/dev目录下找到fb0的设备节点文件。上述函数只是尝试打开/dev/fb0文件,如果能够成功打开并获取句柄,则返回成功,否则,返回失败。

static GAL_VideoDevice *HI3535_CreateDevice (int devindex)
{
	GAL_VideoDevice *this;

	/* Initialize all variables that we clean on shutdown */
	this = (GAL_VideoDevice *)malloc(sizeof(GAL_VideoDevice));

	if ( this ) 
	{
		memset(this, 0, (sizeof *this));
		this->hidden = (struct GAL_PrivateVideoData *)malloc(sizeof (struct GAL_PrivateVideoData));
		this->name = "hi3535";
	}

	if ( (this == NULL) || (this->hidden == NULL) ) 
	{
		GAL_OutOfMemory();
		if ( this ) 
		{
			free(this);
		}
		return(0);
	}

	memset(this->hidden, 0, (sizeof (struct GAL_PrivateVideoData)));

	/* Set the function pointers */
	this->VideoInit = HI3535_VideoInit;
	this->ListModes = HI3535_ListModes;
	this->SetVideoMode = HI3535_SetVideoMode;
	this->ToggleFullScreen = HI3535_ToggleFullScreen;
	this->SetColors = HI3535_SetColors;
	this->UpdateRects = HI3535_UpdateRects;
	this->VideoQuit = HI3535_VideoQuit;
#ifndef _MGRM_THREADS
	this->RequestHWSurface = HI3535_RequestHWSurface;
#endif
	this->AllocHWSurface = HI3535_AllocHWSurface;
	this->CheckHWBlit = HI3535_CheckHWBlit;
	this->FillHWRect = HI3535_FillHWRect;
	this->SetHWColorKey = HI3535_SetHWColorKey;
	this->SetHWAlpha = HI3535_SetHWAlpha;
	this->FreeHWSurface = HI3535_FreeHWSurface;
	this->free = HI3535_FBFree;
	this->DeleteSurface = HI3535_DeleteSurface;
	this->SetSurfaceColors = HI3535_SetSurfaceColors;
	this->GetFBInfo = HI3535_GetFBInfo;
	this->UpdateSurfaceRects = HI3535_UpdateSurfaceRects;

	return this;
}

上述函数主要用于创建GAL_VideoDevice结构体变量,初始化并返回。并且分配hidden成员变量的空间。

extern int hi3535_board_init(void);

外部初始化函数,用于实现初始化Hi3535平台。可参考海思SDK中的sample示例。因为miniGUI运行时,并不会去完成平台初始化的工作,因此在miniGUI调用其库完成framebuffer的接口初始化之前,要借助此外部函数完成平台初始化,以确保framebuffer的初始化及相关操作不会出错。

static int HI3535_VideoInit(GAL_VideoDevice *this, GAL_PixelFormat *vformat)
{
	struct fb_fix_screeninfo finfo;
	struct fb_var_screeninfo vinfo;
	int i;
	const char *GAL_fbdev;
    	GAL_VideoInfo* paccel_info =  &this->info;
	HIFB_COLORKEY_S 			stColorKey;
	HIFB_POINT_S 			stPoint;
	HIFB_LAYER_INFO_S		stLayerInfo = {0};
	HI_BOOL 					bShow; 
	
	hi3535_board_init();

	/* 1. open Framebuffer device overlay 0 */
	GAL_fbdev = getenv("FRAMEBUFFER");
	if ( GAL_fbdev == NULL ) 
	{
		GAL_fbdev = "/dev/fb0";
	}
	this->hidden->fd = open(GAL_fbdev, O_RDWR, 0);
	if ( this->hidden->fd < 0 ) 
	{
		GAL_SetError("NEWGAL>HI3535: Unable to open %s\n", GAL_fbdev);
		return -1;
	}


	/*2. all layer surport colorkey*/	
	stColorKey.bKeyEnable	= HI_TRUE;
	stColorKey.u32Key		= 0x0;
	if (ioctl(this->hidden->fd, FBIOPUT_COLORKEY_HIFB, &stColorKey) < 0)
	{
		GAL_SetError("NEWGAL>HI3535:FBIOPUT_COLORKEY_HIFB!\n");
		return -2;
	}
	
	/* 3. set the screen original position */
	stPoint.s32XPos = 0;
	stPoint.s32YPos = 0;
	if (ioctl(this->hidden->fd, FBIOPUT_SCREEN_ORIGIN_HIFB, &stPoint) < 0)
	{
		GAL_SetError("NEWGAL>HI3535:set screen original show position failed!\n");
		return -3;
	}

	/* 4. get the variable screen info */
	if(ioctl(this->hidden->fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
	{
		GAL_SetError("NEWGAL>HI3535:GET_VSCREENINFO failed!\n");
		return -4;
	} 
	
	/* 5. config the default parameters of the variable screen. */
	vinfo.xres_virtual 		= DEFAULT_SCREEN_WIDTH;
	vinfo.yres_virtual 		= DEFAULT_SCREEN_HEIGHT;
	vinfo.xres 			= DEFAULT_SCREEN_WIDTH;
	vinfo.yres 			= DEFAULT_SCREEN_HEIGHT;
	vinfo.transp			= s_a16;
	vinfo.red 				= s_r16;
	vinfo.green 			= s_g16;
	vinfo.blue 			= s_b16;
	vinfo.bits_per_pixel 	= 16;
	vinfo.activate 			= FB_ACTIVATE_NOW;
	if (ioctl(this->hidden->fd, FBIOPUT_VSCREENINFO, &vinfo) < 0)
	{
		GAL_SetError("NEWGAL>HI3535: Put variable screen info failed!\n");
		return -5;
	}
	
	/* 6. set one buffer mode. */
	stLayerInfo.BufMode 	= HIFB_LAYER_BUF_ONE;
	stLayerInfo.u32Mask 	= HIFB_LAYERMASK_BUFMODE;
    	if(ioctl(this->hidden->fd, FBIOPUT_LAYER_INFO, &stLayerInfo) < 0)
	{
		GAL_SetError("NEWGAL>HI3535: PUT_LAYER_INFO failed!\n");
		return -6;
	}
		
	bShow = HI_TRUE;
	if (ioctl(this->hidden->fd, FBIOPUT_SHOW_HIFB, &bShow) < 0)
	{
		GAL_SetError("NEWGAL>HI3535:FBIOPUT_SHOW_HIFB failed!\n");
		return -7;
	}
	
	/* 7. Get the type of video hardware */
	if ( ioctl(this->hidden->fd, FBIOGET_FSCREENINFO, &finfo) < 0 ) 
	{
		GAL_SetError("NEWGAL>HI3535: Couldn't get console hardware info\n");
		HI3535_VideoQuit(this);
		return -6;
	}
	
	/* Memory map the device, compensating for buggy PPC mmap() */
	this->hidden->stCanvasBuf.stCanvas.u32PhyAddr = mmap(NULL, finfo.smem_len,PROT_READ|PROT_WRITE, MAP_SHARED, this->hidden->fd, 0);
	this->hidden->stCanvasBuf.stCanvas.u32Width = vinfo.xres;
	this->hidden->stCanvasBuf.stCanvas.u32Height = vinfo.yres;
	this->hidden->stCanvasBuf.stCanvas.u32Pitch = vinfo.xres*2;
	this->hidden->stCanvasBuf.stCanvas.enFmt = HIFB_FMT_ARGB1555;
	memset((Uint16*)(this->hidden->stCanvasBuf.stCanvas.u32PhyAddr), 0x00, this->hidden->stCanvasBuf.stCanvas.u32Pitch*this->hidden->stCanvasBuf.stCanvas.u32Height);
	this->hidden->memLen = finfo.smem_len;
	
	vformat->BitsPerPixel = vinfo.bits_per_pixel;

	for ( i=0; i<vinfo.red.length; ++i ) 
	{
		vformat->Rmask <<= 1;
		vformat->Rmask |= (0x00000001<<vinfo.red.offset);
	}
	for ( i=0; i<vinfo.green.length; ++i ) 
	{
		vformat->Gmask <<= 1;
		vformat->Gmask |= (0x00000001<<vinfo.green.offset);
	}
	for ( i=0; i<vinfo.blue.length; ++i ) 
	{
		vformat->Bmask <<= 1;
		vformat->Bmask |= (0x00000001<<vinfo.blue.offset);
	}

	for ( i=0; i<vinfo.transp.length; ++i ) 
	{
		vformat->Amask <<= 1;
		vformat->Amask |= (0x00000001<<vinfo.transp.offset);
	}

	paccel_info->hw_available = 1;
	paccel_info->video_mem = finfo.smem_len/1024;
	paccel_info->blit_fill = 1;
	paccel_info->blit_hw = 1;
	paccel_info->blit_hw_A = 1;
	paccel_info->blit_hw_CC = 1;
	
	return(0);
}

参考sample_hifb.c中的初始化过程实现。但在内存映射上做了修改。

static GAL_Surface *HI3535_SetVideoMode(GAL_VideoDevice *this, GAL_Surface *current, int width, int height, int bpp, Uint32 flags)
{
	struct fb_fix_screeninfo finfo;
	struct fb_var_screeninfo vinfo;
	int i;
	Uint32 Rmask;
	Uint32 Gmask;
	Uint32 Bmask;
	Uint32 Amask;
	char *surfaces_mem;
	int surfaces_len;
	
	/* Set the video mode and get the final screen format */
	if ( ioctl(this->hidden->fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) 
	{
		fprintf (stderr, "Couldn't get console screen info");
		return(NULL);
	}
	
    	if ((vinfo.xres != width) || (vinfo.yres != height) ||(vinfo.bits_per_pixel != bpp))
        {
		vinfo.activate = FB_ACTIVATE_NOW;
		vinfo.accel_flags = 0;
		vinfo.bits_per_pixel = bpp;
		vinfo.xres = width;
		vinfo.xres_virtual = width;
		vinfo.yres = height;
		vinfo.yres_virtual = height;
		vinfo.xoffset = 0;
		vinfo.yoffset = 0;
		vinfo.red.length = vinfo.red.offset = 0;
		vinfo.green.length = vinfo.green.offset = 0;
		vinfo.blue.length = vinfo.blue.offset = 0;
		vinfo.transp.length = vinfo.transp.offset = 0;
        	if ( ioctl(this->hidden->fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) 
		{
			GAL_SetError("NEWGAL>HI3535: Couldn't set console screen info\n");
			vinfo.yres_virtual = height;
			if ( ioctl(this->hidden->fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) 
			{
				GAL_SetError("NEWGAL>HI3535: Couldn't set console screen info[2]\n");
				return(NULL);
            		}
        	}
    	}
	else
	{
	        int maxheight;

	        /* Figure out how much video memory is available */
	        maxheight = height;
		if ( vinfo.yres_virtual > maxheight ) 
		{
			vinfo.yres_virtual = maxheight;
		}
    	}

	Rmask = 0;
	for ( i=0; i<vinfo.red.length; ++i ) 
	{
		Rmask <<= 1;
		Rmask |= (0x00000001<<vinfo.red.offset);
	}
	Gmask = 0;
	for ( i=0; i<vinfo.green.length; ++i ) 
	{
		Gmask <<= 1;
		Gmask |= (0x00000001<<vinfo.green.offset);
	}
	Bmask = 0;
	for ( i=0; i<vinfo.blue.length; ++i ) 
	{
		Bmask <<= 1;
		Bmask |= (0x00000001<<vinfo.blue.offset);
	}
	Amask = 0;
	for ( i=0; i<vinfo.transp.length; ++i ) 
	{
		Amask <<= 1;
		Amask |= (0x00000001<<vinfo.transp.offset);
	}

	if (!GAL_ReallocFormat(current, vinfo.bits_per_pixel,Rmask, Gmask, Bmask, Amask) ) 
	{
		return(NULL);
	}

	if ( vinfo.bits_per_pixel < 8 ) 
	{
		current->format->MSBLeft = !(vinfo.red.msb_right);
	}

	/* Set up the new mode framebuffer */
	current->flags = GAL_FULLSCREEN;
	current->w = vinfo.xres;
	current->h = vinfo.yres;
	current->pitch = vinfo.xres*2;
	current->pixels = this->hidden->stCanvasBuf.stCanvas.u32PhyAddr;

	return(current);
}

最后在hi3535_fbvideo.c中包含hi3535SDK中与Framebuffer有关的头文件:hi_type.h和hifb.h,并将这两个头文件拷贝到src/newgal/hisi目录下。

完成后重新配置编译,在配置之前先运行make distclean清除之前的配置

./configure --prefix=/home/zkliu/miniGUI/libminigui-3.0.12-linux/_install CC=arm-hisiv100nptl-linux-gcc --host=arm-hisiv100nptl-linux --disable-pcxvfb --disable-screensaver --disable-splash --disable-jpgsupport --enable-videoqvfb=no --enable-rtosxvfb=no --enable-pcxvfb=no --enable-videohi3535=yes

注意增加了对hi3535的支持

然后编译全套代码:

make
make install

测试

准备资源文件

解压miniGUI的资源文件,在资源文件根目录下建立_install目录。运行一下命令配置编译:

./configure --host=arm-hisiv100nptl-linux  --prefix=[mg_res]/ minigui-res-be-3.0.12 /_install
make
make install

成功编译完成后在_install目录下可得到需要的资源文件。

建立helloworld sample

在hi3535SDK中的sample目录下建立一个单独的目录,比如miniGUI。拷贝helloworld.c(该文件来自于miniGUI网站中的sample实例)文件到目录下。拷贝_install下的include目录到miniGUI目录下。拷贝_install/lib/ libminigui_ths.a文件到miniGUI/lib目录下。新建board.c文件,实现int hi3535_board_init(void);包括sys模块、VO、HDMI等跟输出相关模块的初始化。修改miniGUI目录下的makefile如下:

# Hisilicon Hi3535 sample Makefile

include ../Makefile.param

# target source
SRC  := $(wildcard *.c) 
OBJ  := $(SRC:%.c=%.o)

TARGET := helloworld
.PHONY : clean all

all: $(TARGET)

MPI_LIBS := $(REL_LIB)/libmpi.a
MPI_LIBS += $(REL_LIB)/libhdmi.a
CFLAGS += -I./include 

$(TARGET):$(OBJ)
	$(CC) $(CFLAGS) -lpthread -lm -o aaa@qq.com $^ $(MPI_LIBS) $(AUDIO_LIBA) -L./lib -lminigui_ths

%.o:%.c
	$(CC) -c $(CFLAGS) $^ -o aaa@qq.com
	
clean:
	@rm -f $(TARGET)
	@rm -f $(OBJ)

在sample文件夹下的makefile中增加对miniGUI文件夹的编译:

mg:
	@cd miniGUI; make
	
mg_clean:
	@cd miniGUI; make clean

至此,可对helloworld例子进行编译。

建立调试目录

将资源文件_install/share/minigui目录拷贝的nfs挂载目录,将miniGUI动态库和软连接文件拷贝到nfs挂载目录中的miniGUILibs目录(如果没有就新建)。软连接文件如果失效,使用ln –sf命令重新建立软连接。拷贝示例helloworld到nfs挂载目录。修改miniGUI.cfg文件如下:

[system]
# GAL engine and default options
gal_engine=hi3535
defaultmode=800x600-16bpp

# IAL engine
ial_engine=dummy
mdev=/dev/input/mice
mtype=IMPS2

[fbcon]
defaultmode=1024x768-16bpp

[hi3535]
defaultmode=1920x1080-16bpp

第3行修改gal_engine:

第14行增加hi3535 gal_engine定义,设置缺省分辨率。

修改鼠标资源文件定向,找到以下位置修改:

cursorpath=./minigui/res/cursor/

修改图片资源文件定向,找到以下位置修改:

respath=./minigui/res/

完成上述修改后将miniGUI.cfg拷贝到nfs挂载目录下。

修改Hi3535单板上/etc/profile文件,将miniGUI的动态库文件所在路径包含到LD_LIBRARY_PATH变量中:

LD_LIBRARY_PATH="/usr/local/lib:/usr/lib:/mnt/miniGUILibs"

运行示例:./helloworld

可在HDMI接口看到欢迎窗口如图:

miniGUI 3.0.2 在Hi3535平台上的移植

参考文献

  1. Minigui3在海思Hi3520D/Hi3531平台上运行  https://blog.csdn.net/jhting/article/details/51059484
  2. HiFBAPI参考.pdf
  3. HiFB开发指南.pdf

源代码资源已上传,下载地址点击打开链接