章節說明
STM32 IAP固件升級實驗分為一下的章節(加粗的字體是本章節的內容):
一、Flash和RAM的區域划分、工程建立、程序分散加載、程序燒寫
二、Stm32 bootloader、application、firmware 程序的分析和編寫
三、使用DMA收發串口的不定長數據
四、通信協議的設計
五、STM32 IAP程序的設計
六、上位機的程序的編寫
一、Flash區域的划分
1.區域划分
- 實驗使用的是 STM32F103VET6型號的MCU。這個單片機的型號的內部flash的大小是512Kb, RAM的大小是64Kb。
- 因為一般使用的都是flash的啟動方式(即flash 的起始地址
0x0800 0000被映射到0x0000 0000。STM32的啟動方式可以查看《STM32中文參考手冊》) 所以flash的區域划分如下:

2. flash 分區說明
0x0800 0000到0x0800 b7FF地址的flash塊划分給bootloader,大小是46kb0x0800 B800到0x0800 BFFF的flash塊划分為參數表(parameters),大小是2Kb0x0800 C000到0x0804 3FFF的flash塊划分為應用程序區 (application),大小是224Kb0x0804 4000到0x0807 BFFF的flash塊划分為程序升級區 (update region),大小跟應用程序區一樣 224kb0x0807 C000到0x0807 FFFF的flash塊划分為固件區(firmware),大小是16Kb
3. 每個分區作用
bootloader啟動加載程序,主要用來加載和啟動應用程序,還有更新應用程序parameters主要用來記錄信息,bootloader 和 application 的信息交互application應用程序區,主要用來實現所需要的業務的程序update region程序更新區,主要存放更新下載的程序,當然也可以直接下載到application區,但是如果更新失敗了,應用程序就不能執行了。所以單獨划分一塊區域,存放更新下載的序,更新完后再覆蓋到application然后復位運行firmware固件區,主要存放一些函數接口,用戶可以通過函數指針直接調用。像tiny-4412、smart210、esp32等這些板子的芯片在irom里面都提供了一些函數接口,通過地址可以直接調用這些函數。
二、RAM內存的划分
1、區域划分
RAM(內存)的起始地址是
0x2000 0000,大小是64Kb。在實驗主要將它划分為兩塊。一塊是從0x2000 0000到0x2000 FBFF大小是63Kb。另一塊是從0x2000 FC00到0x2001 0000大小是 1Kb,划分如下圖

2、區域的作用
- 63Kb這塊內存區域主要是用於
bootloader和application應用程序的可讀可寫段(RW),未初始化或者初始化為0的數據段(ZI)、堆空間、棧空間- 1kb這塊內存區域主要是用於
firmware區域的可讀可寫段(RW),未初始化或者初始化為0的數據段(ZI)- 注意:firmware因為沒有初始化堆,所以不能使用malloc這類堆內存管理函數。
3、簡單說明
- 因為STM32的flash 是norflash 讀的時候可以像內存一樣讀,但是寫的時候不能像內存那樣子寫,所以這些 RW 段 ZI 段都是加載到內存里。加載到哪里,這是由分散加載文件
.sct文件(和鏈接腳本一個意思)里面說明。至於怎么加載 ,stm32 函數庫的start_up.s文件的__main 到 main函數的過程就是加載數據到RAM空間。后面再介紹.sct文件
三、工程建立
工程中需要三個project,分別是 bootloader application firmware 如下圖:

