問題提出
大家不妨設想一下,cpu 的工作是什么,cpu 是沒有主觀意識的,它只會按照特定的指令執(zhí)行相應的操作,用專業(yè)術語來說就是: 取指 -> 譯碼 -> 執(zhí)行 ,譯碼和執(zhí)行肯定是在 cpu 內部進行操作的,并且前提是已經取到了指令。那現在問題來了,指令在哪?
cpu上電復位后執(zhí)行的第一步操作就是取指令
- 問題1:指令存儲在何處
我們在電腦上編寫的程序最終是要燒寫到芯片內部的 FLASH中(此處特指STM32)。
- 問題2:如何將可執(zhí)行文件燒寫至 FLASH 上
STM32 的啟動方式有很多種,從主存 FLASH 啟動,從 system memory 啟動,從 SRAM 中啟動。
- 問題3:從 SRAM 中啟動,為什么需要重新設置中斷向量表
接下來,我們將圍繞這三個問題進行解答
猜想
既然 cpu 上電復位后第一步操作就是取指令,那么這個指令肯定是存儲在掉電不丟失的存儲介質上(rom、flash)。
- 猜想1:指令存儲在掉電不丟失的存儲介質上
我們最終生成的、cpu可以執(zhí)行的可執(zhí)行文件肯定是要通過某種外設將用戶程序燒寫到 FLASH 上,這一點肯定是毋庸置疑的,因為 cpu 與外圍設備進行數據交互的時候是通過外設控制器來進行的。
- 猜想2:通過某種外設將可執(zhí)行文件燒寫至 FLASH 上
STM32 的 FLASH 基地址為 0X0800 0000 ,SRAM 基地址為 0X2000 0000??刹豢赡苁且驗檫@兩個存儲介質的地址不同,所以才要重新設置中斷向量表。
因為我們都知道,中斷向量表的首地址就是程序的入口地址。
- 猜想3:可能與基地址有關
實驗驗證
實驗前必備知識
1. XIP設備
eXecute In Place,即芯片內執(zhí)行,指應用程序可以直接在 flash 閃存內運行,不必再把代碼讀到系統(tǒng) RAM中。在我們的印象里,應用程序必須要從硬盤中加載到內存當中才可以被運行,但實際上應用程序是可以直接在flash 閃存運行的,也就是說,cpu 可以直接從 flash 中取出指令。對于 STM32 而言,它是有 XIP 設備的。
STM32F1 內存圖

如上圖所示,FLASH、SYSTEM MEMORY、OPTION BYTES 都是STM32內部的XIP設備。
F1 內存圖信息不是很全,再看下 F4 的內存圖。
STM32F4內存圖:

我們可以看到,不論是 F1 還是 F4,XIP 設備都屬于內存圖中的 BLOCK0 區(qū)域內。
這樣我們大概就知道了 STM32 內部的 XIP 設備在 0x0000 0000 ~ 0x1FFF FFFF 內。
上述的內存圖是通過映射的方式將芯片的框圖進行映射得到的,也就是說,上述這幅圖是為了開發(fā)人員更好地面向芯片編程而抽象出來的一幅圖。我們先來看下面這副圖
STM32F1框圖:

STM32F4框圖:

對比兩幅框圖可以看出,F4 比 F1 復雜很多,特別體現在外設上,架構還是差不多的。

紅色箭頭所指向的就是譯碼電路。
如果你學過微機原理,那么你肯定知道,外設是通過譯碼電路連接到地址總線上,每一個外設都有其相對應的內存范圍,當 cpu 發(fā)出的地址信息處于某一個外設的地址范圍內,就選中了該外設,cpu就可以與該外設進行數據交互。
一個外設對應一個內存范圍,那所有的外設結合起來,是不是就是對應一張圖了。
2. STM32 啟動配置
在 STM32F10xxx 里,可以通過 BOOT[1:0] 引腳選擇三種不同啟動模式。

