特别说明:完整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)。
库版本 |
说明 |
GUI_ARM_B.lib |
大端模式的库 |
GUI_ARM_L.lib |
小端模式的库 |
GUI_CM0.lib |
M0内核 |
GUI_CM3.lib |
M3内核 |
GUI_CM4F.lib |
M4内核 |
在这里有一个问题要跟大家说明,emWin的官方手册中有这样一句话:
其实这个是针对SEGGER自己做的emWin源码而言的,SEGGER授权给其它厂商后,芯片厂商都对源码进行了优化,要不FPU的存在就没有意义了。上面的GUI_CM4F.lib文件就是KEIL公司对emWin中需要使用浮点的地方进行了优化。 第二步:注册RL-ARM,点击File->License Management 第三步:注册RL-ARM,点击File->License Management 第四步:注册机的设置
这些准备工作做好后就可以开始移植工作了。
2.2.2 STemWin移植
STemWin的移植准备工作比较简单,用户只需在初始化STemWin前使能CRC校验即可。STemWin的库文件如下:
这里面含有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 工程中添加的文件
添加如图所示的几个文件:
这几个文件从上往下依次进行一下简单的说明:
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
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. 触摸滤波,主要滤的是飞点,正是因为这些飞点的存在,才使得触摸很不稳定。 下面的这个函数,大家应该很熟悉,就是滤除前几个点和后面几个点,然后中间几个点取平均 - /*
- *********************************************************************************************************
- * 函 数 名: TOUCH_DataFilter
- * 功能说明: 读取一个坐标值(x或者y)
- * 连续读取XPT2046_READ_TIMES次数据,对这些数据升序排列,
- * 然后去掉最低和最高XPT2046_LOST_VAL个数,取平均值
- * 形 参:无
- * 返 回 值: 读到的数据
- *********************************************************************************************************
- */
- /* 读取次数 */
- #define XPT2046_READ_TIMES 5
- /* 丢弃值 */
- #define XPT2046_LOST_VAL 1
- uint16_t TOUCH_DataFilter(uint8_t _ucCh)
- {
- uint16_ti, j;
- uint16_tbuf[XPT2046_READ_TIMES];
- uint16_tusSum;
- uint16_tusTemp;
-
- /* 读取READ_TIMES次数据*/
- for(i=0;i < XPT2046_READ_TIMES; i++)
- {
- if(g_ChipID == IC_8875)
- {
- if(_ucCh== ADC_CH_X)
- {
- buf= RA8875_TouchReadX();
- }
- else
- {
- buf= RA8875_TouchReadY();
- }
- }
- else
- {
- buf= TSC2046_ReadAdc(_ucCh);
- }
- }
-
- /* 升序排列 */
- for(i =0; i < XPT2046_READ_TIMES - 1; i++)
- {
- for(j= i + 1; j < XPT2046_READ_TIMES; j++)
- {
- if(buf> buf[j])
- {
- usTemp= buf;
- buf= buf[j];
- buf[j]= usTemp;
- }
- }
- }
-
- usSum =0;
-
- /*求和 */
- for(i =XPT2046_LOST_VAL; i < XPT2046_READ_TIMES - XPT2046_LOST_VAL; i++)
- {
- usSum+= buf;
- }
- /*求平均 */
- usTemp =usSum / (XPT2046_READ_TIMES - 2 * XPT2046_LOST_VAL);
-
- returnusTemp;
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: TOUCH_ReadAdcXY
- * 功能说明: 连续2次读取触摸屏IC,且这两次的偏差不能超过
- * ADC_ERR_RANGE,满足条件,则认为读数正确,否则读数错误.
- * 该函数能大大提高准确度
- * 形 参:x,y:读取到的坐标值
- * 返 回 值: 0,失败;1,成功
- *********************************************************************************************************
- */
- /* 误差范围 */
- uint8_t ADC_ERR_RANGE = 5;
- uint8_t TOUCH_ReadAdcXY(int16_t *_usX, int16_t*_usY)
- {
- uint16_tiX1, iY1;
- uint16_tiX2, iY2;
- uint16_tiX, iY;
-
- iX1 =TOUCH_DataFilter(ADC_CH_X);
- iY1 =TOUCH_DataFilter(ADC_CH_Y);
- iX2 =TOUCH_DataFilter(ADC_CH_X);
- iY2 =TOUCH_DataFilter(ADC_CH_Y);
-
- iX =TOUCH_Abs(iX1 - iX2);
- iY =TOUCH_Abs(iY1 - iY2);
-
- /* 前后两次采样在+-ERR_RANGE内 */
- if ((iX<= ADC_ERR_RANGE) && (iY <= ADC_ERR_RANGE))
- {
- *_usX= (iX1 + iX2) / 2;
- *_usY= (iY1 + iY2) / 2;
-
- return1;
- }
- else
- {
- return0;
- }
- }
-
- /*
- *********************************************************************************************************
- * 函 数 名: TOUCH_Scan
- * 功能说明: 触摸板事件检测程序。该函数被周期性调用,每ms调用1次. 见 bsp_Timer.c
- * 形 参:无
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void TOUCH_SCAN(void)
- {
- uint8_ts_invalid_count = 0;
-
- if(TOUCH_PressValid== 0)
- {
- while(!TOUCH_ReadAdcXY(&g_tTP.usAdcNowX,&g_tTP.usAdcNowY)&&s_invalid_count < 20);
- {
- s_invalid_count++;
- }
- if(s_invalid_count>= 20)
- {
- g_tTP.usAdcNowX= -1;
- g_tTP.usAdcNowY= -1;
- }
- }
- else
- {
- g_tTP.usAdcNowX= -1;
- g_tTP.usAdcNowY= -1;
- }
-
- }
复制代码触摸的驱动就这些东西,详细的使用看例程级可以,然后在文件GUI_X_Touch_Analog.c里面调用就可以了。 - #include "GUI.h"
- #include "LCD_RA8875.h"
- #include "bsp_touch.h"
-
- void GUI_TOUCH_X_ActivateX(void)
- {
-
- }
-
- void GUI_TOUCH_X_ActivateY(void)
- {
-
- }
-
- int GUI_TOUCH_X_MeasureX(void)
- {
- TOUCH_SCAN();
- return(g_tTP.usAdcNowX);
- }
-
- int GUI_TOUCH_X_MeasureY(void)
- {
- return(g_tTP.usAdcNowY);
- }
复制代码
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的配置工作,这个是官方提供的配置流程: 1. GUI的配置 主要是配置STemWin所需的动态内存,下面的配置方式支持使用芯片内部存储器也支持使用外部存储器(比如:SRAM,SDRAM),使用外部存储器的话,一定要记得初始化相应器件。 - ----------------------------------------------------------------------
- File : GUIConf.c
- Purpose : Display controller initialization
- ---------------------------END-OF-HEADER------------------------------
- */
- #include "GUI.h"
- #include "bsp.h"
-
- /*
- **********************************************************************
- *
- * Defines
- *
- **********************************************************************
- */
-
- /* Define the available number of bytes availablefor the GUI */
- //#define GUI_NUMBYTES (1024*105)
- #define GUI_NUMBYTES (1024*100)
- /* Define the average block size */
- #define GUI_BLOCKSIZE 0x80
-
- /*********************************************************************
- *
- * GUI_X_Config
- *
- * Purpose:
- * Calledduring the initialization process in order to set up the
- * available memory for the GUI.
- **********************************************************************
- */
- void GUI_X_Config(void)
- {
- #if 1 //使用芯片内部内存
- /* 32bit aligned memory area */
- staticU32 aMemory[GUI_NUMBYTES / 4];
-
- /* Assign memory to emWin */
- GUI_ALLOC_AssignMemory(aMemory,GUI_NUMBYTES);
- GUI_ALLOC_SetAvBlockSize(GUI_BLOCKSIZE);
- #else//使用外部内存
- staticU32 *aMemory;
- aMemory= (U32 *)EXT_SRAM_ADDR;
- /* Assign memory to emWin */
- GUI_ALLOC_AssignMemory(aMemory,GUI_NUMBYTES);
- GUI_ALLOC_SetAvBlockSize(GUI_BLOCKSIZE);
- #endif
- }
复制代码2. LCD的配置 LCD的配置按照上面官方提供的驱动流程执行即可,下面是详细的代码。 - /*
- ****************************************************************************
- *
- * LCD_X_Config
- *
- * Purpose:
- * Calledduring the initialization process in order to set up the
- * displaydriver configuration.
- *
- ****************************************************************************
- */
- void LCD_X_Config(void)
- {
- /* 读取EEPROM中的参数 */
- ee_ReadBytes((uint8_t*)&g_tTPSL, 1024, sizeof(g_tTPSL));
-
- /* Setdisplay driver and color conversion for 1st layer */
- GUI_DEVICE_CreateAndLink(DISPLAY_DRIVER, COLOR_CONVERSION, 0, 0);
-
- if(g_ChipID == IC_8875)
- {
- if(g_ucGPIX == 1) /* GPIX = 1 4.3 480x272 */
- {
- /*Display driver configuration */
- LCD_SetSizeEx (0, 480, 272);
- LCD_SetVSizeEx (0, 480, 272);
-
- /*Touch calibration */
- GUI_TOUCH_Calibrate(GUI_COORD_X,0, 479, g_tTPSL.usAdcX1, g_tTPSL.usAdcX2);
- GUI_TOUCH_Calibrate(GUI_COORD_Y,0, 271, g_tTPSL.usAdcY1, g_tTPSL.usAdcY2);
-
- /*查看是否需要切换X,Y*/
- if(g_tTPSL.XYChange== 1)
- {
- GUI_TOUCH_SetOrientation(GUI_SWAP_XY);
- }
- }
- else /* GPIX= 0 7 800*480 */
- {
- /*Display driver configuration */
- LCD_SetSizeEx (0, XSIZE_PHYS, YSIZE_PHYS);
- LCD_SetVSizeEx (0, VXSIZE_PHYS, VYSIZE_PHYS);
-
- GUI_TOUCH_Calibrate(GUI_COORD_X,0, XSIZE_PHYS - 1, g_tTPSL.usAdcX1, g_tTPSL.usAdcX2);
- GUI_TOUCH_Calibrate(GUI_COORD_Y,0, YSIZE_PHYS - 1, g_tTPSL.usAdcY1, g_tTPSL.usAdcY2);
-
- /*查看是否需要切换X,Y*/
- if(g_tTPSL.XYChange== 1)
- {
- GUI_TOUCH_SetOrientation(GUI_SWAP_XY);
- }
- }
- }
- else
- {
- LCD_SetSizeEx (0, 400, 240);
- LCD_SetVSizeEx (0, 400, 240);
-
- /*Touch calibration */
- GUI_TOUCH_Calibrate(GUI_COORD_X,0, 399, 300, 3600);
- GUI_TOUCH_Calibrate(GUI_COORD_Y,0, 239, 273, 3671);
- }
-
- }
复制代码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 用户更具自己使用的OS,并添加此驱动即可,下面是FreeRTOS的工程目录。 2.5 总结
|