问题:1 d) h0 X2 |& o9 M7 X
有客户在初次使用 STM32 MCU IAP 的例程的,可能会对跳转到 APP 部分的函数的实现产生疑问 :9 [6 D" h+ u9 i, v( w; t
问题 1:JumpAddress 地址为什么指向 APPLICATION_ADDRESS + 4 ;
/ E' I& J9 o6 r7 ?: m2 q# HMSP 主堆栈指针为什么指向 APPLICATION_ADDRESS ;
" z1 W5 L' h! q& T+ r9 {问题 2:为什么需要做以下判断 :
3 j+ t9 V* ~: P8 @; k) n, P9 Q- if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
( s/ H& M# U5 y# P0 j6 ]9 S3 T5 Y% m - {6 O9 q1 {$ ^9 ?( Q# y
- }
复制代码
' Y) i$ v, l7 M, j6 p+ E H此 Tips 对于这两个个问题做简要分析.进行所以说主要代码如下 :& b9 R* e0 J0 r
. y) P( o7 @! K3 G" \. O$ _- /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */6 E* H1 T6 c3 ?6 s% l$ p
- if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
1 S' K3 N& q* ?4 u4 q3 e - {( |8 v3 b6 }+ K' d4 y; K
- /* Jump to user application */
+ |6 ?3 c/ e7 H - JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
6 T1 s) y- ~. n2 | ~& q - Jump_To_Application = (pFunction) JumpAddress;
A; @$ a- f; y$ N9 z - /* Initialize user application's Stack Pointer */
6 f. N0 ~/ X' \/ K7 \9 |* b1 ~ - __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
8 w- e8 `* _6 {6 R9 ^+ V - Jump_To_Application();9 }( C, o: E, W- J
- }
复制代码 4 i+ _) S) z' C" v7 q+ Q
调研:* I& g. _0 u3 G; G' g- Q
问题 1 分析 :
7 N5 u' U) ]" C. e1 {( J, b 从 startup_stm32f4xx.s 中的启动代码可以看出:程序开始第一条指令地址为 CSTACK,第二条指令地址为复位指令 ,参考代码中的红色部分(蓝色为注释);4 s; O9 P Y4 ~0 D7 x6 K! X4 L( |
& d( L# N* y5 \- |+ Y. E |/ s
- EXTERN __iar_program_start/ h2 F) P, | k. G+ o
- EXTERN SystemInit% ^# \& G3 U+ |+ a
- PUBLIC __vector_table
5 T; T: P; ~' w' X - DATA
; q* O+ {* ?! a5 `3 q - __vector_table
; v) ~. p# o1 j) o+ v+ O! H - DCD sfe(CSTACK) ; APPLICATION_ADDRESS
% N) x/ ?. n. z- \ - DCD Reset_Handler ; Reset Handler ; APPLICATION_ADDRESS + 41 n6 i2 D. ?" O: F7 }2 k0 F5 b
- DCD NMI_Handler ; NMI Handler+ Q% Z1 i9 B9 E
- DCD HardFault_Handler ; Hard Fault Handler8 U7 Z3 |6 H5 B2 |
- DCD MemManage_Handler ; MPU Fault Handler; ]1 |) n$ X, I0 t# Z
- DCD BusFault_Handler ; Bus Fault Handler* Q, I( F- R3 m V3 d3 x
- DCD UsageFault_Handler ; Usage Fault Handler
1 S! w. I5 g9 ~) j - DCD 0 ; Reserved& @* h+ n# p2 y( E7 j
- DCD 0 ; Reserved' [: l8 V8 N, u; W+ _; _
- DCD 0 ; Reserved6 j/ q6 K7 P- p. n$ p* c& x$ J& I
- DCD 0 ; Reserved
/ Z. L& Q5 s* B, ~+ l. n, U - DCD SVC_Handler ; SVCall Handler
' F+ x& d, K' w- E0 W! J# W - DCD DebugMon_Handler ; Debug Monitor Handler
$ E, g1 e P; x. s2 S3 [, q - DCD 0 ; Reserved2 D! O: c8 E9 ]1 |
- DCD PendSV_Handler ; PendSV Handler. [. r: m$ j! y; U
- DCD SysTick_Handler ; SysTick Handler
复制代码 2 m2 b8 S9 x* {) E9 i$ f
当程序启动时首先要执行复位程序,因此 JumpAddress 地址指向复位指令地址(即APPLICATION_ADDRESS + 4) ;
- \( a8 f L. E# \) t MSP 对应的是主堆栈指针,指向 CSTACK 地址(即 APPLICATION_ADDRESS).- h/ B* K- z6 ?' C
8 s) h2 i) {" c8 @6 O
问题 2 分析 :
7 S& x' X6 d) H, ~. H g
9 O# |3 e- r1 f ApplicationAddress 存放的是程序的主堆栈地址,CSTACK 堆栈地址指向 RAM,而 RAM 的起始地址是 0x20000000;
5 r# P4 D e3 z- O- E! q% d/ C* T6 K因此上面的判断语句执行:判断用户代码的堆栈地址是否落在:0x20000000~0x2001ffff 区间中,这个区间的大小为 128K.
6 e9 _% J# f5 c4 f' \1 E& t* @! k例程中使用芯片 RAM=128K,因此做上面的判断;如果芯片 RAM 比 128K 大的话,可以在此判断语句做调整.4 ]. Z% P. |- g4 c+ N
q$ u9 b' l5 g9 C; a$ ]
& }$ |# r# W" l- C+ D
结论 :
6 f }' M% F& h2 T x& q3 ]$ ^/ G* d3 o# O: I0 [ Y
以上分析可以看出,程序跳转部分的设计与 APP 启动代码和芯片 RAM 的大小有关系;移植和调试时需加以注意.
5 a9 ^% E2 J" b3 P% ^6 C! Q- X. \# {% C
# n1 h: u% v( P1 R4 A
|