zoukankan      html  css  js  c++  java
  • S5PV210开发系列四_uCGUI的移植

    S5PV210开发系列四

    uCGUI的移植

    象棋小子          1048272975

    GUI(图形用户界面)极大地方便了非专业用户的使用,用户无需记忆大量的命令,取而代之的是能够通过窗体、菜单、按键等方式进行操作。

    在某些场合,设计一款人机界面丰富友好的嵌入式产品能赢得很多其它的用户。笔者此处就S5PV210基于uCGUI图形用户界面的使用作一个简单的介绍。

    1. uCGUI移植概述

    1.1. S5PV210 Bootloader

    笔者的S5PV210的Bootloader设置最高的CPU主频1GHZ,MMU进行1:1内存空间线性映射,并开启L1 I/D Cache、L2 Cache、硬件分支预測功能,使CPU能达到最大的吞吐量性能。初始化内存,可以识别sd/mmc启动和Nand flash启动,自己主动载入应用代码到RAM位置。统一的中断管理架构、重定向底层IO操作。支持代码直接下载内存执行以及Nandflash下载。可以更加专注于应用的开发。

    1.2. uCGUI源代码

    笔者以uCGUI 3.98这个版本号移植作为解说。这个版本号的uCGUI是开放源代码的最高版本号。之后版本号仅仅提供库文件,不再开源。关于uCGUI概述、使用、移植等具体内容,能够直接阅读uCGUI用户手冊。

    1.3. uCGUI接口实现

    uCGUI依据其使用的功能,必须先实现其对应的功能接口。对于uCGUI,显示以及时基计时这两部分是必须的。因此必须实现其接口。

    显示即是实现对应的屏驱动。时基计时即是实现1ms/tick的定时计数,uCGUI用来实现时间计时。

    此处还使用uCGUI触摸屏功能,因此也应实现对应的触摸屏驱动。

    2. 接口移植驱动

    2.1. 屏驱动

    屏驱动主要提供设置某一坐标像素颜色接口Display_SetPixel 和从某一坐标读出像素颜色接口Display_GetPixel给uCGUI就可以。S5PV210具有RGB接口。因此屏驱动也主要是RGB接口的初始化。依据详细的屏,设置其水平分辩率、垂直分辩率、像素时钟、缓存位置等就可以。RGB控制器是通过DMA的方式把显存帧传输数据到外部接口。因此CPU对显存数据的更改均应写回显存所在的物理主存。不然会有Cache数据一致性的问题。

    Bootloader对于Cache提供了相应的四种内存分配策略:

    cached, write-back。写回模式,CPU的每次读写假设Cache命中则仅仅读写Cache,不读写主存。这样的模式不用过多地读写缓慢的主存,因此CPU具有最高的性能,默认的内存分配方式。

    cached, write-through。写通模式。CPU每次读假设Cache命中则仅仅读Cache。不读主存。每次写即使Cache命中更新Cache外。还会随后写入主存,减少了系统的写速度,在Bootloader中的内存域为” .mem_cnb”。

    non-cached, buffered,不可Cached,写缓存开启。CPU每次读写均不会Cache命中。CPU写数据时写入缓存后马上继续运行,缓存随后更新到主存。

    未用Cache功能,CPU读写性能相对低下。在Bootloader中的内存域为” .mem_ncb”。

     non-cached, non-buffered,不可Cached。未开启写缓存。

    CPU每次读写均从主存读写。因为主存的缓慢。这样的模式读写性能低下。在Bootloader中的内存域为” .mem_ncnb”。

    对于RGB显存,除了写回模式外,其他模式写均会更新主存,不存在显示的一致性问题。为了达到最高的CPU性能,RGB显存应分配在写通模式内存区。

    //16 bit(565)

    uint16_tDisplayBuffer[HSize*VSize] @ ".mem_cnb"; // cached, write through

    同一时候。对于数据DMA,为保证数据一致性总是,可用最简单的方式,DMA区域内存分配到non-cached, non-buffered域,尽管牺牲性能,但没有Cache一致性问题。

    uint32_tDMA_Buffer[xxx] @ ".mem_ncnb";

    2.2. 触摸屏驱动

    触摸屏驱动主要提供有触摸时返回触摸点X位置接口TP_GetPoint1_X和返回触摸点Y位置接口TP_GetPoint1_Y给uCGUI就可以。

    笔者使用的是电容屏,一般电容屏均是使用I2C接口。因此必须先实现I2C驱动。电容屏一般支持多点触摸。但uCGUI仅仅支持单点触摸。因此电容屏中断输出配置成查询方式,通过查询中断线的电平状态来确定有无触摸事件。

    int32_tTP_GetPoint1_X(void)

    {

        uint8_t Point1_X[2];

        if (!(GPH0DAT_REG & FT5206_INT)) { // 触屏按下时。INT拉低      

            // 获得12位X轴坐标

            TP_ReadRegs(FT5206_TOUCH1_XH, Point1_X,2);

            if (!(GPH0DAT_REG & FT5206_INT)) {

                //获得AD时应保持按下。不然AD值可能不准确。应丢弃

                return((((int32_t)(Point1_X[0]&0xf)) << 8) | Point1_X[1]);

            }  

        }  

        return -1; //返回无效值,表未按下或释放了

    }

    int32_tTP_GetPoint1_Y(void)

    {

        uint8_t Point1_Y[2];

       

        if (!(GPH0DAT_REG & FT5206_INT)) { // 触屏按下时,INT拉低

            // 获得12位Y轴坐标

            TP_ReadRegs(FT5206_TOUCH1_YH, Point1_Y,2);

            if (!(GPH0DAT_REG & FT5206_INT)) {

                //获得AD时应保持按下,不然AD值可能不准确。应丢弃

                return((((int32_t)(Point1_Y[0]&0xf)) << 8) | Point1_Y[1]);

            }  

        }  

        return -1; //返回无效值,表未按下或释放了

    }

    int32_tTP_WriteRegs(uint8_t WriteAddr, uint8_t *pData,uint8_t Len)

    {  

        uint8_t Packet[64];

        uint8_t i;

        if (Len >= sizeof(Packet)) {

            return -1;

        }

        Packet[0] = WriteAddr;

        for (i=0; i<Len; i++) {

            Packet[i+1] = pData[i];

        }

        return I2C_WriteBytes(FT5206_ADDR, Packet,Len+1);

    }

    int32_tTP_ReadRegs(uint8_t ReadAddr, uint8_t *pData, uint8_t Len)

    {

        int32_t Ret;

        // 写需读取的内部寄存器地址

        Ret = I2C_WriteBytes(FT5206_ADDR,&ReadAddr, 1);

        if (Ret == 0) {

            return I2C_ReadBytes(FT5206_ADDR, pData,Len); 

        }

        return Ret;

    }

    2.3. 定时器驱动

    uCGUI通过OS_TimeMS来作为时基,因此须要一个定时器实现1ms/tick更新OS_TimeMS这个时基计数器。

    此处採用S5PV210的Timer4。初始化并注冊对应的中断后。在当中断回调函数更新OS_TimeMS。同一时候处理uCGUI约100HZ频率查询触摸屏输入任务。

    uint8_tTP_Period;

    staticvoid Timer4_Callback(void)

    {

        extern volatile int OS_TimeMS;

        OS_TimeMS++; // 1ms计数,在GUI_X.c中定义,用来uCGUI延时计数

    #ifGUI_SUPPORT_TOUCH

        TP_Period++;

        if (TP_Period >= 10) { // 每隔10ms检查触摸屏输入

            TP_Period = 0;

            IRQ_DisableInt(INT_TIMER4); // 禁止同一中断重入

            IRQ_Enable(); // 在定时器中断处理中同意I2C嵌套中断

            GUI_TOUCH_Exec(); // 保证100HZ的触摸屏输入检查

            IRQ_EnableInt(INT_TIMER4);

        }

    #endif

    }

    3. uCGUI改动

    3.1. GUIConfig文件夹

    进入GUIConfig文件夹,打开GUIConf.h对GUI进行整体的配置。因为内存充足。能够设置较大的动态内存以及支持内存设备。此处并不支持操作系统以及鼠标。改动后的内容例如以下:

    #ifndef GUICONF_H

    #define GUICONF_H

    #define GUI_OS                    (0)  /* 不支持多任务 */

    #defineGUI_SUPPORT_TOUCH         (1)  /* Support a touch screen (req. win-manager)*/

    #define GUI_SUPPORT_MOUSE         (0) /* 不支持鼠标 */

    #defineGUI_SUPPORT_UNICODE       (1)  /* Support mixed ASCII/UNICODE strings */

    #defineGUI_DEFAULT_FONT         &GUI_Font6x8

    #defineGUI_ALLOC_SIZE            (4*1024*1024)  /* 动态内存4M*/

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

    *

    *         Configuration of available packages

    */

    #defineGUI_WINSUPPORT            1  /* Window manager package available */

    #defineGUI_SUPPORT_MEMDEV        1  /* Memory devices available */

    #defineGUI_SUPPORT_AA            1  /* Anti aliasing available */

    #endif  /* Avoidmultiple inclusion */

    打开LCDConf.h对LCD进行配置。笔者使用的是16位(R:5-G:6-B:5)色深800*480的RGB屏,清空LCDConf.h中的全部内容,由于这是其他LCD屏的配置,与所用屏全然不一致。改动后的内容例如以下:

    #ifndef LCDCONF_H

    #define LCDCONF_H

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

    *                   Generalconfiguration of LCD

    **********************************************************************

    */

    #define LCD_XSIZE          (800)      /* 屏X水平像素点 */

    #define LCD_YSIZE          (480)      /* 屏Y水平像素点 */

    #define LCD_BITSPERPIXEL   (16)     /* 16位色深*/

    #define LCD_CONTROLLER     (-1)       /* 宏开关,使用LCDDriver下的模板 */

    #define LCD_FIXEDPALETTE   (565)      /* R:5-G:6-B:5 */

    #define LCD_SWAP_RB        (1)      /*RB颜色调换 */

    #define LCD_SWAP_XY        (0)      /* 屏x,y方向不调换 */

    #define LCD_INIT_CONTROLLER()   Display_Init()/* 屏驱动初始化接口 */

    #endif /* LCDCONF_H */

    打开GUITouchConf.h对触摸屏进行配置,笔者使用的是电容屏,驱动IC已处理好返回的触摸坐标值与屏像素坐标一一相应,也能够在移植后进行校准。

    #ifndefGUITOUCH_CONF_H

    #defineGUITOUCH_CONF_H

    #define GUI_TOUCH_AD_LEFT    0   /* 触摸屏能返回最左边的值 */

    #defineGUI_TOUCH_AD_RIGHT   800  /* 触摸屏能返回最右边的值 */

    #defineGUI_TOUCH_AD_TOP     0    /* 触摸屏能返回最上面的值 */

    #defineGUI_TOUCH_AD_BOTTOM  480  /* 触摸屏能返回最以下的值 */  

    #defineGUI_TOUCH_SWAP_XY    0    /* 触摸屏x,y方向不调换  */

    #defineGUI_TOUCH_MIRROR_X   0    /* 触摸屏x方向不镜像调换*/

    #defineGUI_TOUCH_MIRROR_Y   0    /* 触摸屏y方向不镜像调换*/

    #endif /*GUITOUCH_CONF_H */

    3.2. LCDDriver文件夹

    进入GUI->LCDDriver文件夹,需改动uCGUI关于实际LCD的底层接口调用。

    因为我们在LCDConf.h里配置LCD_CONTROLLER为-1,这个宏开关会选择LCDTemplate.c这个模板文件进行编译,其他的接口文件不会被编译。LCDTemplate.c里面已经有相关的模板代码,仅仅需增加LCD_L0_SetPixelIndex()和LCD_L0_GetPixelIndex()的实现就可以,LCD_L0_SetPixelIndex设置LCD某一坐标的像素值,LCD_L0_GetPixelIndex从LCD某一坐标读出像素值,分别相应RGB屏驱动底层函数Display_SetPixel ()和Display_GetPixel()。增加这两个底层函数就可以。

    LCD_L0_SetPixelIndex()改动后代码例如以下:

    void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex) {

      GUI_USE_PARA(x);

      GUI_USE_PARA(y);

      GUI_USE_PARA(PixelIndex);

      /* Convert logical into physicalcoordinates (Dep. on LCDConf.h) */

      #if LCD_SWAP_XY | LCD_MIRROR_X|LCD_MIRROR_Y

        int xPhys = LOG2PHYS_X(x, y);

        int yPhys = LOG2PHYS_Y(x, y);

      #else

        #define xPhys x

        #define yPhys y

      #endif

      /* Write into hardware ... Adapt toyour system */

      {

        Display_SetPixel(x, y, (unsignedshort)PixelIndex);

      }

    }

    LCD_L0_GetPixelIndex()改动后的代码例如以下:

    unsigned int LCD_L0_GetPixelIndex(int x, int y) {

      LCD_PIXELINDEX PixelIndex;

      GUI_USE_PARA(x);

      GUI_USE_PARA(y);

      /* Convert logical into physicalcoordinates (Dep. on LCDConf.h) */

      #if LCD_SWAP_XY | LCD_MIRROR_X|LCD_MIRROR_Y

        int xPhys = LOG2PHYS_X(x, y);

        int yPhys = LOG2PHYS_Y(x, y);

      #else

        #define xPhys x

        #define yPhys y

      #endif

      /* Read from hardware ... Adapt toyour system */

      {

        PixelIndex= (LCD_PIXELINDEX)(Display_GetPixel(x, y));

      }

      return PixelIndex;

    }

    3.3. GUI_X文件夹

    GUI启动前,除了LCD可能还有其他需初始化的硬件设备,比如uCGUI要用到LCD以及触摸屏,那么在GUI使用前就应先初始化这些设备,这部分在GUI_X_Init()函数中处理。在GUI_X_Init()函数中实现例如以下:

    void GUI_X_Init(void)

    {

    #if GUI_SUPPORT_TOUCH

      TP_Init();// 使用uCGUI时先初始化触摸屏

    #endif

    }

    GUI_X_Touch.c为uCGUI触摸屏訪问接口,仅仅要实现GUI_TOUCH_X_MeasureX()和GUI_TOUCH_X_MeasureY()就可以。这两个函数分别与电容屏驱动获得第一个触摸点x,y位置的底层函数TP_GetPoint1_X()与TP_GetPoint1_Y()相应。

    int  GUI_TOUCH_X_MeasureX(void) {

      return TP_GetPoint1_X();

    }

    int  GUI_TOUCH_X_MeasureY(void) {

      return TP_GetPoint1_Y();

    }

    4. uCGUI  Demo应用

    应用程序中调用对应的uCGUI的例程Demo,其效果例如以下:

     

     

     

    5. 附录

    S5PV210_uCGUI.rar,uCGUI在IAR下的移植project,包含S5PV210 Bootloader、uCGUI源代码、以及对应的RGB、TP、I2C、Timer驱动。

    http://pan.baidu.com/s/1sj1F2W1

  • 相关阅读:
    存储过程参数不能使用函数
    .gitignore git已跟踪文件不生效
    Css选择器-层次选择器(关系选择器)
    Mysql自定义变量的作用
    jQuery 鼠标滑过Div变色
    DataTable导出excel 设置单元格格式
    layui table 详细讲解
    npm 常用命令详解
    SQL Server 2008下轻松调试T-SQL语句和存储过程
    帆软报表常用功能
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5346965.html
Copyright © 2011-2022 走看看