參考資料:《STM32F4xx 參考手冊 2》、《STM32F4xx 規格書》、庫幫助文檔《stm32f4xx_dsp_stdperiph_lib_um.chm》。
關於 SDRAM 存儲器,請參考前面的“常用存儲器介紹”,實驗中 SDRAM 芯片的具體參數,請參考其規格書《IS42-45S16400J》來了解。
1、 SDRAM 控制原理
STM32 控制器芯片內部有一定大小的 SRAM 及 FLASH 作為內存和程序存儲空間,但當程序較大,內存和程序空間不足時,就需要在 STM32 芯片的外部擴展存儲器了。
STM32F429 系列芯片擴展內存時可以選擇 SRAM 和 SDRAM,由於 SDRAM 的“容量/價格”比較高,即使用 SDRAM 要比 SRAM 要划算得多。我們以 SDRAM 為例講解如何為 STM32 擴展內存。
給 STM32 芯片擴展內存與給 PC擴展內存的原理是一樣的,只是 PC上一般以內存條的形式擴展,內存條實質是由多個內存顆粒(即 SDRAM 芯片)組成的通用標准模塊,而STM32 直接與 SDRAM 芯片連接。見圖 26-2,這是一種型號為 IS42-45S16400J 的 SDRAM芯片內部結構框圖,以它為模型進行學習。
1.1 SDRAM 信號線
上圖虛線框外引出的是 SDRAM 芯片的控制引腳,其說明見下表:
除了時鍾、地址和數據線,控制 SDRAM 還需要很多信號配合,它們具體作用在描述時序圖時進行講解。
1.2 、控制邏輯
SDRAM 內部的“控制邏輯”指揮着整個系統的運行,外部可通過 CS、WE、CAS、RAS以及地址線來向控制邏輯輸入命令,命令經過“命令器譯碼器”譯碼,並將控制參數保存到“模式寄存器中”,控制邏輯依此運行。
1.3、 地址控制
SDRAM 包含有“A”以及“BA”兩類地址線,A類地址線是行(Row)與列(Column)共用的地址總線,BA地址線是獨立的用於指定 SDRAM 內部存儲陣列號(Bank)。在命令模式下,A類地址線還用於某些命令輸入參數。
1.4 、SDRAM 的存儲陣列
要了解 SDRAM 的儲存單元尋址以及“A”、“BA”線的具體運用,需要先熟悉它內部存儲陣列的結構。見下圖:SDRAM的存儲陣列模型。
SDRAM 內部包含的存儲陣列,可以把它理解成一張表格,數據就填在這張表格上。和表格查找一樣,指定一個行地址和列地址,就可以精確地找到目標單元格,這是SDRAM 芯片尋址的基本原理。這樣的每個單元格被稱為存儲單元,而這樣的表則被稱為存儲陣列(Bank),目前設計的 SDRAM 芯片基本上內部都包含有 4 個這樣的 Bank,尋址時指定 Bank號以及行地址,然后再指定列地址即可尋找到目標存儲單元。SDRAM 內部具有多個 Bank時的結構見下圖:
SDRAM 芯片向外部提供有獨立的 BA類地址線用於 Bank尋址,而行與列則共用 A類地址線。
圖 26-2標號4中表示的就是它內部的存儲陣列結構,通訊時當 RAS線為低電平,則“行地址選通器”被選通,地址線 A[11:0]表示的地址會被輸入到“行地址譯碼及鎖存器”中,作為存儲陣列中選定的行地址,同時地址線 BA[1:0]表示的 Bank也被鎖存,選中了要操作的 Bank號;接着控制 CAS線為低電平,“列地址選通器”被選通,地址線 A[11:0]表示的地址會被鎖存到“列地址譯碼器”中作為列地址,完成尋址過程。
1.5 、數據輸入輸出
若是寫 SDRAM 內容,尋址完成后,DQ[15:0]線表示的數據經過圖 26-2 標號5中的輸入數據寄存器,然后傳輸到存儲器陣列中,數據被保存;數據輸出過程相反。
本型號的 SDRAM 存儲陣列的“數據寬度”是 16位(即數據線的數量),在與 SDRAM進行數據通訊時,16 位的數據是同步傳輸的,但實際應用中我們可能會以 8 位、16 位的寬度存取數據,也就是說 16 位的數據線並不是所有時候都同時使用的,而且在傳輸低寬度數據的時候,我們不希望其它數據線表示的數據被錄入。如傳輸 8位數據的時候,我們只需要 DQ[7:0]表示的數據,而 DQ[15:8]數據線表示的數據必須忽略,否則會修改非目標存儲空間的內容。所以數據輸入輸出時,還會使用 DQM[1:0]線來配合,每根 DQM 線對應 8 位數據,如“DQM0(LDQM)”為低電平,“DQM1(HDQM)”為高電平時,數據線 DQ[7:0]表示的數據有效,而 DQ[15:8]表示的數據無效。
1.6 、SDRAM 的命令
控制 SDRAM 需要用到一系列的命令,見下表。各種信號線狀態組合產生不同的控制命令。
表中的 H 表示高電平,L 表示低電平,X表示任意電平,High-Z 表示高阻態。
本型號的 SDRAM 芯片表示列地址時僅使用 A[7:0]線,而 A10 線用於控制是否“自動預充電”,該線為高電平時使能,低電平時關閉。
6. 刷新
SDRAM 要不斷進行刷新(Refresh)才能保留住數據,因此它是 DRAM 最重要的操作。刷新操作與預充電中重寫的操作本質是一樣的。
但因為預充電是對一個或所有 Bank 中的工作行操作,並且不定期,而刷新則是有固定的周期,依次對所有行進行操作,以保證那些久久沒被訪問的存儲單元數據正確。
刷新操作分為兩種:“自動刷新”(Auto Refresh)與“自我刷新”(Self Refresh),發送命令后 CKE 時鍾為有效時(低電平),使用自動刷新操作,否則使用自我刷新操作。不論是何種刷新方式,都不需要外部提供行地址信息,因為這是一個內部的自動操作。
對於“自動刷新”, SDRAM 內部有一個行地址生成器(也稱刷新計數器)用來自動地依次生成行地址,每收到一次命令刷新一行。在刷新過程中,所有 Bank都停止工作,而每次刷新所占用的時間為 N 個時鍾周期(視 SDRAM 型號而定,通常為 N=9),刷新結束之后才可進入正常的工作狀態,也就是說在這 N 個時鍾期間內,所有工作指令只能等待而無法執行。一次次地按行刷新,刷新完所有行后,將再次對第一行重新進行刷新操作,這個對同一行刷新操作的時間間隔,稱為 SDRAM 的刷新周期,通常為 64ms。顯然刷新會對SDRAM 的性能造成影響,但這是它的 DRAM 的特性決定的,也是 DRAM 相對於 SRAM取得成本優勢的同時所付出的代價。
“自我刷新”則主要用於休眠模式低功耗狀態下的數據保存,也就是說即使外部控制器不工作了,SDRAM 都能自己確保數據正常。在發出“自我刷新”命令后,將 CKE 置於無效狀態(低電平),就進入自我刷新模式,此時不再依靠外部時鍾工作,而是根據 SDRAM內部的時鍾進行刷新操作。在自我刷新期間除了 CKE 之外的所有外部信號都是無效的,只有重新使 CKE 有效才能退出自我刷新模式並進入正常操作狀態。(用於低功耗)
7. 加載模式寄存器
前面提到 SDRAM 的控制邏輯是根據它的模式寄存器來管理整個系統的,而這個寄存器的參數就是通過“加載模式寄存器”命令(LOAD MODE REGISTER)來配置的。發送該命令時,使用地址線表示要存入模式寄存器的參數“OP-Code”,各個地址線表示的參數如下圖:
模式寄存器的各個參數介紹如下:
Burst Length
Burst Length譯為突發長度,下面簡稱 BL。突發是指在同一行中相鄰的存儲單元連續進行數據傳輸的方式,連續傳輸所涉及到存儲單元(列)的數量就是突發長度。
上文講到的讀/寫操作,都是一次對一個存儲單元進行尋址,如果要連續讀/寫就還要對當前存儲單元的下一個單元進行尋址,也就是要不斷的發送列地址與讀/寫命令(行地址不變,所以不用再對行尋址)。雖然由於讀/寫延遲相同可以讓數據的傳輸在 I/O 端是連續的,但它占用了大量的內存控制資源,在數據進行連續傳輸時無法輸入新的命令,效率很低。
為此,人們開發了突發傳輸技術,只要指定起始列地址與突發長度,內存就會依次地自動對后面相應數量的存儲單元進行讀/寫操作而不再需要控制器連續地提供列地址。這樣,除了第一筆數據的傳輸需要若干個周期外,其后每個數據只需一個周期的即可獲得。其實我們在 EERPOM 及 FLASH 讀寫章節講解的按頁寫入就是突發寫入,而它們的讀取過程都是突發性質的。
非突發連續讀取模式:不采用突發傳輸而是依次單獨尋址,此時可等效於 BL=1。雖然也可以讓數據連續地傳輸,但每次都要發送列地址與命令信息,控制資源占用極大。突發連續讀取模式:只要指定起始列地址與突發長度,尋址與數據的讀取自動進行,而只要控制好兩段突發讀取命令的間隔周期(與 BL 相同)即可做到連續的突發傳輸。 而 BL 的數值,也是不能隨便設或在數據進行傳輸前臨時決定。在初始化 SDRAM 調用 LOAD MODEREGISTER 命令時就被固定。BL可用的選項是 1、2、4、8,常見的設定是 4 和 8。若傳輸時實際需要數據長度小於設定的 BL值,則調用“突發停止”(BURST TERMINATE)命令結束傳輸。
BT
模式寄存器中的 BT位用於設置突發模式,突發模式分為順序(Sequential)與間隔(Interleaved)兩種。在順序方式中,操作按地址的順序連續執行,如果是間隔模式,則操作地址是跳躍的。跳躍訪問的方式比較亂,不太符合思維習慣,我們一般用順序模式。順序訪問模式時按照 “0-1-2-3-4-5-6-7”的地址序列訪問。
CASLatency
模式寄存器中的 CASLatency是指列地址選通延遲,簡稱 CL。在發出讀命令(命令同時包含列地址)后,需要等待幾個時鍾周期數據線 DQ 才會輸出有效數據,這之間的時鍾周期就是指 CL,CL一般可以設置為 2 或 3個時鍾周期。如下圖:
CL只是針對讀命令時的數據延時,在寫命令時不需要這個延時的,發出寫命令時可同時發送要寫入的數據。
Op Mode
OP Mode指 Operating Mode,SDRAM 的工作模式。當它被配置為“00”的時候表示工作在正常模式,其它值是測試模式或被保留的設定。實際使用時必須配置成正常模式。
WB
WB用於配置寫操作的突發特性,可選擇使用 BL設置的突發長度或非突發模式。
Reserved
模式寄存器的最后三位的被保留,沒有設置參數。
7 SDRAM 的初始化流程
最后我們來了解 SDRAM 的初始化流程。SDRAM 並不是上電后立即就可以開始讀寫數據的,它需要按步驟進行初始化,對存儲矩陣進行預充電、刷新並設置模式寄存器,見圖 26-10。
其中 t RP 、t RFC 、t MRD 等時間參數跟具體的 SDRAM 有關,可查閱其數據手冊獲知,STM32 FMC訪問時配置需要這些參數。
SDRAM 的讀寫流程
初始化步驟完成,開始讀寫數據,其時序流程見圖 26-11 及圖 26-12。
1. 通訊引腳
在框圖的右側是 FMC外設相關的控制引腳,由於控制不同類型存儲器的時候會有一些不同的引腳,看起來有非常多,其中地址線 FMC_A和數據線 FMC_D 是所有控制器都共用的。這些 FMC引腳具體對應的 GPIO 端口及引腳號可在《STM32F4xx 規格書》中搜索查找到,不在此列出。針對 SDRAM 控制器,我們是整理出以下的 FMC與 SDRAM 引腳對照表 26-3。
其中比較特殊的是 FMC_A[15:14]引腳用作 Bank的尋址線;而 FMC_SDCKE 線和FMC_SDNE 都各有 2 條,FMC_SDCKE 用於控制 SDRAM 的時鍾使能,FMC_SDNE 用於控制 SDRAM 芯片的片選使能。它們用於控制 STM32 使用不同的存儲區域驅動 SDRAM,使用編號為 0 的信號線組會使用 STM32 的存儲器區域 1,使用編號為 1的信號線組會使用存儲器區域 2。使用不同存儲區域時,STM32 訪問 SDRAM 的地址不一樣。
2. 存儲器控制器
上面不同類型的引腳是連接到 FMC內部對應的存儲控制器中的。NOR/PSRAM/SRAM設備使用相同的控制器,NAND/PC 卡設備使用相同的控制器,而 SDRAM 存儲器使用獨立的控制器。不同的控制器有專用的寄存器用於配置其工作模式。
控制 SDRAM 的有 FMC_SDCR1/FMC_SDCR2 控制寄存器、FMC_SDTR1/FMC_SDTR2 時序寄存器、FMC_SDCMR命令模式寄存器以及 FMC_SDRTR刷新定時器寄存器。其中控制寄存器及時序寄存器各有 2 個,分別對應於 SDRAM 存儲區域 1 和存儲區域 2的配置。
FMC_SDCR 控制寄存器可配置 SDCLK 的同步時鍾頻率、突發讀使能、寫保護、CAS延遲、行列地址位數以及數據總線寬度等。
FMC_SDTR 時序寄存器用於配置 SDRAM 訪問時的各種時間延遲,如 TRP行預充電延遲、TMRD 加載模式寄存器激活延遲等。
FMC_SDCMR命令模式寄存器用於存儲要發送到 SDRAM 模式寄存器的配置,以及要向 SDRAM 芯片發送的命令。
FMC_SDRTR 用於配置 SDRAM 的自動刷新周期。
3. 時鍾控制邏輯
FMC外設掛載在 AHB3 總線上,時鍾信號來自於 HCLK(默認 180MHz),控制器的時鍾輸出就是由它分頻得到。如 SDRAM 控制器的 FMC_SDCLK 引腳輸出的時鍾,是用於與SDRAM 芯片進行同步通訊,它的時鍾頻率可通過 FMC_SDCR1 寄存器的 SDCLK 位配置,可以配置為 HCLK 的 1/2 或 1/3,也就是說,與 SDRAM 通訊的同步時鍾最高頻率為90MHz。
FMC 的地址映射
FMC連接好外部的存儲器並初始化后,就可以直接通過訪問地址來讀寫數據,這種地址訪問與 I2C EEPROM、SPI FLASH 的不一樣,后兩種方式都需要控制 I2C或 SPI總線給存儲器發送地址,然后獲取數據;在程序里,這個地址和數據都需要分開使用不同的變量存儲,並且訪問時還需要使用代碼控制發送讀寫命令。而使用 FMC外接存儲器時,其存儲單元是映射到 STM32 的內部尋址空間的;在程序里,定義一個指向這些地址的指針,然后就可以通過指針直接修改該存儲單元的內容,FMC外設會自動完成數據訪問過程,讀寫命令之類的操作不需要程序控制。
圖中左側的是 Cortex-M4 內核的存儲空間分配,右側是 STM32 FMC 外設的地址映射。可以看到 FMC的 NOR/PSRAM/SRAM/NAND FLASH 以及 PC卡的地址都在 External RAM地址空間內,而 SDRAM 的地址是分配到 External device區域的。正是因為存在這樣的地址映射,使得訪問 FMC控制的存儲器時,就跟訪問 STM32 的片上外設寄存器一樣(片上外設的地址映射即圖中左側的“Peripheral”區域)。
1. SDRAM 的存儲區域
FMC把 SDRAM 的存儲區域分成了 Bank1 和 Bank2 兩塊,這里的 Bank與 SDRAM 芯片內部的 Bank是不一樣的概念,只是 FMC的地址區域划分而已。每個 Bank有不一樣的起始地址,且有獨立的 FMC_SDCR 控制寄存器和 FMC_SDTR 時序寄存器,還有獨立的FMC_SDCKE 時鍾使能信號線和 FMC_SDCLK 信號線。FMC_SDCKE0和 FMC_SDCLK0對應的存儲區域 1 的地址范圍是 0xC000 0000-0xCFFF FFFF,而 FMC_SDCKE1 和FMC_SDCLK1 對應的存儲區域 2 的地址范圍是 0xD000 0000- 0xDFFF FFFF。當程序里控制內核訪問這些地址的存儲空間時,FMC外設會即會產生對應的時序,對它外接的SDRAM 芯片進行讀寫。
2. External RAM 與 External device 的區別
比較遺憾的是 FMC給 SDRAM 分配的區域不在 External RAM 區,這個區域可以直接執行代碼,而 SDRAM 所在的 External device區卻不支持這個功能。這里說的可直接執行代碼的特性就是在“常用存儲器”章節介紹的 XIP(eXecute In Place)特性,即存儲器上若存儲了代碼,CPU可直接訪問代碼執行,無需緩存到其它設備上再運行;而且 XIP特性還對存儲器的種類有要求,SRAM/SDRAM 及 NOR Flash都支持這種特性,而 NAND FLASH及 PC卡是不支持 XIP的。結合存儲器的特性和 STM32 FMC存儲器種類的地址分配,就發現它的地址規划不合理了,NAND FLASH 和 PC卡這些不支持 XIP的存儲器卻占據了External RAM 的空間,而支持 XIP的 SDRAM 存儲器的空間卻被分配到了 Extern device區。為了解決這個問題,通過配置“SYSCFG_MEMRMP”寄存器的“SWP_FMC”寄存器位可用於交換 SDRAM 與 NAND/PC 卡的地址映射,使得存儲在 SDRAM 中的代碼能被執行,只是由於 SDRAM 的最高同步時鍾是 90MHz,代碼的執行速度會受影響。
本章主要講解當 STM32 的片內 SRAM 不夠用時使用 SDRAM 擴展內存,但假如程序太大,它的程序空間 FLASH 不夠用怎么辦呢?首先是裁剪代碼,目前 STM32F429 系列芯片內部 FLASH 空間最高可達 2MB,實際應用中只要我們把代碼中的圖片、字模等占據大空間的內容放到外部存儲器中,純粹的代碼很難達到 2MB。如果還不夠用,非要擴展程序空間的話,一種方法是使用 FMC擴展 NOR FLASH,把程序存儲到 NOR上,程序代碼能夠直接在 NOR FLASH 上執行。另一種方法是把程序存儲在其它外部存儲器,如 SD卡,需要時把存儲在 SD 卡上的代碼加載到 SRAM 或 SDRAM 上,再在 RAM 上執行代碼。
如果 SDRAM 不是用於存儲可執行代碼,只是用來保存數據的話,在 External RAM 或Exteranl device 區域都沒有區別,不需要與 NAND 的映射地址交換。
5、 SDRAM 時序結構體
控制 FMC使用 SDRAM 存儲器時主要是配置時序寄存器以及控制寄存器,利用 ST標准庫的 SDRAM 時序結構體以及初始化結構體可以很方便地寫入參數。
這個結構體成員定義的都是 SDRAM 發送各種命令后必須的延遲,它的配置對應到FMC_SDTR 中的寄存器位。所有成員參數值的單位是周期,參數值大小都可設置成“1-16”。關於這些延時時間的定義可以看“SDRAM 初始化流程”和“SDRAM 讀寫流程”小節的時序圖了解。具體參數值根據 SDRAM 芯片的手冊說明來配置。各成員介紹如下:
這個 SDRAMTimingInitTypeDef 時序結構體配置的延時參數,將作為下一節的 FMC SDRAM 初始化結構體的一個成員。
SDRAM 初始化結構體
這個結構體,除最后一個成員是上一小節講解的時序配置外,其它結構體成員的配置都對應到 FMC_SDCR 中的寄存器位。各個成員意義在前面的小節已有具體講解,其可選參數介紹如下,括號中的是 STM32 標准庫定義的宏:
配置完 SDRAM 初始化結構體后,調用 FMC_SDRAMInit 函數把這些配置寫入到 FMC的 SDRAM 控制寄存器及時序寄存器,實現 FMC的初始化。
SDRAM 命令結構體
控制 SDRAM 時需要各種命令,通過向 FMC的命令模式寄存器 FMC_SDCMR寫入控制參數,即可控制 FMC對外發送命令,為了方便使用,STM32 標准庫也把它封裝成了結構體,見代碼清單 26-3。
命令結構體中的各個成員介紹如下:
配置完這些結構體成員,調用庫函數 FMC_SDRAMCmdConfig即可把這些參數寫入到FMC_SDCMR寄存器中,然后 FMC外設就會發送相應的命令了。
特殊引腳:
. 編程要點
1、 初始化通訊使用的目標引腳及端口時鍾;
2、使能 FMC外設的時鍾;
3、 配置 FMC SDRAM 的時序、工作模式;
4、根據 SDRAM 的初始化流程編寫初始化函數;
5、 建立機制訪問外部 SDRAM 存儲器;
6、編寫測試程序,對讀寫數據進行校驗。
把 FMC SDRAM 硬件相關的配置都以宏的形式定義到 “bsp_sdram.h”文件中,
以上代碼根據硬件的連接,把與 SDRAM 通訊使用的引腳號、引腳源以及復用功能映射都以宏封裝起來。其中 FMC_CKE和 FMC_CLK 引腳對應的是 FMC的存儲區域 2,所以后面我們對 SDRAM 的尋址空間也是要指向存儲區域 2 的。
初始化 FMC 的 GPIO
利用上面的宏,編寫 FMC的 GPIO 引腳初始化函數,
與所有使用到 GPIO 的外設一樣,都要先把使用到的 GPIO 引腳模式初始化,以上代碼把 FMC SDRAM 的所有信號線全都初始化為 FMC 復用功能,所有引腳配置都是一樣的。
配置 FMC
接下來需要配置 FMC SDRAM 的工作模式,這個函數的主體是根據硬件連接的SDRAM 特性,對時序結構體以及初始化結構體進行賦值。
設置自動刷新周期
在上面 SDRAM_InitSequence 函數的最后,我們還調用了庫函數 FMC_SetRefreshCount設置 FMC自動刷新周期,這個函數會向刷新定時寄存器 FMC_SDRTR 寫入計數值,這個計數值每個 SDCLK 周期自動減 1,減至 0 時 FMC會自動向 SDRAM 發出自動刷新命令,控制 SDRAM 刷新,SDRAM 每次收到刷新命令后,刷新一行,對同一行進行刷新操作的時間間隔稱為 SDRAM 的刷新周期。
根據 STM32F4xx 參考手冊的說明,COUNT值的計算公式如下:
直接定義一個全局變量:
#define SDRAM_BASE_ADDR (0XD0000000)
/*把變量ptest強制定義到SDRAM_BASE_ADDR中*/
/*使用這種語法一定要定義成全局變量*/
uint16_t ptest __attribute__ ((at(SDRAM_BASE_ADDR+100))); //0X64
uint16_t tempt __attribute__ ((at(SDRAM_BASE_ADDR+40))); //0X28
uint16_t test;
在main函數中給對應變量賦值:
ptest = 0xaa;
tempt = 0x34;
test = 0xaa;
在.map中可以看到,test是直接定義到內部SRAM中( 0x20000010),tempt 和 ptest是定義到外部SRAM中的(0xd0000028)。