在系統(tǒng)復位后,SYSCLK 的第 4 個上升沿, BOOT 引腳的值將被鎖存。用戶可以通過設置 BOOT1 和 BOOT0 引腳的狀態(tài),來選擇在復位后的啟動模式。
在啟動延遲之后, CPU 從地址 0x0000 0000 獲取堆棧頂的地址,并從啟動存儲器的 0x0000 0004 指示的地址開始執(zhí)行代碼。(這里先不驗證,在之后的博客中會進行驗證,但你需要記住,后面用的上)
因為固定的存儲器映像,代碼區(qū)始終從地址 0x0000 0000 開始(通過 ICode 和 DCode 總線訪問),而數據區(qū)(SRAM)始終從地址 0x2000 0000 開始(通過系統(tǒng)總線訪問)。Cortex-M3 的 CPU 始終從 ICode 總線獲取復位向量,即啟動僅適合于從代碼區(qū)開始(典型地從 Flash 啟動)。STM32F10xxx 微控制器實現了一個特殊的機制,系統(tǒng)可以不僅僅從 Flash 存儲器或系統(tǒng)存儲器啟動,還可以從內置 SRAM 啟動。
根據選定的啟動模式,主閃存存儲器、系統(tǒng)存儲器或 SRAM 可以按照以下方式訪問:
- 從主閃存存儲器啟動 :主閃存存儲器被映射到啟動空間(
0x00000000),但仍然能夠在它原有的地址(0x08000000)訪問它,即閃存存儲器的內容可以在兩個地址區(qū)域訪問,0x00000000或0x08000000。 - 從系統(tǒng)存儲器啟動 :系統(tǒng)存儲器被映射到啟動空間(
0x00000000),但仍然能夠在它原有的地址(互聯型產品原有地址為0x1FFFB000,其它產品原有地址為0x1FFFF000)訪問它。 - 從內置 SRAM 啟動 :只能在
0x20000000開始的地址區(qū)訪問SRAM(當從內置SRAM啟動,在應用程序的初始化代碼中,必須使用NVIC的異常表和偏移寄存器,重新映射向量表到SRAM中)。
一般情況下都是從主閃存模式啟動的,也就是用戶代碼被燒寫到 0x08000000 地址處。
內嵌的自舉程序 (Bootloader)
內嵌的自舉程序存放在系統(tǒng)存儲區(qū),由 ST 在生產線上寫入,用于通過可用的串行接口對閃存存儲器進行重新編程,也就是這個自舉程序在出廠的時候就已經固化了。大家可以想一下內嵌的自舉程序的作用是什么?想不出來也沒關系,后面會講到。
如果想要詳細了解這個自舉程序到底干了什么,可以看下官方文檔:
STM32 microcontroller system memory boot mode
3. 可執(zhí)行文件的形成過程
STM32 | hex文件、bin文件、axf文件的區(qū)別?
大家可以看下這篇博文,寫的還是挺不錯的!描述了最終燒寫到STM32中的可執(zhí)行代碼的形成過程。
4. 三種復位
- 硬件復位
顧名思義通過硬件給系統(tǒng)一個復位,比如在電路板上設計一復位電路,通過按下按鍵就可以給系統(tǒng)實現一個復位,而無論系統(tǒng)在執(zhí)行什么樣的程序。復位后初始化一些配置芯片,硬件復位的作用區(qū)域一般是全局的。
- 軟件復位
是通過軟件給系統(tǒng)一個復位信號,如低電平或許是高電平(具體看系統(tǒng)設置)來實現復位操作軟件復位一般是一些塊結構復位。
- 上電復位
系統(tǒng)在上電的瞬間就執(zhí)行復位操作, 上電復位里面包括硬件復位和軟復位的操作,硬件復位和軟復位是從上電復位里面的某點開始的啟動操作。
復位需要初始化CPU系統(tǒng),包括CPU和內存等。
驗證猜想
1. 驗證猜想-1
對于猜想1,其實不需要驗證。代碼肯定是要存儲在掉電不丟失的存儲介質上,否則,每次重新上電都要重新燒寫程序,這是與事實相反的。而在實驗前必備知識中,我們了解到 STM32 內部的 XIP 設備,那不就是代碼存儲的地方嗎?并且也在 STM32 啟動方式中詳細地描述了代碼存儲位置。
- 如果從主FLASH啟動,用戶代碼存儲在0X 0800 0000
- 如果從
SYSTEM MEMORY啟動,里面存儲的是Bootloader,是芯片出廠的時候就已經固化好了的,可以從中讀數據,但是不可以向其中寫數據,它的作用就是:將用戶程序通過可用的外設燒寫到指定的地址處,然后啟動STM32。 - 如果從 SRAM 啟動,用戶代碼存儲在
0X2000 0000
2. 驗證猜想-2
實驗前的必備知識中已經大概地描述了最終燒寫到 STM32 中的可執(zhí)行文件的形成過程,現在我們需要驗證的就是如何將可執(zhí)行文件燒寫到指定的存儲設備中去(假設是 FLASH,其實也可以是 SRAM)
我第一次使用 Flymcu(串口下載軟件的時候),我腦海里就有一個疑問,就是這個軟件到底是怎樣使得 STM32 將生成的代碼燒寫到內部 FLASH 上的。這真的是很不可思議!因為 STM32 上電復位后肯定是要執(zhí)行代碼的,可是我還沒有給它代碼呢,它怎么會運作呢?當時我真的很迷惑。
其實,STM32 出廠的時候 Bootloader(用于將用戶程序下載到 STM32 內部指定地址處的固件(程序))就已經固化在了 System Memory 上了,可讀寫無效。
從 STM32 啟動配置一節(jié)中我們知道,可以通過對 BOOT1 和 BOOT0 引腳上高低電平的改變從而實現 STM32 啟動方式的不同。

