STM32F103_外部RAM用作運存---IS62WV51216


https://www.cnblogs.com/lilto/p/9548736.html

STM32F103_外部RAM用作運存

 

概述

SRAM的簡介

折騰過電腦的朋友都知道,當電腦運行比較卡的時候,我們可以通過給電腦加裝內存條來改善電腦的性能。那么號稱微型計算機的單片機能不能像電腦一樣加裝內存條呢?裝內存條倒是不行,但是我們可以給單片機外加和內存條效果一樣的SRAM來提升單片機的性能。下面以STM32F407ZGT6單片機來講解一下來擴展外部SRAM。

原理:給STM32芯片擴展內存與給PC擴展內存的原理是一樣的,只是PC上一般以內存條的形式擴展,內存條實質是由多個內存顆粒(即SRAM芯片)組成的通用標准模塊,而STM32直接與SRAM芯片連接。

SRAM,型號IS62WV51216,管腳圖如下:

IS62WV51216的管腳總的來說大致分為:電源線、地線、地址線、數據線、片選線、寫使能端、讀使能端和數據掩碼信號線

從這個圖中我們可以看出IS62WV51216有19根地址線和16根數據線,從這些數據中我們可以分析出IS62WV51216的存儲大小為1M,那么這個1M是怎么分析出來的呢?

我們得來說說IS62WV51216的存儲原理。首先,我們來談一談一般的SRAM的存儲原理:

sram的存儲模型我們可以用矩陣來說明:

SRAM內部包含的存儲陣列,可以把它理解成一張表格,數據就填在這張表格上。和表格查找一樣,指定一個行地址和列地址,就可以精確地找到目標單元格,這是SRAM芯片尋址的基本原理。這樣的每個單元格被稱為存儲單元,而這樣的表則被稱為存儲矩陣。地址譯碼器把N根地址線轉換成2的N次方根信號線,每根信號線對應一行或一列存儲單元,通過地址線找到具體的存儲單元,實現尋址。如果存儲陣列比較大,地址線會分成行和列地址,或者行、列分時復用同一地址總線,訪問數據尋址時先用地址線傳輸行地址再傳輸列地址。

但是呢?你會發現,這個原理好像不太適用於IS62WV51216,為什么呢?

其實不然,因為我們使用的SRAM比較小,IS62WV51216沒有列地址線。它只有19根行地址線,那么,我們就可以這么來解釋:IS62WV51216有16根數據線,也就是說它的數據寬度為16位,一個行地址也就對應16位,即2字節空間。好,那現在來計算一下IS62WV51216有多少個行地址。2的19次方等於512K,在512K的基礎之上在乘我們之前計算的2字節,不正好是1024K,也就是1M嗎?1M后面的單位是B,即Byte,而不是Bit哦。這樣的話你就會發現IS62WV51216這個名字中本身就包含了大量的信息:IS62WV51216共有512K個行地址,數據寬度為16位,再加以計算就可以得到它的存儲大小為1M啦,有趣吧!

 

FSMC的簡介

FSMC是Flexible StaticMemory Controller的縮寫,就是靈活的靜態存儲控制器。它可以用於驅動包括SRAM、NOR FLASH以及NAND FLSAH類型的存儲器。其他我們不用管,從上面我們可以總結的是,stm32雇佣FSMC這個管家來管理我們的IS62WV51216。來來來,我們來看看FSMC的廬山真面目:

蒙了吧!又是這么多信號線,不要怕,我們還是來總結歸納一下。我們FSMC控制SRAM為例來說明:通過查看STM32F103系列的參考手冊:

你會發現居然和SRAM中的線居然高度統一(那是當然喏,我們就是講的FSMC嘛!)

  1. FSMC_NBL[1:0]分別對應於LB#、UB#,有什么用呢?提供數據掩碼信號。具體是怎么回事呢?還記得前面提到的行地址線嗎?

    一根行地址線對應16位的數據,我們可以把16位的數據分為高字節和低字節。當要訪問寬度為16位的數據時,使用行地址線指出地址,然后把UB#和LB#線都設置為低電平(FSMC_NBL0和FSMC_NBL1為低電平),那么I/O0-I/O15線(FSMC_D0到FSMC_D15)都有效,它們一起輸出該地址的16位數據(或者接收16位數據到該地址);當要訪問寬度為8位的數據時,使用行地址線指出地址,然后把UB#(FSMC_NBL0)設置為低電平,I/O8-I/O15(FSMC_D8到FSMC_D15)會對應輸出該地址的高8位,I/O0-I/O7的信號無效(或者把LB#(FSMC_NBL1)設置為低電平,I/O0-I/O7(FSMC_D0到FSMC_D7)會對應輸出該地址的低8位,I/O8-I/O15的信號無效。這樣是不是有一部分信號沒有用呢?好像被掩蓋了。因此它們被稱為數據掩碼信號。

  2. FSMC_NE[1:4]是個很有趣的東西,它決定了FSMC可以控制多個存儲器。這里就要提及FSMC的地址映射啦!

