关于ucgui的移植,网上多是stm32上的或者是带fb设备的板卡上的移植,由于我用的板卡不支持fb,所以整个移植是建立在v4l2的基础上的,由于不懂驱动什么的,纠结了快一个月,磕磕巴巴地终于在昨天成功移植,真的是很感谢热情如火的大神,所以在这里也分享一下自己的移植心得,希望有一天也能帮到某个需要的人。
硬件平台:SEET-DVS6467
UCGUI版本:3.90
下载ucgui源码
----Sample
----Start
----Tool
在做移植的时候,把Sample中的GUI_X中的GUI_X.c、Start中的GUI和Config拷出来放在一个文件夹下。
由于板卡没有framebuffer硬件,所以需要通过v4l2提供显示接口,由此,需要将v4l2和ucgui的LCD驱动接口相连。
需要修改的有四个地方:
1、首先是配置文件,Config中的GUIConf.h和LCDConf.h,
GUIConf主要是图形化界面的相关配置,主要修改如下:
#defineGUI_OS (1) /* Compile with multitasking support */
#defineGUI_SUPPORT_TOUCH (0) /* Support a touch screen (req. win-manager)*/
#defineGUI_SUPPORT_UNICODE (1) /* Support mixed ASCII/UNICODE strings */
#defineGUI_DEFAULT_FONT &GUI_Font6x8
#defineGUI_ALLOC_SIZE 25*1024 /* Size of dynamic memory ... For WM and memory devices*/
#defineGUI_WINSUPPORT 1 /* Window manager package available */
#defineGUI_SUPPORT_MEMDEV 1 /* Memory devices available */
#defineGUI_SUPPORT_AA 1 /* Anti aliasing available */
LCDConf主要是显示器的相关配置,主要修改如下:
#defineLCD_XSIZE (720) /* X-resolution of LCD, Logical coor. */
#defineLCD_YSIZE (576) /* Y-resolution of LCD, Logical coor. */
#defineLCD_BITSPERPIXEL (8)
#defineLCD_CONTROLLER (-1)
2、其次是GUI_X.c中初始化部分,在初始化过程中最关键是要实现v4l2的初始化,申请缓存区,映射到用户空间,将缓存区加入缓存队列(在initDisplay中实现),获得缓存区地址赋给全局变量video_buffer,然后打开流,具体实现如下:
void GUI_X_Init(void) {
int i= 0,ret = 0;
struct v4l2_format display_fmt;
int display_numbuffers= MAX_BUFFER;
char dev[40];
AddrObj *display_buff;
sprintf(dev,"/dev/video%d",2);
/* open display channel */
ret = initDisplay(&display_fd,dev,&display_numbuffers,"COMPOSITE", "PAL",&display_fmt);
if(ret < 0) {
printf("Error in opening display device\n");
return ret;
}
ret = startDisplay(&display_fd);
if(ret < 0) {
printf("Error in starting display\n");
return ret;
}
}
static int initDisplay(int *display_fd, char *devname, int*numbuffers, char *outputname,char *stdname, struct v4l2_format *fmt)
{
int mode =O_RDWR, j;
structv4l2_buffer buf;
int ret,i=0;
structv4l2_requestbuffers reqbuf;
charcommand[80];
video_buffer=(char*)malloc(sizeof(char)*576*720);
strcpy(command,"echo ");
strcat(command,outputname);
strcat(command," > ");
strcat(command,OUTPUTPATH);
if(system(command)){
printf("Cannot set the output\n");
return -1;
}
/* Set modewhich is same as the one detected in the capture */
strcpy(command, "echo ");
strcat(command, stdname);
strcat(command, " >");
strcat(command, STDPATH);
if(system(command)) {
printf("Cannotset the output\n");
return -1;
}
for(i = 0; i < MAX_BUFFER; i++) {
display_buff_info[i].start= NULL;
}
/* Open the channel-2 displaydevice */
*display_fd= open((const char *)devname, mode);
if(*display_fd<= 0) {
printf("Cannotopen %s\n",devname);
return-1;
}
reqbuf.type= V4L2_BUF_TYPE_VIDEO_OUTPUT;
reqbuf.count= *numbuffers;
reqbuf.memory= V4L2_MEMORY_MMAP;
ret =ioctl(*display_fd, VIDIOC_REQBUFS, &reqbuf);
if (ret< 0) {
perror("cannotallocate memory\n");
return-1;
}
/* Storethe numbfer of buffers allocated */
*numbuffers= reqbuf.count;
/* It isbetter to zero all the members of buffer structure */
memset(&buf,0, sizeof(buf));
/* Mmap thebuffers
* To access driver allocated buffer inapplication space, they have
* to be mmapped in the application space usingmmap system call */
for(i = 0 ;i < reqbuf.count ; i ++) {
/*Query physical address of the buffers */
buf.index= i;
buf.type= V4L2_BUF_TYPE_VIDEO_OUTPUT;
buf.memory = V4L2_MEMORY_MMAP;
ret= ioctl(*display_fd, VIDIOC_QUERYBUF, &buf);
if(ret < 0) {
perror("VIDIOC_QUERYCAP\n");
return-1;
}
/*Mmap the buffers in application space */
display_buff_info[i].length= buf.length;
display_buff_info[i].index= i;
display_buff_info[i].start=
mmap(NULL,buf.length, PROT_READ | PROT_WRITE,
MAP_SHARED,*display_fd, buf.m.offset);
if((unsigned int) display_buff_info[i].
start == MAP_SHARED) {
printf("Cannotmmap = %d buffer\n", i);
return-1;
}
display_buff_phy[i]=buf.m.offset;
/*It is better to zero buffers */
memset(display_buff_info[i].start,0x80,
display_buff_info[i].length);
printf("%d\n",display_buff_info[i].length);
}
video_buffer=display_buff_info[buf.index].start;
printf("phy=%x\n",display_buff_phy[buf.index]);
printf("vir=%x\n",video_buffer);
/* Enqueuebuffers
* Before starting streaming, all the buffersneeds to be en-queued
* in the driver incoming queue. */
/* Enqueuebuffers */
for (i = 0;i < reqbuf.count; i++) {
buf.type= V4L2_BUF_TYPE_VIDEO_OUTPUT;
buf.memory = V4L2_MEMORY_MMAP;
buf.index= i;
ret= ioctl(*display_fd, VIDIOC_QBUF, &buf);
if(ret < 0) {
perror("VIDIOC_QBUF\n");
return-1;
}
}
fmt->type= V4L2_BUF_TYPE_VIDEO_OUTPUT;
ret =ioctl(*display_fd, VIDIOC_G_FMT, fmt);
if(ret <0) {
perror("VIDIOC_G_FMT\n");
return-1;
}
printf("width=%d,heigth=%d\n",fmt->fmt.pix.width,fmt->fmt.pix.height);
return 0;
}
3、由于V4L2是输入输出实际就是在维护一个缓存区队列,所以在对缓存区进行修改后,需要放进队列中,并且在队列中获取新的一个缓存区,所以还需要修改GUI/Core/GUI_Exec.c,
int GUI_Exec(void) {
int r = 0;
while (GUI_Exec1()) {
r = 1; /* We have done something */
}
if(r==1)
{
AddrObj *display_buff;
int ret=0;
ret = putDisplayBuffer(&display_fd, 3,video_buffer);
if(ret < 0) {
printf("Error in put displaybuffer\n");
return ret;
}
display_buff=getDisplayBuffer(&display_fd);
if(NULL == display_buff) {
printf("Error in get displaybuffer\n");
return ret;
}
}
return r;
}
4、最后需要做的就是重写LCD驱动函数,其实需要重写的只有两个,分别是LCD_L0_GetPixelIndex和LCD_L0_SetPixelIndex,利用前面得到的用户空间地址video_buffer进行读写
LCD_L0_GetPixelIndex修改如下:
/* Read fromhardware ... Adapt to your system */
{
PixelIndex = video_buffer[yPhys*720+xPhys];
}
类似的,LCD_L0_SetPixelIndex的修改如下:
/* Write into hardware ... Adapt to yoursystem */
{
video_buffer[yPhys*720+xPhys]=PixelIndex;
}
至此,ucgui的移植修改全部结束。需要注意的是,video_buffer应该是char类型,因为我的显示器是8bpp,之前因为设的是int产生了横向的偏移。