uCGUI 驱动LCD提速 STM32F主芯
在这里首先感谢wzt的文章《ucgui液晶显示深度优化篇》写的很详细,运行很高效。
http://www.docin.com/p-453546222.html
在这里我提出另一种方法,在完全不破坏原有的uCGUI接口功能上进行强力提速。当然速度方面要弱于wzt的速度,当然优点就在于不破坏所有接口功能,保留下了uCGUI的所有功能。例如两个图片交叉异或显示。
好了,下面开始改进。
这里先提一下我用的LCD是3.2寸SSD1289屏,神舟三号开发板。 这里不管用什么屏,只要屏写像素点后如图所示移动就可以了。 从这里大家应该也看出来了, 我主要用到的方法就是在写连续像素时省去每次设置坐标点的问题。这就是我下面文章思想的基础了。
我用的是LCDTemplate.c接口文件。直接在其上进行改进。
在文件最上方添加以下几个基本函数:
1 typedef struct 2 { 3 vu16 LCD_REG; 4 vu16 LCD_RAM; 5 } LCD_TypeDef; 6 7 #define LCD_BASE ((u32)(0x60000000 | 0x0C000000)) 8 static volatile LCD_TypeDef *LCD = ((volatile LCD_TypeDef *) LCD_BASE); 9 10 /********************************************************************* 11 * 12 * 设定坐标 13 */ 14 15 __forceinline void LCD_SetCursor(U16 x, U16 y) 16 { 17 int xPhys; 18 int yPhys; 19 /* Convert logical into physical coordinates (Dep. on LCDConf.h) */ 20 #if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y 21 xPhys = LOG2PHYS_X(x, y); 22 yPhys = LOG2PHYS_Y(x, y); 23 #else 24 xPhys = x; 25 yPhys = y; 26 #endif 27 28 LCD->LCD_REG = 0x004F; 29 LCD->LCD_RAM = 319 - xPhys; 30 LCD->LCD_REG = 0x004E; 31 LCD->LCD_RAM = yPhys; 32 } 33 34 /********************************************************************* 35 * 36 * 当前坐标读一个像素 37 */ 38 __forceinline U16 LCD_GetPoint() 39 { 40 LCD->LCD_REG = 0x22; 41 LCD->LCD_RAM > 0; //等待数据稳定 42 return LCD->LCD_RAM; 43 } 44 45 /********************************************************************* 46 * 47 * 当前坐标写一个像素 48 */ 49 50 __forceinline void LCD_SetPoint(U16 point) 51 { 52 LCD->LCD_REG = 0x22; 53 LCD->LCD_RAM = point; 54 } 55 56 /********************************************************************* 57 * 58 * 当前坐标开始画一条水平线 59 * xEnd:结束坐标 60 */ 61 __forceinline void LCD_DrawHLineExt(int x, int xEnd, U16 point) 62 { 63 LCD->LCD_REG = 0x22; 64 while (x++ <= xEnd) 65 LCD->LCD_RAM = point; 66 }
这些基本函数 要根据各自的lcd屏驱动所定的。
在原先的移植上 做如下修改:
1 原函数 2 void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex) { 3 int xPhys = 0; 4 int yPhys = 0; 5 GUI_USE_PARA(x); 6 GUI_USE_PARA(y); 7 GUI_USE_PARA(PixelIndex); 8 /* Convert logical into physical coordinates (Dep. on LCDConf.h) */ 9 #if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y 10 xPhys = LOG2PHYS_X(x, y); 11 yPhys = LOG2PHYS_Y(x, y); 12 #else 13 xPhys = x; 14 yPhys = y; 15 #endif 16 /* Write into hardware ... Adapt to your system */ 17 { 18 ili9320_SetPoint(xPhys, yPhys, PixelIndex);/* ... */ 19 } 20 } 21 unsigned int LCD_L0_GetPixelIndex(int x, int y) { 22 int xPhys = 0; 23 int yPhys = 0; 24 LCD_PIXELINDEX PixelIndex; 25 26 GUI_USE_PARA(x); 27 GUI_USE_PARA(y); 28 /* Convert logical into physical coordinates (Dep. on LCDConf.h) */ 29 #if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y 30 xPhys = LOG2PHYS_X(x, y); 31 yPhys = LOG2PHYS_Y(x, y); 32 #else 33 xPhys = x; 34 yPhys = y; 35 #endif 36 /* Read from hardware ... Adapt to your system */ 37 { 38 PixelIndex = ili9320_GetPoint(xPhys, yPhys);/* ... */ 39 } 40 return PixelIndex; 41 } 42 43 44 45 修改后 46 void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex) { 47 GUI_USE_PARA(x); 48 GUI_USE_PARA(y); 49 GUI_USE_PARA(PixelIndex); 50 51 LCD_SetCursor(x, y); 52 LCD_SetPoint(PixelIndex); 53 } 54 unsigned int LCD_L0_GetPixelIndex(int x, int y) { 55 GUI_USE_PARA(x); 56 GUI_USE_PARA(y); 57 58 LCD_SetCursor(x, y); 59 return LCD_GetPoint(); 60 }
1 原文件 2 void LCD_L0_DrawHLine (int x0, int y, int x1) { 3 if (GUI_Context.DrawMode & LCD_DRAWMODE_XOR) { 4 for (; x0 <= x1; x0++) { 5 LCD_L0_XorPixel(x0, y); 6 } 7 } else { 8 for (; x0 <= x1; x0++) { 9 LCD_L0_SetPixelIndex(x0, y, LCD_COLORINDEX); 10 } 11 } 12 } 13 14 15 16 修改后 17 void LCD_L0_DrawHLine (int x0, int y, int x1) { 18 if (GUI_Context.DrawMode & LCD_DRAWMODE_XOR) { 19 while(x0++ <= x1) 20 LCD_L0_XorPixel(x0, y); 21 } else { 22 LCD_SetCursor(x0, y); 23 LCD_DrawHLineExt(x0, x1, LCD_COLORINDEX); 24 } 25 }
细节观察,这个函数只是把写坐标分离出来了。
关键的修改,大部分刷屏程序都用到LCD_L0_DrawHLine函数,所以优化他对你的程序提速起了决定性的改变。
原理很简单,只要画水平线时,每写一个像素,坐标会自动后移一位。所以没必要每次都指定坐标,把设置坐标的时间给节约出来。
最后就是画图函数了,我的LCD是16位的,所以我只修改了DrawBitLine16BPP一个函数,如果你的是低于16位的,同理进行修改。
参考如下
1 原函数 2 static void DrawBitLine16BPP(int x, int y, U16 const GUI_UNI_PTR * p, int xsize, const LCD_PIXELINDEX * pTrans) { 3 LCD_PIXELINDEX pixel; 4 if ((GUI_Context.DrawMode & LCD_DRAWMODE_TRANS) == 0) { 5 if (pTrans) { 6 for (; xsize > 0; xsize--, x++, p++) { 7 pixel = *p; 8 LCD_L0_SetPixelIndex(x, y, *(pTrans + pixel)); 9 } 10 } else { 11 for (;xsize > 0; xsize--, x++, p++) { 12 LCD_L0_SetPixelIndex(x, y, *p); 13 } 14 } 15 } else { 16 if (pTrans) { 17 for (; xsize > 0; xsize--, x++, p++) { 18 pixel = *p; 19 if (pixel) { 20 LCD_L0_SetPixelIndex(x, y, *(pTrans + pixel)); 21 } 22 } 23 } else { 24 for (; xsize > 0; xsize--, x++, p++) { 25 pixel = *p; 26 if (pixel) { 27 LCD_L0_SetPixelIndex(x, y, pixel); 28 } 29 } 30 } 31 } 32 } 33 34 35 修改后如下 36 static void DrawBitLine16BPP(int x, int y, U16 const GUI_UNI_PTR * p, int xsize, const LCD_PIXELINDEX * pTrans) { 37 LCD_PIXELINDEX pixel; 38 39 LCD_SetCursor(x, y); 40 if ((GUI_Context.DrawMode & LCD_DRAWMODE_TRANS) == 0) { 41 if (pTrans) { 42 for (; xsize > 0; xsize--, x++, p++) { 43 pixel = *p; 44 LCD_SetPoint(*(pTrans + pixel)); 45 } 46 } else { 47 for (;xsize > 0; xsize--, x++, p++) { 48 LCD_SetPoint(*p); 49 } 50 } 51 } else { 52 if (pTrans) { 53 for (; xsize > 0; xsize--, x++, p++) { 54 pixel = *p; 55 if (pixel) { 56 LCD_SetPoint(*(pTrans + pixel)); 57 } 58 } 59 } else { 60 for (; xsize > 0; xsize--, x++, p++) { 61 pixel = *p; 62 if (pixel) { 63 LCD_SetPoint(pixel); 64 } 65 } 66 } 67 } 68 }
好了,修改完了,可以进行测试了。
这里附上我的测试工程:
http://pan.baidu.com/share/link?shareid=63325&uk=118334538
视频预览。