首先,有一點我們必須明白,對於32位的stm32單片機來說,它能夠管理的地址大小為4GB,而stm32將4GB的地址空間中的0x60000000到0x9FFFFFFF共1GB的空間分給外部內存,所以這1GB的空間就成了我們的小天地,供我們自由玩耍。然后強勢的FSMC就接管了這1GB的空間,FSMC將圖中的1GB大小的External RAM存儲區域分成了4個Bank區域,每個Bank對應於stm32內部尋址空間的不同地址范圍。那么為什么要分為不同的Bank區域呢?因為不同的Bank可以來管理不同的外部存儲設備,比如NOR Flash及SRAM存儲器只能使用Bank1的地址,NAND Flash存儲器只能使用Bank2和Bank3的地址,等。

細心的你肯定還會發現,每個Bank中居然還有4x64MB這種文字,這是什么意思呢?

Bank內部的256MB空間又被分成4個小塊,每塊64M,各自有相應的控制引腳用於連接片選信號。FSMC_NE[4:1]信號線就分別對應圖中的FSMC bank1 NOR/PSRAM4到FSMC bank1 NOR/PSRAM1。當STM32訪問0x6C000000-0x6FFFFFFF地址空間時,會訪問到Bank1的第3小塊區域:FSMC bank1 NOR/PSRAM3相應的FSMC_NE3信號線會輸出控制信號(即片選信號),如果這個時候FSMC_NE3處剛好接上IS62WV51216的CS端,那么IS62WV51216就可以任由我們擺布啦。因此,對於你使IS62WV51216來說,一定要注意你的CS端是接的FSMC的哪個FSMC_NE端,這決定你在程序訪問哪個地址范圍。

下面來說一下在stm32F407中SRAM的硬件連接:對於FSMC來說,它已經集成到了單片機內部,它的提供給的管腳已經確定了,是不能改動的,這個可以參考STM32對應芯片的Datasheet。唯一具有靈活性的就是FSMC_NE,具體用哪個FSMC_NE管腳來和你的SRAM相連,當然是你的自由,但是不要忘了,你要找到你選的FSMC_NE所對應的地址范圍,不然寫程序的時候就搞不清喏!

 

一、配置啟動文件

我們使用官方標准庫,拷貝標准庫FSMC例程里面的"startup_stm32f10x_hd.s"文件(工程使用103ZE,若使用互聯型芯片拷貝對應文件),替換掉我們之前工程的啟動文件,如下圖:

 

二、配置FSMC

我們使用官方標准庫里面"system_stm32f10x.c"文件里面現成的函數接口(使用寄存器配置)來配置FSMC,只需要打開"system_stm32f10x.c"文件里面第122行的宏"DATA_IN_ExtSRAM",見下圖:

 

三、分配RAM

RAM地址的分配是由編譯器完成的,因此需要對工程進行相應配置,就是使用外部RAM,見下圖:

 

四、測試函數說明

該函數位於main.c文件下面;

這個函數主要就是對上面配置及整改工程的測試。定義一個全局變量和一個局部變量,通過串口打印出他們的地址就可以判斷運行內存是使用外部還是內部。

 

五、打印(測試)結果

看了測試函數就知道依次打印出來的數據是什么,這里我們很明顯的可以看到打印出的地址是0x6800xxxx,這里的0x6800xxxx地址數據就是外部SRAM地址(不懂的話,請看昨天的講解),說明運行內存確實是外部SRAM.

 

六、變量定位定義

對於一個使用單片機內部 RAM 的訪問相當容易,基本上定義變量是不需要思考其定位問題的,當把外部 SRAM 考慮進來時,則需要考慮內部及外部的問題;比如,如何讓一個變量定位在內部或者外部 RAM;定位於內部是如何訪問,定位於外部時又如何訪問。這里說的是一個變量,或者一個數組的定位問題,當涉及到一個文件或者多個文件其內部所有變量的定位問題就復雜得多了。變量定位定義的一般方法(使用__attribute__)。

