stm32提高LCD显式字符的速度,从打点显式到DMA填充

背景:

最近在使用裸机的方式绘制LCD显式页面,主要参考中景园LCD的历程,在显式驱动移植成果后,设计了两个页面,页面切换中有肉眼可见的延迟,因此想着能不能提高字符显式的频率。

中景园代码分析:

这里使用的代码是基于中景园LCD修改的,逻辑大体一直,可能部分会有不同,此处重在分析代码的逻辑。

中景园历程中代码中显式字符方式使用依次打点的方式显式的,具体过程如下;

1、查找字符font,

2、设置lcd填充区域为font字体大小,如16字体的char实际填充为宽8高16

2、在对应的font字体中逐bit查找,

3、bit如果是1则写入颜色为字体色,如果bit为0,则写入颜色为背景色

4、直到一个char的font查找完成

代码分析

/*
 * function:drawChar
 * parameter: x:x 轴显式坐标,
 *            y:y 轴显式坐标
 *			  ch:显式的字符
 *            charColor: 字符的颜色
 * 			  backgroundColor:背景的颜色
 *            size:字号:12,16,24,32
 * return:void
 */
void TFT_ST7789::drawChar(uint16_t x, uint16_t y, const char ch,
						  uint16_t color, uint16_t bgColor, uint8_t size)
{
	uint8_t temp, sizex, t, m = 0;// m用于标记一行中的颜色bit数
	uint16_t i, TypefaceNum; //一个字符所占字节大小
	uint16_t x0 = x;
	sizex = size / 2;// sizex用于记录字符显式的宽度的bit数
	TypefaceNum = (sizex / 8 + ((sizex % 8) ? 1 : 0)) * size;// 计算font中byte的格式
	char chTemp = ch - ' '; //得到偏移后的值

	startWrite();						// 使能lcd写功能
	setAddrWindow(x, y, sizex, size); //设置光标位置,以及填充区域
	for (i = 0; i < TypefaceNum; i++)
	{
		if (size == 12)
			temp = ascii_1206[chTemp][i]; //调用6x12字体
		else if (size == 16)
			temp = ascii_1608[chTemp][i]; //调用8x16字体
		else if (size == 24)
			temp = ascii_2412[chTemp][i]; //调用12x24字体
		else if (size == 32)
			temp = ascii_wenquan_3216[chTemp][i]; //调用16x32字体
		else
			return;
		for (t = 0; t < 8; t++) // 在font中的每个byte的每个bit依次判断,
								// 如果bit为1,则写字体color,如果bit为0,ze 写入背景色gbColor
		{
			//非叠加模式
			if (temp & (0x01 << t))
				writeWord(color);
			else
				writeWord(bgColor);
			m++;                // 记录字体宽度,
			if (m % sizex == 0) // 一行的宽度达到后,切换下一行
			{
				m = 0;
				break;
			}
		}
	}
	endWrite();                 // 失能写功能
}

优化后的代码分析

为了提高刷屏效率,改为先写内存,后使用dma刷新屏幕的方式

1、需要在写char时先在内存中声明一块内存,为了方便,声明为二维数组

2、根据字体大小,在二维数组中填充背景色

3、查找char的font,

4、如果font中bit为1,则在对应二维数组的位置写入字体色

5、直达遍历完char的font数组

6、将二维数组使用dma逐行写入lcd

void TFT_ST7789::drawChar(uint16_t x, uint16_t y, const char ch,
						  uint16_t color, uint16_t bgColor, uint8_t size)
{
	uint16_t temp, sizex, t, m = 0, n = 0; // sizex为字符宽度,m记录行,n记录列
	uint16_t i, TypefaceNum;			   //一个字符所占字节大小
	uint16_t x0 = x;
	sizex = size / 2;
	TypefaceNum = (sizex / 8 + ((sizex % 8) ? 1 : 0)) * size;
	char chTemp = ch - ' '; //得到偏移后的值

	uint16_t localDisplayBuff[32][16] = {0}; // 先将底色绘制到内存中,最大字体为32*16
	for (int i = 0; i < size; i++)
	{
		for (int j = 0; j < sizex; j++)
		{
			localDisplayBuff[i][j] = bgColor;
		}
	}

	for (i = 0; i < TypefaceNum; i++)
	{
		if (size == 12)
		{
			temp = ascii_1206[chTemp][i]; //调用6x12字体
		}
		else if (size == 16)
		{
			temp = ascii_1608[chTemp][i]; //调用8x16字体
		}
		else if (size == 24)
		{
			temp = ascii_2412[chTemp][i]; //调用12x24字体
		}
		else if (size == 32)
		{
			temp = ascii_wenquan_3216[chTemp][i]; //调用16x32字体
		}
		else
		{
			return;
		}
		for (t = 0; t < 8; t++)
		{
			if (temp & (0x01 << t))
			{
				localDisplayBuff[n][m] = color;
			}
			m++; // 记录一行中的像素点位置
			if (m % sizex == 0)
			{
				n++;   // 一行记录完成,行号加一
				m = 0; // 列号清零
				break;
			}
		}
	}
	startWrite();
	setAddrWindow(x, y, sizex, size); // 设置光标位置与填充区域
	for (int i = 0; i < size; i++)	  // 逐行绘制到LCD
	{
		writePixels(&localDisplayBuff[i][0], sizex);
	}
	endWrite();
}

进一步优化

将二维数组修改为一位数组,使用DAM一次写入。


/*
 * function:drawChar
 * parameter: x:x 轴显式坐标,
 *            y:y 轴显式坐标
 *			  ch:显式的字符
 *            charColor: 字符的颜色
 * 			  backgroundColor:背景的颜色
 *            size:字号:12,16,24,32
 * return:void
 */

void TFT_ST7789::drawChar(uint16_t x, uint16_t y, const char ch,
						  uint16_t color, uint16_t bgColor, uint8_t size)
{
	uint16_t temp, sizex, t, m = 0, n = 0; // sizex为字符宽度,m记录行,n记录列
	uint16_t i, TypefaceNum;			   //一个字符所占字节大小
	uint16_t x0 = x;
	sizex = size / 2;
	TypefaceNum = (sizex / 8 + ((sizex % 8) ? 1 : 0)) * size;
	char chTemp = ch - ' '; //得到偏移后的值

	uint16_t localDisplayBuff[32 * 16] = {0}; // 先将底色绘制到内存中,最大字体为32*16
	for (int i = 0; i < size * sizex; i++)
	{
		localDisplayBuff[i] = bgColor;
	}

	for (i = 0; i < TypefaceNum; i++)
	{
		if (size == 12)
		{
			temp = ascii_1206[chTemp][i]; //调用6x12字体
		}
		else if (size == 16)
		{
			temp = ascii_1608[chTemp][i]; //调用8x16字体
		}
		else if (size == 24)
		{
			temp = ascii_2412[chTemp][i]; //调用12x24字体
		}
		else if (size == 32)
		{
			temp = ascii_wenquan_3216[chTemp][i]; //调用16x32字体
		}
		else
		{
			return;
		}
		for (t = 0; t < 8; t++)
		{
			if (temp & (0x01 << t))
			{
				localDisplayBuff[n * sizex + m] = color;
			}
			m++; // 记录一行中的像素点位置
			if (m % sizex == 0)
			{
				n++;   // 一行记录完成,行号加一
				m = 0; // 列号清零
				break;
			}
		}
	}
	startWrite();
	setAddrWindow(x, y, sizex, size); // 设置光标位置与填充区域
	writePixels(localDisplayBuff, size * sizex);
	endWrite();
}

总结

使用先在内存中绘制,然后再使用DMA写入LCD的方式极大的提高的LCD显式字符的效率,缺点是会增加代码中stack的使用量,综合起来,使用stack换时间的代价是值得的。

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值