FSMC稱為靈活的靜態(tài)存儲器,它能夠與同步或異步存儲器和16位PC存儲器卡連接,STM32F4的FSMC接口支持包括SRAM、NAND FLASH、NOR FLASH和PSRAM等存儲器。
FSMC框圖
從FSMC框圖可以看到,F(xiàn)SMC將外部設(shè)備分為2類:NOR/PSRAM設(shè)備和NAND/PC卡設(shè)備。所有外部存儲器共享地址、數(shù)據(jù)和控制信號,但有各自的片選信號。FSMC 一次只能訪問一個外部器件。
這里將LCD的片選接口與FSMC_NE4相連,即利用FSMC_NE4實現(xiàn)對LCD的片選;另外SRAM芯片的片選接口與FSMC_NE3相連,即利用FSMC_NE3實現(xiàn)對SRAM芯片的片選。FSMC本身就是靜態(tài)存儲器控制器,通過FSMC接口訪問SRAM是理所當(dāng)然的事,這里能將LCD也連接到FSMC,顯然說明LCD在操作上與SRAM有相似之處。
SRAM的控制一般有:地址線(如A18A0)、數(shù)據(jù)線(如D15D0)、寫信號(WE)、讀信號(OE)、片選信號(CS),如果SRAM支持字節(jié)控制,那么還有UB/LB信號。
LCD的信號則包括:寄存器選擇(RS)、數(shù)據(jù)線(D15-D0)、寫信號(WE)、讀信號(OE)、片選信號(CS)、復(fù)位信號RST和背光BL。
除去與訪問過程無關(guān)的信號RST、BL,則兩者的控制信號是極度的一致,區(qū)別僅在于SRAM有地址線(A18-A0),而LCD有RS信號線,從作用上看,兩者也是一致的,都決定訪問數(shù)據(jù)的位置。若假定SRAM僅一根地址線A0,則說明數(shù)據(jù)位置僅有兩個,通過A0取0和取1,區(qū)分訪問的數(shù)據(jù)到底在哪個地址空間;而LCD的RS取0和取1,也說明有兩個存儲空間,即ILI9341的寄存器的GRAM。顯然,當(dāng)把RS理解成一根地址線時,LCD就等效成SRAM了。RS與地址線A6進(jìn)行相連,因此通過把地址線中的A6置0可以訪問ILI9341的寄存器,而把A6置1則可以訪問GRAM。
STM32F4xx的FSMC支持 8/16/32 位數(shù)據(jù)寬度,這里用到的 LCD 是 16 位寬度的,所以在設(shè)置數(shù)據(jù)寬度時,用戶應(yīng)選擇16位寬。使用FSMC的目的,是把STM32F4XX的片外外設(shè)映射到片內(nèi)ARM核可尋址的地址空間當(dāng)中,這樣通過訪問片內(nèi)對應(yīng)的地址空間,就可以操作片外外設(shè)了。顯然,這樣的操作等同于把“片外外設(shè)”變成了“片內(nèi)外設(shè)”,在訪問方式上,和訪問片內(nèi)外設(shè)一模一樣。
FSMC存儲區(qū)域
FSMC 的外部存儲器被劃分為 4 個固定大小的存儲區(qū)域,每個存儲區(qū)域的大小為256 MB。
● 存儲區(qū)域 1 可連接多達(dá) 4 個 NOR Flash 或 PSRAM 存儲器器件。此存儲區(qū)域被劃分為 4 個
NOR/PSRAM 區(qū)域,帶 4 個專用片選信號。
● 存儲區(qū)域 2 和 3 用于連接 NAND Flash 器件(每個存儲區(qū)域一個器件)
● 存儲區(qū)域 4 用于連接 PC 卡設(shè)備
對于每個存儲區(qū)域,所要使用的存儲器類型由用戶在配置寄存器中定義。
Bank1的256M字節(jié)空間由 28 根地址線(HADDR[27:0])(注意:這里的HADDR是內(nèi)部AHB的地址線,它的地址是按字節(jié)進(jìn)行“編號”的)尋址。這里HADDR[25:0]來自外部存儲器地址FSMC_A[25:0],而HADDR[27:26]對4個區(qū)進(jìn)行尋址。
NOR/PSRAM 存儲區(qū)域選擇
由于我的LCD片選信號與FSMC的FSMX_NE4連接,所以LCD對應(yīng)尋址空間的首地址為0x60000000+0xC000000=0x6C000000。LCD的RS接到了地址A6,而沒有其他地址線,因此按照道理,其他的地址線可取任意值。
HADDR[25:0] 包含外部存儲器地址。由于 HADDR 為字節(jié)地址,而存儲器按字尋址,所以根據(jù)存儲器數(shù)據(jù)寬度不同,實際向存儲器發(fā)送的地址也將有所不同,如下表所示。
LCD配置為16位數(shù)據(jù)寬度,因此內(nèi)部地址的偏移量是外部地址2倍,即假定FSMC_A的地址值取x,則映射到內(nèi)部地址,則實際地址首地址應(yīng)為0x6C000000+2x。由于此次僅用到A6,即FSMC_A[6],若該位取0時,其他地址線也取0,則FSMC_A的值為0,此時其映射的AHB地址為0x6C000000;若FSMC_A[6]取1,且其他地址線都取0,則FSMC_A的值為0x40,此時映射的AHB地址即為0x6C000000+2*0x40,即0x6C000080。找到了地址,就可以像訪問片內(nèi)外設(shè)那樣去訪問片外外設(shè)了。
這里直接宏定義地址,方便調(diào)用。
//未使用的地址線全部取0(注意:取任意值均可,這里取0)
#define LCD_CMD_ADD (volatile u16 *)0X6C000000
#define LCD_DATA_ADD (volatile u16 *)(0X6C000000 + 0X80)
為進(jìn)一步簡化操作,可為以上兩個地址宏定義加地址訪問符“*”,以便于訪問這兩個地址空間。
#define LCD_CMD *LCD_CMD_ADD
#define LCD_DATA *LCD_DATA_ADD
定義了這兩個宏,以后寫命令和寫數(shù)據(jù)就方便多了。若要發(fā)命令,只需給LCD_CMD賦值即可,若要發(fā)數(shù)據(jù),只需給LCD_DATA發(fā)數(shù)據(jù)就行了。
得到了片外設(shè)備(LCD)映射到片內(nèi)AHB空間的地址,就方便用戶對ILI9341的寄存器和GRAM進(jìn)行訪問了,但訪問要有合適的時序才可以。SRAM的可編程訪問參數(shù)如下表所示:
由于ILI9341在寫入和讀取時,速度差異較大,為合理地利用讀寫速度,這里采用異步模式A,如此以來,只需關(guān)注上表的前三個參數(shù),即:地址建立時間、地址保持時間、數(shù)據(jù)建立時間。
ILI9341的8080-II讀寫時序
上圖中所對應(yīng)電氣參數(shù)的取值如表所示:
從上圖表可以得到ILI9341在8080-II時序下的讀寫控制信號電平狀態(tài)為:寫控制脈沖高電平持續(xù)的時間為:twrh<15ns(HCLK=168MHz,因此twrh<3個HCLK);寫控制脈沖低電平持續(xù)的時間為:twrl<15ns(同理,twrl<3個HCLK)。讀GRAM控制脈沖高電平持續(xù)的時間為:trdhfm<90ns(即:trdhfm<15個HCLK); 讀GRAM控制脈沖低電平持續(xù)的時間為:trdlfm<355ns(即:trdlfm<60個HCLK)。讀ID號控制脈沖高電平持續(xù)的時間為:trdh<90ns(即:trdh<15個HCLK); 讀ID號控制脈沖低電平持續(xù)的時間為:trdl<45ns(即:trdl<8個HCLK)。
ILI9341的寫操作周期相對于讀操作周期要短很多,即寫的速度要明顯快于讀的速度。另外,為保證讀GRAM和讀ID號可共用同一讀時序,應(yīng)保證讀控制脈沖的低電平持續(xù)時間trd至少為60個HCLK。這里,為充分發(fā)揮寫入速度快的優(yōu)勢,這里分開配置讀時序和寫時序。
FSMC在模式A下的讀/寫時序
讀時序中地址建立時間ADDSET,即為讀控制脈沖的高電平時間,由以上結(jié)論可知,ADDSET(RD)的值為90ns(15個HCLK周期);讀時序中數(shù)據(jù)保持時間DATAST,即讀控制脈沖的低電平時間,由以上結(jié)論可知,DATAST(RD)的值為355ns(60個HCLK周期);寫時序?qū)?yīng)的建立時間ADDSET,即為寫控制信號的高電平,由以上結(jié)論可知,此時的ADDSET(WR)的值為15ns(3個HCLK周期);寫時序?qū)?yīng)的數(shù)據(jù)保持時間DATAST,即寫控制脈沖的低電平時間,由以上結(jié)論可知,此時的DATAST(WR)的值為15ns(3個HCLK)。
有了以上的時序參數(shù),就可以配置FSMC相關(guān)寄存器了。
下面對寄存器進(jìn)行簡要說明:
SRAM/NOR-Flash片選控制寄存器1..4(FSMC_BCR1..4):
bit19:寫入突發(fā)使能。對于CRAM(PSRAM),該位可在寫操作時使能同步突發(fā)協(xié)議。讀取訪問期間同步突發(fā)協(xié)議的使能位為FSMC_BCRx寄存器中的BURSTEN位。0:始終在異步模式下進(jìn)行寫入操作;1:在同步模式下進(jìn)行寫入操作。操作LCD時,始終在異步模式下進(jìn)行操作,因此這里設(shè)置為0。
bit15:異步傳輸期間的等待信號。該位可使能/禁止FSMC使用等待信號,即使是在異步協(xié)議期間該位也有作用。0:運行異步協(xié)議時不考慮NWAIT信號(復(fù)位后的默認(rèn)值);1:運行異步協(xié)議時考慮NWAIT信號。這里不考慮NWAIT信號。
bit14:擴(kuò)展模式使能。FSMC可對FSMC_BWTR寄存器中的寫入時間進(jìn)行配置,此配置由EXTMOD位使能,進(jìn)而使讀取和寫入操作采用不同的時序。0:不考慮FSMC_BWTR寄存器中的值;1:考慮FSMC_BWTR寄存器中的值。由于此次采用的時序是模式A,因此采用擴(kuò)展模式,并分開設(shè)置讀寫時序。這里將EXTMOD設(shè)置為1。
bit13:等待使能位。該位可使能/禁止在同步模式下訪問FLASH時通過NWAIT信號插入等待周期。0:禁止NWAIT信號;1:使能NWAIT信號。這里禁止即可。
bit12:寫入使能。用于指示FSMC是否在存儲區(qū)域內(nèi)使能/禁止寫入操作。0:FSMC在存儲區(qū)域內(nèi)禁止寫入操作;1:FSMC在存儲區(qū)內(nèi)使能寫入操作。因此就是想利用FSMC讀寫ILI9341,因此,這里需使能存儲區(qū)域的寫入操作。
bit11:等待時序配置。NWAIT信號指示存儲器中的數(shù)據(jù)是否有效,或者在同步模式下訪問FLASH時是否必須插入等待周期。該配置位決定存儲器是在等待周期之前的一個時鐘周期還是等待周期期間使能NWAIT。0:NWAIT信號在等待周期之前的一個數(shù)據(jù)周期有效;1:NWAIT信號在等待周期期間有效。這里無需設(shè)置。
bit10:環(huán)回突發(fā)模式支持。定義控制器是否將一個AHB突發(fā)環(huán)回訪問分割成兩個線性訪問。僅在突發(fā)模式下訪問存儲器時有效。0:未使能直接環(huán)回突發(fā);1:使能直接環(huán)回突發(fā)。這里不采用環(huán)回突發(fā)模式。
bit9:等待信號極性位。定義存儲器的等待信號極性。僅在突發(fā)模式下訪問存儲器時有效。0:NWAIT低電平有效;1:NWAIT高電平有效。該位無需設(shè)置。
bit8:BURSTEN,突發(fā)使能位。用于使能/禁止讀取操作期間的同步突發(fā)訪問。僅對同步突發(fā)存儲器有效。0:禁止;1:有效。此用于同步模式,因此這里無需設(shè)置。
bit6:FLASH訪問使能。用于使能NOR FLASH訪問操作。0:禁止訪問;1:使能訪問。這里是把LCD等效成SRAM,因此禁止即可。
bit[5:4]:存儲器數(shù)據(jù)總線寬度。00:8位;01:16位;10和11:保留,不使用。顯然,這里需設(shè)置為16位。
bit[3:2]:存儲器類型。定義與相應(yīng)存儲區(qū)域相連的外部存儲器類型;00:SRAM、ROM;01:PSRAM;10:NOR FLASH/OneNAND FLASH。這里配置為SRAM。
bit1:地址/數(shù)據(jù)復(fù)用使能功能。該位置1時,僅對NOR和PSRAM存儲器有效;0:地址/數(shù)據(jù)非復(fù)用;1:地址/數(shù)據(jù)在數(shù)據(jù)總線上復(fù)用。無關(guān)項,無需設(shè)置。
bit0:存儲區(qū)域使能。0:禁止相應(yīng)的存儲區(qū)域;1:使能相應(yīng)的存儲區(qū)域。這里一定要使能的。
SRAM/NOR-Flash片選時序寄存器1..4(FSMC_BTR1..4):
bit[29:28]:訪問模式。00:模式A;01:模式B;10:模式C:11:模式D。顯然,此次選擇模式A。
bit[27:24]:DATLAT,同步突發(fā)NOR FLASH的數(shù)據(jù)延遲。這里不需要進(jìn)行設(shè)置。
bit[23:20]:CLKDIV,CLK信號的時鐘分頻比。在異步模式上,該值為無關(guān)值,因此這里無需關(guān)注。
bit[19:16]:這里采用默認(rèn)值即可。
bit[15:8]:DATST,數(shù)據(jù)階段的持續(xù)時間。該寄存器是針對讀操作的,由前面時序分析可知,這里取為60個HCLK。
bit[7:4]:ADDHLD,地址保持階段持續(xù)的時間。在異步模式,該字段是無關(guān)項,因此無需設(shè)置。
bit[3:0]:ADDSET,地址建立時間。由前面時序分析可知,讀操作時ADDSET可取15個HCLK。
SRAM/NOR-FLASH寫入時序寄存器1..4(FSMC_BWTR1..4):
bit[29:28]:ACCMOD,訪問模式。這里同讀時序,配置為模式A。
bit[27:24]:DATLAT,數(shù)據(jù)延遲。期用于同步突發(fā)NOR FLASH,因此這里可以不設(shè)置。
bit[23:20]:CLKDIV,CLK信號時鐘分頻比。這里仍是無關(guān)項,不設(shè)置。
bit[19:16]:總線周轉(zhuǎn)階段的持續(xù)時間。這里按默認(rèn)值設(shè)置即可。
bit[15:8]:數(shù)據(jù)階段的持續(xù)時間。由前面的時序分析可得,寫操作時,DATST取3個HCLK。
bit[7:4]:地址階段的保持時間。在異步模式,該字段是無關(guān)項,無需設(shè)置。
bit[3:0]:地址階段的建立時間。由前面的時序分析可得,寫操作時,ADDSET取3個HCLK。
分析完如何配置FSMC寄存器,開始GPIO引腳并復(fù)用為FSMC,并按上述分析配置寄存器,即可讓FSMC模塊為用戶提供正確的時序。
但在stm32f4xx.h文件當(dāng)中,ST公司并沒有按照中文手冊中那樣,去命名FSMC的寄存器。
FSMC寄存器映射表
stm32f4xx.h當(dāng)中定義FSMC的數(shù)據(jù)結(jié)構(gòu)為:
typedef struct
{
__IO uint32_t BTCR[8]; /*!< NOR/PSRAM chip-select control register(BCR) and chip-select timing register(BTR) */
}FSMC_Bank1_TypeDef;
#define FSMC_Bank1 ((FSMC_Bank1_TypeDef *) FSMC_Bank1_R_BASE)
上述結(jié)構(gòu)體當(dāng)中成員為一個8元素的數(shù)組。由C數(shù)組知識易知,數(shù)組成員在內(nèi)存當(dāng)中地址是相鄰的。宏定義FSMC_Bank1為FSMC_Bank1_TypeDef類型的地址,而FSMC_Bank1_R_BASE即為0xA0000000。FSMC_Bank1所指向的第一個成員即為FSMC_BCR1。由地址連續(xù)性,顯然可得如下對應(yīng)關(guān)系:
BTCR[0]對應(yīng)FSMC_BCR1,BTCR[1]對應(yīng)FSMC_BTR1;
BTCR[2]對應(yīng)FSMC_BCR2,BTCR[3]對應(yīng)FSMC_BTR2;
BTCR[4]對應(yīng)FSMC_BCR3,BTCR[5]對應(yīng)FSMC_BTR3;
BTCR[6]對應(yīng)FSMC_BCR4,BTCR[7]對應(yīng)FSMC_BTR4。
同理,寫入時序寄存器對應(yīng)的數(shù)據(jù)結(jié)構(gòu)為:
BWTR[0]對應(yīng)FSMC_BWTR1,BWTR[2]對應(yīng)FSMC_BWTR2;
BWTR[4]對應(yīng)FSMC_BWTR3,BWTR[6]對應(yīng)FSMC_BWTR2;
這里元素存在跳躍性,原因是寄存器地址間隔為8,因此,為保證地址上的一致性,這里必須這樣定義數(shù)據(jù)結(jié)構(gòu)。
配置FSMC
static void ILI9341_GpioInit()
{
//1. 開時鐘PB/PD/PE/PF/PG
RCC- >AHB1ENR |= 1< 1 | 0XF< 3;
//2. 背光引腳:通用推挽輸出
//端口設(shè)置(pb15)
GPIOB- >MODER &= ~(0X3< 30);
GPIOB- >MODER |= 1< 30; //普通輸出
GPIOB- >OTYPER &= ~(1< 15); //推挽
GPIOB- >OSPEEDR |= 0X3< 30;
GPIOB- >PUPDR &= ~(0X3< 30); //無上下拉
//其他所有引腳復(fù)用為FSMC
/*
LCD_CS:PG12
RS:PF12 = >FSMC_A[6]
WR:PD5
RD:PD4
D0-D1:PD14/PD15
D2-D3:PD0/PD1
D4-D12:PE7-PE15
D13-D15:PD8-PD10
*/
//2. PD(配置為復(fù)用)
GPIOD- >MODER &= ~(0XF< 0 | 0XF< 8 | 0X3F< 16 | 0xf< 28);
GPIOD- >MODER |= 0X0a< 0 | 0xa< 8 | 0x2a < 16 |0xa< 28; //PD口復(fù)用
GPIOD- >OTYPER &= ~(0X3< 0 | 0X3< 4 | 0X7< 8 | 0X3< 14); //推挽
GPIOD- >OSPEEDR |= (0XF< 0 | 0XF< 8 | 0X3F< 16 | 0xf< 28); //速度100Mhz
GPIOD- >PUPDR &= ~(0XF< 0 | 0XF< 8 | 0X3F< 16 | 0xf< 28); //無上下拉
//PE口配置
GPIOE- >MODER &= 0X00003FFF;
GPIOE- >MODER |= 0Xaaaa8000; //PE復(fù)用
GPIOE- >OTYPER &= 0X007F; //PE7-15推挽
GPIOE- >OSPEEDR |= 0XFFFFC000; //PE7-15速度為100Mhz
GPIOE- >PUPDR &= 0X00003FFF; //PE7-15無上下拉
//FP12
GPIOF- >MODER &= ~(0X3< 24);
GPIOF- >MODER |= 2< 24;
GPIOF- >OTYPER &= ~(1< 12); //推挽
GPIOF- >OSPEEDR |= 0X3< 24; //100mHZ
GPIOF- >PUPDR &= ~(0X3< 24); //無上下拉
//FG12
GPIOG- >MODER &= ~(0X3< 24);
GPIOG- >MODER |= 2< 24;
GPIOG- >OTYPER &= ~(1< 12); //推挽
GPIOG- >OSPEEDR |= 0X3< 24; //100mHZ
GPIOG- >PUPDR &= ~(0X3< 24); //無上下拉
//選擇復(fù)用的功能:復(fù)用為FSMC
//復(fù)用功能選擇
//PD:
GPIOD- >AFR[0] &= 0XFF00FF00;
GPIOD- >AFR[0] |= 0x00cc00cc; //PD0/1/4/5復(fù)用為FSMC
GPIOD- >AFR[1] &= 0X00FFF000;
GPIOD- >AFR[1] |= 0XCC000CCC; //PD8/9/10/14/15復(fù)用為FSMC
//PE:
GPIOE- >AFR[0] &= 0X0FFFFFFF;
GPIOE- >AFR[0] |= 0XC0000000; //PE7復(fù)用為FSMC
GPIOE- >AFR[1] &= 0x00000000;
GPIOE- >AFR[1] |= 0XCCCCCCCC; //PE8-15復(fù)用,可以直接往AFR[1]中賦值
//PF:
GPIOF- >AFR[1] &= 0xfff0ffff;
GPIOF- >AFR[1] |= 0X000C0000; //PF12復(fù)用為FSMC
//PG:
GPIOG- >AFR[1] &= 0xfff0ffff;
GPIOG- >AFR[1] |= 0X000C0000; //PG12復(fù)用為FSMC
//3. 開FSMC時鐘
RCC- >AHB3ENR |= 1< 0;
//4. 配置FSMC寄存器
//BCR4
FSMC_Bank1- >BTCR[6] &= ~(1< 19); //始終在異步模式下操作
FSMC_Bank1- >BTCR[6] &= ~(1< 15); //不考慮等待信號
FSMC_Bank1- >BTCR[6] |= 1< 14; //使能擴(kuò)展功能,即讀寫時序分開
FSMC_Bank1- >BTCR[6] &= ~(1< 13); //禁止等待nWait信號
FSMC_Bank1- >BTCR[6] |= 1< 12; //使能寫操作
FSMC_Bank1- >BTCR[6] &= ~(0x3< 4);
FSMC_Bank1- >BTCR[6] |= 1< 4; //16位數(shù)據(jù)寬度
FSMC_Bank1- >BTCR[6] &= ~(0x3< 2); //存儲器類型為:SRAM
//BTR4:
//BTR4(讀時序)
FSMC_Bank1- >BTCR[7] &= ~(0x3< 28); //異步模式A
FSMC_Bank1- >BTCR[7] |= 0xf< 16; //總線周轉(zhuǎn)階段持續(xù)時間為默認(rèn)值
FSMC_Bank1- >BTCR[7] &= 0xffff00ff;
FSMC_Bank1- >BTCR[7] |= 60< 8; //DATAST為60HCLK
FSMC_Bank1- >BTCR[7] |= 0xf< 0; //ADDSET為15HCLK
//BWTR(寫時序)
FSMC_Bank1E- >BWTR[6] = 0;
FSMC_Bank1E- >BWTR[6] &= ~(0x3< 28); //異步模式A
FSMC_Bank1E- >BWTR[6] |= 0xf< 16; //總線周轉(zhuǎn)階段持續(xù)時間為默認(rèn)值
FSMC_Bank1E- >BWTR[6] |= 3< 8; //DATAST為3個HCLK
FSMC_Bank1E- >BWTR[6] |= 3< 0; //ADDSET為3個HCLK
//使能存儲塊
FSMC_Bank1- >BTCR[6] |= 1< 0;
GPIOB- >BSRRH = 0X1< 15; //關(guān)背光
}
配置完FSMC,替代之前用IO口模擬8080時序的ILI9341GPIO初始化函數(shù),并放入之前的圖片顯示和碰撞小球?qū)嶒炛?,可以發(fā)現(xiàn)刷屏速度得到了很大的提高。
可以看到,F(xiàn)SMC操作LCD比GPIO模擬8080時序會快很多,可能有人會說硬件實現(xiàn)就是比軟件實現(xiàn)快。但其實不是這樣的,用軟件模擬時序,給出的延時與標(biāo)準(zhǔn)時序可能不是完全一致,導(dǎo)致速度比較慢,如果用軟件模擬時序時使用邏輯分析儀對時序的延時時間進(jìn)行優(yōu)化,GPIO模擬8080時序也是可以達(dá)到FSMC的速度的,有興趣的可以自己嘗試一下。
評論
查看更多