一般的定義方法如下圖:

圖1

定義了 3 數組(屬於公共變量),現在檢查下對應的 map 文件如下圖所示:

圖2

如上圖的 2998 行 3012 行 3013 行可見與上面定義的位置是對應的,所以這樣實現了變量定義的定位功能;當內部 RAM 不足時或者有意定義一個變量定位到外部 RAM 中就可以采用這種方法(使用外部 RAM 有前提條件這里就不說了)。

 

七、批量定義變量到外部 SRAM

如何實現批量的變量定義到外部 RAM 呢?除了批量地使用__attribute__定義變量,還是有更快捷的方法的。

配置外部 SRAM 可用起始地址及大小—如下圖:

圖3

 

圖4

如上圖 所示,最左最右邊的小方框不要打勾…千萬不要打勾,開始地址及大小必須如實填寫(Size 的值可以小於但絕對不能大於實際外置芯片值),開始地址安裝原理圖連線確定其值。

 

八、定義一個文件內的所有變量於外部SRAM

首先定一個小目標:確定你要一個所有變量需要定位於外部 SRAM 的文件,接着按照下圖來配置(這里讓 main.c 這個文件,讓里面定義的所有變量均定位於外部SRAM 中)在工程窗口選擇 main.c 點鼠標右鍵如下圖:

圖5

 

菜單選擇第一行"Options for File 'main.c' "之后顯示如下圖:

圖6

如上圖我們僅需關注"Memory Assignment"組,Code/Const 定義代碼及 const 的定位,Zero Initialized Data 及 Other Data 是變量的定位,此處我們關心的僅數據(變量)部分的定位。定位設置如下圖:

圖7

至此,main.c 文件內部的所有變量均已定位到外部 SRAM 中(前提是沒忘記點 OK 按鈕),到這里應該會發現一個問題如圖 7 每一項都有一個<default>選項;在 keil 的工程里每個文件的變量安排都會有一個默認選項,當這里選擇<default>時則會啟用如圖3 所示的默認選項,可以看到圖 4 那里,說到千萬不要打勾的那里。打勾的話那里就變成了第一默認選項,那么圖 7 的配置就多余了。這個是可以驗證的。那么再回頭驗證一下圖 7 的配置是否實現了將 main.c 文件中的變量定位到外部 SRAM…..同樣查看MAP 文件驗證一下。首先在 main.c 中定義變量如下圖:

圖8

如上圖所示定義了一個結構體實例,兩個 16 的數組,對應 map 文件如下圖:

圖9

如上圖所示, 3009 行 3010 行使用__attribute__定義占用了外部 SRAM的部分地址,《main.c》文件中並沒有使用__attribute__來定義變量,其定位也處於外部 SRAM 中,其數組的大小定義與 map

文件是一致的,在此證明經過配置之后,在 main.c 文件中定義的變量均會被定位到外部 SRAM 中。再驗證 GraphicsDac_t 的大小。printf(" GraphicsDac_t size=%d \r\n",sizeof(GraphicsDac_t));

圖 10(可見 printf 的大小與 map 的大小是一致的)

 

九、將變量定義到內部SRAM

參考圖 3,將內部 SRAM 的《default》打勾,之后將圖 7 的下兩個選項配置為《default》即可,這樣實現一個文件其變量定位的切換。多個外部 SRAM 芯片時適當參考配置。

 

十、定位到外部 SRAM的變量的訪問方法

方法一、一般訪問外部 SRAM 的方法

首先使用 SRAM_Init();之后使用下面兩個函數讀寫外部 SRAM:

SRAM_ReadBuffer(uint16_t* pBuffer, uint32_t ReadAddr, uint32_t NumHalfwordToRead)

SRAM_WriteBuffer(uint16_t* pBuffer, uint32_t WriteAddr, uint32_t NumHalfwordToWrite)

方法二、編譯器

如第 3 節變量定位定義方法,變量的訪問就由編譯器自己搞定了(關於這一點還沒有實際硬件驗證---這里僅是理所當然的推測,至於還要使用方法一是不可思議的),變量的讀寫就和內部變量一樣操作。

 

備注:文件內部函數內部的變量被定義在堆棧里,同時說明上面所說的定位到外部 SRAM 的變量均為全局變量,其文件內的局部變量還是在堆棧里(此處為我的推測,沒經過驗證)。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM