【海東青電子原創(chuàng)文章,轉(zhuǎn)載請注明出處:http://www.itdecent.cn/p/62d1ef042d0c】
TouchGFX是一套圖形中間件代碼,屬于嵌入式軟件范疇,它不可避免的要跟STM32的硬件資源發(fā)生聯(lián)系,在使用STM32CUBEMX配置TouchGFX時(shí),要配置FMC(FSMC)、顯示接口(DSI或LTDC等)、QSPI等,就是這個(gè)原因。歸納起來,TouchGFX主要用到的MCU的資源有:
1)內(nèi)存(RAM):為了處理圖像,需要RAM來作為圖像的緩存(buffer)。這個(gè)RAM,可以是MCU片內(nèi)的,也可以是片外擴(kuò)展的。LCD的顯示像素一般都比較多,需要的RAM也比較大,所以TouchGFX應(yīng)用基本上都需要MCU擴(kuò)展RAM,而MCU與RAM最方便的連接方式就是通過FMC(或FSMC)接口。
2)顯示接口(DSI或LTDC等)。
3)代碼和靜態(tài)圖形存儲區(qū)。實(shí)際應(yīng)用中,可能要用到不止一個(gè)背景圖形,這些圖形資源被編譯到代碼中,存儲在flash里。如果MCU的片內(nèi)flash不夠用,就需要外擴(kuò)flash,常用的接口是QSPI。
了解了上述幾個(gè)接口,再使用CUBEMX配置TouchGFX時(shí),就容易的多了。我們先從配置FMC接口開始,并且從F103具有的FSMC開始,因?yàn)樗唵我恍?/p>
FSMC,F(xiàn)lexible Static Memory Controller,靈活的靜態(tài)存儲控制器,是MCU里的一個(gè)硬件結(jié)構(gòu),它的作用主要是簡化了連接外設(shè)的接口。如果使用過IIC總線,就會(huì)知道,大致有2種使用IIC的方式:一種是用2根IO口線模擬IIC的時(shí)序、用戶自己寫相關(guān)的代碼。另一種方法是,利用MCU提供的IIC總線控制器,先配置好IIC有關(guān)的一些控制寄存器(可以使用CUBEMX),然后通過HAL函數(shù)(或中斷)直接讀寫IIC數(shù)據(jù)即可。后者是“流程化”的,是IIC操作的標(biāo)準(zhǔn)流程,使用起來更方便,也更穩(wěn)定。FSMC于此類似,它包含了連接外設(shè)(靜態(tài)RAM,NOR,NAND)所必須的接口信號:
1)片選信號CS;
2)數(shù)據(jù)總線D0-D15(16bit,也支持8-bit);
3)地址總線(可以跟數(shù)據(jù)總線復(fù)用,接LCD顯示屏?xí)r,經(jīng)常用來配置LCD的指令信號,見下面例子);
4)讀信號;
5)寫信號。
本例中,我們將實(shí)現(xiàn)STM32F103通過FSMC接口對 ILI9325 (ILI9320) 顯示屏的驅(qū)動(dòng),接口示意圖如下:
對于?ILI9325 ,還需要一個(gè)reset復(fù)位信號,將MCU的一個(gè)GPIO配置成輸出模式,并與 LCD 連接即可。
先來看看STM32F103的FSMC的結(jié)構(gòu)(從103的用戶手冊中截圖):
為了簡化,我們只關(guān)心 NOR/SRAM 部分:
其中,做了標(biāo)記的信號線是實(shí)例中要用到的。下面結(jié)合一個(gè)具體的例子來說明這些信號線的用法。本例是一個(gè)STM32F103通過FSMC連接了一個(gè) ILI9325 LCD。在STM32F103板子上,MCU與LCD接口電路如圖:
MCU電路:
16根數(shù)據(jù)線D0-D15不多說了,這里重點(diǎn)說一下幾個(gè)控制信號:
上表說明了讀、寫、片選信號是如何對應(yīng)MCU的管腳編號的(是pin腳的復(fù)用功能,通過CUBEMX配置FSMC時(shí),這些pin的復(fù)用功能被自動(dòng)配置好了)。RS控制信號需要單獨(dú)解釋一下:RS用來告訴 ILI9325 控制器,當(dāng)前收到MCU送來的數(shù)據(jù)是“命令”、還是“數(shù)據(jù)”(詳見 ILI9325 數(shù)據(jù)手冊),MCU與RS信號連接有2種方式:一種是通過一個(gè)MCU的GPIO與RS相連,每次MCU向 ILI9325 發(fā)送數(shù)據(jù)之前,都根據(jù)是發(fā)送命令、還是數(shù)據(jù),對應(yīng)地設(shè)置GPIO為0或1;另一種方法是將MCU的一個(gè)地址線(本例中是A16)與RS相連,并且在代碼中使用與該地址線(A16)對應(yīng)的“地址”來訪問 ILI9325 即可(下面的代碼會(huì)詳述如何實(shí)現(xiàn))。A16對應(yīng)的pin如下:
下面開始使用CUBEMX配置STM32F103的FSMC:
使用外部晶振:
FSMC的配置:
FSMC的NOR(這里用來驅(qū)動(dòng)LCD)區(qū)塊部分,內(nèi)部又分成了4個(gè)“子區(qū)塊”:
這里要注意FSMC占用的地址,這是一個(gè)32位的地址,連接不同的外設(shè),F(xiàn)SMC對應(yīng)地使用不同的地址,比如連接NOR的話,MCU內(nèi)部地址是從0x6000 0000 開始的,如果連接的是NAND,則地址是0x7000 0000 。而NOR的內(nèi)部又分成了4個(gè)部分,起始地址由32位地址的bit[27:26]決定,用二進(jìn)制表示為:
Bank1:0110-0000 0000-0000?0000-0000?0000-0000 ,即 60 00 00 00;
Bank1:0110-0100 0000-0000?0000-0000?0000-0000 ,即 64 00 00 00;
Bank2:0110-1000 0000-0000?0000-0000?0000-0000 ,即 68 00 00 00;
Bank3:0110-1100 0000-0000?0000-0000?0000-0000 ,即 6c 00 00 00;
本例中使用的是Bank1,則地址范圍為0x6000 0000-0x63ff ffff (共64M個(gè)byte地址)。對應(yīng)的,訪問這個(gè)地址空間時(shí),F(xiàn)SMC自動(dòng)輸出NE1片選信號(即,PD7輸出0,見圖六)。
再來看一個(gè)特殊地址:0x6002 0000,二進(jìn)制為 0110-0000 0000-0010 0000-0000 0000-0000,注意,這里的bit[17]特意設(shè)置為1 。FSMC的地址,是“字節(jié)地址”,從低到高的地址依次為:
0x6000 0000,0x6000 0001,0x6000 0002,......,共有64M個(gè)地址。
但是,當(dāng)把FSMC配置為16-bit“地址模式”時(shí)(由FSMC控制寄存器 FSMC_BCR1 的 MWID 位來配置),顯然就應(yīng)該只有32M個(gè)地址了。此時(shí),F(xiàn)SMC做了一個(gè)特殊處理:“丟棄”地址的bit-0,從bit-1開始對地址計(jì)數(shù)(相當(dāng)于只計(jì)算偶數(shù)地址,總共有32M個(gè)地址),F(xiàn)SMC在實(shí)際輸出地址時(shí),將地址的值右移一位(相當(dāng)于除以2,變成了偶數(shù)地址),輸出到實(shí)際的地址線上。F103的文檔上是這么寫的:
以地址:0x6002 0000為例,F(xiàn)SMC為16-bit模式時(shí),地址bit[17]的1右移一位后輸出到地址線,即A16對應(yīng)的pin(PD11,見圖七)將輸出1,也就是RS信號線將為1 。羅嗦了這么多,實(shí)際上就是想說明一件事:對 ILI9325 寫數(shù)據(jù)時(shí),使用地址 0x6002 0000 來訪問;對 ILI9325 寫命令時(shí),使用地址?0x6000 0000 來訪問!
最后配置LCD的復(fù)位管腳:
在CUBEMX中生成KEIL的代碼,在main.c中添加針對 ILI9325 讀寫的函數(shù):
main.c
#define LCD_Data_Addr ((uint32_t)0x60020000)? ? ?//寫數(shù)據(jù)地址
#define LCD_Reg_Addr? ? ((uint32_t)0x60000000)? //寫命令地址
//寫索引(命令)寄存器
void LCD_WriteIndex(unsigned int index)
{
? ? *(volatile uint16_t *)(LCD_Reg_Addr) = index;
}
//讀寄存器
uint16_t LCD_ReadReg(uint16_t reg)
{
? ? uint16_t ret;
? ? LCD_WriteIndex(reg);
? ? ret = *(volatile uint16_t *)(LCD_Data_Addr);
? ? return ret;
}
程序初始化之后,復(fù)位LCD,然后讀取 ILI9325 的版本,如果能正確讀出數(shù)據(jù) “9325”,即表明FSMC配置正確:
//復(fù)位LCD
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET);
//讀
tmp = LCD_ReadReg(0x0000);? ? //0000為編碼,詳見 ILI9325手冊
//tmp should be 0x9325 now!!!
if(tmp == 0x9325)
{
? ? //led1 on
? ? HAL_GPIO_WritePin(GPIOB , GPIO_PIN_8, GPIO_PIN_RESET);
} else
{
? ? //led2 on
? ? ?HAL_GPIO_WritePin(GPIOB , GPIO_PIN_9, GPIO_PIN_RESET);
}
printf("ret=0x%x\n", tmp);
//通過TM_SendChar() 在KEIL中觀察變量數(shù)值,詳見《STM32的ITM跟蹤調(diào)試功能介紹及實(shí)現(xiàn)(一)KEIL篇》和《STM32的ITM跟蹤調(diào)試功能介紹及實(shí)現(xiàn)(四)printf() 篇》。
......
運(yùn)行結(jié)果:
本例只是為了說明如何配置FSMC,所以只實(shí)現(xiàn)了對 ILI9325 的讀出數(shù)據(jù)。增加對 ILI9325 的初始化代碼后,就可以容易地實(shí)現(xiàn) ILI9325 顯示圖像。
有了FSMC配置的基礎(chǔ)知識,將方便我們進(jìn)一步理解 STM32F746G-DISCO 板子上使用FMC訪問外部DRAM的配置過程,這個(gè)內(nèi)容將在下一節(jié)中介紹 -- STM32硬件基礎(chǔ)--FMC讀寫片外SDRAM。