1 前言STSW-STM32116是ST官网基于标准库的针对STM32F0的USART进口IAP示例程序+ f6 @. O! `" X: m6 W3 \5 x
工程原本是针对STM32F051,本文将介绍如何移植到STM32F070,并针对移植的过程中的问题逐个处理。7 v2 x9 y- V' ?' Q n9 f
4 y5 ~1 V/ Y6 Q6 s9 n3 |4 B8 Y) j R. R$ _8 o6 W8 |- z
2 KEIL下移植
7 K' d; g9 k1 W$ ]% Y7 EIAP程序一般分为两个,一个是IAP,一个是APP,IAP存放在内置FLASH的0x8000000的起始位置,而APP则存放在离这个位置一定距离的位置,这个距离一定是大于或等于IAP本身所占空间大小,本例子为0x8003000。! n& {* H0 c) _$ V( {; l# N: c
z p; ?% [/ e% x
下载资源后,打开STM32F0xx_AN4065_FW_V1.0.0\Project\STM32F0xx_IAP\下的binary_template工程,这个就是APP工程,首先用KEIL打开,修改device为STM32F070,7 N; i% G A0 ]0 |4 ?8 K
2 [; J, H2 i: h X- R. H" h# \% u
: v" c% C5 c% o/ w
5 d2 |( ~9 k7 I" y6 R( A1 _
7 |3 o! g3 B* {/ I" _
并编译,结果发现原始的公式是编译不过的,如下错误信息:2 @. I! t1 q0 [" i9 \
/ O( m% G6 `: ]/ b* \
# S- [( J$ g/ k/ z/ T' Q
7 A( {* i6 l: i. d. D* }/ M; K
1 D: I" U, t4 K$ G. C8 r; U/ N+ P从字面上判断为编译system_stm32f0xx.c文件生成的目标文件system_stm32f0xx.o中的数据段(.data)内的RW数据与main.o中的数据在地址0x20000000产生冲突。
7 C$ l! ~, H v! n! g仔细查看代码,发现main函数之前这么一段:
; o+ m2 t/ P, c* L+ z; `9 v& s% f) ^. R
: e5 G0 z. J7 E s P" L! q) K
. ^( L4 I6 V6 G* I l* F# {4 \7 P0 N) K
可见代码是要将中断向量表VectorTable强制定义在内存0x20000000上,但是此地址与system_stm32f0xx.c定义的全局变量位置有冲突。于是,需要修改避免冲突。中断向量的地址是固定的,但其他全局变量的地址可以相应地移动下,并且APP的烧录位置为0x8003000,如下图:
5 i: T }3 J; C" b, M! D( f) z; {0 J" V2 J
5 H5 B2 u/ ~2 e7 `5 G5 @
( m! C* L0 f% p8 Q) _1 K
4 t) t$ g3 _( d$ L& u, h4 n: D" M8 U3 f+ n# P0 d6 k& Q
再次编译,错误就会消失了。
: C( J+ O0 Y$ r5 ]/ h j# S
; C4 B% F& X+ X- t6 u8 {7 Q另外需要将main函数内前面几行代码做些修改:
( ?8 y- z2 t" n9 L; Z- int main(void)
* n$ E/ g5 G6 H! Z: W5 [; J1 r; [ - { 0 \( }4 L% F b
- uint32_t i = 0; 3 A& M6 i# y2 |- s l0 X
-
1 P# I5 o: d: k$ S - /*!< At this stage the microcontroller clock setting is already configured, 5 u- R4 U9 x' ]/ N
- this is done through SystemInit() function which is called from startup ; ]3 K; O& `+ [6 e* U' c( y
- file (startup_stm32f0xx.s) before to branch to application main.
. c' d W) t3 F. N- O/ r - To reconfigure the default setting of SystemInit() function, refer to
3 w1 j$ S Z& @1 |( B% n; ^ - system_stm32f0xx.c file $ a' C1 E$ n g0 J7 m
- */ & m `8 T, ~3 y$ M
-
( q0 i# L+ h( Z) t - /* Relocate by software the vector table to the internal SRAM at 0x20000000 ***/ 2 z: g; `' L9 B( L
-
: t( b6 E5 i1 Z0 {" { - /* Copy the vector table from the Flash (mapped at the base of the application
' Z" z* w, U1 L: w: T - load address 0x08003000) to the base address of the SRAM at 0x20000000. */
# ]: B1 K) M. z. R4 P4 I$ z6 G! { - for(i = 0; i < 48; i++) . G4 c, M3 c, O4 E! {
- { - O! i4 G8 P" O3 Y( e
- VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2));
* T% C( @) d( H" H( ?$ x! \ - }
2 q: k& A- M- z - ) n$ @( e8 Y( z: U
- /* Enable the SYSCFG peripheral clock*/ , K2 R8 d4 W6 o0 Y+ {! B
- //RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE); , r9 d, X/ A9 D. K5 ]7 w
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //需要修改成这样
# d) `3 E( ^. x - /* Remap SRAM at 0x00000000 */
- ^2 C: @+ V2 I% S2 M - SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
. C: h+ t6 x/ Y) g6 q( j& L -
6 S* Q* l( n2 x, o# r; G0 o# s/ U - /...
2 H8 F0 O V7 h/ h! c - }
复制代码 ! `1 U/ a) g4 Z
: J4 u/ g& C+ t) w* O# U
打开对应的map文件,有如下内容:
2 a9 @+ @7 J/ G" A, n" w- [plain] view plain copy- C2 ^: o+ e1 g
- GPIO_PIN 0x08003470 Data 8 stm320518_eval.o(.constdata) ' \- Q* {" F1 W9 B" g+ y
- GPIO_CLK 0x08003478 Data 16 stm320518_eval.o(.constdata)
o9 F8 d; W0 d% N+ X - BUTTON_PIN 0x08003488 Data 14 stm320518_eval.o(.constdata)
7 s. B* _3 z, s* u* U% B - BUTTON_CLK 0x08003498 Data 28 stm320518_eval.o(.constdata) ; i0 ~+ R3 l* h9 P
- BUTTON_EXTI_LINE 0x080034b4 Data 14 stm320518_eval.o(.constdata)
' @& S; |! a6 {9 ]7 @$ m# f7 A1 j - BUTTON_PORT_SOURCE 0x080034c2 Data 14 stm320518_eval.o(.constdata) ! R* E$ C9 z& N6 m
- BUTTON_PIN_SOURCE 0x080034d0 Data 14 stm320518_eval.o(.constdata) 3 @& r" W7 ^" k. f; g+ H2 P
- BUTTON_IRQn 0x080034de Data 14 stm320518_eval.o(.constdata)
( Y1 D' E& O* v) K8 v& r - COM_USART_CLK 0x080034ec Data 4 stm320518_eval.o(.constdata)
F+ ]! n; r6 w& m - COM_TX_PORT_CLK 0x080034f0 Data 4 stm320518_eval.o(.constdata) 1 F, o9 N8 {4 r* M) h& A
- COM_RX_PORT_CLK 0x080034f4 Data 4 stm320518_eval.o(.constdata) 7 @" ] O# G' g5 A3 h g
- COM_TX_PIN 0x080034f8 Data 2 stm320518_eval.o(.constdata)
. a8 C0 ~4 h( Z- a. I3 F* K g, D. D - COM_RX_PIN 0x080034fa Data 2 stm320518_eval.o(.constdata) % v* L( I' S2 R
- COM_TX_PIN_SOURCE 0x080034fc Data 2 stm320518_eval.o(.constdata)
5 \6 F Y2 [. Q) ] - COM_RX_PIN_SOURCE 0x080034fe Data 2 stm320518_eval.o(.constdata)
7 o E0 a9 }6 z" T$ B' v - COM_TX_AF 0x08003500 Data 2 stm320518_eval.o(.constdata) - N1 q' y8 r W ^4 ^
- COM_RX_AF 0x08003502 Data 2 stm320518_eval.o(.constdata)
$ r1 ?! ?$ b4 o; f8 a! V - Region+ \3 N! ~: v! T+ q
- Base 0x08003504 Number 0 anon
' N6 w& a N- b1 E/ N/ T - Table) 1 D, M* `7 U' Y0 i
- Region- j/ ?8 I$ l+ Y- h
- Limit 0x08003524 Number 0 anon
. v( ?) X! v' m6 J! ~( X - Table)
/ j& j7 {0 p! K) s( f- K - VectorTable 0x20000000 Data 192 main.o(.ARM.__AT_0x20000000) //向量表位置为0x20000000
+ ~3 r; u" k- I6 M: d - SystemCoreClock 0x200000c0 Data 4 system_stm32f0xx.o(.data) //其他全局变量的起始位置为0x200000C0 ' O7 g! Q8 L0 J3 G! I" O
- AHBPrescTable 0x200000c4 Data 16 system_stm32f0xx.o(.data)
& \$ o0 h2 }1 k) q4 {" g) d - GPIO_PORT 0x200000d4 Data 16 stm320518_eval.o(.data)
% a, ?1 ~% [# L - BUTTON_PORT 0x200000e4 Data 28 stm320518_eval.o(.data)
- R" H' g; L: s; Y - COM_USART 0x20000100 Data 4 stm320518_eval.o(.data) % b5 y4 {. J# I4 D l& W
- COM_TX_PORT 0x20000104 Data 4 stm320518_eval.o(.data) $ C4 R8 H3 a- q4 Z k3 b7 w p$ |
- COM_RX_PORT 0x20000108 Data 4 stm320518_eval.o(.data) 1 }; d+ {' p# A$ F8 `3 p) V
- __initial_sp 0x20000510 Data 0 startup_stm32f0xx.o(STACK)
复制代码
0 [& e3 ^3 N- s e' a5 L7 y如上所述,中断向量表被编译在0x20000000,内存的起始位置,而system_stm32f0xx.c下的全局变量SystemCoreClock被KEIL编译成放在紧挨着的0x200000C0的位置,与预期完全相符。分别将IAP与APP烧录进FLASH,测试可以正常运行。! i& a3 Q( B- w4 Z& P* A
; Z# v0 E# ?7 K Y9 X4 E- M
注:在KEIL下,必须存在IAP才能调试APP!,这点是与IAR不同的。4 S! n: E- V+ J, d% l6 s
. c b. L/ @( ~' C1 p3 y
" y* N2 j) Y9 d9 J! {- ~# \, D3 IAR下移植( T/ S4 m& o$ b* L6 ^$ v
在IAR下的IAP没有什么特殊的,主要还是看APP的配置。 使用IAR打开APP工程,修改device为STM32F070:
1 ~) p5 J# C( j# q/ O2 v ]) Y
& N2 W; J' R; {" P5 ^

! r# ~4 H* Y# I- B0 P4 w
链接配置: 中断向量表: ( k( H! Y+ u2 R8 I7 o
# @0 _0 c9 t, C/ T; @+ W' ?8 I

f8 I! u# H1 u0 ^' }( h
内存映射:
# m% E6 i2 z0 Q+ {9 s# [. h

( P' T0 T+ u8 L# @/ S . |! p0 L% A2 P* e2 I _
如上,APP存放在FLASH的位置0x8003000,内存还是设置为:0x20000000. 编译后,打开对应的map文件如下所示: - Entry Address Size Type Object $ p9 X- L- M) h4 n
- ----- ------- ---- ---- ------
# f4 f1 U2 _2 A; t8 ?4 [ - .iar.init_table$Base 0x080034fc -- Gb - Linker created - ; A* H, V1 c; _, y" M6 h# y7 z
- .iar.init_table$Limit 0x08003510 -- Gb - Linker created -
, M: I4 Z" c7 H( _ ` - ?main 0x08003511 Code Gb cmain.o [4]
% V7 K/ @+ X: e% t$ c+ G- G% L( d' f - CSTACK$Base 0x200000d8 -- Gb - Linker created - ) H. |6 }# `/ x ^+ J" F% q
- CSTACK$Limit 0x200010d8 -- Gb - Linker created - 4 O, o" q; O7 T/ o
- Delay 0x080031e3 0x10 Code Gb main.o [1]
: ?: K$ {8 e/ ]3 l: q5 G - GPIO_PIN 0x080035a0 0x8 Data Gb stm320518_eval.o [1] . n& J: t- h: y9 a& c6 `
- GPIO_PORT 0x200000c0 0x10 Data Gb stm320518_eval.o [1] //stm320518_eval.c文件内的全局变量GPIO_PORT数组存放在0x200000c0
" J4 ^" Y) ?4 k. z! D - HardFault_Handler 0x08003573 0x4 Code Gb stm32f0xx_it.o [1] + N5 O {' k X/ ~/ S
- NMI_Handler 0x08003571 0x2 Code Gb stm32f0xx_it.o [1] ) q3 M( H' s4 f: i6 U& _' A
- NVIC_SetPriority 0x080030c1 0x84 Code Lc main.o [1]
. _% ]" |9 f$ w/ z - PendSV_Handler 0x08003579 0x2 Code Gb stm32f0xx_it.o [1]
$ w! ]9 Y) w2 z+ G; P - RCC_APB2PeriphClockCmd 0x08003229 0x20 Code Gb stm32f0xx_rcc.o [1]
7 a7 ~( T$ {, b" z# N - Region6 z' \; w; n1 V; v1 ]$ }
- Base 0x080034fc -- Gb - Linker created - , ^+ i: k& V0 u" w7 Z: P) d
- Region
1 D$ w' T( z9 X; d - Limit 0x08003510 -- Gb - Linker created - 8 y4 E! a% ~6 _, s- z7 `2 q
- STM_EVAL_LEDToggle 0x08003315 0x26 Code Gb stm320518_eval.o [1]
7 H5 G0 e- u/ K E - SVC_Handler 0x08003577 0x2 Code Gb stm32f0xx_it.o [1]
- Q* D3 M( S1 ^% L6 I7 `# _ l - SYSCFG_MemoryRemapConfig
" j0 l: N7 J' f( K' ? - 0x0800324d 0x14 Code Gb stm32f0xx_syscfg.o [1] , i4 _3 H" [2 U& y
- SetSysClock 0x080033b7 0xbe Code Lc system_stm32f0xx.o [1] 3 m* Y& W# |2 W* t: b t; V
- SysTick_Config 0x08003145 0x32 Code Lc main.o [1] 9 g% r; U+ a/ d. S* g
- SysTick_Handler 0x0800357b 0x8 Code Gb stm32f0xx_it.o [1]
/ _: W2 s0 S0 p! ~. h1 N7 ~ - SystemCoreClock 0x200000d0 0x4 Data Gb system_stm32f0xx.o [1] , J4 {2 h) |& z' n
- SystemInit 0x08003349 0x6e Code Gb system_stm32f0xx.o [1] * E& k. Q) }. V9 u
- TimingDelay 0x200000d4 0x4 Data Lc main.o [1] 2 K6 k+ V4 k$ c4 K& y+ s& q
- TimingDelay_Decrement 0x080031f3 0x16 Code Gb main.o [1]
" Z6 m6 R z9 j9 r! u! i - VectorTable 0x20000000 0xc0 Data Gb main.o [1] //向量表编译位置为0x20000000 8 }9 N( c0 p0 r' L
- __aeabi_idiv0 0x08003345 Code Gb IntDivZer.o [4] 7 E) Q# }3 [- N) m7 H/ k( ^( W
- __aeabi_uidiv 0x08003265 Code Gb I32DivModFast.o [4]
& |1 J! Z* L- e8 w* D- @0 ?' ? - __aeabi_uidivmod 0x08003265 Code Gb I32DivModFast.o [4] ! C' f# f4 e2 U- v5 k% }3 Q7 G
- __cmain 0x08003511 Code Gb cmain.o [4] $ Y9 H4 g; z! R% y% C4 U% P/ X
- __exit 0x08003545 0x14 Code Gb exit.o [5] 8 C8 L0 E8 ^! M9 Q5 b, @% a
- __iar_copy_init3 0x080034a5 0x30 Code Gb copy_init3.o [4]
/ B! ]( R8 l! M9 K" B" P; {; t/ F - __iar_data_init3 0x080034d5 0x28 Code Gb data_init.o [4]
4 Q( Z1 { C7 Y( I( U - __iar_program_start 0x08003595 Code Gb cstartup_M.o [4] 8 p/ ~ D/ O+ j: ?1 P
- __low_level_init 0x0800352b 0x4 Code Gb low_level_init.o [3] 8 ]# R: `# M, x2 F+ X6 V1 V
- __vector_table 0x08003000 Data Gb startup_stm32f0xx.o [1]
; [$ J. A7 x# f4 V - _call_main 0x0800351d Code Gb cmain.o [4] # c1 p) y& N! i* x) n% k5 ^0 y
- _exit 0x08003539 Code Gb cexit.o [4]
! P2 t' T; H2 H9 A" |8 a - _main 0x08003527 Code Gb cmain.o [4] 2 v: T% C2 ]3 U m1 @
- exit 0x0800352f 0x8 Code Gb exit.o [3] & B( L1 N9 |6 q2 n! k+ b: _& W8 S0 X
- main 0x08003177 0x6c Code Gb main.o [1]
2 Y% d$ D0 E. I/ W' S& K
复制代码
; `; \) T/ ~! O4 R" T7 \2 @6 ^如上所示,在IAR编译下,中断向量表被编译在0x20000000,内存的起始位置,而stm320518_eval.c下的全局变量GPIO_PORT被IAR编译成放在紧挨着的0x200000C0的位置。分别将IAP与APP烧录进FLASH,测试可以正常运行。
6 C1 {& d. Q" n% c9 o% `! b6 O4 g5 L! g
注:从IAR工程的链接配置来看,并没有像KEIL那样配置RAM位置为:0x2000000,编译后的结果向量表也不会与其他全局变量相冲突,可见IAR编译器已经自动计算并避免这种冲突,不像KEIL那样会出现链接错误,以此来提示用户。 ! k+ `" i3 S- s$ |" M, a7 a
另外:在IAR下,在不存在IAP的情况下也是可以调试APP的,这点是KEIL所不具备的功能,看样子,IAR在细节的处理上比KEIL要好。 5 O$ D4 a# ^- B0 z5 @; w/ E1 c
& P$ J& q+ q3 U0 ]# S& ] |