硬汉嵌入式论坛

 找回密码
 立即注册
查看: 9518|回复: 0
收起左侧

[emWin教程入门篇] 【STemWin教程】第2章 STemWin5.xx详细移植步骤

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2015-1-6 14:45:51 | 显示全部楼层 |阅读模式
特别说明:完整STemWin的1-60期教程和配套实例下载地址:链接
第2章  STemWin5.xx详细移植步骤

    本期教程开始带领大家学习STemWin的移植,对于初学者STemWin的移植不是必须要先学的,可以先学一些基本的应用,然后再来学习移植就方面很多了,考虑到教程正常的编排顺序,这里就把STemWin的移植放在了第二章。本章提供的移植方法可以自适应安富莱生产的3.0寸,4.3寸,5寸,7寸TFT屏。这里只讲STemWin在MDK上面的移植,在IAR上面的移植是类似的。开发板使用安富莱STM32-V5开发板,主芯片STM32F407IGT6。
    2.1 关于STemWin移植的重要说明
    2.2 移植前的准备工作
    2.3 STemWin的裸机移植
    2.4 STemWin带RTOS的移植
    2.5 总结
2.1  关于STemWin移植的重要说明
    关于STemWin的移植一定要明确以下几点:
1.     emWin手册里面有这样一句话:“驱动接口的改变始于emWin V5。不再支持针对emWin V4 或更早版本开发的老显示驱动”。
2.     如果不使用V5以后版本的新特性,基本和以前的版本使用是一样的,也就是说,大家用V5以前版本实现的功能,直接升级到现有的版本,基本可以正常运行。
3.     尽管emWin提供了大部分屏的驱动,但是不能包含所有,这篇移植文档就因此而生。不管是emWin已经支持的,还是没有提供支持的,均可采用这种方法。
4.     本章教程提供了一个非常好的触摸滤波方法,此方法可以有效的滤除飞点。
5.     使用STemWin的库,一定得记得开启CRC,使用MDK安装目录里面的emWin库,一定得注册MDK的RL-ARM。
2.2  移植前的准备工作
    这里分别讲一下MDK安装目录中emWin的移植和STemWin的移植,准备工作做好以后,剩下的移植步骤基本是一样的。只是使用的各自的库即可。

2.2.1      MDK安装目录中emWin移植
    第一步:我们以MDK5.10中emWin5.22库进行说明。安装目录中有如下几个文件(路径:C:\Keil5.10\ARM\Pack\Keil\MDK-Middleware\5.1.4\emWin,如果使用的是MDK4.73等4.xx版本,路径:C:\Keil4.73\ARM\Segger\emWin)。
2.1.jpg

库版本

说明

GUI_ARM_B.lib

大端模式的库

GUI_ARM_L.lib

小端模式的库

GUI_CM0.lib

M0内核

GUI_CM3.lib

M3内核

GUI_CM4F.lib

M4内核

    在这里有一个问题要跟大家说明,emWin的官方手册中有这样一句话:
2.2.png
    其实这个是针对SEGGER自己做的emWin源码而言的,SEGGER授权给其它厂商后,芯片厂商都对源码进行了优化,要不FPU的存在就没有意义了。上面的GUI_CM4F.lib文件就是KEIL公司对emWin中需要使用浮点的地方进行了优化。
    第二步:注册RL-ARM,点击File->License Management
2.3.jpg
    第三步:注册RL-ARM,点击File->License Management
2.4.jpg
    第四步:注册机的设置
2.5.png

    这些准备工作做好后就可以开始移植工作了。

2.2.2      STemWin移植
    STemWin的移植准备工作比较简单,用户只需在初始化STemWin前使能CRC校验即可。STemWin的库文件如下:
2.6.jpg
    这里面含有KEIL,IAR和GCC三个版本的库。而且还区分带OS和不带OS版本。本教程讲的是不带OS版本的移植,带OS版本的移植也很简单,用户只需添加相应的文件即可。
    STemWin的下载地址:http://www.st.com/web/en/catalog/tools/PF259225#  (版本1.1.2)
    Lib文件所在的路径:STemWin_Library_V1.1.2\Libraries\STemWinLibrary522\Lib

2.3  STemWin的裸机移植
2.3.1      工程中添加的文件
    添加如图所示的几个文件:
2.7.png

    这几个文件从上往下依次进行一下简单的说明:
1.     bsp_tft_lcd.c, LCD_RA887, LCD_SPFD5420.c是用户要实现的TFT驱动文件。
2.     bsp_touch.c是触摸文件,也是用户要实现的。
3.     GUIDRV_Template.c文件在ST官方提供的STemWin包里面没有,需要在MDK的安装目录里面找。
        比如在MDK4.73安装目录中查找位置是:C:\Keil4.73\ARM\Segger\emWin\Sample\DisplayDriver
2.8.png

4.    上面MDK工程目录中GUI_X中的几个文件在MDK安装目录和STemWin软件包中都有:
     Ø  STemWin软件包中路径如下:STemWin_Library_V1.1.2\Libraries\STemWinLibrary522\OS,只是STemWin软件包中相关文件比较少。
     Ø  MDK4.73安装目录中的如下路径中:C:\Keil4.73\ARM\Segger\emWin\Sample\GUI_X,这里文件夹里面的内容比较全。
5.    GUI和LCD配置文件所在位置:
      MDK4.73安装目录:C:\Keil4.73\ARM\Segger\emWin\Sample\Config
      STemWin软件包:STemWin_Library_V1.1.2\Libraries\STemWinLibrary522\Config
6.    GUI/DEMO中的函数需要用户实现,简单的写个程序即可。
7.    GUI/Lib里面是emWin,所在位置
        MDK4.73安装目录:C:\Keil4.73\ARM\Segger\emWin\Lib
        STemWin软件包:STemWin_Library_V1.1.2\Libraries\STemWinLibrary522\Lib


2.3.2      触摸屏滤波的实现
    这里提供了一种有效的滤波方法。具体函数在bsp_touch.c这个文件里面,得到触摸数值后供emWin中的函数GUI_TOUCH_X_MeasureX 和GUI_TOUCH_X_MeasureY两个函数的调用。
    特别注意这里改变触摸的滤波方法,以前的时候大家都是采用舍弃触摸数值的前几个点和后几个点,然后中间数值取平均的方法,效果并不理想,因为这种方法不能有效的滤除飞点,这里提供一个新的方法。
    1. 在STemWin里面使用触摸的中断方式,效果并不好,所以这里使用查询,查询此引脚的电平,这样可以避免不必要的读取触摸数据。
    2. 触摸滤波,主要滤的是飞点,正是因为这些飞点的存在,才使得触摸很不稳定。
    下面的这个函数,大家应该很熟悉,就是滤除前几个点和后面几个点,然后中间几个点取平均
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: TOUCH_DataFilter
  4. *    功能说明: 读取一个坐标值(x或者y)
  5. *            连续读取XPT2046_READ_TIMES次数据,对这些数据升序排列,
  6. *            然后去掉最低和最高XPT2046_LOST_VAL个数,取平均值
  7. *    形    参:无
  8. *    返 回 值: 读到的数据
  9. *********************************************************************************************************
  10. */
  11. /* 读取次数 */
  12. #define XPT2046_READ_TIMES    5
  13. /* 丢弃值  */
  14. #define XPT2046_LOST_VAL      1      
  15. uint16_t TOUCH_DataFilter(uint8_t _ucCh)
  16. {
  17.      uint16_ti, j;
  18.      uint16_tbuf[XPT2046_READ_TIMES];
  19.      uint16_tusSum;
  20.      uint16_tusTemp;
  21.      /* 读取READ_TIMES次数据*/
  22.      for(i=0;i < XPT2046_READ_TIMES; i++)
  23.      {
  24.          if(g_ChipID == IC_8875)
  25.          {
  26.               if(_ucCh== ADC_CH_X)
  27.               {
  28.                    buf= RA8875_TouchReadX();
  29.               }
  30.               else
  31.               {
  32.                    buf= RA8875_TouchReadY();   
  33.               }
  34.          }
  35.          else
  36.          {
  37.               buf= TSC2046_ReadAdc(_ucCh);
  38.          }   
  39.      }
  40.      
  41.      /* 升序排列 */                  
  42.      for(i =0; i < XPT2046_READ_TIMES - 1; i++)
  43.      {
  44.          for(j= i + 1; j < XPT2046_READ_TIMES; j++)
  45.          {
  46.               if(buf> buf[j])
  47.               {
  48.                    usTemp= buf;
  49.                    buf= buf[j];
  50.                    buf[j]= usTemp;
  51.               }
  52.          }
  53.      }
  54.          
  55.      usSum =0;
  56.      /*求和 */
  57.      for(i =XPT2046_LOST_VAL; i < XPT2046_READ_TIMES - XPT2046_LOST_VAL; i++)
  58.      {
  59.          usSum+= buf;
  60.      }
  61.      /*求平均 */
  62.      usTemp =usSum / (XPT2046_READ_TIMES - 2 * XPT2046_LOST_VAL);
  63.      returnusTemp;
  64. }
  65. /*
  66. *********************************************************************************************************
  67. *    函 数 名: TOUCH_ReadAdcXY
  68. *    功能说明: 连续2次读取触摸屏IC,且这两次的偏差不能超过
  69. *            ADC_ERR_RANGE,满足条件,则认为读数正确,否则读数错误.
  70. *            该函数能大大提高准确度
  71. *    形    参:x,y:读取到的坐标值
  72. *    返 回 值: 0,失败;1,成功
  73. *********************************************************************************************************
  74. */
  75. /* 误差范围 */  
  76. uint8_t ADC_ERR_RANGE = 5;
  77. uint8_t TOUCH_ReadAdcXY(int16_t *_usX, int16_t*_usY)
  78. {
  79.      uint16_tiX1, iY1;
  80.      uint16_tiX2, iY2;
  81.      uint16_tiX, iY;
  82.      iX1 =TOUCH_DataFilter(ADC_CH_X);
  83.      iY1 =TOUCH_DataFilter(ADC_CH_Y);
  84.      iX2 =TOUCH_DataFilter(ADC_CH_X);
  85.      iY2 =TOUCH_DataFilter(ADC_CH_Y);
  86.      
  87.      iX =TOUCH_Abs(iX1 - iX2);
  88.      iY =TOUCH_Abs(iY1 - iY2);
  89.      
  90.      /* 前后两次采样在+-ERR_RANGE内 */  
  91.     if ((iX<= ADC_ERR_RANGE) && (iY <= ADC_ERR_RANGE))
  92.     {         
  93.          *_usX= (iX1 + iX2) / 2;
  94.          *_usY= (iY1 + iY2) / 2;   
  95.          return1;
  96.     }
  97.      else
  98.      {
  99.          return0;
  100.      }   
  101. }
  102. /*
  103. *********************************************************************************************************
  104. *    函 数 名: TOUCH_Scan
  105. *    功能说明: 触摸板事件检测程序。该函数被周期性调用,每ms调用1次. 见 bsp_Timer.c
  106. *    形    参:无
  107. *    返 回 值: 无
  108. *********************************************************************************************************
  109. */
  110. void TOUCH_SCAN(void)
  111. {
  112.      uint8_ts_invalid_count = 0;
  113.      
  114.      if(TOUCH_PressValid== 0)
  115.      {            
  116.          while(!TOUCH_ReadAdcXY(&g_tTP.usAdcNowX,&g_tTP.usAdcNowY)&&s_invalid_count < 20);
  117.          {
  118.               s_invalid_count++;
  119.          }
  120.          if(s_invalid_count>= 20)
  121.          {
  122.               g_tTP.usAdcNowX= -1;
  123.               g_tTP.usAdcNowY= -1;  
  124.          }
  125.      }
  126.      else
  127.      {
  128.          g_tTP.usAdcNowX= -1;
  129.          g_tTP.usAdcNowY= -1;  
  130.      }
  131.               
  132. }
