26.1 實(shí)驗(yàn)內(nèi)容
通過(guò)本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容:
? LCD顯示原理
? EXMC NOR/SRAM模式時(shí)序和8080并口時(shí)序
? LCD顯示控制
26.2 實(shí)驗(yàn)原理
使用MCU的EXMC外設(shè)實(shí)現(xiàn)8080并口時(shí)序,和TFT-LCD控制器進(jìn)行通信,控制LCD顯示圖片、字符、色塊等。
26.2.1 TFT-LCD介紹
薄膜晶體管液晶顯示器(英語(yǔ):Thin film transistor liquid crystal display,常簡(jiǎn)稱(chēng)為TFT-LCD)是多數(shù)液晶顯示器的一種,它使用薄膜晶體管技術(shù)改善影象品質(zhì)。雖然TFT-LCD被統(tǒng)稱(chēng)為LCD,不過(guò)它是種主動(dòng)式矩陣LCD,被應(yīng)用在電視、平面顯示器及投影機(jī)上。
簡(jiǎn)單說(shuō),TFT-LCD面板可視為兩片玻璃基板中間夾著一層液晶,上層的玻璃基板是彩色濾光片、而下層的玻璃則有晶體管鑲嵌于上。當(dāng)電流通過(guò)晶體管產(chǎn)生電場(chǎng)變化,造成液晶分子偏轉(zhuǎn),藉以改變光線(xiàn)的偏極性,再利用偏光片決定像素的明暗狀態(tài)。此外,上層玻璃因與彩色濾光片貼合,形成每個(gè)像素各包含紅藍(lán)綠三顏色,這些發(fā)出紅藍(lán)綠色彩的像素便構(gòu)成了面板上的視頻畫(huà)面。
為了對(duì)TFT-LCD的顯示進(jìn)行控制,需要通過(guò)接口和液晶屏通信,但所謂與液晶屏通信,實(shí)際上還是與液晶屏驅(qū)動(dòng)控制芯片在通信,而主控制器需要按控制芯片支持的通信進(jìn)行交互,通常有UART、IIC、SPI、8080、MIPI等各類(lèi)接口。另外需要注意的一點(diǎn)是:一般支持普通MCU接口的LCD驅(qū)動(dòng)芯片,都需要內(nèi)置GRAM(Graphics RAM), 至少能存儲(chǔ)一個(gè)屏幕的數(shù)據(jù)。
這這里,我們使用了8080接口通過(guò)并行總線(xiàn)傳輸控制命令和數(shù)據(jù),并通過(guò)往LCD液晶模組自帶的GRAM更新數(shù)據(jù)實(shí)現(xiàn)屏幕的刷新。
GD32F3紅楓派開(kāi)發(fā)板TFT-LCD如下圖所示,采用了ILI9488 LCD驅(qū)動(dòng)器,分辨率320*480,支持多種通信接口,在GD32F303xx上,適合使用16-bit Parallel MCU Interface接口進(jìn)行通信,開(kāi)發(fā)板配套的LCD模塊也采用了該接口設(shè)計(jì)和開(kāi)發(fā)板進(jìn)行連接。
26.2.2 LCD 8080并口時(shí)序介紹(16-bit Parallel MCU Interface)
8080接口是由英特爾設(shè)計(jì),是一種并行、異步、半雙工通信協(xié)議,作用是用于外擴(kuò)RAM、ROM,后面也用于LCD接口。并行接口又分為 8位/16位/24位 三種, 顧名思義,就是數(shù)據(jù)總線(xiàn)的位寬。
? 如下圖所示是16-bit Parallel MCU Interface的接口和MCU的連接信號(hào):
? 如下圖所示是LCD驅(qū)動(dòng)器 16BIT 8080并口讀寫(xiě)時(shí)序:
? CS拉低后,并口DATA IO在WR的上升沿被采樣;
? 可以理解為16線(xiàn)的SPI,而WR是寫(xiě)“CLK”,RD是讀“CLK”;
? 但這里還多了D/C引腳用于選擇傳輸命令或數(shù)據(jù)
? 8080接口的RGB顏色數(shù)據(jù)編碼
? 像素信息用RGB三原色表示,所以向液晶屏傳輸?shù)臄?shù)據(jù)幀主要也就是傳輸?shù)腞GB顏色數(shù)據(jù)。
? 像素的顏色數(shù)據(jù)并不總是用 8R8G8B的24位真彩色 表示,共有下面幾種表示情況:
? 12-bits/pixel (R 4-bit, G 4-bit, B 4-bit), 4,096 Colors, 簡(jiǎn)稱(chēng)444;
? 16-bits/pixel (R 5-bit, G 6-bit, B 5-bit), 65,536 Colors, 簡(jiǎn)稱(chēng)565;
? 18-bits/pixel (R 6-bit, G 6-bit, B 6-bit), 262,144 Colors, 簡(jiǎn)稱(chēng)666;
? 24-bits/pixel (R 8-bit, G 8-bit, B 8-bit), 16,777,216 Colors, 簡(jiǎn)稱(chēng)888;
不同顏色表示方法和不同的總線(xiàn)位寬相組合,就會(huì)組合成多種RGB顏色數(shù)據(jù)編碼。
? 綜合顯示效果、內(nèi)存資源開(kāi)銷(xiāo)等,我們采取了RGB565像素格式,這樣16BIT 8080每次傳輸就是一個(gè)像素點(diǎn)的像素值,傳輸數(shù)據(jù)就為像素顏色值。
26.2.3 EXMC外設(shè)和EXMC NOR/SRAM模式實(shí)現(xiàn)8080時(shí)序
? 這里我們使用EXMC中時(shí)序和接口類(lèi)似的NOR/SRAM模式,來(lái)實(shí)現(xiàn)8080接口驅(qū)動(dòng)TFT-LCD顯示,EXMC外設(shè)可參考上文介紹東方紅開(kāi)發(fā)板使用手冊(cè) ,EXMC NOR/SRAM模式可參考上文介紹東方紅開(kāi)發(fā)板使用手冊(cè)
? 這里我們使用SRAM模式異步模式A(擴(kuò)展模式),時(shí)序如下圖:
我們對(duì)比上面的時(shí)序和16-bit Data Bus 8080 LCD時(shí)序,發(fā)現(xiàn)一些信號(hào)的時(shí)序是類(lèi)似的,我們可以將這些信號(hào)進(jìn)行對(duì)應(yīng):
EXMC_NEx -> CSx
EXMC_NOE->RDx
EXMC_NWE->WR
EXMC_D[15:0]->DB[15:0]
EXMC_Ax->D/C
這里巧妙的是使用EXMC_Ax引腳實(shí)現(xiàn)D/C的數(shù)據(jù)/命令切換功能,所以我們只需要選擇一個(gè)方便布線(xiàn)的EXMC_Ax引腳,然后在軟件中對(duì)該引腳對(duì)應(yīng)的EXMC邏輯地址進(jìn)行操作就可以實(shí)現(xiàn)程序讀寫(xiě)不同地址時(shí),D/C引腳的狀態(tài)切換,從而實(shí)現(xiàn)訪(fǎng)問(wèn)一個(gè)EXMC地址時(shí)是數(shù)據(jù)或命令類(lèi)似,訪(fǎng)問(wèn)該地址位反向的任意地址就是另外一個(gè)類(lèi)型。對(duì)于程序中邏輯地址的影響,除了Ax引腳的選擇外還有NEx引腳的選擇。NE[0]-NE[3]對(duì)應(yīng)如下圖的NOR/SRAM BANK下的Region0-Region3。
26.3 硬件設(shè)計(jì)
在紅楓派開(kāi)發(fā)板設(shè)計(jì)中,我們使用EXMC_NE1引腳作為CS,EXMC_A12引腳作為D/C,同時(shí)LCD觸摸接口使用SPI,LCD_BL為背光控制引腳,這里的引腳選用了帶PWM的引腳,可以實(shí)現(xiàn)LCD的背光亮度調(diào)節(jié)。
LCD在顯示過(guò)程電源電流會(huì)有變化,為了穩(wěn)定電源我們?cè)?.3V和5V接口上使用了1uf電容。
26.4 代碼解析
26.4.1 CSx、D/C、BL相關(guān)功能定義和注冊(cè);
在EXMC LCD驅(qū)動(dòng)代碼中存在和電路設(shè)計(jì)匹配的變更點(diǎn),往往讓開(kāi)發(fā)者頭大,需要詳細(xì)閱讀用戶(hù)手冊(cè)來(lái)進(jìn)行配置調(diào)整、讀寫(xiě)地址調(diào)整;而在我們的驅(qū)動(dòng)文件bsp_lcd.c中定義注冊(cè)背光引腳、Ax、NEx引腳,當(dāng)硬件設(shè)計(jì)變更時(shí)只需要在這里調(diào)整,驅(qū)動(dòng)就可以在新的硬件中正常使用。
C
//定義背光引腳的PWM通道和GPIO
TIMER_CH_DEF(LCD_BL,TIMER12,0,TIMER_CH_PWM_HIGH,F,8,AF_PP,GPIO_TIMER12_REMAP);
//定義使用的EXMC_Ax引腳
GPIO_DEF(EXMC_Ax_GPIO,G,2,AF_PP,SET,NULL);
//定義使用的EXMC_NEx引腳
GPIO_DEF(EXMC_NEx_GPIO,D,7,AF_PP,SET,NULL);
//LCD數(shù)據(jù)、命令地址轉(zhuǎn)換
26.4.2 gpio和exmc初始化:
exmc使用了擴(kuò)展模式,這樣讀和寫(xiě)的時(shí)序可以單獨(dú)配置,因?yàn)長(zhǎng)CD對(duì)讀和寫(xiě)的要求時(shí)間是不同的,讀的時(shí)候速率不能太高,如果使用一種參數(shù)類(lèi)型就會(huì)為了滿(mǎn)足讀的要求而降低寫(xiě)的速率,影響最終刷屏的性能。這里主要調(diào)整讀和寫(xiě)時(shí)的地址建立、數(shù)據(jù)建立時(shí)間,通常和硬件設(shè)計(jì)也有較大關(guān)系,這里紅楓派開(kāi)發(fā)板和配套LCD的電路可以在120M主頻下,設(shè)置讀數(shù)據(jù)建立5個(gè)clk、地址建立1個(gè)clk,寫(xiě)數(shù)據(jù)建立2個(gè)clk,地址建立1個(gè)clk。
C
/*!
* 說(shuō)明 ????emxc LCD模式通用gpio初始化
* 輸入[1] ?norsram_region: @EXMC_BANK0_NORSRAM_REGION0/EXMC_BANK0_NORSRAM_REGION1/EXMC_BANK0_NORSRAM_REGION2/EXMC_BANK0_NORSRAM_REGION3
* 返回值 ??無(wú)
*/
void driver_exmc_lcd_16bit_gpio_init(void)
{
/* EXMC clock enable */
rcu_periph_clock_enable(RCU_EXMC);
/* GPIO clock enable */
rcu_periph_clock_enable(RCU_GPIOD);
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_GPIOG);
rcu_periph_clock_enable(RCU_AF);
/* configure EXMC_D[0~15]*/
/* PD14(EXMC_D0), PD15(EXMC_D1),PD0(EXMC_D2), PD1(EXMC_D3), PD8(EXMC_D13), PD9(EXMC_D14), PD10(EXMC_D15) */
gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_0 | GPIO_PIN_1| GPIO_PIN_8 | GPIO_PIN_9 |
GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15);
/* PE7(EXMC_D4), PE8(EXMC_D5), PE9(EXMC_D6), PE10(EXMC_D7), PE11(EXMC_D8), PE12(EXMC_D9),
PE13(EXMC_D10), PE14(EXMC_D11), PE15(EXMC_D12) */
gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 |
GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |
GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
// ???/* configure PE2(EXMC_Ax) */
// ???gpio_init(GPIOE, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_2);
/* configure NOE and NWE */
gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_4 | GPIO_PIN_5);
// ???/* configure EXMC NEx */
// ???gpio_init(GPIOD, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_7);
gpio_compensation_config(GPIO_COMPENSATION_ENABLE);
while(gpio_compensation_flag_get()==RESET);
}
/*!
* 說(shuō)明 ????emxc LCD模式初始化
* 輸入[1] ?norsram_region: @EXMC_BANK0_NORSRAM_REGION0/EXMC_BANK0_NORSRAM_REGION1/EXMC_BANK0_NORSRAM_REGION2/EXMC_BANK0_NORSRAM_REGION3
* 返回值 ??無(wú)
*/
void driver_exmc_lcd_init(uint32_t norsram_region)
{
exmc_norsram_parameter_struct nor_init_struct;
exmc_norsram_timing_parameter_struct nor_timing_read_init_struct;
exmc_norsram_timing_parameter_struct nor_timing_write_init_struct;
/* EXMC clock enable */
rcu_periph_clock_enable(RCU_EXMC);
nor_init_struct.read_write_timing = &nor_timing_read_init_struct;
nor_init_struct.write_timing = &nor_timing_write_init_struct;
exmc_norsram_struct_para_init(&nor_init_struct);
/* config timing parameter */
nor_timing_read_init_struct.asyn_access_mode = EXMC_ACCESS_MODE_A;
nor_timing_read_init_struct.syn_data_latency = EXMC_DATALAT_2_CLK;
nor_timing_read_init_struct.syn_clk_division = EXMC_SYN_CLOCK_RATIO_2_CLK;
nor_timing_read_init_struct.bus_latency = 1;
nor_timing_read_init_struct.asyn_data_setuptime = 5;
nor_timing_read_init_struct.asyn_address_holdtime = 1;
nor_timing_read_init_struct.asyn_address_setuptime = 1;
/* config timing parameter */
nor_timing_write_init_struct.asyn_access_mode = EXMC_ACCESS_MODE_A;
nor_timing_write_init_struct.syn_data_latency = EXMC_DATALAT_2_CLK;
nor_timing_write_init_struct.syn_clk_division = EXMC_SYN_CLOCK_RATIO_2_CLK;
nor_timing_write_init_struct.bus_latency = 1;
nor_timing_write_init_struct.asyn_data_setuptime = 2;
nor_timing_write_init_struct.asyn_address_holdtime = 1;
nor_timing_write_init_struct.asyn_address_setuptime = 1;
/* config EXMC bus parameters */
nor_init_struct.norsram_region = norsram_region;
nor_init_struct.write_mode = EXMC_ASYN_WRITE;
nor_init_struct.extended_mode = ENABLE;
nor_init_struct.asyn_wait = DISABLE;
nor_init_struct.nwait_signal = DISABLE;
nor_init_struct.memory_write = ENABLE;
nor_init_struct.nwait_config = EXMC_NWAIT_CONFIG_BEFORE;
nor_init_struct.wrap_burst_mode = DISABLE;
nor_init_struct.nwait_polarity = EXMC_NWAIT_POLARITY_LOW;
nor_init_struct.burst_mode = DISABLE;
nor_init_struct.databus_width = EXMC_NOR_DATABUS_WIDTH_16B;
nor_init_struct.memory_type = EXMC_MEMORY_TYPE_SRAM;
nor_init_struct.address_data_mux = DISABLE;
exmc_norsram_init(&nor_init_struct);
/* enable the EXMC bank0 NORSRAM */
exmc_norsram_enable(norsram_region);
}
26.4.3 LCD數(shù)據(jù)、命令讀寫(xiě):
LCD的命令、數(shù)據(jù)的讀寫(xiě)都通過(guò)EXMC來(lái)實(shí)現(xiàn),在讀寫(xiě)EXMC的邏輯地址時(shí)對(duì)應(yīng)的波形會(huì)發(fā)送到LCD上,命令/數(shù)據(jù)目前通過(guò)地址引腳控制,所以我們需要定義兩個(gè)地址分別對(duì)應(yīng)命令、數(shù)據(jù)地址,對(duì)這兩個(gè)地址讀和寫(xiě)就可以實(shí)現(xiàn)LCD讀寫(xiě)數(shù)據(jù)、寫(xiě)命令功能。
C
/**
* 說(shuō)明 ??????LCD寫(xiě)數(shù)據(jù)
* 輸入 ??????data: 要寫(xiě)入的數(shù)據(jù)
* 返回值 ?????無(wú)
*/
void bsp_lcd_wr_data(__IO uint16_t data)
{
//delay_sysclk(1);
EXMC_LCD_D = data;
}
/**
* 說(shuō)明 ??????LCD寫(xiě)寄存器編號(hào)/地址函數(shù)
* 輸入 ??????regno: 寄存器編號(hào)/地址
* 返回值 ?????無(wú)
*/
void bsp_lcd_wr_regno(__IO uint16_t regno)
{
//delay_sysclk(1);
EXMC_LCD_C = regno; ??/* 寫(xiě)入要寫(xiě)的寄存器序號(hào) */
}
/**
* 說(shuō)明 ??????LCD寫(xiě)寄存器
* 輸入 ??????regno:寄存器編號(hào)/地址
* 輸入 ??????data:要寫(xiě)入的數(shù)據(jù)
* 返回值 ?????無(wú)
*/
void bsp_lcd_write_reg(__IO uint16_t regno,__IO uint16_t data)
{
//delay_sysclk(1);
EXMC_LCD_C = regno; ??/* 寫(xiě)入要寫(xiě)的寄存器序號(hào) */
//delay_sysclk(1);
EXMC_LCD_D = data; ???/* 寫(xiě)入數(shù)據(jù) */
}
/**
* 說(shuō)明 ??????LCD讀數(shù)據(jù)
* 輸入 ??????無(wú)
* 返回值 ?????讀取到的數(shù)據(jù)
*/
static uint16_t bsp_lcd_read_data(void)
{
//delay_sysclk(1);
return EXMC_LCD_D;
}
26.4.4 LCD初始化
LCD初始化序列通常LCD驅(qū)動(dòng)器廠(chǎng)家會(huì)提供相關(guān)寄存器配置,為了兼容不同的LCD,可以讀取LCD ID后執(zhí)行不同的驅(qū)動(dòng)芯片初始化,初始化過(guò)程的寄存器配置就通過(guò)25.4.3章節(jié)實(shí)現(xiàn)的命令、數(shù)據(jù)讀寫(xiě)接口實(shí)現(xiàn):
C
/**
* 說(shuō)明 ??????初始化LCD
* ??@note ?????該初始化函數(shù)可以初始化各種型號(hào)的LCD(詳見(jiàn)本.c文件最前面的描述)
*
* 輸入 ??????無(wú)
* 返回值 ?????無(wú)
*/
uint32_t bsp_lcd_init(void)
{
bsp_lcd_port_init();
bsp_lcd_backlight_duty_set(BACK_LIGHT_DUTY);
bsp_lcd_backlight_on(); ?????????/* 點(diǎn)亮背光 */
/* LCD的畫(huà)筆顏色和背景色 */
bsp_lcd_parameter.g_point_color = WHITE; ???/* 畫(huà)筆顏色 */
bsp_lcd_parameter.g_back_color ?= BLACK; ???/* 背景色 */
delay_ms(1); ????/* 初始化FSMC后,必須等待一定時(shí)間才能開(kāi)始初始化 */
/* 嘗試9341 ID的讀取 */
bsp_lcd_wr_regno(0XD3);
bsp_lcd_parameter.id = bsp_lcd_read_data(); ?/* dummy read */
bsp_lcd_parameter.id = bsp_lcd_read_data(); ?/* 讀到0X00 */
bsp_lcd_parameter.id = bsp_lcd_read_data(); ?/* 讀取0X93 */
bsp_lcd_parameter.id <<= 8;
bsp_lcd_parameter.id |= bsp_lcd_read_data(); /* 讀取0X41 */
if (bsp_lcd_parameter.id == 0X9488)
{
lcd_ex_ili9488_reginit(); ??/* 執(zhí)行ILI9388初始化 */
}
else if (bsp_lcd_parameter.id == 0X9341)
{
lcd_ex_ili9341_reginit(); ??/* 執(zhí)行ILI9341初始化 */
}else{
return DRV_ERROR;
}
bsp_lcd_display_dir(0); /* 默認(rèn)為豎屏 */
bsp_lcd_clear(WHITE);
return DRV_SUCCESS;
}
/**
* @brief ??????ILI9488寄存器初始化代碼
* @param ??????無(wú)
* @retval ?????無(wú)
*/
void lcd_ex_ili9488_reginit(void)
{
//************* Start Initial Sequence **********//
bsp_lcd_wr_regno(0XF7);
bsp_lcd_wr_data(0xA9);
bsp_lcd_wr_data(0x51);
bsp_lcd_wr_data(0x2C);
bsp_lcd_wr_data(0x82);
bsp_lcd_wr_regno(0XEC);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x02);
bsp_lcd_wr_data(0x03);
bsp_lcd_wr_data(0x7A);
bsp_lcd_wr_regno(0xC0);
bsp_lcd_wr_data(0x13);
bsp_lcd_wr_data(0x13);
bsp_lcd_wr_regno(0xC1);
bsp_lcd_wr_data(0x41);
bsp_lcd_wr_regno(0xC5);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x28);
bsp_lcd_wr_data(0x80);
bsp_lcd_wr_regno(0xB1); ??//Frame rate 70HZ
bsp_lcd_wr_data(0xB0);
bsp_lcd_wr_data(0x11);
bsp_lcd_wr_regno(0xB4);
bsp_lcd_wr_data(0x02);
bsp_lcd_wr_regno(0xB6); //RGB/MCU Interface Control
bsp_lcd_wr_data(0x02); ??//MCU
bsp_lcd_wr_data(0x22);
bsp_lcd_wr_regno(0xB7);
bsp_lcd_wr_data(0xc6);
bsp_lcd_wr_regno(0xBE);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x04);
bsp_lcd_wr_regno(0xE9);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_regno(0xF4);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x0f);
bsp_lcd_wr_regno(0xE0);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x04);
bsp_lcd_wr_data(0x0E);
bsp_lcd_wr_data(0x08);
bsp_lcd_wr_data(0x17);
bsp_lcd_wr_data(0x0A);
bsp_lcd_wr_data(0x40);
bsp_lcd_wr_data(0x79);
bsp_lcd_wr_data(0x4D);
bsp_lcd_wr_data(0x07);
bsp_lcd_wr_data(0x0E);
bsp_lcd_wr_data(0x0A);
bsp_lcd_wr_data(0x1A);
bsp_lcd_wr_data(0x1D);
bsp_lcd_wr_data(0x0F);
bsp_lcd_wr_regno(0xE1);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x1B);
bsp_lcd_wr_data(0x1F);
bsp_lcd_wr_data(0x02);
bsp_lcd_wr_data(0x10);
bsp_lcd_wr_data(0x05);
bsp_lcd_wr_data(0x32);
bsp_lcd_wr_data(0x34);
bsp_lcd_wr_data(0x43);
bsp_lcd_wr_data(0x02);
bsp_lcd_wr_data(0x0A);
bsp_lcd_wr_data(0x09);
bsp_lcd_wr_data(0x33);
bsp_lcd_wr_data(0x37);
bsp_lcd_wr_data(0x0F);
bsp_lcd_wr_regno(0xF4);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x00);
bsp_lcd_wr_data(0x0f);
bsp_lcd_wr_regno(0x36);
bsp_lcd_wr_data(0x08);
bsp_lcd_wr_regno(0x3A); ?//Interface Mode Control
bsp_lcd_wr_data(0x55); ?//0x66 18bit; 0x55 16bit
bsp_lcd_wr_regno(0x20);
bsp_lcd_wr_regno(0x11);
delay_ms(120);
bsp_lcd_wr_regno(0x29);
delay_ms(50);
}
26.4.5 LCD畫(huà)點(diǎn)函數(shù)實(shí)現(xiàn)
LCD在任意點(diǎn)顯示想要的顏色值,需要設(shè)置顯示光標(biāo)到目標(biāo)位置,然后就可以從該光標(biāo)進(jìn)行顏色數(shù)據(jù)寫(xiě)入,顏色信息將顯示到LCD的指定坐標(biāo)上。
C
/**
* 說(shuō)明 ??????畫(huà)點(diǎn)
* 輸入 ??????x,y: 坐標(biāo)
* 輸入 ??????color: 點(diǎn)的顏色(32位顏色,方便兼容LTDC)
* 返回值 ?????無(wú)
*/
void bsp_lcd_draw_point(uint16_t x, uint16_t y, uint32_t color)
{
bsp_lcd_set_cursor(x, y); ??????/* 設(shè)置光標(biāo)位置 */
EXMC_LCD_C = bsp_lcd_parameter.wramcmd; ???/* 開(kāi)始寫(xiě)入GRAM */
EXMC_LCD_D = color;
}
26.4.6 窗口設(shè)置和色塊填充
LCD可以設(shè)置需顯示的窗口,設(shè)置窗口后可以連續(xù)的寫(xiě)數(shù)據(jù),像素信息會(huì)從窗口起始坐標(biāo)開(kāi)始自動(dòng)遞增和換行顯示顏色。通過(guò)圖塊設(shè)置函數(shù)可以顯示圖片,移植到GUI等;這里我們通過(guò)DMA的MEM TO MEM模式可以降低色塊填充過(guò)程的CPU占用率,同時(shí)提升刷屏速率。
C
/**
* 說(shuō)明 ??????在指定區(qū)域內(nèi)填充指定顏色塊
* 輸入 ??????(sx,sy),(ex,ey):填充矩形對(duì)角坐標(biāo),區(qū)域大小為:(ex - sx + 1) * (ey - sy + 1)
* 輸入 ??????color: 要填充的顏色數(shù)組首地址
* 返回值 ?????無(wú)
*/
void bsp_lcd_color_fill(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t *color)
{
uint16_t height, width;
// ???uint32_t i;
width = ex - sx + 1; ???????????/* 得到填充的寬度 */
height = ey - sy + 1; ??????????/* 高度 */
bsp_lcd_set_window(sx,sy,width,height);
EXMC_LCD_C = bsp_lcd_parameter.wramcmd;
driver_dma_mem_to_exmclcd_start((void*)&EXMC_LCD_D,&color[0],DMA_Width_16BIT,height*width);
// ???for(uin32_t i = 0; i < height*width; i++)
// ???{
// ???????EXMC_LCD_D = color[i];
// ???}
}
26.4.7 字符顯示和LCD Printf
實(shí)現(xiàn)上述功能后,通過(guò)字庫(kù)信息結(jié)合打點(diǎn)函數(shù)就可以實(shí)現(xiàn)字符的顯示,我們同時(shí)實(shí)現(xiàn)了在lcd上打印信息,以printf的形式更輕易便捷的輸出信息到LCD上。
C
/**
* 說(shuō)明 ??????LCD打印
* 輸入 ??????...和printf相同用法,自動(dòng)換行
* 返回值 ?????無(wú)
*/
void bsp_lcd_printf(const char * sFormat, ...)
{
char printf_buffer[64];
char* p=printf_buffer;
uint16_t len=0,count=0;
va_list ParamList;
va_start(ParamList, sFormat);
vsprintf(printf_buffer,sFormat, ParamList);
va_end(ParamList);
len=strlen(printf_buffer);
while( ( ((*p <= '~') && (*p >= ' ')) || (*p =='\r') || (*p =='\n') ) && (count<len) ) ??/* 判斷是不是非法字符! */
{
if((*p =='\r'))
{
bsp_lcd_pritnf_parameter.x_now = bsp_lcd_pritnf_parameter.x_start;
}
else if((*p =='\n'))
{
bsp_lcd_pritnf_parameter.y_now += bsp_lcd_pritnf_parameter.size;
bsp_lcd_fill(bsp_lcd_pritnf_parameter.x_now,bsp_lcd_pritnf_parameter.y_now,bsp_lcd_pritnf_parameter.x_end,bsp_lcd_pritnf_parameter.y_now+bsp_lcd_pritnf_parameter.size,bsp_lcd_pritnf_parameter.back_color);
}
else if( (bsp_lcd_pritnf_parameter.x_now + bsp_lcd_pritnf_parameter.size/2) > bsp_lcd_pritnf_parameter.x_end)
{
bsp_lcd_pritnf_parameter.x_now = bsp_lcd_pritnf_parameter.x_start;
bsp_lcd_pritnf_parameter.y_now += bsp_lcd_pritnf_parameter.size;
bsp_lcd_fill(bsp_lcd_pritnf_parameter.x_now,bsp_lcd_pritnf_parameter.y_now,bsp_lcd_pritnf_parameter.x_end,bsp_lcd_pritnf_parameter.y_now+bsp_lcd_pritnf_parameter.size,bsp_lcd_pritnf_parameter.back_color);
}
else if ( (bsp_lcd_pritnf_parameter.y_now+bsp_lcd_pritnf_parameter.size) > bsp_lcd_pritnf_parameter.y_end)
{
bsp_lcd_pritnf_parameter.x_now = bsp_lcd_pritnf_parameter.x_start;
bsp_lcd_pritnf_parameter.y_now = bsp_lcd_pritnf_parameter.y_start;
bsp_lcd_fill(bsp_lcd_pritnf_parameter.x_start,bsp_lcd_pritnf_parameter.y_start,bsp_lcd_pritnf_parameter.x_end,bsp_lcd_pritnf_parameter.y_end,bsp_lcd_pritnf_parameter.back_color);
}
if((*p !='\r')&&(*p !='\n'))
{
bsp_lcd_show_char(bsp_lcd_pritnf_parameter.x_now, bsp_lcd_pritnf_parameter.y_now, *p, bsp_lcd_pritnf_parameter.size, 0, bsp_lcd_pritnf_parameter.point_color,bsp_lcd_pritnf_parameter.back_color);
bsp_lcd_pritnf_parameter.x_now += bsp_lcd_pritnf_parameter.size / 2;
}
p++;
count++;
}
}
26.5 實(shí)驗(yàn)結(jié)果
復(fù)位后顯示聚沃和GD LOG圖片,大字顯示LCD ID,刷屏?xí)r間、聚沃相關(guān)鏈接地址等。在下方設(shè)置了一個(gè)printf區(qū)窗口,循環(huán)打印亮度信息和系統(tǒng)tic信息。左右波動(dòng)搖桿可以調(diào)節(jié)LCD亮度。
實(shí)驗(yàn)結(jié)果視頻詳見(jiàn)飛書(shū)文檔
紅楓派開(kāi)發(fā)板使用手冊(cè):??????????????????????????????????????????????????GD32F303紅楓派使用手冊(cè) - 飛書(shū)云文檔 (feishu.cn)