1、前言
之前曾經(jīng)介紹過(guò)在TFTLCD顯示屏中使用DMA傳輸可以大幅度的提升傳輸效率。
但是當(dāng)時(shí)只修改了原先全屏刷新的算法以及圖片刷新的LCD算法。
今天測(cè)試在顯示字符的時(shí)候,依舊效率低下。
于是自己查看了一下字符顯示的算法,嘗試能不能提高一下效率。
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傳輸?shù)模虼擞绊懶实闹饕蚴秋@示字符算法的效率。
函數(shù)參數(shù)傳遞進(jìn)來(lái)的是一個(gè)字符、坐標(biāo)、字體定義、前景色和背景色,我們逐行來(lái)分析這個(gè)函數(shù)。
ST7789_Select();
ST7789_SetAddressWindow(x, y, x +?font.width?-?1, y +?font.height?-?1);
該部分用于SPI通訊選中,并且設(shè)置顯示窗口的地址。
? for (i = 0; i < font.height; i++) {
? ? for (j = 0; j < font.width; j++) {
? ? ? }
? ? }
? }
兩個(gè)for循環(huán)代表著這個(gè)函數(shù)采用的逐行逐列刷新像素的方式將字符描出來(lái)。
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));
}
這段在顯示每個(gè)像素點(diǎn)數(shù)據(jù)的時(shí)候,利用將字模數(shù)據(jù)的每一行(存放在變量b)判斷每個(gè)像素點(diǎn)的掩膜值來(lái)確定這個(gè)像素是顯示前景色還是背景色。
當(dāng)然這里最大的一個(gè)問(wèn)題還是,該方法是每個(gè)像素逐點(diǎn)刷新的,會(huì)頻繁的調(diào)用ST7789_WriteData這個(gè)命令。
3、優(yōu)化方式
我們注意到,SPI的傳輸是可以多個(gè)數(shù)據(jù)包一起發(fā)送的,因此我們嘗試修改一下刷新方式,可以創(chuàng)建一個(gè)緩存區(qū)存放一個(gè)字符區(qū)域的整體內(nèi)容(前景色背景色處理完之后的數(shù)據(jù)),之后利用硬件SPI統(tǒng)一發(fā)送,而不是像原先那樣子對(duì)每個(gè)字符。
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; ?// 緩沖區(qū),用于存儲(chǔ)像素?cái)?shù)據(jù)
? ??uint16_t?width?=?font.width;
? ??uint16_t?height?=?font.height;
? ??// 計(jì)算像素?cái)?shù)據(jù)緩沖區(qū)的大?。好肯袼?2 字節(jié)(16 位顏色),寬 × 高
? ??uint16_t?buffer_size?=?width * height;
? ? uint8_t buffer[2?* buffer_size]; ?// 2 × 16-bit = 32-bit per pixel
? ??// 填充緩沖區(qū)
? ??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;
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ??// 寫(xiě)入數(shù)據(jù)
? ? ST7789_Select();
? ? ST7789_SetAddressWindow(x, y, x + width -?1, y + height -?1);
? ? ST7789_WriteData(buffer, sizeof(buffer));
? ? ST7789_UnSelect();
}
這種辦法雖然會(huì)犧牲臨時(shí)變量,需要更多的空間,但是實(shí)際上使用中極大的提升了刷新速度。