1 前言STSW-STM32116是ST官网基于标准库的针对STM32F0的USART进口IAP示例程序* {) [ @. ]1 e3 H) y, n0 \2 Z
工程原本是针对STM32F051,本文将介绍如何移植到STM32F070,并针对移植的过程中的问题逐个处理。
/ j& \" |; V/ w) r1 [: g! K& |) q) l. @8 {) d; {9 n
. K1 N; N. w3 ?/ n* E* e: J
2 KEIL下移植8 w: j+ N4 B) y3 a+ x
IAP程序一般分为两个,一个是IAP,一个是APP,IAP存放在内置FLASH的0x8000000的起始位置,而APP则存放在离这个位置一定距离的位置,这个距离一定是大于或等于IAP本身所占空间大小,本例子为0x8003000。
* K, l! D* e& D" Q$ J" [# R: y, P3 h o2 R) E7 \: \3 D+ P E* M
下载资源后,打开STM32F0xx_AN4065_FW_V1.0.0\Project\STM32F0xx_IAP\下的binary_template工程,这个就是APP工程,首先用KEIL打开,修改device为STM32F070,& U' ?6 ~ f6 M
9 l1 A5 _. @$ E d3 {2 W
, G' L/ e5 n) n7 _! X m; V2 P9 Z# e* [

0 n; Z/ c* ^* R# r. }" E& q( K2 V- R8 M8 `# `
并编译,结果发现原始的公式是编译不过的,如下错误信息:
( A% F8 D2 j6 a w" O7 ~: F& I$ C8 T( ~. u1 w, t5 S" q: m2 p
7 r9 u2 s, G1 e4 X6 P: v
+ D0 K. ~% C$ a) ?- j) ^$ ^" d& _5 ^6 {% c
从字面上判断为编译system_stm32f0xx.c文件生成的目标文件system_stm32f0xx.o中的数据段(.data)内的RW数据与main.o中的数据在地址0x20000000产生冲突。
# B; b, E- D3 w仔细查看代码,发现main函数之前这么一段:
7 _; u7 H2 ]5 a8 A! m$ U
0 Y2 K5 J" p5 ]! T5 d1 v0 N' d* |+ X- o2 z8 G
# \1 z o7 `1 S6 _" n/ }0 f
9 ]$ k/ j& A3 M {+ L
可见代码是要将中断向量表VectorTable强制定义在内存0x20000000上,但是此地址与system_stm32f0xx.c定义的全局变量位置有冲突。于是,需要修改避免冲突。中断向量的地址是固定的,但其他全局变量的地址可以相应地移动下,并且APP的烧录位置为0x8003000,如下图:
5 m; D9 T0 w. H9 o% g$ z: o7 y5 E+ c* j& {4 @' \& x/ E2 `% B
- U" E6 N+ J9 w* I* n, k3 l, u! t
/ D5 k6 A- P0 _2 f
1 I8 |; u6 h$ e7 K* Y
( _6 s$ F0 e- q) K: [再次编译,错误就会消失了。
0 m; U8 ~3 L, s6 T, o1 \% A# q8 L6 U/ f. O% k* t3 B
另外需要将main函数内前面几行代码做些修改:
2 g) r, N. @0 J, r; X# ^4 m- int main(void) - ~+ f; V6 ]4 Q Y/ W
- { & j9 \: G" w! D4 K6 A0 D
- uint32_t i = 0; 9 {& {; R+ y8 h6 }" s
- - Q! ]9 w! o. n" R0 N$ ?
- /*!< At this stage the microcontroller clock setting is already configured,
1 O& x% w$ a/ r - this is done through SystemInit() function which is called from startup
2 c% p w' I- s! y4 ]+ z8 w - file (startup_stm32f0xx.s) before to branch to application main.
8 N" [. w: q* j; t; a2 I - To reconfigure the default setting of SystemInit() function, refer to
+ w! N/ g% N& t; t6 k5 _& Q& c - system_stm32f0xx.c file 9 p7 N% G. ~5 [
- */
7 U8 R* L) D7 d, y" t) H. {% |: E - . y3 I: `0 [+ Z4 e% i1 G
- /* Relocate by software the vector table to the internal SRAM at 0x20000000 ***/
; Q( e' C; O% W/ Y+ u# N' r - 2 ~: e6 b* ?$ t& X% ~, l9 [
- /* Copy the vector table from the Flash (mapped at the base of the application
* N9 C7 x, G5 a% H2 h - load address 0x08003000) to the base address of the SRAM at 0x20000000. */ . ^# ?4 L+ T: {" {; V# m" V* h
- for(i = 0; i < 48; i++)
2 y) W3 S8 z1 t" e - { - H6 {+ _0 K! @5 p" L' ]
- VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2));
$ d8 r% s8 _7 v0 N. d; w& S - } 8 |2 T8 Z: C( |$ V7 O5 @' _
- 1 ^0 ^8 v; e M) A2 _, D d' N
- /* Enable the SYSCFG peripheral clock*/ , l d& |: \* t1 }5 x# u3 w
- //RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE); 7 g+ M$ b9 C3 F5 }. a8 j
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //需要修改成这样 / p( \' R1 c- |$ ~+ H: e( r
- /* Remap SRAM at 0x00000000 */ 9 B' F% j* S. Y. R8 h
- SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
7 Q1 `$ ^5 r9 G2 U - * Y+ S0 {$ Z" G D
- /... . b& [3 f3 E* S/ ] v
- }
复制代码
% B3 Z5 Y) v0 W: h
8 h$ O+ g& F& v打开对应的map文件,有如下内容:
5 v& E6 N5 L3 K) u$ o- [plain] view plain copy+ y" v4 D% S* S+ J) S5 k, v
- GPIO_PIN 0x08003470 Data 8 stm320518_eval.o(.constdata) / j' \# n4 g: Y4 \) x* W
- GPIO_CLK 0x08003478 Data 16 stm320518_eval.o(.constdata) 8 o @0 e5 x+ G. `5 c- z9 v% ~# \
- BUTTON_PIN 0x08003488 Data 14 stm320518_eval.o(.constdata)
% I1 k- Z0 A3 C# c - BUTTON_CLK 0x08003498 Data 28 stm320518_eval.o(.constdata) " K+ ~3 j N( X# r6 f2 M
- BUTTON_EXTI_LINE 0x080034b4 Data 14 stm320518_eval.o(.constdata)
4 ^# s5 |% M& R" g3 J - BUTTON_PORT_SOURCE 0x080034c2 Data 14 stm320518_eval.o(.constdata) F4 l x% C3 S' i0 ^' X
- BUTTON_PIN_SOURCE 0x080034d0 Data 14 stm320518_eval.o(.constdata) 4 r! {2 P! t8 _/ _- I
- BUTTON_IRQn 0x080034de Data 14 stm320518_eval.o(.constdata) 7 B9 h* K$ T- Y7 Y% u5 m. u
- COM_USART_CLK 0x080034ec Data 4 stm320518_eval.o(.constdata)
* K, A, ~" B- ]3 O% U e+ B% r - COM_TX_PORT_CLK 0x080034f0 Data 4 stm320518_eval.o(.constdata)
- [* L6 D9 C7 ~* x/ C+ r7 D - COM_RX_PORT_CLK 0x080034f4 Data 4 stm320518_eval.o(.constdata) ! r5 E' ]9 d2 Y3 q/ f
- COM_TX_PIN 0x080034f8 Data 2 stm320518_eval.o(.constdata) " S, t5 Q" Q$ O1 H# ~- y
- COM_RX_PIN 0x080034fa Data 2 stm320518_eval.o(.constdata)
3 ^9 E- C4 c, C9 G - COM_TX_PIN_SOURCE 0x080034fc Data 2 stm320518_eval.o(.constdata) , G$ z( i- l. l9 ~2 ~) `/ Q
- COM_RX_PIN_SOURCE 0x080034fe Data 2 stm320518_eval.o(.constdata) + n4 k0 o/ F/ Y! F& s# n2 i8 [7 v
- COM_TX_AF 0x08003500 Data 2 stm320518_eval.o(.constdata) ' V4 X: a( T: s/ ^6 y" L
- COM_RX_AF 0x08003502 Data 2 stm320518_eval.o(.constdata) 2 u7 e: w t1 X5 l. N4 y4 |
- Region
+ ~* W; W. m( @# E f - Base 0x08003504 Number 0 anon: \- o8 a& v- |* |* R
- Table)
4 I9 V# d. T' F# p6 S- a0 z - Region$ C) S# q3 {# q. p* z
- Limit 0x08003524 Number 0 anon( R/ z; M% ^( C( c9 d9 `
- Table) + V5 j X! V4 F g# f' r* U$ T
- VectorTable 0x20000000 Data 192 main.o(.ARM.__AT_0x20000000) //向量表位置为0x20000000 2 I/ [3 b8 O5 B/ f
- SystemCoreClock 0x200000c0 Data 4 system_stm32f0xx.o(.data) //其他全局变量的起始位置为0x200000C0
5 k: g. b, j1 G* @ - AHBPrescTable 0x200000c4 Data 16 system_stm32f0xx.o(.data) 0 ]+ [2 `0 _* a6 M
- GPIO_PORT 0x200000d4 Data 16 stm320518_eval.o(.data)
( s4 o2 n( W5 h* G- V6 N - BUTTON_PORT 0x200000e4 Data 28 stm320518_eval.o(.data)
* \ g2 _# D, \) ^. V3 J - COM_USART 0x20000100 Data 4 stm320518_eval.o(.data)
( L! \+ S: H1 a- g: u. S - COM_TX_PORT 0x20000104 Data 4 stm320518_eval.o(.data)
' b5 j( Z/ u$ {: k - COM_RX_PORT 0x20000108 Data 4 stm320518_eval.o(.data)
' S/ j1 V: v! `& c5 v# r, T$ j - __initial_sp 0x20000510 Data 0 startup_stm32f0xx.o(STACK)
复制代码
( m" T3 K' u8 D$ L3 s如上所述,中断向量表被编译在0x20000000,内存的起始位置,而system_stm32f0xx.c下的全局变量SystemCoreClock被KEIL编译成放在紧挨着的0x200000C0的位置,与预期完全相符。分别将IAP与APP烧录进FLASH,测试可以正常运行。
0 p; R/ h4 u+ \6 C" P9 U" N
* R/ @9 n# r4 r注:在KEIL下,必须存在IAP才能调试APP!,这点是与IAR不同的。' I% `6 R9 J- z* A; f% F
4 [8 ]8 v5 [9 r2 o' w- g; j$ m" \5 j4 R% f1 F8 m. i8 v1 L+ L
3 IAR下移植 B+ E. A* Y( v$ S" Q s- r" W3 \
在IAR下的IAP没有什么特殊的,主要还是看APP的配置。 使用IAR打开APP工程,修改device为STM32F070: ' i8 |3 u4 F- }. t$ @$ Z. M2 ^" g2 h/ W
! {2 N2 k d5 O5 b, V2 }

1 W; y& H4 v) v' L6 f; K- Q
链接配置: 中断向量表: / t8 W+ z* Q1 T" e+ P- y
7 Z* E. A3 b" n) z

- g% J# W7 N5 O3 N3 I1 b5 e& s6 S- h
内存映射: " @ _' X$ J) J! A/ l
1 c+ t( z3 u7 n9 n; {
) O: b2 D" L6 X2 R1 f如上,APP存放在FLASH的位置0x8003000,内存还是设置为:0x20000000. 编译后,打开对应的map文件如下所示: - Entry Address Size Type Object
5 M; o! T. s" i# z - ----- ------- ---- ---- ------
) w' ~ V- b; g* S+ h - .iar.init_table$Base 0x080034fc -- Gb - Linker created - + u& u! p3 b& Q6 b
- .iar.init_table$Limit 0x08003510 -- Gb - Linker created -
! I. h/ Y+ z/ P" D8 g4 ^ - ?main 0x08003511 Code Gb cmain.o [4] & }# X/ o3 g1 y
- CSTACK$Base 0x200000d8 -- Gb - Linker created - 3 R/ C+ @; I; ^9 l
- CSTACK$Limit 0x200010d8 -- Gb - Linker created -
) T, c% N3 X. t( N P$ g5 V" q - Delay 0x080031e3 0x10 Code Gb main.o [1] 2 `5 I# W- h$ y
- GPIO_PIN 0x080035a0 0x8 Data Gb stm320518_eval.o [1]
% [: V" N; Q- ?9 p - GPIO_PORT 0x200000c0 0x10 Data Gb stm320518_eval.o [1] //stm320518_eval.c文件内的全局变量GPIO_PORT数组存放在0x200000c0
3 Q7 K2 T2 m8 I/ ~- Y1 U ] - HardFault_Handler 0x08003573 0x4 Code Gb stm32f0xx_it.o [1]
5 g, i2 ~+ P* b! p* W - NMI_Handler 0x08003571 0x2 Code Gb stm32f0xx_it.o [1] 5 W: W1 K& h; E
- NVIC_SetPriority 0x080030c1 0x84 Code Lc main.o [1] : r: ?( I& }( E+ \
- PendSV_Handler 0x08003579 0x2 Code Gb stm32f0xx_it.o [1] ( j+ _* q7 u- W1 y
- RCC_APB2PeriphClockCmd 0x08003229 0x20 Code Gb stm32f0xx_rcc.o [1] ( r1 i1 V8 o. S7 {' J
- Region
7 k+ w4 x. J& ` J2 A5 ^4 ` - Base 0x080034fc -- Gb - Linker created - " A8 p* h6 d' O, p5 Y" X
- Region
) @- g' G! R, {' `" y) m - Limit 0x08003510 -- Gb - Linker created - 5 \$ s4 H: i1 {4 O) z+ G( X
- STM_EVAL_LEDToggle 0x08003315 0x26 Code Gb stm320518_eval.o [1]
0 P. A' Q; ~9 G9 u8 w G# S7 B - SVC_Handler 0x08003577 0x2 Code Gb stm32f0xx_it.o [1] 9 O9 N6 _/ X n. Y7 v5 \) _
- SYSCFG_MemoryRemapConfig $ ]* ? M b$ |3 C$ x
- 0x0800324d 0x14 Code Gb stm32f0xx_syscfg.o [1] 9 A$ R5 o: z. I' k# w
- SetSysClock 0x080033b7 0xbe Code Lc system_stm32f0xx.o [1]
1 p5 A' ?* O7 e: b6 `1 f: J' M - SysTick_Config 0x08003145 0x32 Code Lc main.o [1]
1 e- D. l2 K7 _5 f: O- { - SysTick_Handler 0x0800357b 0x8 Code Gb stm32f0xx_it.o [1] 8 z% `: H; ] p$ f) A
- SystemCoreClock 0x200000d0 0x4 Data Gb system_stm32f0xx.o [1] 9 _4 V, s9 D5 ?& c9 v
- SystemInit 0x08003349 0x6e Code Gb system_stm32f0xx.o [1]
! D' D* {7 c8 x$ R - TimingDelay 0x200000d4 0x4 Data Lc main.o [1]
7 r5 H1 `# Y) r - TimingDelay_Decrement 0x080031f3 0x16 Code Gb main.o [1]
- H e, K Z( H% K' Z - VectorTable 0x20000000 0xc0 Data Gb main.o [1] //向量表编译位置为0x20000000 5 s' n6 ]# k8 ^; j( y' S
- __aeabi_idiv0 0x08003345 Code Gb IntDivZer.o [4]
: K4 m- u, w9 H - __aeabi_uidiv 0x08003265 Code Gb I32DivModFast.o [4] 1 d% D$ _. q, k n/ C
- __aeabi_uidivmod 0x08003265 Code Gb I32DivModFast.o [4] 8 r! Y" a S) _! a" {' }$ ?" n' |
- __cmain 0x08003511 Code Gb cmain.o [4]
" A4 f, O0 F' F9 k - __exit 0x08003545 0x14 Code Gb exit.o [5] + C" ]! y8 }# x
- __iar_copy_init3 0x080034a5 0x30 Code Gb copy_init3.o [4] w% X& F* S$ W( ]1 Z4 z
- __iar_data_init3 0x080034d5 0x28 Code Gb data_init.o [4]
' c* B- d" e( n% k+ R! k | - __iar_program_start 0x08003595 Code Gb cstartup_M.o [4] 9 \6 w) L" R- b! a
- __low_level_init 0x0800352b 0x4 Code Gb low_level_init.o [3] 3 j0 q% b& K- m* P4 k' k# R/ ^
- __vector_table 0x08003000 Data Gb startup_stm32f0xx.o [1]
- c$ E% c4 Y6 @! O - _call_main 0x0800351d Code Gb cmain.o [4]
4 T; H" j* C/ h( z" r X0 Y3 K. ? - _exit 0x08003539 Code Gb cexit.o [4]
* [0 b( ^. Y8 r- ?' S' r - _main 0x08003527 Code Gb cmain.o [4]
- D: C) m+ s- | s - exit 0x0800352f 0x8 Code Gb exit.o [3] * x6 p; A3 G+ w7 X9 h0 ]
- main 0x08003177 0x6c Code Gb main.o [1] ) ~3 ~7 G) o: I7 m" ]" `9 @5 u+ q9 [
复制代码 % C5 I- K! T, r8 B. M: ?2 z3 Y
如上所示,在IAR编译下,中断向量表被编译在0x20000000,内存的起始位置,而stm320518_eval.c下的全局变量GPIO_PORT被IAR编译成放在紧挨着的0x200000C0的位置。分别将IAP与APP烧录进FLASH,测试可以正常运行。1 R7 L. N# j: _' v# [0 i" X F
3 T; n# a$ |7 h, J
注:从IAR工程的链接配置来看,并没有像KEIL那样配置RAM位置为:0x2000000,编译后的结果向量表也不会与其他全局变量相冲突,可见IAR编译器已经自动计算并避免这种冲突,不像KEIL那样会出现链接错误,以此来提示用户。
( E4 k1 o. Y8 n" r另外:在IAR下,在不存在IAP的情况下也是可以调试APP的,这点是KEIL所不具备的功能,看样子,IAR在细节的处理上比KEIL要好。
, B( m$ c& j, S- P/ G3 G6 T0 y, D3 D [8 ?6 {: ]: f1 H$ Z. t" y
|