1 前言STSW-STM32116是ST官网基于标准库的针对STM32F0的USART进口IAP示例程序4 U! n& c; z/ ^! N% N; |
工程原本是针对STM32F051,本文将介绍如何移植到STM32F070,并针对移植的过程中的问题逐个处理。
; a: g( O. j4 ~9 j) F2 v9 B$ |: H4 G
" e4 |; O7 Z1 V- e( e8 M
2 KEIL下移植3 W4 w+ D( E: e/ F
IAP程序一般分为两个,一个是IAP,一个是APP,IAP存放在内置FLASH的0x8000000的起始位置,而APP则存放在离这个位置一定距离的位置,这个距离一定是大于或等于IAP本身所占空间大小,本例子为0x8003000。
; i. g" \+ z# ?7 W9 _0 z4 I. l' s% h6 v5 H% M" t3 D
下载资源后,打开STM32F0xx_AN4065_FW_V1.0.0\Project\STM32F0xx_IAP\下的binary_template工程,这个就是APP工程,首先用KEIL打开,修改device为STM32F070,7 ?6 @+ l# h3 H
6 S6 H8 L+ m7 T+ Q+ A
" U8 A/ H4 a& y: X$ @9 R* w5 k* x$ z4 ^. o o! R3 J2 _7 O
# I2 T" }$ X- @0 H6 h
/ k# C" z! q' o0 n2 ~+ _
并编译,结果发现原始的公式是编译不过的,如下错误信息:+ k- X9 b2 F6 N# {; a: {2 Y) Y
8 U2 T+ S7 f _
) b( X1 b6 G" J- T8 `% y8 R3 n' ?; w, e
* n: f: r1 k$ {' L" N从字面上判断为编译system_stm32f0xx.c文件生成的目标文件system_stm32f0xx.o中的数据段(.data)内的RW数据与main.o中的数据在地址0x20000000产生冲突。
$ {4 j! Z" }4 C1 [9 E仔细查看代码,发现main函数之前这么一段:
7 V" @/ m% y7 X% J' `) f/ J/ Q' l: l# R! v; R+ l
. t" D3 s2 g( O- V3 J, E2 V% N
& x4 d! r# F- z1 J i7 ^9 G
! R8 G* `" I, L- V" B9 u' S可见代码是要将中断向量表VectorTable强制定义在内存0x20000000上,但是此地址与system_stm32f0xx.c定义的全局变量位置有冲突。于是,需要修改避免冲突。中断向量的地址是固定的,但其他全局变量的地址可以相应地移动下,并且APP的烧录位置为0x8003000,如下图:0 m5 K! `( a: s; A; ]* Y/ V( o7 I. k
3 p! t M1 o) E G9 }$ J E
7 T: c4 k: Y) B9 Z$ e1 B% M
+ { b, U! Y( K3 ~& H
: d# ^) x: {1 ]; W7 m. D U, ^/ c, V! o
再次编译,错误就会消失了。6 p( h- Z& q* \$ H
1 D1 \+ q) G1 C8 D/ l/ O% ~另外需要将main函数内前面几行代码做些修改:
% K; d- g" W M- z& s" T- R4 [1 E- int main(void) / O! e8 y! W2 `. B! ^$ t) l
- {
- Z4 l; Q8 O! k* W' I& W; ?9 k - uint32_t i = 0;
4 l# X( E1 e! ^ z - ) ^/ p, i6 h- }+ h
- /*!< At this stage the microcontroller clock setting is already configured,
; G7 `* j7 C% T& j0 j - this is done through SystemInit() function which is called from startup , ^, y* [7 d+ h9 t w% b9 w
- file (startup_stm32f0xx.s) before to branch to application main.
! F X0 X: _3 n5 f - To reconfigure the default setting of SystemInit() function, refer to
1 k+ J0 w- v; \9 n. c* ]+ { - system_stm32f0xx.c file " T4 P6 `+ ~- F% q6 _3 M
- */
! Z7 ^5 l1 L) _% t) I W - % Y1 G, h( Z6 ^7 t( ]3 ], J. E- k
- /* Relocate by software the vector table to the internal SRAM at 0x20000000 ***/
& J) _( ^+ Q* [6 e0 \9 z5 H -
/ }! J' v# A/ ~7 D4 u+ c, r - /* Copy the vector table from the Flash (mapped at the base of the application ' X! M2 _' Z5 ^; ?. r/ c2 ^" H
- load address 0x08003000) to the base address of the SRAM at 0x20000000. */ 4 }8 K$ C+ h3 Y. e
- for(i = 0; i < 48; i++) & n- G( c& O# J) d/ X) e
- {
, a/ U+ ?; t6 h# S5 U - VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2)); $ C x5 x% E4 `$ N7 @- z4 B4 N1 m
- }
- e% m/ U1 P2 Y! N; j - ; i& h8 ]8 k: U* {
- /* Enable the SYSCFG peripheral clock*/
# m8 ^" N9 Z8 X! H8 ?0 ` - //RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);
' x4 `- A( [: k$ Q8 K9 O3 C8 B - RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //需要修改成这样
) ^$ C& G5 B/ t" I: P6 I4 n - /* Remap SRAM at 0x00000000 */ * l/ {! b4 ^" D( P2 R
- SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
! I4 @* c3 R/ [ A -
Q, \0 P2 U C- e3 _ _7 i; G - /...
7 f0 \( a- F# W' _* H$ t5 l5 V! w - }
复制代码
! C6 Q. U/ ^1 U0 W. @& G. P
, Q( r$ H( z( W' Y+ \% Q/ l8 Y6 b" Z打开对应的map文件,有如下内容:- I1 j# b3 e d" s w
- [plain] view plain copy/ b ~ ~) Q3 n* H5 v
- GPIO_PIN 0x08003470 Data 8 stm320518_eval.o(.constdata)
( w& S, u+ c: K f - GPIO_CLK 0x08003478 Data 16 stm320518_eval.o(.constdata)
7 `8 j* w' m! b _" R8 O - BUTTON_PIN 0x08003488 Data 14 stm320518_eval.o(.constdata) ! a8 E: O7 ~! \, n6 o
- BUTTON_CLK 0x08003498 Data 28 stm320518_eval.o(.constdata)
2 H, m* d0 p+ O) @& g - BUTTON_EXTI_LINE 0x080034b4 Data 14 stm320518_eval.o(.constdata)
: t! g0 V0 m8 K, q) H - BUTTON_PORT_SOURCE 0x080034c2 Data 14 stm320518_eval.o(.constdata) 6 B, C0 X: f H4 B
- BUTTON_PIN_SOURCE 0x080034d0 Data 14 stm320518_eval.o(.constdata)
; ?/ j1 E7 L2 Q# k - BUTTON_IRQn 0x080034de Data 14 stm320518_eval.o(.constdata) " W, @/ U) e5 z. i) G; `, z/ F
- COM_USART_CLK 0x080034ec Data 4 stm320518_eval.o(.constdata)
' \, k. K) A( t8 X - COM_TX_PORT_CLK 0x080034f0 Data 4 stm320518_eval.o(.constdata)
' `3 c& O* K: L - COM_RX_PORT_CLK 0x080034f4 Data 4 stm320518_eval.o(.constdata) / f0 G" v* l& T" e" y9 Q
- COM_TX_PIN 0x080034f8 Data 2 stm320518_eval.o(.constdata) 6 K" e i: V/ S
- COM_RX_PIN 0x080034fa Data 2 stm320518_eval.o(.constdata) & ?$ n' f+ Y) m' Z9 G/ o
- COM_TX_PIN_SOURCE 0x080034fc Data 2 stm320518_eval.o(.constdata) " T4 O% D) E x; @) W4 \
- COM_RX_PIN_SOURCE 0x080034fe Data 2 stm320518_eval.o(.constdata) 4 `6 \/ W# P* Y% x2 K
- COM_TX_AF 0x08003500 Data 2 stm320518_eval.o(.constdata) / d f4 M! o3 G' U/ L% o
- COM_RX_AF 0x08003502 Data 2 stm320518_eval.o(.constdata)
% I0 Q7 I# O1 x$ x* j2 t8 Q4 t4 ^9 U - Region! G6 {8 }& _& |* K3 w% j t
- Base 0x08003504 Number 0 anon4 I# e$ {: }; c4 M$ I
- Table)
# g/ o! X* g3 }3 A - Region; h( C9 D6 s1 H
- Limit 0x08003524 Number 0 anon
: G8 F s6 Y% X* U, Q) A9 K - Table)
* l( d9 _( ?3 G" {" u: @4 Y - VectorTable 0x20000000 Data 192 main.o(.ARM.__AT_0x20000000) //向量表位置为0x20000000 " ]6 C+ [ k; g0 W1 n" l
- SystemCoreClock 0x200000c0 Data 4 system_stm32f0xx.o(.data) //其他全局变量的起始位置为0x200000C0
* w0 ]4 G* ^8 ~( o/ V4 R- a - AHBPrescTable 0x200000c4 Data 16 system_stm32f0xx.o(.data)
2 N7 R k+ v% u% B$ N - GPIO_PORT 0x200000d4 Data 16 stm320518_eval.o(.data) 3 q$ r# q+ a% l0 Q3 V: k
- BUTTON_PORT 0x200000e4 Data 28 stm320518_eval.o(.data)
- E- t! d* J% l1 n5 c# F - COM_USART 0x20000100 Data 4 stm320518_eval.o(.data) 1 L. `9 C* V* R5 W1 a9 D% @: _% M
- COM_TX_PORT 0x20000104 Data 4 stm320518_eval.o(.data) , {6 j1 |9 x' O# `
- COM_RX_PORT 0x20000108 Data 4 stm320518_eval.o(.data)
, {0 g3 G4 r j' j; @ - __initial_sp 0x20000510 Data 0 startup_stm32f0xx.o(STACK)
复制代码 + h2 l0 M4 L. s' I. N
如上所述,中断向量表被编译在0x20000000,内存的起始位置,而system_stm32f0xx.c下的全局变量SystemCoreClock被KEIL编译成放在紧挨着的0x200000C0的位置,与预期完全相符。分别将IAP与APP烧录进FLASH,测试可以正常运行。# D4 Y s, |- T' p' {8 L, r
6 n. j- m' h: B t
注:在KEIL下,必须存在IAP才能调试APP!,这点是与IAR不同的。- {7 Q9 t) ?+ Q2 b: S% L5 h9 P& S/ f
: n5 E- J6 R; K3 ^' y
8 o* d* T8 v. C3 IAR下移植
9 `) @+ J* ]; L5 A3 _1 K0 H3 }在IAR下的IAP没有什么特殊的,主要还是看APP的配置。 使用IAR打开APP工程,修改device为STM32F070:
& i: y. W$ N8 m t% a8 q
4 |3 ]3 ]" H) ~3 I

0 e* Q6 [( V- d% M" _3 q( l
链接配置: 中断向量表:
( G1 k) l( H5 n" y& [# ?
: S( U) i, C+ J4 j2 N- G/ G

7 V! t. Y$ n% X7 J6 F
内存映射: o/ y$ E1 ^- c) H4 K5 U: |

' T% i Q3 y X, A 4 P' E6 Y: b" ?; S9 ^
如上,APP存放在FLASH的位置0x8003000,内存还是设置为:0x20000000. 编译后,打开对应的map文件如下所示: - Entry Address Size Type Object 9 N1 \" z9 y) a0 L% i, G
- ----- ------- ---- ---- ------
; }! V9 _; T% v+ w' @- i - .iar.init_table$Base 0x080034fc -- Gb - Linker created -
/ I( D% `. x; [/ w - .iar.init_table$Limit 0x08003510 -- Gb - Linker created - 2 R( z+ A+ l8 t3 T: }6 Z
- ?main 0x08003511 Code Gb cmain.o [4] 7 l5 _3 K. k$ D& R# c5 O
- CSTACK$Base 0x200000d8 -- Gb - Linker created - 2 U* Q: G& ]8 \+ S
- CSTACK$Limit 0x200010d8 -- Gb - Linker created -
4 Y9 ^' y) t# w5 ^. F6 d. H8 U - Delay 0x080031e3 0x10 Code Gb main.o [1] % l7 |* z4 {; o! W
- GPIO_PIN 0x080035a0 0x8 Data Gb stm320518_eval.o [1]
# t! \/ |# T4 u) ^' d0 X) c: i% F - GPIO_PORT 0x200000c0 0x10 Data Gb stm320518_eval.o [1] //stm320518_eval.c文件内的全局变量GPIO_PORT数组存放在0x200000c0 # e( ~+ ~' a: f. P U P3 F
- HardFault_Handler 0x08003573 0x4 Code Gb stm32f0xx_it.o [1]
9 e ^, _: ]/ R. g - NMI_Handler 0x08003571 0x2 Code Gb stm32f0xx_it.o [1] + Z$ A; t* D7 N% N+ {
- NVIC_SetPriority 0x080030c1 0x84 Code Lc main.o [1] & O4 L( A8 I5 q1 N m. Q
- PendSV_Handler 0x08003579 0x2 Code Gb stm32f0xx_it.o [1] 7 w( z/ G! |& H2 p+ U
- RCC_APB2PeriphClockCmd 0x08003229 0x20 Code Gb stm32f0xx_rcc.o [1]
+ P1 J+ \: x x* n - Region3 c1 ]5 A% W* s7 h8 Q j7 v
- Base 0x080034fc -- Gb - Linker created - ( f' b. z% Y& l: _4 L
- Region8 I& `5 _* z0 F+ `/ T) f$ s, [
- Limit 0x08003510 -- Gb - Linker created -
$ O( G* X6 b8 t. l+ n - STM_EVAL_LEDToggle 0x08003315 0x26 Code Gb stm320518_eval.o [1] 8 `% u) _: e& l$ G
- SVC_Handler 0x08003577 0x2 Code Gb stm32f0xx_it.o [1] & c3 V9 B. i0 x6 b, p
- SYSCFG_MemoryRemapConfig 3 C- e* f7 z0 g# I; _
- 0x0800324d 0x14 Code Gb stm32f0xx_syscfg.o [1]
# q. h: a. m5 j2 ]2 h; h - SetSysClock 0x080033b7 0xbe Code Lc system_stm32f0xx.o [1] 5 o- V3 U* f; t
- SysTick_Config 0x08003145 0x32 Code Lc main.o [1] , H' F6 z; d3 ]7 L. [# V/ q
- SysTick_Handler 0x0800357b 0x8 Code Gb stm32f0xx_it.o [1]
, f1 a0 g0 i1 V% P, | - SystemCoreClock 0x200000d0 0x4 Data Gb system_stm32f0xx.o [1]
' u1 q( w( v9 |; h - SystemInit 0x08003349 0x6e Code Gb system_stm32f0xx.o [1]
, G' P& J1 S$ P6 B' S - TimingDelay 0x200000d4 0x4 Data Lc main.o [1] ) B/ w( V6 z% h; C
- TimingDelay_Decrement 0x080031f3 0x16 Code Gb main.o [1] 1 ^6 d- m- c+ Y2 c6 ?
- VectorTable 0x20000000 0xc0 Data Gb main.o [1] //向量表编译位置为0x20000000
8 V* r* v3 ?% F% c6 S - __aeabi_idiv0 0x08003345 Code Gb IntDivZer.o [4] & a% f) k6 W7 L7 H7 E8 |7 E( }+ E
- __aeabi_uidiv 0x08003265 Code Gb I32DivModFast.o [4]
& Q: P, }* H- k3 c* a6 V; {& V - __aeabi_uidivmod 0x08003265 Code Gb I32DivModFast.o [4] ! k2 r0 X! G; G$ ?# S* n+ k
- __cmain 0x08003511 Code Gb cmain.o [4]
8 c( k5 ~$ O. ?/ u, Z: Q9 Z - __exit 0x08003545 0x14 Code Gb exit.o [5] 7 o+ k( q9 V* p6 q" F; }
- __iar_copy_init3 0x080034a5 0x30 Code Gb copy_init3.o [4]
# ]# x. h; S6 l- T - __iar_data_init3 0x080034d5 0x28 Code Gb data_init.o [4]
. A- n4 D2 ^1 \/ k. U1 M: H! R - __iar_program_start 0x08003595 Code Gb cstartup_M.o [4]
3 h( k) R% ^! B4 o% A: z; _- z - __low_level_init 0x0800352b 0x4 Code Gb low_level_init.o [3] 7 `" I X6 {- m1 s/ l
- __vector_table 0x08003000 Data Gb startup_stm32f0xx.o [1] . q! h) q3 N# C) _5 z
- _call_main 0x0800351d Code Gb cmain.o [4]
: |+ m) r0 s% e/ o$ }- ^( \ - _exit 0x08003539 Code Gb cexit.o [4] $ j" q$ U. i4 @- f3 }" `2 v- j
- _main 0x08003527 Code Gb cmain.o [4] 9 B& z! J8 {' q7 U! @
- exit 0x0800352f 0x8 Code Gb exit.o [3] * s: ?8 E9 ~4 h1 P8 `
- main 0x08003177 0x6c Code Gb main.o [1]
5 v; d3 Z+ Y8 d, b2 D: y* x; _; O
复制代码
" [8 b$ f% {4 J. W如上所示,在IAR编译下,中断向量表被编译在0x20000000,内存的起始位置,而stm320518_eval.c下的全局变量GPIO_PORT被IAR编译成放在紧挨着的0x200000C0的位置。分别将IAP与APP烧录进FLASH,测试可以正常运行。) Y/ u( ?* _* H* f4 E: }( Y4 _
' b2 m; o9 |! c) u( Z
注:从IAR工程的链接配置来看,并没有像KEIL那样配置RAM位置为:0x2000000,编译后的结果向量表也不会与其他全局变量相冲突,可见IAR编译器已经自动计算并避免这种冲突,不像KEIL那样会出现链接错误,以此来提示用户。
! u/ f2 y3 A( i& v- k9 ?另外:在IAR下,在不存在IAP的情况下也是可以调试APP的,这点是KEIL所不具备的功能,看样子,IAR在细节的处理上比KEIL要好。
% S6 |- ?9 W& W( h# q) e8 X' `7 Z$ C( z
|