章節說明
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
現象如下圖: