一念花开
自控笔记
LPC1788的emWIN移植好以后发现,静态的画片显示效果良好,虽然上次选择USE MICROLIB后,效果好的多,但是一旦加上交互(比如触屏动作)或者画面切换时仍然会出现瞬间的闪屏和图片错位,虽然不影响使用,但是对用户体验来说还是有很大的影响的。怀疑是SDRAM速度跟不上的原因,但是别人移植的emWIN同样的时钟频率,同样的SDRAM都没有出现这种情况,心中甚是疑惑,搞了好久,问题都没有解决。
今天把EMC时钟调高后瞬间闪屏错位的现象完全消除。
原来的EMC时钟为CPU核心时钟的一半,现在改为和CPU时钟频率相同。CPU核心时钟为120MHz,所以原来EMC时钟为60MHz,现在为120MHz。看了下SDRAM的数据手册,最高支持频率可达:166MHz/CL3,133MHz/CL2,所以SDRAM 120MHz在规定的频率范围内。

一念花开
自控笔记
emWIN移植, LPC1788
昨天对emWIN的LCD驱动进行了移植,今天要对触摸屏驱动进行移植。
对emWIN编写触摸屏驱动很简单,方法也有很多。在这里只详细介绍其中一种方法。
对emWIN触屏驱动进行移植,只需要配置GUI_TOUCH_X_ActivateX(), GUI_TOUCH_X_ActivateY(),GUI_TOUCH_X_MeasureX(), GUI_TOUCH_X_MeasureY()四个函数即可。
可以根据自己的驱动编写方式进行配置,一般GUI_TOUCH_X_ActivateX(), GUI_TOUCH_X_ActivateY()可以为空,只需要在GUI_TOUCH_X_MeasureX(), GUI_TOUCH_X_MeasureY()函数中返回触摸屏X轴和Y轴物理测量值即可。
还有一个十分重要的函数GUI_TOUCH_Exec(),这个函数需要定期调用已更新触摸屏的输出值。这个函数会在执行期间调用GUI_TOUCH_X_ActivateX(), GUI_TOUCH_X_ActivateY(),GUI_TOUCH_X_MeasureX(), GUI_TOUCH_X_MeasureY()四个函数来获取触摸屏X轴和Y轴物理测量值,然后根据GUI_TOUCH_Calibrate()校准后的参数进行触摸坐标的物理值和逻辑值的转换。然会把坐标的逻辑值存储在emWIN系统中。所以在触摸屏初始化时,需要调用GUI_TOUCH_Calibrate()函数进行校准。
GUI_TOUCH_Exec()可以放在系统节拍定时器或者普通定时器的中断函数中,至少应每10ms调用一次,利用查询的方式对触摸坐标进行更新;也可以放在触摸屏的外部中中断函数中,及时的对触摸坐标进行更新。
根据NXP官方例程中已有的触屏驱动,只要对其修改即可。项目中HW_X_Config()对系统节拍时钟进行了初始化,并使能了中断,每1ms中断一次。
项目中是通过系统节拍SysTick对GUI_TOUCH_Exec()进行调用,GUI_TOUCH_Exec()在ExecTouch()函数中,所以修改ExecTouch()函数即可。ExecTouch()在LCDconf.c中。

ExecTouch()中只需要把_CheckUpdateTouch()函数改成自己获取X轴和Y轴物理值的驱动即可,同时删除_SSP_SendCmd(PWRDOWN);

由于在ExecTouch()函数中调用了获取X轴和Y轴物理值的驱动函数,并且存储在了全局变量_TouchX和_TouchY中,所以在GUI_TOUCH_X_MeasureX()和GUI_TOUCH_X_MeasureY()中只需要返回变量_TouchX和_TouchY的值即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
/********************************************************************* * * GUI_TOUCH_X_MeasureX() * * Function decription: * Called from GUI, if touch support is enabled. * Measures voltage of X-axis. */ int GUI_TOUCH_X_MeasureX(void) { return _TouchX; } /********************************************************************* * * GUI_TOUCH_X_MeasureY() * * Function decription: * Called from GUI, if touch support is enabled. * Measures voltage of Y-axis. */ int GUI_TOUCH_X_MeasureY(void) { return _TouchY; } |
下面只剩下最后一步,对触屏进行校准,以找到触屏坐标物理值和逻辑值的对应关系。
找到LCD_X_DisplayDriver中调用的_InitController函数,接触在移植LCD驱动时对_InitTouch()函数的注释,并对_InitTouch()函数进行修改。修改为
|
#ifndef _WINDOWS static void _InitTouch(void) { U32 TouchOrientation; // // Calibrate touch // TouchOrientation = (GUI_MIRROR_X * LCD_GetMirrorXEx(0)) | (GUI_MIRROR_Y * LCD_GetMirrorYEx(0)) | (GUI_SWAP_XY * LCD_GetSwapXYEx (0)) ; GUI_TOUCH_SetOrientation(TouchOrientation); GUI_TOUCH_Calibrate(GUI_COORD_X, 0, XSIZE_PHYS, TOUCH_BOARD_800_480_AD_LEFT, TOUCH_BOARD_800_480_AD_RIGHT); GUI_TOUCH_Calibrate(GUI_COORD_Y, 0, YSIZE_PHYS, TOUCH_BOARD_800_480_AD_TOP , TOUCH_BOARD_800_480_AD_BOTTOM); } #endif |
TOUCH_BOARD_800_480_AD_LEFT,TOUCH_BOARD_800_480_AD_RIGHT,TOUCH_BOARD_800_480_AD_TOP,TOUCH_BOARD_800_480_AD_BOTTOM值可以根据NXP_emWin522_BSP\Start\Sample\Tutorial目录下的TOUCH_Sample.c测得。

