STM32外部存儲器使用資料,很有參考價值
最近在學習一些gui方面的操作,并且是要跑os的;突然就發(fā)現(xiàn)自己的硬件平臺的內(nèi)部SRAM資源不夠用了(硬件平臺:戰(zhàn)艦V2,stm32f103ze、外擴SRAM:1M);怎么破,那只能把外部的SRAM給用起來,不用就是浪費啊,要知道SRAM可是不便宜; 然后就開始借鑒了配套例程:外部SRAM的使用;通過fsmc來控制實現(xiàn),外部sram可以正常使用了,但是我想嘗試下其他的方法來使用外部的SRAM: 1、 不使用attribute關(guān)鍵字來實現(xiàn)變量等在外部的分配,讓編譯器自己來完全支配,這樣我們就不用計算我們指定的地址是否會重合等問題; 2、 讓內(nèi)部的64K SRAM、外部的1M SRAM都能用,而且讓編譯器自己處理使用; 3、 完全不使用內(nèi)部的SRAM,只使用外部的SRAM
上網(wǎng)上查閱一些資料后,發(fā)現(xiàn)這個需要在2010年就有了,而且當時網(wǎng)友遇到的問題,我在實驗中也遇到了,關(guān)鍵是前面的帖子,也沒有很明確或是清晰的給出解釋,有的帖子給的方法是可以實現(xiàn)要求的,但是沒有說為什么這樣可以,所以我自己一邊實驗一邊驗證,下面把自己遇到的問題和現(xiàn)象做一個記錄: 1、 按照網(wǎng)友的方法來配置,讓編譯器自動處理SRAM的使用 (1) 實驗前提,例程采用配套例程的:37外部SRAM實驗;外部SRAM的初始化使用system_stm32f10x.c官方提供的fsmc初始化; (2) 工程配置 開啟system_stm32f10x.c中的fsmc初始化外部SRAM函數(shù); 配置工程中SRAM的分配,注意:SRAM部分有兩塊,兩個√ 注意去掉main文件中的testsram[]的屬性定義 (3) 實驗結(jié)果,程序正常執(zhí)行; 鏈接加載控制文件內(nèi)容: 工程的map文件,如果對map文件不熟悉的可以自行查閱資料 是不是很明顯:一大堆的變量和數(shù)據(jù)段都分配在了內(nèi)部的SRAM,只有一個.bss段分配到了外部的SRAM 0x68000000地址處,為什么會這樣,因為內(nèi)部放不下了啊,另外咱們的testsram數(shù)組是沒有初始化的,你試一下在定義時就初始化,看看地址有什么變化;要理解這里的原理,就需要對分散加載文件有深入的了解了,自行查找;
2、 完全不使用內(nèi)部SRAM,只使用外部SRAM (1) 工程配置和上面的實驗一致,只修改一個部分,去掉內(nèi)部SRAM的配置 (2) 編譯測試 編譯是沒有任何問題的,下載驗證吧,程序跑不起來,失敗了; 在線jlink調(diào)試一下: 看到了吧,死在這里和,硬件fault了;先不解釋為什么; (3) 解決問題的過程 之前在網(wǎng)上搜到一些建議,但是我還是選擇了,先用jlink調(diào)試一下看看; 我在用jlink在線調(diào)試操作過程是: 第一步:單步調(diào)試,看一下是哪里進入了硬件fault;我在void SystemInit (void)函數(shù)中增加了一些調(diào)試 目的是看一下,這的fsmc對外部的SRAM的操作是否正確,結(jié)果是正確的,說明官方的fsmc初始化沒有問題,此時外部的SRAM已經(jīng)可以正常使用了; 第二步:繼續(xù)單步調(diào)試,發(fā)現(xiàn)是在這個地方進入了硬件fault了:static void SetSysClockTo72(void)函數(shù)的退出時 到這里你在執(zhí)行單步一次,就會進入硬件fault,可以確定了是在函數(shù)返回時進入硬件fault,這里先不解釋原因;
第三步:我借鑒了一下網(wǎng)友的建議,如下: 工程配置不用改動任何地方,還是只配置外部SRAM作為唯一的選擇,注意這里和 的配置是不一樣的,它的同時配置了外部和內(nèi)部SRAM,如果這樣那他所做的操作就有些多余了,不用修改啟動文件就可以啊,就和我上面第1中的工程配置一樣啊,編譯器自己就可以處理了,不用你在修改啟動文件啊,這也是該貼下面很多網(wǎng)友說不用修改啟動文件中的 __initial_sp EQU 0x20000000 + Stack_Size 也可以正常運行;如果你按照下面的工程配置,再不添加啟動文件中的__initial_sp EQU 0x20000000 + Stack_Size設(shè)置,你試一下可以正常運行嗎?答案是:不能; 工程配置不變: 修改啟動文件startup_stm32f10x_hd.s中的關(guān)于棧的位置定義:等價于強制把復(fù)位后的棧指針指向內(nèi)部的SRAM位置處
好了,其它一切不變,編譯下載吧
第四步:下載驗證 成功運行程序 Sct文件內(nèi)容:完全是把數(shù)據(jù)段放在了外部的SRAM中; Map文件內(nèi)容:所有數(shù)據(jù)段都在了外部SRAM上面;
到這里,你會有疑問吧,那我們剛才設(shè)置啟動文件中__initial_sp EQU 0x20000000 + Stack_Size的目的是啥啊,為啥在配置不變情況下,不加程序就不正常,加了就可以正常運行;后面解釋,先附張圖,自己先分析一下
這里分享一個巧合事件: 我在2、完全不使用內(nèi)部SRAM,只使用外部SRAM -> (3)解決問題的過程 -> 第三步 中給出的結(jié)論:如果你按照我的工程配置,只啟用外部sram配置選項,然后你又不設(shè)置啟動文件中棧指針的設(shè)置,程序是不會正常啟動的; 有的朋友可能在實驗中會出現(xiàn),即按照只使用外部sram配置,且不添加啟動文件設(shè)置,程序也正常啟動了,會說我的結(jié)論是錯的,其實結(jié)論是對的,你這個配置下能正常運行程序,完全是個巧合,下面給出巧合呈現(xiàn)方法: 第一步:按照下面的配置、下載、運行程序,系統(tǒng)正常運行,沒有任何問題
第二步:你為了推翻我的結(jié)論,在工程配置不變的情況下,只修改了啟動文件的配置,刪除了對棧指針的設(shè)置 接下來編譯、燒寫程序,進行驗證(注意這個過程前提是,你的平臺還在上次的程序下正常上電運行,這里直接按照第二步的設(shè)置編譯后,用jlink下載驗證,為了說明問題我把兩次的程序作了小處理,說明確實是連個不同的程序;上面的LCD上顯示是"WarShip ZG008",這里我們顯示是 "WarShip ZG009") 程序正常運行了,你的結(jié)論是錯的,別急:此時你把平臺的電源斷掉,在上電看看,程序能正常運行嗎,不能吧; 原因我還沒有深究,預(yù)估是,當你的平臺正常運行下,你用jilink在線下載程序時,外設(shè)的配置還會保持之前的狀態(tài),至少fsmc的配置沒有改變,仍然可以操作外部的sram,所以你刪除了啟動文件的配置后,下載程序仍正常運行,斷電后在上電,就不行了;這里只是我的猜測,還沒有驗證;
到這里,大家是否明白了,這一切的設(shè)置,是不是都離不開一個東西:sp
3、 上面實驗現(xiàn)象分析 第一步:要清楚,cm3的內(nèi)核是在上電后進入復(fù)位中斷處理,但是復(fù)位中斷的pc值可不是存儲在0x0000 0000 地址,而是下一個4字節(jié)的位置,0x0000 0000存儲的是sp的棧指針; 第二步:通過調(diào)試,你可以看到,程序進入上電復(fù)位中斷后,先跳轉(zhuǎn)到SystemInit()函數(shù),調(diào)試截圖如下: LDR R0, =SystemInit BLX R0 當單步執(zhí)行 BLX r0后,注意觀察左邊寄存器的變化,以及上面的匯編語句: 看到了:R13的sp值改變了,因為發(fā)生了函數(shù)調(diào)用,需要保存上下文環(huán)境,所有有PUSH的操作,切記,這里對棧進行了操作,即入棧,那么當你從systeminit()函數(shù)返回時,就要涉及到出站,這點很重要,這就是你進入硬件fault的根源;
第三步:分析上面工程配置1中的設(shè)置, 這種配置,你只改變了SRAM的配置,讓外部和內(nèi)部的都啟用,讓編譯器自己解決分配問題;通過map文件你可以很清楚:編譯器把大部分的數(shù)據(jù)段都還是放在了內(nèi)部SRAM中,包括主要的__initial_sp棧頂指針,只把一個很大的內(nèi)部sram放不下的main.c中定義的testsram[]放在了外部sram; 此時,堆棧指針在內(nèi)部sram中,所以在復(fù)位中斷中的函數(shù)調(diào)用引發(fā)的入棧、出?梢酝耆_\行;
第四步:分析上面工程2中的配置 這里分兩種情況,工程配置不變下,是否設(shè)置啟動文件的__initial_sp EQU 0x20000000 + Stack_Size; (1) 不修改啟動文件中的棧的設(shè)置 此時通過編譯后的map和調(diào)試文件可以知道: 當調(diào)用LDR R0, =SystemInit BLX R0 后會發(fā)生入棧的push操作,注意觀察此時的R13的數(shù)值:0x680F 4AF8;已經(jīng)指向了外部的sram; 此處發(fā)生了push入棧操作,但是重點是此時我們還沒有對外部sram進行操作啊,試問你這個入棧能成功嗎,不能,那么里面的數(shù)值是函數(shù)返回后的下一條PC值嗎,肯定不是,是個垃圾值;然后,你調(diào)用pop操作,將一個垃圾值給了PC,那只能進入硬件fault了;
那我們找到了問題的根源,那咋改進呢:首先要明白一點,開發(fā)板硬件上電復(fù)位前,我們是無法完成STM32對外部SRAM的配置,只能上電后進行配置了才可以使用。也就是說,只有正常的硬件復(fù)位序列完成后,我們可以在Reset_Handler(復(fù)位中斷服務(wù)程序)中完成對SRAM的配置,但是在這之前,局部變量和函數(shù)調(diào)用用到的Stack棧空間,我們都得使用STM32內(nèi)部SRAM,明白了這點,很重要; (2) 修改啟動文件,設(shè)置 __initial_sp EQU 0x20000000 + Stack_Size 此時,我們分析編譯后的map、調(diào)試信息: 注意觀察:此時的map中數(shù)據(jù)段信息,沒有__initial_sp的值;我們在看一下,調(diào)試時的信息: 很清晰:此時發(fā)生函數(shù)調(diào)用時,我們使用的棧指向了內(nèi)部的sram控件,R13 = 0x2000 0400;所以當發(fā)生push、pop操作時,數(shù)據(jù)都是正確的,PC也可以得到正確的數(shù)值,從而按流程執(zhí)行; 所以我們在啟動文件中添加的那一條:__initial_sp EQU 0x20000000 + Stack_Size很重要,就是強制把棧定義在了內(nèi)部的sram中了,雖然通過map文件我們可以看到,在外部的sram中我們也分配了heap、stack的空間,但是我們的sp指針沒有指向他們,其實這里還有很多擴展的空間;
到這里,分析完了,外部sram的用法,以及為什么會出現(xiàn)這種現(xiàn)象,其中涉及到map文件的解析;以及分散加載。Sct的知識,沒有做仔細分析,合理安排、設(shè)計分散加載文件可以讓你的工程的鏈接、加載更加符合你的設(shè)計要求,所以在工程設(shè)置中,IDE才允許我們設(shè)置使用自己定義的.sct文件;有時間,后面再細分析;
以上圖文的Word格式文檔下載(內(nèi)容和本網(wǎng)頁上的一模一樣,方便大家保存):
12 STM32的外部SRAM使用的總結(jié).docx
(1.78 MB, 下載次數(shù): 3)
2023-12-4 09:33 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|