1、前言
之前曾经介绍过在TFTLCD显示屏中使用DMA传输可以大幅度的提升传输效率。
但是当时只修改了原先全屏刷新的算法以及图片刷新的LCD算法。
今天测试在显示字符的时候,依旧效率低下。
于是自己查看了一下字符显示的算法,尝试能不能提高一下效率。
2、字符显示
void ST7789_WriteChar(uint16_t x, uint16_t y, char ch, FontDef font, uint16_t color, uint16_t bgcolor)
{
uint32_t i, b, j;
ST7789_Select();
ST7789_SetAddressWindow(x, y, x + font.width - 1, y + font.height - 1);
for (i = 0; i < font.height; i++) {
b = font.data[(ch - 32) * font.height + i];
for (j = 0; j < font.width; j++) {
if ((b << j) & 0x8000) {
uint8_t data[] = {color >> 8, color & 0xFF};
ST7789_WriteData(data, sizeof(data));
}
else {
uint8_t data[] = {bgcolor >> 8, bgcolor & 0xFF};
ST7789_WriteData(data, sizeof(data));
}
}
}
ST7789_UnSelect();
}
ST7789_WriteData这条命令是利用DMA传输的,因此影响效率的主要原因是显示字符算法的效率。
函数参数传递进来的是一个字符、坐标、字体定义、前景色和背景色,我们逐行来分析这个函数。
ST7789_Select();
ST7789_SetAddressWindow(x, y, x + font.width - 1, y + font.height - 1);
该部分用于SPI通讯选中,并且设置显示窗口的地址。
for (i = 0; i < font.height; i++) {
for (j = 0; j < font.width; j++) {
}
}
}
两个for循环代表着这个函数采用的逐行逐列刷新像素的方式将字符描出来。
if ((b << j) & 0x8000) {
uint8_t data[] = {color >> 8, color & 0xFF};
ST7789_WriteData(data, sizeof(data));
}
else {
uint8_t data[] = {bgcolor >> 8, bgcolor & 0xFF};
ST7789_WriteData(data, sizeof(data));
}
这段在显示每个像素点数据的时候,利用将字模数据的每一行(存放在变量b)判断每个像素点的掩膜值来确定这个像素是显示前景色还是背景色。
当然这里最大的一个问题还是,该方法是每个像素逐点刷新的,会频繁的调用ST7789_WriteData这个命令。
3、优化方式
我们注意到,SPI的传输是可以多个数据包一起发送的,因此我们尝试修改一下刷新方式,可以创建一个缓存区存放一个字符区域的整体内容(前景色背景色处理完之后的数据),之后利用硬件SPI统一发送,而不是像原先那样子对每个字符。
void ST7789_WriteChar(uint16_t x, uint16_t y, char ch, FontDef font, uint16_t color, uint16_t bgcolor)
{
uint32_t i, j;
uint16_t *pixel_buffer; // 缓冲区,用于存储像素数据
uint16_t width = font.width;
uint16_t height = font.height;
// 计算像素数据缓冲区的大小:每像素 2 字节(16 位颜色),宽 × 高
uint16_t buffer_size = width * height;
uint8_t buffer[2 * buffer_size]; // 2 × 16-bit = 32-bit per pixel
// 填充缓冲区
for (i = 0; i < height; i++)
{
uint16_t row_data = font.data[(ch - 32) * height + i];
for (j = 0; j < width; j++)
{
uint32_t index = (i * width + j) * 2;
if ((row_data << j) & 0x8000)
{
buffer[index] = color >> 8;
buffer[index + 1] = color & 0xFF;
}
else
{
buffer[index] = bgcolor >> 8;
buffer[index + 1] = bgcolor & 0xFF;
}
}
}
// 写入数据
ST7789_Select();
ST7789_SetAddressWindow(x, y, x + width - 1, y + height - 1);
ST7789_WriteData(buffer, sizeof(buffer));
ST7789_UnSelect();
}
这种办法虽然会牺牲临时变量,需要更多的空间,但是实际上使用中极大的提升了刷新速度。
阅读全文