四、分散加載
因為程序存放在不同的區域了,並且每段區域的程序是獨立的,所以在鏈接每個程序的時候需要告訴連接器,程序怎么放,程序加載啟動的時候又應該怎么加載,堆區和棧區的位置這些都要告訴鏈接器。我們可以通過分散加載文件
.sct 文件來告訴鏈接器。下面來看一下這個文件
1.原來的分散加載文件
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
;LR_IROM1 段名/域名
;0x08000000 程序加載的起始地址
;0x00080000 加載域的大小
LR_IROM1 0x08000000 0x00080000 { ; load region size_region
;ER_IROM1 執行域的名稱
;0x08000000 程序的執行起始地址
;0x00080000 執行域的大小
;一般程序是在 flash 里面運行的所以 程序的執行地址等於加載地址,如果想要讓程序運行在RAM中,執行地址修改為RAM的地址
ER_IROM1 0x08000000 0x00080000 { ; load address = execution address
;下面就是指定某些段怎么鏈接了
*.o (RESET, +First) ;鏈接的時候最先存放的是 所有.o文件的RESET段,緊跟的是First段(RESET段在start_up.s文件中有定義)
*(InRoot$$Sections) ;然后存放 __main 到 main的這段代碼,這段代碼主要是將flash的RW和ZI段加載到RAM中
.ANY (+RO) ;緊跟着的是所有文件的只讀數據(RO段),一般是向量表、代碼段和常量(字符串常量,和const修飾的數據)
}
;RW_IRAM1 可讀可寫數據的段名
;0x20000000起始地址
;0x00010000大小
RW_IRAM1 0x20000000 0x00010000 { ; RW data
.ANY (+RW +ZI);緊接着的是(RW段),(ZI)段
}
}
Region的名稱可以自己定義或者修改,重要的是地址要分配對就可以了。
Heart_of_Eagle這位博主有一篇比較詳細的博文值得參考,不過不是MDK的sct文件的,原理都是大同小異
MDK也是有詳細的幫助文檔,不過是純英文的,想用好sct可以閱讀里面的內容
1.
2.
2.修改bootloader的分散加載文件
根據上面的flash和RAM的划分修改sct加載文件,如下代碼塊:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
;因為bootloader是第一個啟動的程序,而且機器上電復位的時候是從0x0800 0000開始執行(因為被映射到了0x0000 0000)地址
;所以bootloader加載域的起始地址和執行地址都是0x0800 0000
; 0x0000B800域的大小(46kb)也是通過上面的設計的分區來填寫
LR_IROM1 0x08000000 0x0000B800 { ; load region size_region
ER_IROM1 0x08000000 0x0000B800 { ; load address = execution address
;里面段的存放位置使用默認的就可以
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
; 0x20000000 這個也是根據上面的RAW的分區填寫,
;0x0000FC00 大小是 63Kb
RW_IRAM1 0x20000000 0x0000FC00 { ; RW data
;段的存放位置使用默認的就可以了
.ANY (+RW +ZI)
}
}
3.修改application的分散加載文件
修改如下,跟bootloader一樣,就不啰嗦了
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x0800C000 0x00038000 { ; load region size_region
ER_IROM1 0x0800C000 0x00038000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x0000FC00 { ; RW data 0x0000FC00
.ANY (+RW +ZI)
}
}
4.修改firmware的分散加載文件
*(InRoot$$Sections)被注釋掉了,因為firmware的程序是沒有__main到main函數部分的代碼的。下一章節寫程序的時候會有講解。其他的內容也跟bootloader文件差不多,上面的分區來寫就可以了
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x0807C000 0x00004000 { ; load region size_region
ER_IROM1 0x0807C000 0x00004000 { ; load address = execution address
*.o (RESET, +First)
;*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x2000FC00 0x00000400 { ; RW data
.ANY (+RW +ZI)
}
}
5. 注意事項
在MDK的默認設置里,鏈接的時候是不使用分散加載文件的
xxx.sct文件。要使用xxx.sct文件需要將下面的設置去掉
五、程序的下載設置
- 由於本章還沒實現IAP這部分的程序,所以
bootloader、application和firmware的程序都是使用燒寫器來燒寫到falsh的不同區域。所以需要設置一下。- 設置的地址跟大小也是根據上面的flash分區來設置的。
- 主要設置MDK里面的
Debug -> Flash Download的這兩個地方,設置完這里就可以用Jlink將不同的程序燒寫到不同的區域了。- 下圖是
bootloader的設置,其他兩個也是根據實際來設置
六、實驗現象
說了這么多先來個實驗現象吧, 對於下面的程序分析和編寫就下一章再寫了。
工程文件已經上傳到碼雲---->點我project!!!
代碼可能存在問題,有問題可以留言討論。
hello bootloader是在bootloader運行的時候打印出來的,打印完后就跳到應用程序執行了num = 10和num1 = 0這兩個值是通過函數指針調用firmware固件區的函數接口來獲取的- 打印完上面的兩個值之后循環打印
hello app
現象如下圖:





