|
本帖最后由 zysxdg 于 2021-9-7 11:50 编辑
实现分段绘制的基本思想(重点优化 _DrawBitmap() 函数):
示意图
对于SPI/I2C接口的TFT,传输数据需要的时间一般大于UI渲染的时间。使用DMA方式发送数据,并且立即开始渲染下一段UI数据,等前一段数据发送完成时,当前段已绘制完成,又可以立即发送,如此循环,相当于渲染和发送同时进行。这种情况下显示帧率基本上能接近数据发送帧率。
实现步骤(重要代码标记蓝色):
先把GUIConfig.h宏定义打开
#define GUI_WINSUPPORT (1) // Use Window Manager
#define GUI_SUPPORT_MEMDEV (1) // Use Memory Devices
GUIConfig.c文件中根据单片机内存大小设置合适的GUI动态内存
1.实现通过WM自动管理缓存大小。
WM_SetCreateFlags(WM_CF_SHOW | WM_CF_MEMDEV );
GUI_Init();
//创建窗口
...
//初始化缓存并设置缓存大小为GUI剩余缓存的一半,从而保证WM分段数据<缓存大小
hMemBuf = GUI_MEMDEV_CreateEx(0, 0, XSIZE_PHYS, GUI_ALLOC_GetNumFreeBytes()/2/2/XSIZE_PHYS+1, GUI_MEMDEV_HASTRANS);
//进入GUI事件循环
while(1)
{
GUI_Delay(10);
}
2.用DMA发送方式实现渲染和发送同时进行(GUIDRV_Template.c文件/DMA中断文件)
//刷屏状态全局变量
volatile static int sign = 0;
//设置刷屏状态
void set_flushSign(int val)
{
if(val == 0)
sign = 0;
else
sign = 1;
}
//获取刷屏状态
int get_flushSign(void)
{
if(sign == 0)
return 0;
else
return 1;
}
//分段缓存
GUI_MEMDEV_Handle hMemBuf;
static void _DrawBitmap(GUI_DEVICE * pDevice, int x0, int y0,
int xSize, int ySize,
int BitsPerPixel,
int BytesPerLine,
const U8 * pData, int Diff,
const LCD_PIXELINDEX * pTrans)
{
int i;
u16 *pBuf;
u16 *pTemp;
switch (BitsPerPixel)
{
case 1:
for (i = 0; i < ySize; i++)
{
_DrawBitLine1BPP(pDevice, x0, i + y0, pData, Diff, xSize, pTrans);
pData += BytesPerLine;
}
break;
case 2:
for (i = 0; i < ySize; i++)
{
_DrawBitLine2BPP(pDevice, x0, i + y0, pData, Diff, xSize, pTrans);
pData += BytesPerLine;
}
break;
case 4:
for (i = 0; i < ySize; i++)
{
_DrawBitLine4BPP(pDevice, x0, i + y0, pData, Diff, xSize, pTrans);
pData += BytesPerLine;
}
break;
case 8:
for (i = 0; i < ySize; i++)
{
_DrawBitLine8BPP(pDevice, x0, i + y0, pData, xSize, pTrans);
pData += BytesPerLine;
}
break;
//
// Only required for 16bpp color depth of target. Should be removed otherwise.
//
case 16:
if(NULL == hMemBuf)
{
//缓存未初始化时使用默认方式
for (i = 0; i < ySize; i++)
{
_DrawBitLine16BPP(pDevice, x0, i + y0, (const U16 *)pData, xSize);
pData += BytesPerLine;
}
}
else
{
//等待上一段数据发送完成
while(get_flushSign() != 0);
set_flushSign(1);
//获取缓存地址
pBuf = GUI_MEMDEV_GetDataPtr(hMemBuf);
pTemp = pBuf;
//将分段绘制完成的数据复制到缓存便于用DMA方式发送
for (i = 0; i < ySize; i++)
{
memcpy(pTemp, (const U16 *)pData, xSize*2);
pTemp += xSize;
pData += BytesPerLine;
}
//将缓存数据用DMA发送到LCD
LCD_PartialFlush(x0, y0, xSize, ySize, (uint32_t)pBuf, xSize*2*ySize);
//立即返回开始渲染下段数据
}
break;
//
// Only required for 32bpp color depth of target. Should be removed otherwise.
//
case 32:
for (i = 0; i < ySize; i++)
{
_DrawBitLine32BPP(pDevice, x0, i + y0, (const U32 *)pData, xSize);
pData += BytesPerLine;
}
break;
}
}
DMA中断文件:
DMA完成中断
{
//清除刷屏状态
set_flushSign(0);
//其他信号处理
LCD_CS = 1;
}
3.该方式使用的限制
因为WM才能自动使用分段,所以在窗口WM_PAINT事件之外的地方使用2D绘图函数将无法自动分段绘制,请将所有绘图操作全部放在窗口中进行就可以了。
以上,欢迎讨论。
|
|