如上所說,Bootloader 存儲在 Sytem Memory 上,如果想要讓 Bootloader 運行(將用戶程序下載到指定內存地址處),那啟動模式肯定是要選擇以系統(tǒng)存儲器的方式啟動。
BOOT1 = 0 BOOT0 = 1 -> 系統(tǒng)存儲器模式
因此, 外部電路的設計的目的就是要能夠達到能夠對 BOOT1 和 BOOT0 引腳上高低電平改變的能力 。
接下來,我們就以正點原子的原理圖(探索者)為例,來看下 STM32 外部的電路到底是如何設計的,以及Flymcu 到底是怎樣控制 BOOT1 和 BOOT0 引腳上高低電平改變從而達到具有使得 STM32 從系統(tǒng)存儲器啟動的的神奇能力。

如上圖所示,這就是正點原子探索者一鍵下載電路。
一鍵下載電路涉及到模電知識,下面這篇文章寫的還不錯,并且還描述了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連接肯定是要發(fā)送特定的指令,并且當STM32接收到預先約定好的指令時,也會發(fā)送特定的回復。(和接頭的性質差不多)
注意:STM32 從 Bootloader 啟動到能夠與外部設備進行數據交互需要一定的時間,因此連接需要一定的時間
- 讀出關于芯片相關的數據
- 讀出選項字節(jié)
- 進行全片擦除,去除寫保護,再次重啟
Bootloader(有大佬能告訴我為什么) - 編寫程序,從
0x0800 0000處開始運行
上述的過程中,大家比較疑惑的地方就是,Flymcu 發(fā)送給 STM32 的指令到底是什么,這個指令肯定是事先就確定好的,在這個文檔中提及到了。
stm32 microcontroller system memory boot mode
這個手冊中的內容大家可以自己詳細地去看下,內容不多,我就粗略地說一下必要的知識點。
硬件連接需要(文檔中的第35頁)
通過串口與外部設備進行數據交互時STM32外部電路設計。

通過 DFU 與外部設備進行數據交互時 STM32 外部電路設計

還有其他的連接方式,我想表述的意思就是:
Bootloader 與外部設備進行數據交互的方式有很多種,不僅僅只有串口,只是由于硬件平臺有限(正點原子只有通過串口下載的接口(調試接口除外))而根據不同的交互方式,STM32 外部的電路設計又大不相同。
Bootloader啟動流程

從啟動流程中我們就可以得到Flymcu發(fā)送給STM32的特定連接指令為:0x7F。
STM32F40xxx/41xxx devices bootloader version

通過版本信息中紅色畫線部分可以得知,當 Bootloader 接收到相應的命令之后,就會連續(xù)發(fā)送兩個 response。我們這個時候再看下 Flymcu 中的輸出信息,