复制代码
触摸的驱动就这些东西,详细的使用看例程级可以,然后在文件GUI_X_Touch_Analog.c里面调用就可以了。
  1. #include "GUI.h"
  2. #include "LCD_RA8875.h"
  3. #include "bsp_touch.h"
  4. void GUI_TOUCH_X_ActivateX(void)
  5. {
  6. }
  7. void GUI_TOUCH_X_ActivateY(void)
  8. {
  9. }
  10. int GUI_TOUCH_X_MeasureX(void)
  11. {
  12.      TOUCH_SCAN();
  13.      return(g_tTP.usAdcNowX);         
  14. }
  15. int GUI_TOUCH_X_MeasureY(void)
  16. {   
  17.      return(g_tTP.usAdcNowY);
  18. }
复制代码


2.3.3      底层驱动接口函数(GUIRV_Template)
    STemWin的底层驱动函数也很简单,用户只需提供打点和读点函数即可。但是这种没有经过优化的移植方式非常的影响STemWin的实际性能。这里就针对RA8875说一下需要优化的地方。
l  画水平线的函数
/*********************************************************************
*
*      _DrawHLine
*/
static void _DrawHLine  (GUI_DEVICE * pDevice, int x0, int y,  int x1) {
// LCD_PIXELINDEX ColorIndex;
  if(GUI_pContext->DrawMode & LCD_DRAWMODE_XOR) {
    for (;x0 <= x1; x0++) {
     _XorPixel(pDevice, x0, y);
    }
  } else {
       #if emWin_Optimize
         //LCD8875_DrawHLine(x0,y, x1, LCD_COLORINDEX);
         s_ucRA8875BusyNow = 1;
         LCD_DrawLineH(x0,y, x1, LCD_COLORINDEX);
         s_ucRA8875BusyNow= 0;
       #else
         LCD_PIXELINDEXColorIndex;
         ColorIndex= LCD__GetColorIndex();
         for(; x0 <= x1; x0++) {
           _SetPixelIndex(pDevice, x0, y, ColorIndex);
     
         }
       #endif
    }
}
l  画垂直线的函数
/*********************************************************************
*
*      _DrawVLine
*/
static void _DrawVLine  (GUI_DEVICE * pDevice, int x, int y0,  int y1) {
// LCD_PIXELINDEX ColorIndex;
  if(GUI_pContext->DrawMode & LCD_DRAWMODE_XOR) {
    for (;y0 <= y1; y0++) {
     _XorPixel(pDevice, x, y0);
    }
  } else {
    #ifemWin_Optimize
         s_ucRA8875BusyNow = 1;
         LCD_DrawLineV(x,y0, y1, LCD_COLORINDEX);
         s_ucRA8875BusyNow= 0;
     #else
         LCD_PIXELINDEXColorIndex;
         ColorIndex= LCD__GetColorIndex();
         for (; y0 <= y1; y0++) {
           _SetPixelIndex(pDevice, x, y0,ColorIndex);
         }
     #endif
  }
}
l  矩形填充函数
/*********************************************************************
*
*      _FillRect
*/
static void _FillRect(GUI_DEVICE * pDevice, intx0, int y0, int x1, int y1) {
#if emWin_Optimize
    if(g_ChipID == IC_8875)
     {
         s_ucRA8875BusyNow = 1;
          BTE_SetTarBlock(x0, y0, y1-y0+1, x1-x0+1,0);/* 设置BTE位置和宽度高度 */
         BTE_SetOperateCode(0x0C);          /* 设定BTE 操作码和光栅运算码  REG[51h] Bit[3:0] = 0Ch */
         RA8875_SetFrontColor(LCD_COLORINDEX);    /* 设置BTE前景色 */
         BTE_Start();                        /* 开启BTE 功能 */
         BTE_Wait();                              /* 等待操作结束 */
         s_ucRA8875BusyNow= 0;      
     }
     else
     {
         for(; y0 <= y1; y0++)
         {
              _DrawHLine(pDevice,x0, y0, x1);
         }        
     }
     
#else
     for (;y0 <= y1; y0++)
     {
         _DrawHLine(pDevice,x0, y0, x1);
     }
#endif
}
l  绘制16BPP的函数
/*******************************************************************************************************
*
*       DrawBitmap 16 BPP, not optimized
*/
static void _DrawBitLine16BPP(GUI_DEVICE *pDevice, int x, int y, U16 const GUI_UNI_PTR * p, int xsize) {
#if emWin_Optimize
     s_ucRA8875BusyNow= 1;
     LCD_DrawHColorLine(x,y, xsize, (uint16_t *)p);
     s_ucRA8875BusyNow= 0;
#else
     for(;xsize > 0; xsize--, x++, p++)
     {
         _SetPixelIndex(pDevice,x, y, *p);
     }
#endif
}
l  这里要根据实际的情况进行填写,不能填错,要不系统无法启动。
/*********************************************************************
*
*      _GetDevData
*/
static void * _GetDevData(GUI_DEVICE * pDevice,int Index) {
GUI_USE_PARA(pDevice);
  #ifGUI_SUPPORT_MEMDEV
    switch(Index) {
    case LCD_DEVDATA_MEMDEV:
// TBD: Has to be adapted to the right memory device depending onthe used color depth!
     return (void *)&GUI_MEMDEV_DEVICE_16;
    }
  #else
   GUI_USE_PARA(Index);
  #endif
  returnNULL;
}
优化好上面四个地方即可。


