問題提出
大家不妨設想一下,cpu 的工作是什么,cpu 是沒有主觀意識的,它只會按照特定的指令執行相應的操作,用專業術語來說就是: 取指 -> 譯碼 -> 執行 ,譯碼和執行肯定是在 cpu 內部進行操作的,并且前提是已經取到了指令。那現在問題來了,指令在哪?
cpu上電復位后執行的第一步操作就是取指令
- 問題1:指令存儲在何處
我們在電腦上編寫的程序最終是要燒寫到芯片內部的 FLASH中(此處特指STM32)。
- 問題2:如何將可執行文件燒寫至 FLASH 上
STM32 的啟動方式有很多種,從主存 FLASH 啟動,從 system memory 啟動,從 SRAM 中啟動。
- 問題3:從 SRAM 中啟動,為什么需要重新設置中斷向量表
接下來,我們將圍繞這三個問題進行解答
猜想
既然 cpu 上電復位后第一步操作就是取指令,那么這個指令肯定是存儲在掉電不丟失的存儲介質上(rom、flash)。
- 猜想1:指令存儲在掉電不丟失的存儲介質上
我們最終生成的、cpu可以執行的可執行文件肯定是要通過某種外設將用戶程序燒寫到 FLASH 上,這一點肯定是毋庸置疑的,因為 cpu 與外圍設備進行數據交互的時候是通過外設控制器來進行的。
- 猜想2:通過某種外設將可執行文件燒寫至 FLASH 上
STM32 的 FLASH 基地址為 0X0800 0000 ,SRAM 基地址為 0X2000 0000。可不可能是因為這兩個存儲介質的地址不同,所以才要重新設置中斷向量表。
因為我們都知道,中斷向量表的首地址就是程序的入口地址。
- 猜想3:可能與基地址有關
實驗驗證
實驗前必備知識
1. XIP設備
eXecute In Place
,即芯片內執行,指應用程序可以直接在 flash 閃存內運行,不必再把代碼讀到系統 RAM中。在我們的印象里,應用程序必須要從硬盤中加載到內存當中才可以被運行,但實際上應用程序是可以直接在flash 閃存運行的,也就是說,cpu 可以直接從 flash 中取出指令。對于 STM32 而言,它是有 XIP 設備的。
STM32F1 內存圖
如上圖所示,FLASH、SYSTEM MEMORY、OPTION BYTES 都是STM32內部的XIP設備。
F1 內存圖信息不是很全,再看下 F4 的內存圖。
STM32F4內存圖:
我們可以看到,不論是 F1 還是 F4,XIP
設備都屬于內存圖中的 BLOCK0
區域內。
這樣我們大概就知道了 STM32 內部的 XIP
設備在 0x0000 0000 ~ 0x1FFF FFFF
內。
上述的內存圖是通過映射的方式將芯片的框圖進行映射得到的,也就是說,上述這幅圖是為了開發人員更好地面向芯片編程而抽象出來的一幅圖。我們先來看下面這副圖
STM32F1框圖:
STM32F4框圖:
對比兩幅框圖可以看出,F4 比 F1 復雜很多,特別體現在外設上,架構還是差不多的。
紅色箭頭所指向的就是譯碼電路。
如果你學過微機原理,那么你肯定知道,外設是通過譯碼電路連接到地址總線上,每一個外設都有其相對應的內存范圍,當 cpu 發出的地址信息處于某一個外設的地址范圍內,就選中了該外設,cpu就可以與該外設進行數據交互。
一個外設對應一個內存范圍,那所有的外設結合起來,是不是就是對應一張圖了。
2. STM32 啟動配置
在 STM32F10xxx
里,可以通過 BOOT[1:0]
引腳選擇三種不同啟動模式。
在系統復位后,SYSCLK
的第 4 個上升沿, BOOT 引腳的值將被鎖存。用戶可以通過設置 BOOT1
和 BOOT0
引腳的狀態,來選擇在復位后的啟動模式。
在啟動延遲之后, CPU
從地址 0x0000 0000
獲取堆棧頂的地址,并從啟動存儲器的 0x0000 0004
指示的地址開始執行代碼。(這里先不驗證,在之后的博客中會進行驗證,但你需要記住,后面用的上)
因為固定的存儲器映像,代碼區始終從地址 0x0000 0000
開始(通過 ICode
和 DCode
總線訪問),而數據區(SRAM
)始終從地址 0x2000 0000
開始(通過系統總線訪問)。Cortex-M3
的 CPU 始終從 ICode
總線獲取復位向量,即啟動僅適合于從代碼區開始(典型地從 Flash 啟動)。STM32F10xxx
微控制器實現了一個特殊的機制,系統可以不僅僅從 Flash 存儲器或系統存儲器啟動,還可以從內置 SRAM 啟動。
根據選定的啟動模式,主閃存存儲器、系統存儲器或 SRAM 可以按照以下方式訪問:
- 從主閃存存儲器啟動 :主閃存存儲器被映射到啟動空間(
0x00000000
),但仍然能夠在它原有的地址(0x08000000
)訪問它,即閃存存儲器的內容可以在兩個地址區域訪問,0x00000000
或0x08000000
。 - 從系統存儲器啟動 :系統存儲器被映射到啟動空間(
0x00000000
),但仍然能夠在它原有的地址(互聯型產品原有地址為0x1FFFB000
,其它產品原有地址為0x1FFFF000
)訪問它。 - 從內置 SRAM 啟動 :只能在
0x20000000
開始的地址區訪問SRAM
(當從內置SRAM
啟動,在應用程序的初始化代碼中,必須使用NVIC
的異常表和偏移寄存器,重新映射向量表到SRAM
中)。
一般情況下都是從主閃存模式啟動的,也就是用戶代碼被燒寫到 0x08000000
地址處。
內嵌的自舉程序 (Bootloader)
內嵌的自舉程序存放在系統存儲區,由 ST 在生產線上寫入,用于通過可用的串行接口對閃存存儲器進行重新編程,也就是這個自舉程序在出廠的時候就已經固化了。大家可以想一下內嵌的自舉程序的作用是什么?想不出來也沒關系,后面會講到。
如果想要詳細了解這個自舉程序到底干了什么,可以看下官方文檔:
STM32 microcontroller system memory boot mode
3. 可執行文件的形成過程
STM32 | hex文件、bin文件、axf文件的區別?
大家可以看下這篇博文,寫的還是挺不錯的!描述了最終燒寫到STM32中的可執行代碼的形成過程。
4. 三種復位
- 硬件復位
顧名思義通過硬件給系統一個復位,比如在電路板上設計一復位電路,通過按下按鍵就可以給系統實現一個復位,而無論系統在執行什么樣的程序。復位后初始化一些配置芯片,硬件復位的作用區域一般是全局的。
- 軟件復位
是通過軟件給系統一個復位信號,如低電平或許是高電平(具體看系統設置)來實現復位操作軟件復位一般是一些塊結構復位。
- 上電復位
系統在上電的瞬間就執行復位操作, 上電復位里面包括硬件復位和軟復位的操作,硬件復位和軟復位是從上電復位里面的某點開始的啟動操作。
復位需要初始化CPU系統,包括CPU和內存等。
驗證猜想
1. 驗證猜想-1
對于猜想1,其實不需要驗證。代碼肯定是要存儲在掉電不丟失的存儲介質上,否則,每次重新上電都要重新燒寫程序,這是與事實相反的。而在實驗前必備知識中,我們了解到 STM32
內部的 XIP
設備,那不就是代碼存儲的地方嗎?并且也在 STM32
啟動方式中詳細地描述了代碼存儲位置。
- 如果從主FLASH啟動,用戶代碼存儲在0X 0800 0000
- 如果從
SYSTEM MEMORY
啟動,里面存儲的是Bootloader
,是芯片出廠的時候就已經固化好了的,可以從中讀數據,但是不可以向其中寫數據,它的作用就是:將用戶程序通過可用的外設燒寫到指定的地址處,然后啟動STM32
。 - 如果從 SRAM 啟動,用戶代碼存儲在
0X2000 0000
2. 驗證猜想-2
實驗前的必備知識中已經大概地描述了最終燒寫到 STM32
中的可執行文件的形成過程,現在我們需要驗證的就是如何將可執行文件燒寫到指定的存儲設備中去(假設是 FLASH
,其實也可以是 SRAM
)
我第一次使用 Flymcu
(串口下載軟件的時候),我腦海里就有一個疑問,就是這個軟件到底是怎樣使得 STM32
將生成的代碼燒寫到內部 FLASH
上的。這真的是很不可思議!因為 STM32
上電復位后肯定是要執行代碼的,可是我還沒有給它代碼呢,它怎么會運作呢?當時我真的很迷惑。
其實,STM32
出廠的時候 Bootloader
(用于將用戶程序下載到 STM32
內部指定地址處的固件(程序))就已經固化在了 System Memory
上了,可讀寫無效。
從 STM32
啟動配置一節中我們知道,可以通過對 BOOT1
和 BOOT0
引腳上高低電平的改變從而實現 STM32
啟動方式的不同。
如上所說,Bootloader
存儲在 Sytem Memory
上,如果想要讓 Bootloader
運行(將用戶程序下載到指定內存地址處),那啟動模式肯定是要選擇以系統存儲器的方式啟動。
BOOT1 = 0 BOOT0 = 1 -> 系統存儲器模式
因此, 外部電路的設計的目的就是要能夠達到能夠對 BOOT1
和 BOOT0
引腳上高低電平改變的能力 。
接下來,我們就以正點原子的原理圖(探索者)為例,來看下 STM32
外部的電路到底是如何設計的,以及Flymcu
到底是怎樣控制 BOOT1
和 BOOT0
引腳上高低電平改變從而達到具有使得 STM32
從系統存儲器啟動的的神奇能力。
如上圖所示,這就是正點原子探索者一鍵下載電路。
一鍵下載電路涉及到模電知識,下面這篇文章寫的還不錯,并且還描述了CH340G芯片引腳的作用和功能。
stm32一鍵下載電路(下一篇文章)
從上圖我們可以知道,Flymcu 肯定是通過 usb 線將數據或指令寫入 CH340G
內(CH340 D
+ CH340 D-
)然后CH340G
根據來自 usb 的指令進行相應的工作。
CH340G在此電路中的工作就兩個:
- 與STM32進行數據交互
- 控制BOOT0和RESET高低電平的變化
特別注意:正點原子探索者BOOT0和BOOT1引腳默認都是接地
BOOT0、BOOT1是通過跳線帽和地進行連接的
現在我們知道了,控制 BOOT1
和 BOOT0
引腳上高低電平改變是 CH340G
的作用,而 CH340G
是嚴格按照來自Flymcu 的指令進行的,所以,控制 BOOT1
和 BOOT0
引腳上高低電平改變的幕后黑手就是 Flymcu
。
注意:向 FLASH 中燒寫程序不僅僅只有串口,由于硬件平臺的限制,因此分析串口下載。
問題來了,那 Flymcu 到底干了什么,它是如何將用戶程序燒寫的 STM32 內部指定地址處?
以跑馬燈為例,看下Flymcu燒寫程序過程中輸出的信息。
DTR
電平置低:復位RTS
電平置高:進入 Bootloader- 延時
100ms
:有誰能夠告訴我為什么 DTR
電平置高:釋放復位RTS
維持高 :此時開始運行Bootloader
- 開始連接 :
Flymcu
要與STM32
連接肯定是要發送特定的指令,并且當STM32
接收到預先約定好的指令時,也會發送特定的回復。(和接頭的性質差不多)
注意:STM32
從 Bootloader
啟動到能夠與外部設備進行數據交互需要一定的時間,因此連接需要一定的時間
- 讀出關于芯片相關的數據
- 讀出選項字節
- 進行全片擦除,去除寫保護,再次重啟
Bootloader
(有大佬能告訴我為什么) - 編寫程序,從
0x0800 0000
處開始運行
上述的過程中,大家比較疑惑的地方就是,Flymcu
發送給 STM32
的指令到底是什么,這個指令肯定是事先就確定好的,在這個文檔中提及到了。
stm32 microcontroller system memory boot mode
這個手冊中的內容大家可以自己詳細地去看下,內容不多,我就粗略地說一下必要的知識點。
硬件連接需要(文檔中的第35頁)
通過串口與外部設備進行數據交互時STM32外部電路設計。
通過 DFU
與外部設備進行數據交互時 STM32
外部電路設計
還有其他的連接方式,我想表述的意思就是:
Bootloader
與外部設備進行數據交互的方式有很多種,不僅僅只有串口,只是由于硬件平臺有限(正點原子只有通過串口下載的接口(調試接口除外))而根據不同的交互方式,STM32
外部的電路設計又大不相同。
Bootloader啟動流程
從啟動流程中我們就可以得到Flymcu發送給STM32的特定連接指令為:0x7F。
STM32F40xxx/41xxx devices bootloader version
通過版本信息中紅色畫線部分可以得知,當 Bootloader
接收到相應的命令之后,就會連續發送兩個 response
。我們這個時候再看下 Flymcu 中的輸出信息,
通過紅色畫線部分可以看出,Flymcu
接收到兩個來自 Bootloader
的信息。
此時,接頭成功!!!!!
接頭成功后肯定就可以進行數據交互了!!!
因此,我們最初的猜想是正確的:即 STM32 通過某種外設將可執行文件燒寫至 FLASH 上(也可以是 SRAM)
驗證猜想-3
博客當中已經多次提及到,STM32
不僅可以從 FLASH
上啟動,還可以從 SRAM
上啟動。并且在STM32啟動配置中有一個小提示:從 SRAM
中啟動,需要重新設置中斷向量表。
中斷向量表的設置是用戶在用戶程序中自己實現的!!!
要驗證這個猜想,可以從 SRAM
中啟動,但是不設置中斷向量表,看一下會出現什么情況。
由于正點原子的電路設計(因為我使用的就是正點原子的探索者開發板),使得無法通過串口進行 SRAM
啟動,只能通過調試接口下載程序。
注意:SRAM是掉電數據就會丟失的存儲器介質,因此使用時(前提是已經掉電)要重新下載程序從
SRAM
中啟動的最主要的目的是用來調試程序,產品中的用戶程序肯定都是存儲在 FLASH 上的,不然每次掉電后用戶程序都沒了!!!
如何通過調試接口將用戶程序下載到 SRAM
處,可以參考一下下面兩篇博文:
- STM32 內部 SRAM 調試程序
- 在 SRAM 中調試代碼
假設你現在已經實現了能夠通過調試接口將用戶程序下載到 SRAM
處,那么接下來,我們來驗證一下。如果沒有重新設置中斷向量表會出現什么結果。
得出結論,總結歸納
對于最開始提出的三個猜想,現在可以得出結論:
- 指令存儲在掉電不丟失的存儲介質上
- STM32 通過某種外設將可執行文件燒寫至掉電不丟失的存儲介質上
- 中斷向量表的首地址就是程序的入口地址
注意: 通過串口下載程序,實際上是 Flymcu(上位機)與 STM32 內置的 Bootloader 進行數據交互,但兩者直接需要特定的硬件環境(CH340G(USB轉串口芯片))
注意: 內存圖中的 reserved
有些是不使用,有些是不能用(有其他重要的作用:可讀寫忽略),不可以修改其值
看完這篇博客,你的腦海里必須得有一個流程的框架:
- 用戶面向單片機編寫用戶代碼(C,C++,ASM)
- 用戶代碼通過交叉編譯工具鏈生成單片機可以執行的可執行文件(HEX,BIN,AXF)
- 上位機:各種燒寫工具(不局限于
Flymcu
(因為Bootloader
與外部設備進行數據交互不僅僅只是通過USART)))與單片機內部的Bootloader
進行數據交互(目的是將可執行文件下載到指定的存儲地址處)
將可執行文件下載到指定存儲地址處,然后還會繼續等待上位機的 command
,可以通過復位或上位機發送跳轉到用戶代碼入口地址的命令執行用戶程序。
這個流程的框架總結一句話就是:
可執行程序 -> cpu執行第一條用戶代碼的流程
至于 cpu
執行第一條用戶代碼之后的流程后面的博客會詳細說明,但毋庸置疑的是,這是一個重要轉折點,在這個點之后執行的是你自己編寫的代碼,你比較熟悉這個過程,但是在這個點之前,對大部分人來說都是都是比較陌生的,但是但你對這個過程了解之后,會對你的知識體系有非常大的提升。
-
STM32
+關注
關注
2270文章
10895瀏覽量
355743 -
代碼
+關注
關注
30文章
4779瀏覽量
68524
發布評論請先 登錄
相關推薦
評論