什么是FSMC
FSMC(Flexible Static Memory Controller,可變靜態存儲控制器)是STM32系列采用的一種新型的存儲器擴展技術。在外部存儲器擴展方面具有獨特的優勢,可根據系統的應用需要,方便地進行不同類型大容量靜態存儲器的擴展。
STM32系列微控制器為用戶提供了豐富的選擇,可適用于工業控制、智能家電、建筑安防、醫療設備以及消費類電子產品等多方位嵌入式系統設計。STM32系列采用一種新型的存儲器擴展技術——FSMC,在外部存儲器擴展方面具有獨特的優勢,可根據系統的應用需要,方便地進行不同類型大容量靜態存儲器的擴展。
fsmc就是為了擴展內存的,如我們在STM32芯片外添加一個sram芯片,那么我們只需要把 sram芯片的地址線和數據線和STM32連接后,然后將內核規定的地址數賦給sram的地址,那么我們就可以通過內核規定的地址去訪問sram芯片了。
STM32_FMSC使用理解
第一個角度理解
? ? ? ? STM32有FSMC(其實其他芯片基本都有類似的總線功能),FSMC的好處就是你一旦設置好之后,WR(寫)、RD(讀)、DB0-DB15這些控制線和數據線,都是FSMC自動控制的。打個比方,當你在程序中寫到:
*(volatile unsigned short int *)(0x60000000)=val;
那么FSMC就會自動執行一個寫的操作,其對應的主控芯片的WE、RD這些腳,就會呈現出寫的時序出來(即WE=0,RD=1),數據val的值也
會通過DB0-15自動呈現出來(即FSMC-D0:FSMC-D15=val )。地址0x60000000會被呈現在數據線上(即A0-A25=0,地址線的對應最麻煩,要根據具體情況來,好好看看FSMC手冊)。
那么在硬件上面,我們需要做的,僅僅是MCU和LCD控制芯片的連接關系:
WE-WR,均為低電平有效
RD-RD,均為低電平有效
FSMC-D0-15接LCD DB0-15
FSMC_NE1--CS接PD7
連接好之后,讀寫時序都會被FSMC自動完成。但是還有一個很關鍵的問題,就是RS沒有接因為在FSMC里面,根本就沒有對應RS。怎么辦呢?這個時候,有一個好方法,就是用某一根地址線來接RS。比如我們選擇了A16這根地址線來接,那么當我們要寫寄存器的時候,我們需要RS,也就是A16(RS為高)置高。軟件中怎么做呢?也就是將FSMC要寫的地址改成0x60020000,如下:
*(volatile unsigned short int *)(0x60020000)=val;
這個時候,A16在執行其他FSMC的同時會被拉高,因為A0-A18要呈現出地址0x60020000。0x60020000里面的Bit17=1,就會導致A16為1。
當要讀數據時,地址由0x60020000改為了0x60000000,這個時候A16就為0了。
那么有朋友就會有疑問,第一,為什么地址是0x6xxxxxxx而不是0x0xxxxxxx;第二,CS怎么接;第三,為什么Bit17對應A16?
RS問題:RS為0表示;讀寫寄存器;RS為1,讀寫數據RAM;
先來看前兩個問題,大家找到STM32的FSMC手冊,在FSMC手冊里面,我們很容易找到,FSMC將0x60000000-0x6fffffff的地址用作NOR/PRAM(
共256M地址范圍)。而這個存儲塊,又被分成了四部分,每部分64M地址范圍。當對其中某個存儲塊進行讀寫時,對應的NEx就會置低。這里,
就解決了我們兩個問題,
第一,LCD的操作時序,和NOR/PRAM是一樣的(為什么一樣自己找找NOR/PRAM的時序看看),所以我們選擇0x6xxxxxxx
這個地址范圍(選擇這個地址范圍,操作這個地址時,FSMC就會呈現出NOR/PRAM的時序)。
第二,我們可以將NEx連接到LCD的CS,只要我們操作
的地址是第一個存儲塊內即可(即0-0x3ffffff地址范圍)。
第三個問題再來看一看FSMC手冊關于存儲器字寬的描述,我們發現,當外部存儲器是16位時,硬件管腳A0-A24表示的是地址線A1-A25的值,所以
我們要位移一下,Bit17的值,實際會被反應到A16這根IO來。關于數據寬度及位移的問題,初學的朋友可能會比較疑惑,當你接觸了多NOR/PRAM
這樣的器件后,你會發現,很多芯片的總線,都是這樣設計的,為的是節省地址線。
第二個角度理解:
FSMC總線上看,LCD只有2個地址。
Bank1_LCD_C是寫寄存器,此時RS=1,告訴LCD我在總線上輸出數據的是寄存器的地址
Bank1_LCD_D是寫數據,此時RS=0,告訴LCD我在總線上輸出地數據是寄存器的數據或者GRAM的數據。
寫寄存器數據按2步來:
第一步先往Bank1_LCD_C (對應RS=1),送寄存器的地址:*(__IO uint16_t *) (Bank1_LCD_C)= index; 接著在Bank1_LCD_D這個地址(對應RS=0),寫入剛指向的寄存器的數據: *(__IO uint16_t *) (Bank1_LCD_D)= val;
為什么*(__IO uint16_t *) (Bank1_LCD_C)= index; 就是往 LCD 寫寄存器呢?
這是一個16位的IO賦值操作,地址是Bank1_LCD_C,這個地址就是指向FSMC的 Bank1的NE1對應的地址空間。而LCD片選正是連接到NE1,具體地址要看RS接到哪一根地址線上。當CPU執行到這一條的時候,就會通過FSMC總線控制器在數據總線上進行一個地址為 Bank1_LCD_C的數據寫操作,此操作自動完成CS信號,
RD信號,WR信號,以及地址總線數據(RS信號)的輸出以及數據總線數據的輸出。
其他的操作都是這兩個操作組合完成。也就是我上面所說的,
“所有的寄存器地址和寄存器數據,以及 GRAM數據都是通過 IO0-IO15完成傳輸的,而不是FSMC的地址。這是容易搞混的一個地方.LCD的FSMC地址只有一根 ,就是RS.”
第三個角度理解:
把TFT看做類似SRAM的存儲器,只能接在 BANK1上。對應基地址是0x60000000.
而BANK1又有劃分為四個片選,分別對應基地址:
NE1 0x600000000
NE2 0x640000000
NE3 0x680000000
NE4 0x6C0000000
所以每個NEx能尋址的空間大小為64M,也就是對應了FSMC的A0到A25 共26根地址線。
假如使用NE4接到為LCD的片選CS上,那么就對應基地址 0x6C000000,
如果RS接到地址線的 A0上,那么當 RS為0時對應的地址就是 LCD_REG = 0x6C000000,(其實你用0x6CFFFFF0是一樣的,因為只用到一根地址線)。
RS為1時對應的地址就是 LCD_RAM =0x6C000001,(0x6CFFFFF1一樣對應 LCD_RAM,因為它一樣對應 RS=1)。
如果 RS接到 其他地址線上,情況是類似的。
比如接到 An上,那么
LCD_REG= 0x6C000000,
LCD_RAM= 0x6C000000 | (1《《n)
注意這個地址不是唯一的,只要這個地址能尋址到 BANK1 的 NE4上而且使 RS=0,那么就是 LCD_REG,使 RS=1,就是LCD_RAM.
對應Bank1_LCD_C 的地址,FSMC總線控制器在RS接的那根地址線輸出的是 1,而對應Bank1_LCD_D,輸出的0.
RS接的可不是GPIO,是FSMC地址總線的一根.FSMC進行讀寫操作的時候會在地址總線根據要讀寫的地址輸出電平的。
RS接哪一根地址線雖然沒有固定要求,但是一旦你確定要接哪一根,那么Bank_LCD_C和Bank_LCD_D也要隨之確定,這可不是“自動的“。
雖然沒有手動操作GPIO來操作RS,但是你敲代碼的時候可是手動指定 Bank1_LCD_C 或者 Bank1_LCD_D ,從而確定 RS的電平。
所謂的“自動”是指:不是通過操作GPIO來操作RS,而是直接根據地址總線地址的不同來完成操作RS,這兩種方法的速度差別是非常大的。
如果是GPIO方式,先要通過操作GPIO 分別 輸出 RS,CS,等的電平,然后再通過過GPIO操作輸出數據,然后還要通過GPIO 再操作RD,WR,CS等的電平。
每操作一個GPIO都要好幾個周期,加起來就非常慢了。
而FSMC是在一個FSMC寫周期內就完成了這所有的動作。
評論