2.3.4      系统函数配置
    STemWin的底层驱动做好以后,就可以进行GUI和LCD的配置工作,这个是官方提供的配置流程:
2.9.png
1.    GUI的配置
    主要是配置STemWin所需的动态内存,下面的配置方式支持使用芯片内部存储器也支持使用外部存储器(比如:SRAM,SDRAM),使用外部存储器的话,一定要记得初始化相应器件。
  1. ----------------------------------------------------------------------
  2. File       : GUIConf.c
  3. Purpose    : Display controller initialization
  4. ---------------------------END-OF-HEADER------------------------------
  5. */
  6. #include "GUI.h"
  7. #include "bsp.h"
  8. /*
  9. **********************************************************************
  10. *
  11. *      Defines
  12. *
  13. **********************************************************************
  14. */
  15. /* Define the available number of bytes availablefor the GUI */
  16. //#define GUI_NUMBYTES  (1024*105)
  17. #define GUI_NUMBYTES  (1024*100)
  18. /* Define the average block size */
  19. #define GUI_BLOCKSIZE 0x80
  20. /*********************************************************************
  21. *
  22. *      GUI_X_Config
  23. *
  24. * Purpose:
  25. *   Calledduring the initialization process in order to set up the
  26. *  available memory for the GUI.
  27. **********************************************************************
  28. */
  29. void GUI_X_Config(void)
  30. {
  31. #if 1 //使用芯片内部内存
  32.      /* 32bit aligned memory area */
  33.      staticU32 aMemory[GUI_NUMBYTES / 4];
  34.      
  35.      /*  Assign memory to emWin */
  36.      GUI_ALLOC_AssignMemory(aMemory,GUI_NUMBYTES);
  37.      GUI_ALLOC_SetAvBlockSize(GUI_BLOCKSIZE);
  38. #else//使用外部内存
  39.      staticU32 *aMemory;
  40.      aMemory= (U32 *)EXT_SRAM_ADDR;
  41.      /*  Assign memory to emWin */
  42.      GUI_ALLOC_AssignMemory(aMemory,GUI_NUMBYTES);
  43.      GUI_ALLOC_SetAvBlockSize(GUI_BLOCKSIZE);
  44. #endif
  45. }
复制代码
2.    LCD的配置
    LCD的配置按照上面官方提供的驱动流程执行即可,下面是详细的代码。
  1. /*
  2. ****************************************************************************
  3. *
  4. *      LCD_X_Config
  5. *
  6. * Purpose:
  7. *   Calledduring the initialization process in order to set up the
  8. *   displaydriver configuration.
  9. *
  10. ****************************************************************************   
  11. */
  12. void LCD_X_Config(void)
  13. {
  14.      /* 读取EEPROM中的参数 */   
  15.      ee_ReadBytes((uint8_t*)&g_tTPSL, 1024, sizeof(g_tTPSL));
  16.      
  17.      /* Setdisplay driver and color conversion for 1st layer */
  18.    GUI_DEVICE_CreateAndLink(DISPLAY_DRIVER, COLOR_CONVERSION, 0, 0);
  19.      if(g_ChipID == IC_8875)
  20.      {
  21.          if(g_ucGPIX == 1) /*   GPIX = 1  4.3  480x272 */
  22.          {
  23.               /*Display driver configuration */
  24.               LCD_SetSizeEx    (0, 480, 272);
  25.               LCD_SetVSizeEx   (0, 480, 272);
  26.               
  27.               /*Touch calibration */
  28.               GUI_TOUCH_Calibrate(GUI_COORD_X,0, 479, g_tTPSL.usAdcX1,  g_tTPSL.usAdcX2);
  29.               GUI_TOUCH_Calibrate(GUI_COORD_Y,0, 271, g_tTPSL.usAdcY1, g_tTPSL.usAdcY2);
  30.               
  31.               /*查看是否需要切换X,Y*/
  32.               if(g_tTPSL.XYChange== 1)
  33.               {
  34.                    GUI_TOUCH_SetOrientation(GUI_SWAP_XY);
  35.               }
  36.          }
  37.          else    /*   GPIX= 0  7 800*480 */
  38.          {
  39.               /*Display driver configuration */
  40.               LCD_SetSizeEx    (0, XSIZE_PHYS, YSIZE_PHYS);
  41.               LCD_SetVSizeEx   (0, VXSIZE_PHYS, VYSIZE_PHYS);
  42.               
  43.               GUI_TOUCH_Calibrate(GUI_COORD_X,0, XSIZE_PHYS - 1, g_tTPSL.usAdcX1, g_tTPSL.usAdcX2);
  44.               GUI_TOUCH_Calibrate(GUI_COORD_Y,0, YSIZE_PHYS - 1, g_tTPSL.usAdcY1, g_tTPSL.usAdcY2);  
  45.               
  46.               /*查看是否需要切换X,Y*/
  47.               if(g_tTPSL.XYChange== 1)
  48.               {
  49.                    GUI_TOUCH_SetOrientation(GUI_SWAP_XY);
  50.               }
  51.          }
  52.      }
  53.      else
  54.      {
  55.          LCD_SetSizeEx    (0, 400, 240);
  56.          LCD_SetVSizeEx   (0, 400, 240);
  57.          
  58.          /*Touch calibration */
  59.          GUI_TOUCH_Calibrate(GUI_COORD_X,0, 399, 300, 3600);
  60.          GUI_TOUCH_Calibrate(GUI_COORD_Y,0, 239, 273,  3671);   
  61.      }
  62. }
复制代码
2.4  STemWin带RTOS的移植
    带系统和不带系统的区别就是添加一个驱动文件并添加RTOS相关文件即可,STemWin软件包里面提供了一个FreeRTOS的驱动文件,而MDK安装目录里面提供了好几款RTOS的驱动。所在路径如下:
        MDK4.73安装目录:C:\Keil4.73\ARM\Segger\emWin\Sample\GUI_X
        STemWin软件包:STemWin_Library_V1.1.2\Libraries\STemWinLibrary522\OS
2.10.png
    用户更具自己使用的OS,并添加此驱动即可,下面是FreeRTOS的工程目录。
2.11.png
2.5  总结
    整体来说,STemWin的移植不难,难的是底层驱动的优化,如何让它工作在最佳性能状态。这里有三个DEMO演示视频(分别是3.0寸,4.3寸和7寸的视频)供大家欣赏下:http://www.armbbs.cn/forum.php?mod=viewthread&tid=1545

努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-3 23:51 , Processed in 0.167478 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表