然后在主程序或者_InitTouch函数中加入触摸屏驱动初始化函数,这样emWIN的触摸屏驱动就移植完成了。
测试了一下,触屏正常。

一念花开
自控笔记
最近在学习LPC1788的LCD控制器,做完基本的显示和触屏实验后,就想着学习一下emWIN。
于是,在NXP的网站LPCware.com上下载了emWIN的库和例程。可是例程和自己的板子不是配套的,需要对其修改后才可以使用。经过好几个小时的修改,例程终于在我的LPC1788开发板上跑起来了。期间遇到了一些问题,下面就记录一下移植步骤,以供大家参考。但是仍然存在这一些问题,还望大家指教。
一、修改emWIN配置文件
移植emWIN需要修改GUIconf.c和LCDconf.c两个配置文件即可(GUIconf.c例程中已经写好,这部份不修改也可)。
GUIconf.c主要为emWIN分配管理空间,这一部分主要是修改GUI_X_Config函数,如下图所示。
在MDK中对GUI_X_Config()中起效的是
|
U32 static _aMemory[GUI_NUMBYTES / 4] __attribute__ ((section ("GUI_RAM"), zero_init)); |
这句话会把_aMemory数组放在名为GUI_RAM的段中,zero_init属性表示不对这片区域初始化。这需要在分散加载文件中定位。
在LCDConf.c中也有类似的存储空间分配:

|
__align(8) static U32 _aVRAM[FB_XSIZE * FB_YSIZE / (4 / PIXEL_WIDTH)] __attribute__ ((section ("VRAM"), zero_init)); |
__align(8) 表示对齐方式,8字节对齐,要求首地址的最后三位为0。_aVRAM数组大小为何为FB_XSIZE * FB_YSIZE / (4 / PIXEL_WIDTH)] 自己可以根据屏幕分辨率和像素位深来计算一下。
GUI_RAM段和VRAM段都需要在分散加载文件中分配好存储区域,例程的分散加载文件(FLASH.sct)如下:
|
LR_IROM1 0x00000000 0x00080000 { ; load region size_region ER_IROM1 0x00000000 0x00080000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x10000000 0x00010000 { ; RW data .ANY (+RW +ZI) } RW_RAM1 0xA0000000 UNINIT 0x02000000 { ; RW data * (VRAM, GUI_RAM, GUIDEMO_STACK, FS_RAM, IP_RAM, USB_RAM) } } |
可以在.map文件中看到段对应的地址
GUI_RAM首地址 OXA0000000 VRAM首地址0xA0C00000(因为_aMemory大小为(1024 * 1024) * 12 MByte,故偏移量为0xC00000)
下面需要修改LCDconf.c
修改其中的LCD_X_Config和LCD_X_DisplayDriver函数调用的InitController函数(如下图)

