1 前言
2 D5 s' f/ h9 n4 b( {( {STSW-STM32116是ST官网基于标准库的针对STM32F0的USART进口IAP示例程序
3 V% E2 j, s% F2 f V8 U工程原本是针对STM32F051,本文将介绍如何移植到STM32F070,并针对移植的过程中的问题逐个处理。
3 ?2 G4 E; e" Q0 O; h& {6 `6 M% s+ k' O* T6 _+ F- O
2 KEIL下移植9 k& P% F/ a, I- Z5 E
IAP程序一般分为两个,一个是IAP,一个是APP,IAP存放在内置FLASH的0x8000000的起始位置,而APP则存放在离这个位置一定距离的位置,这个距离一定是大于或等于IAP本身所占空间大小,本例子为0x8003000。
, G+ Q5 ^2 ~5 c) w+ C
" j7 o+ n+ T! u% Q下载资源后,打开STM32F0xx_AN4065_FW_V1.0.0\Project\STM32F0xx_IAP\下的binary_template工程,这个就是APP工程,首先用KEIL打开,修改device为STM32F070,
: E! y, D- x6 ]
4 z4 u& x5 k/ c+ j/ t% f4 x' A" a( Y5 b8 {, X4 @7 f
# D* T: C, i1 p3 F/ J( B, |- F4 l
并编译,结果发现原始的公式是编译不过的,如下错误信息:+ a) t$ M3 m- e& ^1 f, @7 R0 Z; X
- linking...
. l9 g0 }' k, I9 A6 z, J. [1 s - .\STM320518_EVAL\STM320518_EVAL.axf: Error: L6971E: system_stm32f0xx.o(.data) type RW incompatible with main.o(.ARM.__AT_0x20000000) type ZI in er RW_IRAM1.
0 F- U( u# ?' X: { - Not enough information to list image symbols.0 K6 n6 g5 Y0 w( M2 U0 @
- Finished: 1 information, 0 warning and 1 error messages.
* S; m. k% {; ~; \8 M - ".\STM320518_EVAL\STM320518_EVAL.axf" - 1 Error(s), 0 Warning(s).) ~9 V6 p, J, Y" g' ]3 J* U
- Target not created.
/ G8 j! B! b$ v" c - Build Time Elapsed: 00:00:08
复制代码 6 R7 S' S! s4 ]# N4 E
从字面上判断为编译system_stm32f0xx.c文件生成的目标文件system_stm32f0xx.o中的数据段(.data)内的RW数据与main.o中的数据在地址0x20000000产生冲突。. U4 G& ]0 G0 s) |$ ?: G6 ^/ I! l' D
仔细查看代码,发现main函数之前这么一段:/ o- f$ a" S( [7 r7 ]1 N
- #if (defined ( __CC_ARM ))
$ l- R, |# G8 a8 n+ m z - __IO uint32_t VectorTable[48] __attribute__((at(0x20000000)));5 F! _. p' K. \# W
- #elif (defined (__ICCARM__))% n- d2 _2 X2 u7 J% Y- i' ^( F2 v
- #pragma location = 0x20000000+ v4 K0 v* T1 Z* f3 `- }
- __no_init __IO uint32_t VectorTable[48];
. {( a/ C7 ~5 E' U# j8 W - #elif defined ( __GNUC__ )% k3 E$ t0 z' ?
- __IO uint32_t VectorTable[48] __attribute__((section(".RAMVectorTable"))); t n3 A7 d; _7 i6 S
- #elif defined ( __TASKING__ )' b" c, V F8 o9 U: Z
- __IO uint32_t VectorTable[48] __at(0x20000000);6 n* W+ v# A" R4 E6 f) z; |
- #endif
复制代码 # ?3 w/ ^* K+ F( c+ p* z
可见代码是要将中断向量表VectorTable强制定义在内存0x20000000上,但是此地址与system_stm32f0xx.c定义的全局变量位置有冲突。于是,需要修改避免冲突。中断向量的地址是固定的,但其他全局变量的地址可以相应地移动下,并且APP的烧录位置为0x8003000,如下图:/ N- B1 d; t. j
; t! o' s- Y1 }0 e, P$ ]( @ ]7 S: p; f" ~. n$ @& B1 \
4 B) F% y! G ?7 @
再次编译,错误就会消失了。
6 H* |( i [/ x+ w% @; V/ U6 K/ @8 P5 Q% e I+ g
另外需要将main函数内前面几行代码做些修改:
2 L9 V: t) I5 F3 @- int main(void)' Z- ~- n% c2 I6 N* U/ a" ]$ v4 ]
- {& ? S; t: i1 @" j1 _6 U3 D
- uint32_t i = 0;6 x, @: C; p- x( |5 t$ z7 u
- ( u* Q* u- d) ~
- /*!< At this stage the microcontroller clock setting is already configured, ; ]% n( [: X/ G6 c: Y# }( n( @
- this is done through SystemInit() function which is called from startup4 X4 E+ a- X4 R4 m6 f
- file (startup_stm32f0xx.s) before to branch to application main.
4 \! Q* T) F- H( y: T - To reconfigure the default setting of SystemInit() function, refer to4 ~# Q) A; W6 U) m! q
- system_stm32f0xx.c file5 @. B) o8 J+ m8 q$ }$ T# Q
- */ & }' t8 `; q( H+ Q
8 ?5 w4 p- f1 ~) H' {- /* Relocate by software the vector table to the internal SRAM at 0x20000000 ***/ 7 J( B6 |' D( V9 e( B
7 ~$ w) Z8 J4 d# g( M5 [& d- /* Copy the vector table from the Flash (mapped at the base of the application d& [/ Q* @4 S
- load address 0x08003000) to the base address of the SRAM at 0x20000000. */) P; I* e$ u4 R$ w+ s! N
- for(i = 0; i < 48; i++)& s6 L/ Y: W/ y: Q6 [8 i! g
- {
3 L4 Y. R6 q, i* ^+ P - VectorTable<i> = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2));
* I( Q" U; P# D, I" u0 u - </i>}# C+ Q0 u3 [: X
- q7 S x8 D! e! t% r- /* Enable the SYSCFG peripheral clock*/
- Z5 f E* c6 S" G - //RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);
# J! x6 Q- y6 c* L% F6 X - RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //需要修改成这样7 C: ]& D3 D- K6 Q9 G! n5 \- V
- /* Remap SRAM at 0x00000000 */
( t. ?+ J W; C - SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
3 n4 `6 O- a( X- l$ p
* `1 ~ M% |3 _8 {5 S- /...( E" s) C/ W8 A' v# X
- }
复制代码 : K- Y) G8 z& \ ]+ L2 W
打开对应的map文件,有如下内容:
6 D$ d$ \& I+ Z& t) |- GPIO_PIN 0x08003470 Data 8 stm320518_eval.o(.constdata)
' ^1 A# Q0 y0 [! O - GPIO_CLK 0x08003478 Data 16 stm320518_eval.o(.constdata)' c( I. |/ i8 M7 g- j, u, F
- BUTTON_PIN 0x08003488 Data 14 stm320518_eval.o(.constdata)6 e- a0 ~& m. q6 d) j3 Y
- BUTTON_CLK 0x08003498 Data 28 stm320518_eval.o(.constdata)1 U5 _9 n# Z( H+ X# A3 U. G
- BUTTON_EXTI_LINE 0x080034b4 Data 14 stm320518_eval.o(.constdata)
2 s; ?4 x8 E4 B3 f5 M- z( a+ h0 [ - BUTTON_PORT_SOURCE 0x080034c2 Data 14 stm320518_eval.o(.constdata)8 d' Z @4 ]& P. m7 x
- BUTTON_PIN_SOURCE 0x080034d0 Data 14 stm320518_eval.o(.constdata)
( \( \8 J5 g" u5 o. z2 p @+ R5 A - BUTTON_IRQn 0x080034de Data 14 stm320518_eval.o(.constdata)
2 E; Z* M3 K( Z - COM_USART_CLK 0x080034ec Data 4 stm320518_eval.o(.constdata)2 Q/ h+ K: c# Z) o8 Y
- COM_TX_PORT_CLK 0x080034f0 Data 4 stm320518_eval.o(.constdata)0 ^7 `0 f! ?5 @) T C& P% i j
- COM_RX_PORT_CLK 0x080034f4 Data 4 stm320518_eval.o(.constdata)8 Z, ~! g1 B5 Y7 V f& \% D1 B' y: X
- COM_TX_PIN 0x080034f8 Data 2 stm320518_eval.o(.constdata)( ]. \! l- N4 J, Q
- COM_RX_PIN 0x080034fa Data 2 stm320518_eval.o(.constdata)
# q8 p5 j* ]* T6 E0 N$ E! M3 S - COM_TX_PIN_SOURCE 0x080034fc Data 2 stm320518_eval.o(.constdata). n: X; S5 {2 g
- COM_RX_PIN_SOURCE 0x080034fe Data 2 stm320518_eval.o(.constdata)! ]+ P" T8 }* Z( }/ e
- COM_TX_AF 0x08003500 Data 2 stm320518_eval.o(.constdata)6 V0 _# U) I+ `! S% q
- COM_RX_AF 0x08003502 Data 2 stm320518_eval.o(.constdata)% O# u- I+ c* q% p4 G2 p, v
- Region$Table$Base 0x08003504 Number 0 anon$obj.o(Region$Table)
* v7 F0 v9 n9 H, v, ^2 z& @3 v! V - Region$Table$Limit 0x08003524 Number 0 anon$obj.o(Region$Table)0 B, I1 B) D, \! ]$ r' ~
- VectorTable 0x20000000 Data 192 main.o(.ARM.__AT_0x20000000) //向量表位置为0x200000005 J1 a. s% v+ x
- SystemCoreClock 0x200000c0 Data 4 system_stm32f0xx.o(.data) //其他全局变量的起始位置为0x200000C0* `: w. r& A9 G; l$ K# `# ~
- AHBPrescTable 0x200000c4 Data 16 system_stm32f0xx.o(.data), J3 _# _6 e; |6 i+ J, o+ `
- GPIO_PORT 0x200000d4 Data 16 stm320518_eval.o(.data)6 g# s7 o$ S8 N" @" b
- BUTTON_PORT 0x200000e4 Data 28 stm320518_eval.o(.data)6 r! F0 I- P4 `3 V7 @6 U ~
- COM_USART 0x20000100 Data 4 stm320518_eval.o(.data)
. k) S. c9 ?/ @! z - COM_TX_PORT 0x20000104 Data 4 stm320518_eval.o(.data)
9 m& ~+ j2 P# D5 d0 P4 E - COM_RX_PORT 0x20000108 Data 4 stm320518_eval.o(.data)
: L3 ^! A, x. b$ V - __initial_sp 0x20000510 Data 0 startup_stm32f0xx.o(STACK), i6 ?1 A8 z3 G: C: @/ u
复制代码 ; ?0 z, M1 g1 T7 {3 F
如上所述,中断向量表被编译在0x20000000,内存的起始位置,而system_stm32f0xx.c下的全局变量SystemCoreClock被KEIL编译成放在紧挨着的0x200000C0的位置,与预期完全相符。分别将IAP与APP烧录进FLASH,测试可以正常运行。6 E9 F4 ^5 r/ e8 F p
8 M3 `, t# I- Z9 C% n$ C# K
注:在KEIL下,必须存在IAP才能调试APP!,这点是与IAR不同的。1 c* \* y" D* O% n
4 P2 k7 F: T$ I3 a; L" T- D0 x& }
) K" T; k' t$ |. Q3 IAR下移植
( L l \/ L' o8 R+ P在IAR下的IAP没有什么特殊的,主要还是看APP的配置。
8 H( `1 g& l) A7 Z$ U& t
% h0 j$ C: t' {9 S- D' A( ^( N( G, X使用IAR打开APP工程,修改device为STM32F070:
- ]9 e6 b" q9 [# N1 D/ Z" }$ I: A; N; D0 y
1 l" I: k# ?6 s. W7 N7 A1 }+ W( ^& Q0 j" y2 z! @ R
链接配置:# G9 h+ Q; } M0 V8 `9 w p
) w0 B; N5 a0 I; i$ l+ P
中断向量表:' |+ u- h' K% N) j
2 v- b; C" s6 ~- ]% b$ ~# w( o
8 R+ C7 K8 q# \2 o1 f$ D: n% G- _2 }% r. x3 n" f' D8 n
内存映射:
( N% b% G! E& g- k
2 T+ t7 ?. F9 R% R8 T1 x7 N
& H6 w3 q6 O1 W; B, u8 |5 ~0 n: c+ r1 n- F% r
/ o: T- Y2 Q/ t- i
7 [" \. b* J% i2 G如上,APP存放在FLASH的位置0x8003000,内存还是设置为:0x20000000.
6 I* ]1 z/ |/ J* |& H1 P5 {2 c$ _- C' \8 k5 @' z' a! V
编译后,打开对应的map文件如下所示:
9 `9 p1 y; o! a4 f! b! d1 @9 c% w' o' ^! O. h; D
- Entry Address Size Type Object
( g+ A3 o% L: w8 J - ----- ------- ---- ---- ------
; j ~1 q% j+ a5 m2 | - .iar.init_table$Base 0x080034fc -- Gb - Linker created -. Z. p9 I. ~2 l' K8 G# Z
- .iar.init_table$Limit 0x08003510 -- Gb - Linker created -
- h3 c9 b) y/ q, g, h - ?main 0x08003511 Code Gb cmain.o [4]
# J" A3 c5 F' n+ b+ j/ I, u - CSTACK$Base 0x200000d8 -- Gb - Linker created -" [$ ^! I& E5 ^! G3 g3 o2 c! b0 J
- CSTACK$Limit 0x200010d8 -- Gb - Linker created -
6 N$ p c: P* H; @ - Delay 0x080031e3 0x10 Code Gb main.o [1]
( o; {; `; J5 V* x. L - GPIO_PIN 0x080035a0 0x8 Data Gb stm320518_eval.o [1]" q, a9 c6 G- B' U6 G3 [
- GPIO_PORT 0x200000c0 0x10 Data Gb stm320518_eval.o [1] //stm320518_eval.c文件内的全局变量GPIO_PORT数组存放在0x200000c0
8 W8 J% y9 u' I! m - HardFault_Handler 0x08003573 0x4 Code Gb stm32f0xx_it.o [1]
' O9 C$ b5 i5 P( b- u, N - NMI_Handler 0x08003571 0x2 Code Gb stm32f0xx_it.o [1]6 s) T( b/ T1 \
- NVIC_SetPriority 0x080030c1 0x84 Code Lc main.o [1]
; }, D/ Y. D; j - PendSV_Handler 0x08003579 0x2 Code Gb stm32f0xx_it.o [1], b9 d& T3 i9 I: F6 L
- RCC_APB2PeriphClockCmd 0x08003229 0x20 Code Gb stm32f0xx_rcc.o [1]* a) _, G5 b% ]( n
- Region$Table$Base 0x080034fc -- Gb - Linker created -
- U3 Q3 W1 v( G, ^+ s" C - Region$Table$Limit 0x08003510 -- Gb - Linker created -
+ U& Z# F7 C' X1 I3 s8 l6 R6 g - STM_EVAL_LEDToggle 0x08003315 0x26 Code Gb stm320518_eval.o [1]
3 V) B% ?: J4 {1 w% @4 k - SVC_Handler 0x08003577 0x2 Code Gb stm32f0xx_it.o [1]/ x7 D' S2 T6 E/ h
- SYSCFG_MemoryRemapConfig
0 N$ S2 q/ Z" n2 V - 0x0800324d 0x14 Code Gb stm32f0xx_syscfg.o [1]
5 P" {6 c! ~! o# \ - SetSysClock 0x080033b7 0xbe Code Lc system_stm32f0xx.o [1]
& e2 `/ L/ l; g: Q' X4 r8 }% x - SysTick_Config 0x08003145 0x32 Code Lc main.o [1]
% a) p' o3 A j6 n1 a3 J+ r - SysTick_Handler 0x0800357b 0x8 Code Gb stm32f0xx_it.o [1]4 q5 @) R& z* X! f
- SystemCoreClock 0x200000d0 0x4 Data Gb system_stm32f0xx.o [1]
4 U, A2 X7 i+ ]9 Q5 Z0 f - SystemInit 0x08003349 0x6e Code Gb system_stm32f0xx.o [1]9 s* Z2 o+ K) O1 M
- TimingDelay 0x200000d4 0x4 Data Lc main.o [1]
3 _7 z4 ^3 @' X1 g - TimingDelay_Decrement 0x080031f3 0x16 Code Gb main.o [1]
) M0 y4 M. H* ]9 k: E; l% K$ S - VectorTable 0x20000000 0xc0 Data Gb main.o [1] //向量表编译位置为0x200000008 E. \: F; y& K- H& i9 n
- __aeabi_idiv0 0x08003345 Code Gb IntDivZer.o [4]3 b3 a9 Z& W) U1 V( f N2 u
- __aeabi_uidiv 0x08003265 Code Gb I32DivModFast.o [4]
; S, W4 B2 l% }- E( ~ - __aeabi_uidivmod 0x08003265 Code Gb I32DivModFast.o [4]
: l- M- G1 ~7 `: R - __cmain 0x08003511 Code Gb cmain.o [4]
" W. m' Z1 p. y L3 \ - __exit 0x08003545 0x14 Code Gb exit.o [5]! D: D" a; ]! L, R
- __iar_copy_init3 0x080034a5 0x30 Code Gb copy_init3.o [4]
0 d& W" U: v0 V) x - __iar_data_init3 0x080034d5 0x28 Code Gb data_init.o [4]
9 @' {5 |; n" i' B2 j, m - __iar_program_start 0x08003595 Code Gb cstartup_M.o [4]. q$ L: `! t9 B$ _2 q
- __low_level_init 0x0800352b 0x4 Code Gb low_level_init.o [3]1 X0 y2 ^6 \0 t% r. E. ]
- __vector_table 0x08003000 Data Gb startup_stm32f0xx.o [1]
( Z! Z. a# Z$ v1 F5 f) J# P5 I - _call_main 0x0800351d Code Gb cmain.o [4]
. t+ p+ f; Q! A, }) W$ a - _exit 0x08003539 Code Gb cexit.o [4]. x+ ~: f' n% q% R# r* U- A5 h
- _main 0x08003527 Code Gb cmain.o [4]
@" \: k7 ^. U. S$ R) v9 ^# w* [ - exit 0x0800352f 0x8 Code Gb exit.o [3]) k5 k: r1 l! X7 r R
- main <span style="background-color: rgb(255, 255, 255);"> </span><span style="background-color: rgb(255, 255, 255);"> 0x08003177 0x6c Code Gb main.o [1]</span>
复制代码
; d3 ]5 V; R; M8 p* L如上所示,在IAR编译下,中断向量表被编译在0x20000000,内存的起始位置,而stm320518_eval.c下的全局变量GPIO_PORT被IAR编译成放在紧挨着的0x200000C0的位置。分别将IAP与APP烧录进FLASH,测试可以正常运行。5 p7 u8 @/ E; z; n% e
5 K2 V/ h# N+ L1 t" F* d
注:从IAR工程的链接配置来看,并没有像KEIL那样配置RAM位置为:0x2000000,编译后的结果向量表也不会与其他全局变量相冲突,可见IAR编译器已经自动计算并避免这种冲突,不像KEIL那样会出现链接错误,以此来提示用户。
) Q }0 m' l+ m( J. B
9 j; D0 S1 h) _2 F4 ?' D另外:在IAR下,在不存在IAP的情况下也是可以调试APP的,这点是KEIL所不具备的功能,看样子,IAR在细节的处理上比KEIL要好。
& z& ?/ w) ~; B/ t, Q
) U+ C1 h: D9 ]" P$ p$ t- z% L/ q! e; v
' m$ \( H, W0 [: y% r$ Y, X |