BootLoader程序介绍
T2 K( E J' KBootLoader其实就是一段启动程序,它在芯片启动的时候首先被执行,它可以用来做一些硬件的初始化,当初始化完成之后跳转到对应的应用程序中去。例如,我们可以将Flash分为两个区,一个是启动程序区(0x0800 0000 - 0x0800 2000)大小为8K Bytes,剩下的为应用程序区(0x0800 2000 - 0x0801 0000)。芯片上电时先运行启动程序,然后跳转到应用程序区执行应用程序。/ @, k; b1 F- }' Q, o' T8 ~ Z+ h
6 G% |: j2 A" B, j( @9 k
源码实现! A- k( Q) p0 M, o
基本的BootLoader程序仅实现了代码跳转的功能,因此全部在main.c文件中实现。
7 v! z, l7 j( }* Z% s$ B' P% ^% W( G7 r3 y ]* \, W
源文件
6 w( Z! v# F4 B- /*/ i7 C5 p$ ~5 ?. ^" g
- ******************************************************************************& t+ h. @- r+ L4 T! n4 i6 F
- File: main.c
" a% C0 T" G( ]* c2 ~& {1 F( | - Info: Generated by Atollic TrueSTUDIO(R) 9.3.0 2020-09-07& C1 m- U1 k) a3 F8 S I; o& e4 a
- - X! G8 m9 `/ `* y# m/ y
- The MIT License (MIT)' ~; y9 Y' G% g
- Copyright (c) 2019 STMicroelectronics
8 l4 }0 Q" V! T
* g$ g. s8 w5 q( }% k6 ~! V- Permission is hereby granted, free of charge, to any person obtaining a copy
4 I6 y# c r1 \8 f- |5 U - of this software and associated documentation files (the "Software"), to deal
R* @% r- I2 j" w2 O - in the Software without restriction, including without limitation the rights# K+ n( i9 r$ O" i
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell) H1 d8 _% X# X `# e
- copies of the Software, and to permit persons to whom the Software is2 E% J. P4 {! s+ N
- furnished to do so, subject to the following conditions:( ]+ k: ?3 [/ S3 e- {
- s8 E! |& k! k0 s- The above copyright notice and this permission notice shall be included in all
w* L* ~' C) R2 ^4 O - copies or substantial portions of the Software.; d6 H+ I1 S% O9 `/ r
$ B9 I4 Y9 n7 U- C- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR2 E+ u+ b: Y7 o1 E0 \" ?, Y
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,8 i5 o* @$ S# M5 `6 H1 Q& ]# w7 I
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE# B7 e! \1 w( l2 v2 ]# J6 d% ~
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER7 P, y. j2 l5 \1 x1 ^
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,, M2 I4 p) K1 t- i Q
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
! P( X/ O* \+ D; A - SOFTWARE.
2 u( x& Y6 S7 I - 5 O4 d/ } r. A; C. k ]
- ******************************************************************************: B! C" J8 m& j; W/ E
- */
A# e1 L1 N; ^+ u. W2 N- u; I) n. n
/ R* O3 a8 E3 Q- /* Includes */+ F! ]4 J- r0 Q k
- #include "stm32f4xx.h"
% c& r! G8 W* T. O - #include "delay.h"% h! G& {# {( x0 {9 [3 F
- /* Private macro */# A* O3 b4 I$ | W: s! Y
- ( O9 b8 b# \, G
- //用户扇区从第5扇区的起始位置开始启动. ~0 z4 j/ U) p. b
- #define FLASH_APP_ADDR 0x080100002 p( T! v }2 K( t: C, V
- ' i' a- S4 M" l. n) u
- #define MCU_LED GPIOA_OUT(15)
# l% p$ N0 Y6 U. r; K! U - ' W; e0 M9 \, j9 Q2 I- |
- /* Private variables */. P# L" W& L6 {4 ^" _/ S0 V
- typedef void (*UserApplication)(void); //定义一个函数类型的参数.
& O. h& H! p$ K/ ~9 a5 ]4 R - . `$ G4 F2 p8 @( N' Z: H: y
- UserApplication userApp;- [! M$ |3 K, q t5 @
- + n Q! U8 ?3 @ g8 @( _; |5 I
- /* Private function prototypes */
2 [/ z6 o- |$ j: | - void ConfigLED( );
; ^ v- E: F# c1 H' P$ X - void SystemBooting(uint8_t times, uint16_t msDelay);
, c3 d; m4 L; u2 Q6 ^ - void IAPLoadApp(u32 appxaddr);5 C- a0 ~* ]4 Q+ p+ Q W, Y
" I' y: }/ P0 i9 {( v5 m- /* Private functions */
; b4 y% h3 E# @5 }: A7 @
, @' u8 B0 a' {5 ?8 f0 K
4 y: C/ H3 c8 P- /**7 y+ r+ T# x- k. T9 |" v7 B/ o0 g
- **===========================================================================
) M/ U! U2 y- y R. g, f3 P - *** M4 R3 y0 @# c' ` `" U% y
- ** Abstract: main program
2 O" c3 j- {. C$ p3 ?# e4 `, i - **/ _( u, F% _5 h
- **===========================================================================2 y$ C& ~# S/ {$ U) \% g; o0 c& _1 z
- */
4 d! ?4 W( |+ d+ J9 `; |/ n - int main(void)
7 b" H" x6 K5 ?$ I9 p - {
4 T4 M; B- c: q* @3 j - a1 Q; L% R0 d5 C- M7 y- F
9 D4 g5 Y& T% H% N/ u# {! W" [- /**
$ p! O; t6 ^8 D* S% H' I( ?8 ~9 K/ v0 { - * IMPORTANT NOTE!0 {0 j1 F5 A" G p
- * The symbol VECT_TAB_SRAM needs to be defined when building the project
; z, h" w1 o9 o O+ h - * if code has been located to RAM and interrupts are used.9 ~& A$ m# q0 [, |" @) w3 q: K: j
- * Otherwise the interrupt table located in flash will be used.; N" h5 w. t) h: e) j) v" n
- * See also the <system_*.c> file and how the SystemInit() function updates( Q s9 M$ G& m
- * SCB->VTOR register.: n/ b# e; S/ C, |! ]
- * E.g. SCB->VTOR = 0x20000000;
* r$ v, Q9 `0 r6 W2 W! s9 t - */
+ L6 k) |6 P" L# i - ; I' ~$ E) M# ~' U& A2 ^4 V, g
- /* TODO - Add your application code here */
3 ?/ I- W$ x' a' a7 i- u+ V1 b8 `
; c$ P5 y* ?! e5 Q# @4 F- delay_init();
, U% y" K% J: `, f# s9 `; \ - ConfigLED();# R. t8 `" g/ S& q0 d
- SystemBooting(5,100);
: u$ m' J2 r- G% U: _
0 z" f t3 q( U6 P- a9 E7 a- //从第五扇区起始位置开始加载应用程序
; z; {3 z8 w9 m( e - IAPLoadApp(FLASH_APP_ADDR);
: B9 A. V% n; f$ j$ ]' G! F9 j - ) d5 Z! ]4 l! @7 X" y
- while(1);
; S/ f: u# L! q' f- d - }$ e T1 t: o% D* _, C
- * |( b" R- L j4 \# n; I, v
- void ConfigLED( )
' l6 O! z: p7 Z - {
9 T& Z9 t8 p8 D# k6 R$ ] - GPIO_InitTypeDef GPIO_InitStructure;" I- a$ V& f6 m7 [8 Y+ m3 @+ b
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);$ H& ]/ m9 J/ i1 i4 ~, ]9 g! Y
- /**
( l/ A. r/ g: h9 b M' {0 d9 Q4 f: h - * System State LED( g8 a, h5 n; _4 c3 U6 @4 C8 t& o! ?
- */7 q) B& Y' r8 B, P3 y
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;$ l. J( [) v* s& A; j! Y
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;) U1 y0 B/ R: e8 `5 L
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;0 L- K! ?6 E2 R9 {
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;" C$ b* i+ c2 d9 N
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
3 s1 @% d7 I* R
! |; N, X! c- [/ I8 c- GPIO_Init(GPIOA, &GPIO_InitStructure);- B7 n$ R7 ^ l4 t8 m' {) \
- }
" b, d+ s5 w# \ - 5 E3 X4 U3 ~2 x8 U9 v2 w2 l* `- |% i
- void SystemBooting(uint8_t times, uint16_t msDelay)9 Z8 d3 @, e; e9 X% K7 S
- {+ s F0 x3 C" h" P! v6 U
- for (uint8_t i = 0; i < times; i++)
& s4 F# d' g" H8 b" n - {* [6 ? a3 x, }2 A; ]5 t
- MCU_LED = 0;
. i1 X, ]( { S - delay_ms(msDelay);6 M8 v( y) ~1 q* Z
- MCU_LED = 1;1 W5 g; J5 r; A( w7 O
- delay_ms(msDelay);
; l, c: t' O# ]0 | J$ B3 t - }
( F2 Q6 [0 d! x8 i& @* l; J4 q. f1 | - }- r5 d" I: h% ] H" ]' ]
- 7 u* }9 X3 ^! L, S8 \! s" N
- void IAPLoadApp(u32 appxaddr)
! y) x) e- C$ g - {
0 M8 v7 z5 y K) Q. ] - if(((*(vu32*)appxaddr)&0x2FF00000)==0x20000000) //检查栈顶地址是否合法.
, m# m% I% F- S3 b$ ~% D3 s& a+ n - {+ A) @! S4 Y" v; m/ w
- userApp=(UserApplication)*(__IO vu32*)(appxaddr+4); //用户代码区第二个字为程序开始地址(复位地址)
! i0 x7 R# \2 t4 o. ~( e - __set_MSP(*(__IO uint32_t*) appxaddr); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)4 E" L! n2 v2 q" U3 m# a
- userApp(); //跳转到APP.$ q! W& e* _& [2 @- O2 F+ R6 W
- }
" l) @/ { k# _6 ?1 S0 z - }
复制代码
. `, }; j, R5 Wstm32f4_flash.ld
+ Z: c" [9 W4 D设置BootLoader程序在flash中的位置为第1~2扇区,共32K空间。在笔者的项目中,第3~4扇区用来实现EEPROM的软件仿真,用户程序将从第5扇区开始启动。
# ]7 C' s! K# [2 @: i5 y4 z! K: \2 q4 m8 T$ K# v J, K
- /* Specify the memory areas */
6 Y6 P3 O- C% `" P$ e" L - MEMORY# S+ B2 |, O2 N
- {; A* r: W# g( m1 ^8 Y: {1 y5 I
- FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K9 V$ r! d4 r C `
- RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K- a5 R. G2 ~& T L4 K! l9 l
- MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K* L2 S( K$ I' v8 B1 f
- CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
% u O% \5 x* n3 b0 i5 ]( _) F - }
复制代码 0 N$ Q; t4 A: i( A0 O
使用指南
$ L' j0 d* a, I4 f9 P用户程序需要从第5扇区的起始位置开始下载,同时需要设置中断向量的偏移地址。
8 Q$ ^. q0 S* k1 L) p' {) v) A, |; }: t# p8 ?; `
设置用户程序下载位置(stm32f4_flash.ld)
9 B: J/ T! O" }在笔者的项目中,设置BootLoader程序在flash中的位置为第1~2扇区,共32K空间。第3~4扇区用来实现EEPROM的软件仿真,共32K空间。用户程序将从第5扇区开始启动。! o6 W5 y, W9 D
6 {* W- G6 Y g$ a
- /* Memories definition */
3 J) X! V0 L! N5 Y/ Y - MEMORY
+ ~1 A6 o- S1 f( C0 d- [ - {
) X8 T; B/ o! r9 A, ~" u - FLASH (rx) : ORIGIN = 0x8010000, LENGTH = 448K3 G4 V" p2 P0 z P' y
- RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
3 `% @7 q: G) b# \: z7 e! e+ U - CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K4 C7 f& l3 `2 z( A# c1 ~( g
- }
复制代码
, l, L2 G# K/ V: ^* C修改中断向量表偏移量7 z4 _: j# `& w" s
在"system_stm32f4xx.c"文件中,修改宏定义:
" ?5 I2 n' S; C i) o! A, ]- U7 @
! _, W2 C$ b- p; U) R$ a e( e- /*!< Uncomment the following line if you need to relocate your vector Table in
6 `' _4 R3 f9 W j' F - Internal SRAM. */# l2 R# N* H$ E
- /* #define VECT_TAB_SRAM */
! `) V. f0 b% Y8 Y+ x! x - #define VECT_TAB_OFFSET 0x10000 /*!< Vector Table base offset field.5 M0 B# y# Z/ O( |2 Z+ s( Z5 q. \1 p% u
- This value must be a multiple of 0x200. */
复制代码 * L3 z* O8 l) A, n. d6 f- U
在void SystemInit(void)中将会根据上述宏定义,设置中断向量表的偏移量:
2 [0 U+ q% O7 ?+ K6 o W. d8 j
& e, L }$ ~5 w: B- /* Configure the Vector Table location add offset address ------------------*/
3 G" D/ K4 p! T - #ifdef VECT_TAB_SRAM l; Y. B9 |& F. a" H2 W
- SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
; J! H4 p/ A$ \5 K w" K3 ]" t+ d - #else6 t' X0 j7 W( ]. o4 V7 W
- SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */7 @( v; u+ B5 g8 ~
- #endif
复制代码 0 k9 Z6 M& c+ s
+ _5 y- h" v, [
# {, l% h3 I% g
|