原函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
|
void LCD_X_Config(void) { const GUI_DEVICE_API * pDriver; #ifndef _WINDOWS _UpdateDisplayConfig(); #endif // // Check framebuffer size // #ifndef _WINDOWS if ((FB_XSIZE * FB_YSIZE) < (VXSIZE_PHYS * VYSIZE_PHYS)) { while (1); // Error, framebuffer too small } #endif // // Set display driver and color conversion for 1st layer // #ifndef _WINDOWS if (_Display == DISPLAY_TRULY_240_320) { pDriver = DISPLAY_DRIVER_TRULY; } else { pDriver = DISPLAY_DRIVER_OTHER; } #else pDriver = GUIDRV_WIN32; #endif GUI_DEVICE_CreateAndLink(pDriver, COLOR_CONVERSION, 0, 0); // // Display driver configuration, required for Lin-driver // LCD_SetPosEx(0, 0, 0); if (LCD_GetSwapXYEx(0)) { LCD_SetSizeEx (0, YSIZE_PHYS , XSIZE_PHYS); LCD_SetVSizeEx (0, VYSIZE_PHYS, VXSIZE_PHYS); } else { LCD_SetSizeEx (0, XSIZE_PHYS , YSIZE_PHYS); LCD_SetVSizeEx (0, VXSIZE_PHYS, VYSIZE_PHYS); } LCD_SetVRAMAddrEx(0, (void*)VRAM_ADDR_VIRT); // // Set user palette data (only required if no fixed palette is used) // #if defined(PALETTE) LCD_SetLUTEx(0, PALETTE); #endif } #ifndef _WINDOWS static void _InitController(unsigned LayerIndex) { _InitLCD(); // // Set display size and video-RAM address // LCD_SetSizeEx (XSIZE_PHYS, YSIZE_PHYS, LayerIndex); LCD_SetVSizeEx(VXSIZE_PHYS, VYSIZE_PHYS, LayerIndex); LCD_SetVRAMAddrEx(LayerIndex, (void*)VRAM_ADDR_PHYS); // // Init touch // #if GUI_SUPPORT_TOUCH // Used when touch screen support is enabled _InitTouch(); #endif } #endif |
修改后的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
void LCD_X_Config(void) { const GUI_DEVICE_API * pDriver; pDriver = DISPLAY_DRIVER_OTHER; GUI_DEVICE_CreateAndLink(pDriver, COLOR_CONVERSION, 0, 0); // // Display driver configuration, required for Lin-driver // LCD_SetPosEx(0, 0, 0); if (LCD_GetSwapXYEx(0)) { LCD_SetSizeEx (0, YSIZE_PHYS , XSIZE_PHYS); LCD_SetVSizeEx (0, VYSIZE_PHYS, VXSIZE_PHYS); } else { LCD_SetSizeEx (0, XSIZE_PHYS , YSIZE_PHYS); LCD_SetVSizeEx (0, VXSIZE_PHYS, VYSIZE_PHYS); } LCD_SetVRAMAddrEx(0, (void*)VRAM_ADDR_VIRT); // // Set user palette data (only required if no fixed palette is used) // #if defined(PALETTE) LCD_SetLUTEx(0, PALETTE); #endif } |
#ifndef _WINDOWS
|
static void _InitController(unsigned LayerIndex) { //_InitLCD(); // // Set display size and video-RAM address // LCD_SetSizeEx (XSIZE_PHYS, YSIZE_PHYS, LayerIndex); LCD_SetVSizeEx(VXSIZE_PHYS, VYSIZE_PHYS, LayerIndex); LCD_SetVRAMAddrEx(LayerIndex, (void*)VRAM_ADDR_PHYS); // // Init touch // #if GUI_SUPPORT_TOUCH // Used when touch screen support is enabled //_InitTouch(); #endif } #endif |
因为暂时还没有加入触摸屏,所以把_InitTouch();也注释掉了。
此外还需把
|
// Physical display size // #ifndef _WINDOWS #define XSIZE_PHYS _LcdParams.PPL #define YSIZE_PHYS _LcdParams.LPP #else #define XSIZE_PHYS FB_XSIZE #define YSIZE_PHYS FB_YSIZE #endif |
改为
|
// Physical display size // #define XSIZE_PHYS FB_XSIZE #define YSIZE_PHYS FB_YSIZE |
(因为原程序是靠EEPROM来配置的)
至此配置文件已经修改好了。
二、修改项目的启动文件(startup_LPC177x_8x_Keil.s)
|
; Reset Handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT SystemInit IMPORT __low_level_init IMPORT __main LDR R0, =SystemInit BLX R0 LDR R0, =__low_level_init BLX R0 LDR R0, =__main BX R0 ENDP |
修改上面的程序为:
|
; Reset Handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT SystemInit IMPORT __main LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP |
三、修改主程序文件(main.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
#ifndef _WINDOWS #include "HWConf.h" #endif #ifdef __CROSSWORKS_ARM extern void __low_level_init(); // hwconf.c #endif void MainTask(void); // Defined in SEGGERDEMO.c /********************************************************************* * * main */ void main(void) { #ifdef __CROSSWORKS_ARM __low_level_init(); #endif #ifndef _WINDOWS HW_X_Config(); // Initialization of Hardware #endif MainTask(); // emWin application } |
上面的程序改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
#include "sdram_W9825G6JH.h" #include "lcd_lpc177x_8x.h" #include "HWConf.h" //#include "GUIDEMO.h" void MainTask(void); // Defined in SEGGERDEMO.c /********************************************************************* * * main */ //extern void LCD_init(int xSize, int ySize, unsigned short * memory); int main(void) { HW_X_Config(); // Initialization of Hardware SDRAMInit();//写入自己的SDRAM驱动 LCD_init(800 ,480, (unsigned short * )0xA0C00000);//写入自己的LCD驱动 MainTask(); // emWin application } |
在主文件中加入自己的SDRAM驱动以及LCD驱动(LCD驱动也可以写在LCDconf.C中的LCD_X_DisplayDriver函数调用的_InitController()函数里)
LPC1788 官方emWIM例程的移植修改大致就是上面的步骤,具体细节需要根据编译出现的细节对一些函数进行删减,编译后下载就可以看到如下画面:

如过想尝试SEGGER公司的例程,则需要在项目中移除已存在的上面所示的演示例程,添加SEGGER官方例程,在…\NXP_emWin522_BSP\Start\Application\SEGGERDEMO文件目录下:

然后添加相应的头文件目录,在主程序中添加头文件GUIDEMO.h,重新编译即可。演示程序的开关在GUIDEMO.h中,可以选择演示哪个例程。



但是编译下载后,发现LCD显示的动画会出现错位闪屏的现象,在MDK上设置use MicroLIB后情况得到较大幅度好转,但是
问依然存在,不知如何解决。
以后,将会继续添加对触摸程序的移植。


Technorati 标签:
LPC1788,
emWIN移植
一念花开
生活琐事
昨天上午完考科目四,下午就领取了驾驶证。去年11月初报考,到现在5月下旬,历时半年多,终于拿到了驾驶证。真是不容易啊!
本来昨天上午考完科目四,然后就可以领驾驶证了,但是当考试进行到半途,突然断网了,导致我们等了一个多小时,才继续考试,领证也只能推迟到了下午。
看着这小小的长方形黑色外皮,里面夹了两张卡片:一张驾驶证副证,一张驾驶证。这小小的本子花费了我太多的时间乃至金钱(算下来四千四百块多),无论怎样总算是拿到了,心里总算是松了一口气。

一念花开
所思所感
早茶, 紫荆花, 螺蛳山
由于参加了全国研究生电子大赛,这一段时间异常忙碌,没有时间去打理博客。刚好现在闲下来了,记录一下前一段时间的事情。
3月的最后一天,把驾照的科目二给考过了,终于没有辜负一个月来的付出。接下来科目三和科目四就好考了,不用去分散太多精力。
考完科目二,清明节就要到了,接着就要放假。这次广西壮族三月三加上清明节一共放了6天。以前还不知道壮族还有三月三这个节日,不过这次也是对三月三的首次放假。
每次放假,都会乘着假期到学校外边溜达一圈,出去感受感受外边的灵气。在学校,一个月也难得出去一次,对于外边四节的悄然变化,后知后觉。
由于一位师姐要离开学校,导师请我们到他家吃早茶。因为我们以前大都不是生活在南方,所以没有吃早茶的概念,还以为吃早茶就是去老师家喝喝油茶(以前给老师帮忙的时候,师母曾经煮给我们喝过油茶)。所以一早起来就去吃了包子,等到了导师家一看,桌子上放着满满的糕点、熏肉、鸡腿等等,才明白了导师请我们喝油茶原来是就是请我们吃早饭,这下简直亏大了。
桌子上大多是甜食,对于不喜欢吃甜食的我倒是有点不习惯,不过油茶倒是很好喝的。油茶喝第一次是苦的,然后是甜的,师母说,象征着有苦才有甜。“苦尽甘来”这个词来形容油茶正好合适。油茶是师母自己做的,做起来工艺很是复杂,对于材料,制作方法都很有讲究,也许正是由于这么精致的做法,才能做出这么好喝的油茶。
大多数人都喜欢喝甜的油茶,但是我还是比较喜欢喝带有苦味的油茶,或许是不喜欢吃但是又吃了许多甜食的缘故。我感觉油茶带着些许苦味,才更有味道。
吃完早茶,然后我们和导师、师母到学校外边拍照。又一起等了学校里面的螺蛳山。这样是我第二次登螺丝山了,我们一些人中也有是第一次登螺蛳山的。螺蛳山算不是奇,算不上险,虽然平平淡淡,但是作为学校里面唯一的山,学校的标志之一,登一登这螺蛳山也有些留念的价值。
剩下的几天一直呆在实验室,本来打算在实验室带个一两天后,到学校外边转转,看看这姹紫嫣红的春季,可是突然下起的大雨打乱了我的安排,导致放假的几天一直呆在实验室里。
柳州在这个季节,应该是到处开满着紫荆花的。学校北区的食堂前,螺蛳山下,学校东门前的道路边也有紫荆花树,淡淡的紫色小花开满了一树,时不时风飘下来一两朵,看着地上凌乱的一片紫色,倒是有落英缤纷的感觉。
越来越忙了,明年的这个时候就差不多要毕业了,越来越没有时间,没有心情来欣赏这春季里多彩的风景,只是每次在匆匆的路上,瞥一眼这美丽的风景,感叹这大自然的神奇。