通過紅色畫線部分可以看出,Flymcu 接收到兩個來自 Bootloader 的信息。
此時,接頭成功?。。。。?/p>
接頭成功后肯定就可以進行數據交互了!??!
因此,我們最初的猜想是正確的:即 STM32 通過某種外設將可執(zhí)行文件燒寫至 FLASH 上(也可以是 SRAM)
驗證猜想-3
博客當中已經多次提及到,STM32 不僅可以從 FLASH 上啟動,還可以從 SRAM 上啟動。并且在STM32啟動配置中有一個小提示:從 SRAM 中啟動,需要重新設置中斷向量表。
中斷向量表的設置是用戶在用戶程序中自己實現的?。?!
要驗證這個猜想,可以從 SRAM 中啟動,但是不設置中斷向量表,看一下會出現什么情況。

由于正點原子的電路設計(因為我使用的就是正點原子的探索者開發(fā)板),使得無法通過串口進行 SRAM 啟動,只能通過調試接口下載程序。
注意:SRAM是掉電數據就會丟失的存儲器介質,因此使用時(前提是已經掉電)要重新下載程序從
SRAM中啟動的最主要的目的是用來調試程序,產品中的用戶程序肯定都是存儲在 FLASH 上的,不然每次掉電后用戶程序都沒了?。?!
如何通過調試接口將用戶程序下載到 SRAM 處,可以參考一下下面兩篇博文:
- STM32 內部 SRAM 調試程序
- 在 SRAM 中調試代碼
假設你現在已經實現了能夠通過調試接口將用戶程序下載到 SRAM 處,那么接下來,我們來驗證一下。如果沒有重新設置中斷向量表會出現什么結果。
得出結論,總結歸納
對于最開始提出的三個猜想,現在可以得出結論:
- 指令存儲在掉電不丟失的存儲介質上
- STM32 通過某種外設將可執(zhí)行文件燒寫至掉電不丟失的存儲介質上
- 中斷向量表的首地址就是程序的入口地址
注意: 通過串口下載程序,實際上是 Flymcu(上位機)與 STM32 內置的 Bootloader 進行數據交互,但兩者直接需要特定的硬件環(huán)境(CH340G(USB轉串口芯片))
注意: 內存圖中的 reserved 有些是不使用,有些是不能用(有其他重要的作用:可讀寫忽略),不可以修改其值
看完這篇博客,你的腦海里必須得有一個流程的框架:
- 用戶面向單片機編寫用戶代碼(C,C++,ASM)
- 用戶代碼通過交叉編譯工具鏈生成單片機可以執(zhí)行的可執(zhí)行文件(HEX,BIN,AXF)
- 上位機:各種燒寫工具(不局限于
Flymcu(因為Bootloader與外部設備進行數據交互不僅僅只是通過USART)))與單片機內部的Bootloader進行數據交互(目的是將可執(zhí)行文件下載到指定的存儲地址處)
將可執(zhí)行文件下載到指定存儲地址處,然后還會繼續(xù)等待上位機的 command,可以通過復位或上位機發(fā)送跳轉到用戶代碼入口地址的命令執(zhí)行用戶程序。
這個流程的框架總結一句話就是:
可執(zhí)行程序 -> cpu執(zhí)行第一條用戶代碼的流程
至于 cpu執(zhí)行第一條用戶代碼之后的流程后面的博客會詳細說明,但毋庸置疑的是,這是一個重要轉折點,在這個點之后執(zhí)行的是你自己編寫的代碼,你比較熟悉這個過程,但是在這個點之前,對大部分人來說都是都是比較陌生的,但是但你對這個過程了解之后,會對你的知識體系有非常大的提升。
-
STM32
+關注
關注
2307文章
11150瀏覽量
372422 -
代碼
+關注
關注
30文章
4956瀏覽量
73506
發(fā)布評論請先 登錄
詳細的STM32啟動配置流程解析
詳細分析嵌入式Linux系統(tǒng)啟動流程
BOOST的設計詳細流程
深入解讀STM32啟動詳細流程分析-上
BOSHIDA DC電源模塊檢測穩(wěn)定性能詳細流程
STM32啟動詳細流程分析
評論