1 前言STSW-STM32116是ST官网基于标准库的针对STM32F0的USART进口IAP示例程序* r6 T6 a" ~ ~& `9 U* Z
工程原本是针对STM32F051,本文将介绍如何移植到STM32F070,并针对移植的过程中的问题逐个处理。
, I- o" g2 ?. G2 F" I' Z' ?' r! \8 A L# ^) V6 z/ X: H
1 H( q- o8 m/ e% T# c$ X5 z2 KEIL下移植
5 s$ ^' E1 T* iIAP程序一般分为两个,一个是IAP,一个是APP,IAP存放在内置FLASH的0x8000000的起始位置,而APP则存放在离这个位置一定距离的位置,这个距离一定是大于或等于IAP本身所占空间大小,本例子为0x8003000。/ N5 G! c0 |* r& |( Y
- B: x+ F& D2 I+ M. r4 h" h0 |
下载资源后,打开STM32F0xx_AN4065_FW_V1.0.0\Project\STM32F0xx_IAP\下的binary_template工程,这个就是APP工程,首先用KEIL打开,修改device为STM32F070,
+ g+ E K( S, I9 c% h# X; P7 s- O7 [# R& R
0 P. u; P$ h6 [; ?# B4 D+ F& r$ ?
J5 A# j m/ R: N
0 N% u# c/ F. k: C; _) C5 B) P' h- m; L V; r0 ?( S2 @+ W! z
并编译,结果发现原始的公式是编译不过的,如下错误信息:' W/ F7 H/ d# V( \, P$ J# n
) l: a+ w y' K! s, G9 C* w7 S6 C7 v
6 s+ L" \8 m& [/ ^+ Q
7 j7 g) ^/ |" H
5 q @3 W2 R, `$ f7 s从字面上判断为编译system_stm32f0xx.c文件生成的目标文件system_stm32f0xx.o中的数据段(.data)内的RW数据与main.o中的数据在地址0x20000000产生冲突。3 _# u, J1 a2 t
仔细查看代码,发现main函数之前这么一段:
7 y; {# q( h* t; H' y
0 y; o2 `; M, {- [' @' A. m
% w/ O2 D% V1 X# O2 b% r3 q F" G* h- L: Y2 z* F
- l* S' ^' l1 x" B4 @* ?& b可见代码是要将中断向量表VectorTable强制定义在内存0x20000000上,但是此地址与system_stm32f0xx.c定义的全局变量位置有冲突。于是,需要修改避免冲突。中断向量的地址是固定的,但其他全局变量的地址可以相应地移动下,并且APP的烧录位置为0x8003000,如下图:
# ~% P" N( c8 e9 I
h* y6 t: E" q* C& M" p: g7 h4 K" [& @* x+ G; h
6 D# e1 E; M" a

% M" X7 l& I% C% v' N5 C4 w1 L5 W. a8 q8 D. k6 X- \
再次编译,错误就会消失了。# z6 i2 J5 B# n# M
/ J6 I1 S$ c1 m0 I
另外需要将main函数内前面几行代码做些修改:" \! t7 T, }4 U: ^8 ~% I4 p, @
- int main(void)
' }& A, e5 b, s' e# i r - {
7 g; t$ K0 w$ A% ]& g% X1 o - uint32_t i = 0; 6 |7 k6 a9 _! E& I; B+ I# t; q3 }
- ' @7 K9 G+ d0 ~% E4 i- l6 Z5 f
- /*!< At this stage the microcontroller clock setting is already configured, 7 ?, L4 }6 O0 X" c$ z
- this is done through SystemInit() function which is called from startup 9 Z3 t+ t! ~6 m( g6 O; M
- file (startup_stm32f0xx.s) before to branch to application main. ( G. j ~9 i% q. p
- To reconfigure the default setting of SystemInit() function, refer to 9 J: U8 @5 Y7 ~
- system_stm32f0xx.c file
4 f* v, g: M8 X - */
" a# O; ]7 C0 p) K$ ?- W; |; u& y: b -
$ w. p L: z- O+ r! q, U - /* Relocate by software the vector table to the internal SRAM at 0x20000000 ***/
! P+ j. M" p0 e, J+ Z+ A' P -
. Q0 [( _0 P4 N1 Y( [4 x+ k. U* B - /* Copy the vector table from the Flash (mapped at the base of the application 5 _5 }$ ?( w) x% T
- load address 0x08003000) to the base address of the SRAM at 0x20000000. */ & i$ f+ p' L) y: `/ H7 a. j, Y
- for(i = 0; i < 48; i++)
1 P% ]. J* X; g1 Z! O+ T. b - { 0 k0 m3 @9 p9 X) w# e2 k$ a3 [
- VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2)); 8 q0 I6 G! M! n1 L
- }
, _4 E* ~* o5 {0 M# h6 ? - ! V# h& z5 @) {- c: E4 T% q$ c
- /* Enable the SYSCFG peripheral clock*/
$ }) C' [0 g* P; z1 J - //RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);
3 ?& r& x( C$ u. y/ A& Z% f+ z - RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //需要修改成这样 " X/ O# c: M; f* E! f" z
- /* Remap SRAM at 0x00000000 */
8 Q! x: a! G' l8 y W( n, { - SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
) H! }' v2 G( y$ K/ x - $ K, |2 n( ~+ A
- /...
; L! c" r/ y9 ^6 B* ` - }
复制代码 e/ R/ X$ L. J2 d: \9 n2 Z8 {' q
O% _& I: `( g4 f打开对应的map文件,有如下内容:
, l9 C/ b% j( R f! j3 q- [plain] view plain copy. @8 a, f2 T: }+ j
- GPIO_PIN 0x08003470 Data 8 stm320518_eval.o(.constdata)
; p3 S/ u" ^0 u - GPIO_CLK 0x08003478 Data 16 stm320518_eval.o(.constdata)
* H' |; I0 }3 w0 W7 c - BUTTON_PIN 0x08003488 Data 14 stm320518_eval.o(.constdata)
$ x: |2 s" ?5 Z" T1 C# ^ - BUTTON_CLK 0x08003498 Data 28 stm320518_eval.o(.constdata) $ m" R$ @0 X/ U# }% x
- BUTTON_EXTI_LINE 0x080034b4 Data 14 stm320518_eval.o(.constdata) & `" l6 {$ J4 F' M3 J
- BUTTON_PORT_SOURCE 0x080034c2 Data 14 stm320518_eval.o(.constdata)
: w) z, {2 u( j% r: C! \) }) L - BUTTON_PIN_SOURCE 0x080034d0 Data 14 stm320518_eval.o(.constdata) 1 [# A3 b3 q7 R( r3 `. b! ~
- BUTTON_IRQn 0x080034de Data 14 stm320518_eval.o(.constdata) 4 }1 ]" @( {0 H
- COM_USART_CLK 0x080034ec Data 4 stm320518_eval.o(.constdata)
6 f. {/ T& m/ w1 P- f: W- z - COM_TX_PORT_CLK 0x080034f0 Data 4 stm320518_eval.o(.constdata) ; d& F# w" h, U. ?) |! m Y: n
- COM_RX_PORT_CLK 0x080034f4 Data 4 stm320518_eval.o(.constdata)
# L( k& i- S, n) G - COM_TX_PIN 0x080034f8 Data 2 stm320518_eval.o(.constdata)
- q P0 y( Q) S0 O: k; b6 p0 c2 F - COM_RX_PIN 0x080034fa Data 2 stm320518_eval.o(.constdata)
2 R) U! k# H( w - COM_TX_PIN_SOURCE 0x080034fc Data 2 stm320518_eval.o(.constdata) 4 _+ v) a7 @! b( c- }6 w$ N( Z
- COM_RX_PIN_SOURCE 0x080034fe Data 2 stm320518_eval.o(.constdata) ! `1 B, Y% R* B# w+ J* p
- COM_TX_AF 0x08003500 Data 2 stm320518_eval.o(.constdata)
- X5 B! p5 n+ q; r% b5 q1 u: @0 w - COM_RX_AF 0x08003502 Data 2 stm320518_eval.o(.constdata) $ }% F. h) T8 F7 ]8 g8 }
- Region
/ R0 i4 A/ v. G) r5 u; |) N - Base 0x08003504 Number 0 anon
9 P% B5 _. P6 C$ H2 o6 p1 l' }" T - Table) ! h! J8 y4 ]0 M2 E( l
- Region
$ R8 {/ K0 b, E# |7 y' {) R3 Z; t' E - Limit 0x08003524 Number 0 anon
7 F7 j4 E2 ?' j0 }" x) s1 d - Table)
* e/ w, x* |; P1 N - VectorTable 0x20000000 Data 192 main.o(.ARM.__AT_0x20000000) //向量表位置为0x20000000 l% j d& P5 t J* U; l. h
- SystemCoreClock 0x200000c0 Data 4 system_stm32f0xx.o(.data) //其他全局变量的起始位置为0x200000C0 1 ]( E. ?& ^- @- n1 t
- AHBPrescTable 0x200000c4 Data 16 system_stm32f0xx.o(.data) 7 M5 u# S! N# c/ f" u& Y+ O
- GPIO_PORT 0x200000d4 Data 16 stm320518_eval.o(.data) % u0 U2 F* a l8 R" S6 m- a/ d
- BUTTON_PORT 0x200000e4 Data 28 stm320518_eval.o(.data) 2 X! ~1 t* f7 i! w# v# d) f+ S7 U4 F
- COM_USART 0x20000100 Data 4 stm320518_eval.o(.data) & M8 V5 n( l' X7 Z9 O! @: }
- COM_TX_PORT 0x20000104 Data 4 stm320518_eval.o(.data)
) }7 \; K6 j1 O, A) _ - COM_RX_PORT 0x20000108 Data 4 stm320518_eval.o(.data) 6 L2 G2 Y# K% x. m! L. Q* L: }
- __initial_sp 0x20000510 Data 0 startup_stm32f0xx.o(STACK)
复制代码 ' R% D: S, s9 ?
如上所述,中断向量表被编译在0x20000000,内存的起始位置,而system_stm32f0xx.c下的全局变量SystemCoreClock被KEIL编译成放在紧挨着的0x200000C0的位置,与预期完全相符。分别将IAP与APP烧录进FLASH,测试可以正常运行。
) q0 r) }# a% L6 j9 c7 j7 L1 x; h3 B2 X8 t e
注:在KEIL下,必须存在IAP才能调试APP!,这点是与IAR不同的。4 E. \, {1 v4 O8 F( ]
* S" C5 _! t' x g
) G9 r! t7 H9 `3 IAR下移植% W7 z6 d8 g5 k8 X7 Y2 Z6 p
在IAR下的IAP没有什么特殊的,主要还是看APP的配置。 使用IAR打开APP工程,修改device为STM32F070:
5 v7 v! e+ h: ]0 W* j" }
# K; H, Q+ L; u ^! x; ^9 q
; E1 E. O, |5 M9 G( l
链接配置: 中断向量表: 0 x5 ^; i5 r7 R/ v- F
: i1 g, ^6 h! P5 [% i

& A% U) M5 k7 U2 v2 u! e6 G
内存映射:
. Y. x2 C' r; ?: F: C1 Z: j: e
6 r! f* Y3 x; c# ~9 y) x
7 k/ W3 z. h: d如上,APP存放在FLASH的位置0x8003000,内存还是设置为:0x20000000. 编译后,打开对应的map文件如下所示: - Entry Address Size Type Object 7 h% \' ^( Q0 T: W
- ----- ------- ---- ---- ------ # O$ A7 Z( Y2 G5 }! L' X8 I4 s( W8 G
- .iar.init_table$Base 0x080034fc -- Gb - Linker created -
; p8 ? N ^; f T7 C - .iar.init_table$Limit 0x08003510 -- Gb - Linker created - 6 W& p1 q1 F" D; h' `! l
- ?main 0x08003511 Code Gb cmain.o [4] & n: Y; }; F R$ X& e9 \
- CSTACK$Base 0x200000d8 -- Gb - Linker created - ; [) h1 k U( s' i' l/ v. L( I' Q
- CSTACK$Limit 0x200010d8 -- Gb - Linker created - ; p! l+ Y9 W( v2 _; p: h
- Delay 0x080031e3 0x10 Code Gb main.o [1] 4 H8 P: f- \4 \$ X% z
- GPIO_PIN 0x080035a0 0x8 Data Gb stm320518_eval.o [1]
2 W* j) D$ Y; D - GPIO_PORT 0x200000c0 0x10 Data Gb stm320518_eval.o [1] //stm320518_eval.c文件内的全局变量GPIO_PORT数组存放在0x200000c0
3 S0 [5 Q; D, s/ a1 Q; E - HardFault_Handler 0x08003573 0x4 Code Gb stm32f0xx_it.o [1]
( Z8 R5 k. i4 b$ M - NMI_Handler 0x08003571 0x2 Code Gb stm32f0xx_it.o [1]
, f8 @1 m$ s9 X. w - NVIC_SetPriority 0x080030c1 0x84 Code Lc main.o [1]
( I* X1 ^& E% v6 A/ H$ X# J - PendSV_Handler 0x08003579 0x2 Code Gb stm32f0xx_it.o [1]
& U6 w1 W2 K8 g, G - RCC_APB2PeriphClockCmd 0x08003229 0x20 Code Gb stm32f0xx_rcc.o [1] a* Q" L$ ^5 P6 }
- Region7 {) c2 Z) e) B4 G
- Base 0x080034fc -- Gb - Linker created -
: ~3 Q+ Q" B" l. s7 h$ L - Region6 o- G- A+ k7 ]6 I: O _0 Y# R
- Limit 0x08003510 -- Gb - Linker created -
. H& c& [5 B$ w+ R* I# M - STM_EVAL_LEDToggle 0x08003315 0x26 Code Gb stm320518_eval.o [1]
8 p0 |$ G4 h5 F( C) o, n: F - SVC_Handler 0x08003577 0x2 Code Gb stm32f0xx_it.o [1]
* g7 s8 G( e7 f, M# i - SYSCFG_MemoryRemapConfig
3 }7 Y* l3 _3 m2 S - 0x0800324d 0x14 Code Gb stm32f0xx_syscfg.o [1]
N+ R6 ?, ~9 e' ~. T. _2 [ - SetSysClock 0x080033b7 0xbe Code Lc system_stm32f0xx.o [1] % T& n# g5 Q$ S8 g' Q$ h2 p# [7 y
- SysTick_Config 0x08003145 0x32 Code Lc main.o [1] * |9 [' {' r# n9 ~1 G2 f
- SysTick_Handler 0x0800357b 0x8 Code Gb stm32f0xx_it.o [1]
- G; e8 E7 ?+ d# m( B - SystemCoreClock 0x200000d0 0x4 Data Gb system_stm32f0xx.o [1]
% G8 N; n X7 t - SystemInit 0x08003349 0x6e Code Gb system_stm32f0xx.o [1] . F3 k* a/ ^2 r+ w8 o. ]
- TimingDelay 0x200000d4 0x4 Data Lc main.o [1] * v* W- g+ C' i
- TimingDelay_Decrement 0x080031f3 0x16 Code Gb main.o [1]
# E! Y- P) c$ \$ I" L - VectorTable 0x20000000 0xc0 Data Gb main.o [1] //向量表编译位置为0x20000000 $ F9 U- H( C3 f% O
- __aeabi_idiv0 0x08003345 Code Gb IntDivZer.o [4] ) T. k" v e/ O7 G9 W. X8 M, g
- __aeabi_uidiv 0x08003265 Code Gb I32DivModFast.o [4] & N4 i) }+ T- L+ n( l
- __aeabi_uidivmod 0x08003265 Code Gb I32DivModFast.o [4]
5 R1 B& d2 B( C, m V/ j# l. [ - __cmain 0x08003511 Code Gb cmain.o [4]
- S ~9 a5 o8 t - __exit 0x08003545 0x14 Code Gb exit.o [5] & I$ }" A; `8 T. e
- __iar_copy_init3 0x080034a5 0x30 Code Gb copy_init3.o [4]
$ g# X* l& \. O( O+ h" E/ I6 p7 r1 J - __iar_data_init3 0x080034d5 0x28 Code Gb data_init.o [4]
, f) V8 N- \6 P5 L0 v3 d - __iar_program_start 0x08003595 Code Gb cstartup_M.o [4]
6 W- o) T3 T/ r( X' _- A/ w - __low_level_init 0x0800352b 0x4 Code Gb low_level_init.o [3] ( K% ^. O7 A& c4 C+ _& h" J
- __vector_table 0x08003000 Data Gb startup_stm32f0xx.o [1]
; j9 j: N4 m' }/ I3 M/ F - _call_main 0x0800351d Code Gb cmain.o [4] * t! v* `' e% ^' |% h* f. h
- _exit 0x08003539 Code Gb cexit.o [4]
) w' B8 s: D# u8 b+ E- j3 x - _main 0x08003527 Code Gb cmain.o [4] + @9 L/ x, l* f( u4 M" @' t
- exit 0x0800352f 0x8 Code Gb exit.o [3] 5 L; y; O+ @" |& `' e5 v( y
- main 0x08003177 0x6c Code Gb main.o [1]
/ \& b/ I! ?" S2 k1 S
复制代码 3 }& d2 p( ~! L& Z8 }0 s, {
如上所示,在IAR编译下,中断向量表被编译在0x20000000,内存的起始位置,而stm320518_eval.c下的全局变量GPIO_PORT被IAR编译成放在紧挨着的0x200000C0的位置。分别将IAP与APP烧录进FLASH,测试可以正常运行。
- v& u. A1 X- Z' ]4 d$ ? e- s6 k, {3 h: i W
注:从IAR工程的链接配置来看,并没有像KEIL那样配置RAM位置为:0x2000000,编译后的结果向量表也不会与其他全局变量相冲突,可见IAR编译器已经自动计算并避免这种冲突,不像KEIL那样会出现链接错误,以此来提示用户。
$ S" E% [5 n; ?. h8 C) Z另外:在IAR下,在不存在IAP的情况下也是可以调试APP的,这点是KEIL所不具备的功能,看样子,IAR在细节的处理上比KEIL要好。
, j4 o2 Y% `4 ~0 F4 ^4 K
2 f$ M" w) c+ ?9 [' |$ J& j |