1 前言7 a4 t7 Q. r3 c/ o/ f. N
STSW-STM32116是ST官网基于标准库的针对STM32F0的USART进口IAP示例程序
+ `4 Q a8 i9 M1 J, V. B9 t2 X工程原本是针对STM32F051,本文将介绍如何移植到STM32F070,并针对移植的过程中的问题逐个处理。4 D/ u+ r& s8 K1 L; Z
) O* _! Z+ G% a* a! _" ]6 a" v
2 KEIL下移植8 e3 o* F$ A* i9 n* b$ {; l9 v
IAP程序一般分为两个,一个是IAP,一个是APP,IAP存放在内置FLASH的0x8000000的起始位置,而APP则存放在离这个位置一定距离的位置,这个距离一定是大于或等于IAP本身所占空间大小,本例子为0x8003000。7 a& B& d- B" C! [
& R M2 Y2 u! O2 I6 m% {/ P下载资源后,打开STM32F0xx_AN4065_FW_V1.0.0\Project\STM32F0xx_IAP\下的binary_template工程,这个就是APP工程,首先用KEIL打开,修改device为STM32F070,0 R% P2 R6 L- c' t4 P+ P: Y7 O6 l
7 t1 Y' l" t8 o. e' ~; n8 g* s; k4 o9 w! E' B: [- m- ~
+ O4 w- H7 z4 K( s$ w并编译,结果发现原始的公式是编译不过的,如下错误信息: @/ J C" T1 y1 X
- linking...( B' f: B8 r+ t( A' z% A- l4 g
- .\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.
4 j0 ?4 N" b. a* O7 ] @! ]* ^$ i - Not enough information to list image symbols.( q( N! [- _ N ^
- Finished: 1 information, 0 warning and 1 error messages.: d1 H% K% }6 N: @
- ".\STM320518_EVAL\STM320518_EVAL.axf" - 1 Error(s), 0 Warning(s).
7 G5 O& h& a/ I3 @$ z/ o - Target not created.
0 H" J; T; M: b5 q" ^: \* v - Build Time Elapsed: 00:00:08
复制代码 5 c4 Y4 j* ~/ ~8 h8 l' N2 ?, o
从字面上判断为编译system_stm32f0xx.c文件生成的目标文件system_stm32f0xx.o中的数据段(.data)内的RW数据与main.o中的数据在地址0x20000000产生冲突。
" E9 \* M" S, a% w仔细查看代码,发现main函数之前这么一段:# D1 _( V; P8 N+ c
- #if (defined ( __CC_ARM ))* O! d" y( }8 I4 O4 _: ]! O7 B( J! u
- __IO uint32_t VectorTable[48] __attribute__((at(0x20000000)));: d; u' v& w0 o. U" @) V
- #elif (defined (__ICCARM__))
- _" {2 u# `; e) l: O/ h; S - #pragma location = 0x20000000 {7 Q2 r. p8 z/ h8 N; r
- __no_init __IO uint32_t VectorTable[48];
1 n6 z7 V* C1 f! l, |$ L% |# H* W - #elif defined ( __GNUC__ )# V, J9 w2 y( n% v+ U& g* G% s
- __IO uint32_t VectorTable[48] __attribute__((section(".RAMVectorTable")));
3 h4 ^/ ~( {8 {/ T - #elif defined ( __TASKING__ )
$ k2 u/ O0 ^+ Y& _, x- i7 Z. v0 x$ Y5 Z - __IO uint32_t VectorTable[48] __at(0x20000000);
: E- f9 u% K2 z! z, R - #endif
复制代码 $ P9 L' h+ F3 ], q1 y7 M
可见代码是要将中断向量表VectorTable强制定义在内存0x20000000上,但是此地址与system_stm32f0xx.c定义的全局变量位置有冲突。于是,需要修改避免冲突。中断向量的地址是固定的,但其他全局变量的地址可以相应地移动下,并且APP的烧录位置为0x8003000,如下图:
0 j' ^# A, `! f2 H V4 k" r4 d: V Q. _. x
7 [1 T. g+ |* c E+ ?! {( k( y
$ Q4 z* ~9 H6 V6 A再次编译,错误就会消失了。/ n; `6 m9 C+ ^% W# X4 }* j
2 q2 _7 g0 i. A( y另外需要将main函数内前面几行代码做些修改:
& Y/ {5 l+ P$ r9 {0 |4 ^- int main(void)
& ~2 r ~: J5 L+ o& |- ^( ] - {
5 M6 s% b* r5 I% U' ]: _; S - uint32_t i = 0;/ R6 \4 L- C g/ q/ [+ g8 P
- ' S8 f+ m( A" u& }. G8 b/ f( S$ S
- /*!< At this stage the microcontroller clock setting is already configured, # D$ R) p+ T6 ~7 L [
- this is done through SystemInit() function which is called from startup
! M. g5 P% I T - file (startup_stm32f0xx.s) before to branch to application main.
$ q. @ X$ M9 n& e* v; b* Z+ g - To reconfigure the default setting of SystemInit() function, refer to
1 U' j+ Z( X% r+ O6 y5 o - system_stm32f0xx.c file+ {0 g* J9 g5 F- o0 c
- */
/ z) m6 v0 V! @& D$ o% p
; H: e0 x( E4 D, t& L' c- /* Relocate by software the vector table to the internal SRAM at 0x20000000 ***/ ; I& j% F7 X% T( M6 d
( V7 n# U& \) O- /* Copy the vector table from the Flash (mapped at the base of the application3 h( K: z1 C- G7 ^
- load address 0x08003000) to the base address of the SRAM at 0x20000000. */8 M% `+ x) J1 z, W
- for(i = 0; i < 48; i++)! H' U; G/ M% E) `( x* @! O
- {$ Q5 J: f0 r. T1 I8 u- @
- VectorTable<i> = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2));
; U+ ]0 {5 U4 S8 U! [. S - </i>}3 {- {0 K; o1 }$ V
0 l/ @% c1 U! h& F; o- /* Enable the SYSCFG peripheral clock*/$ y; P6 B& z, `+ O+ }3 ]% g
- //RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE); , ^9 Y( d, l( p* U* {
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //需要修改成这样+ O& S0 d, C3 ?3 D# X4 a
- /* Remap SRAM at 0x00000000 */1 |5 z* O: k% n; T
- SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
5 T1 L4 S, E" ?$ H - - @$ v7 {( {# N; x, u, ]3 s' s
- /...
1 B3 }& j$ p# T" s - }
复制代码
3 x: _" N m4 g打开对应的map文件,有如下内容:5 h" i- f1 c# z/ I: ?
- GPIO_PIN 0x08003470 Data 8 stm320518_eval.o(.constdata)& {4 [2 r3 W% u8 h- s
- GPIO_CLK 0x08003478 Data 16 stm320518_eval.o(.constdata)% s7 x$ E; Z2 h" J
- BUTTON_PIN 0x08003488 Data 14 stm320518_eval.o(.constdata)+ @6 @6 [3 |2 {$ J" f/ U5 o% @! j
- BUTTON_CLK 0x08003498 Data 28 stm320518_eval.o(.constdata)+ L& f5 Y5 d d0 X6 S0 N, A
- BUTTON_EXTI_LINE 0x080034b4 Data 14 stm320518_eval.o(.constdata)8 k! [# d( K3 A) K" @, V
- BUTTON_PORT_SOURCE 0x080034c2 Data 14 stm320518_eval.o(.constdata)
% r) b, K ?9 `! z1 X! ?1 N - BUTTON_PIN_SOURCE 0x080034d0 Data 14 stm320518_eval.o(.constdata)
! R& X3 |# P) k$ P, V9 Y0 i9 p8 ` - BUTTON_IRQn 0x080034de Data 14 stm320518_eval.o(.constdata)
& X3 Z1 J5 s q; P+ U' X - COM_USART_CLK 0x080034ec Data 4 stm320518_eval.o(.constdata)9 ?& W* V( Z& n+ ~. j
- COM_TX_PORT_CLK 0x080034f0 Data 4 stm320518_eval.o(.constdata)6 w5 T9 w! O) q" Z# G( k( g2 a" b
- COM_RX_PORT_CLK 0x080034f4 Data 4 stm320518_eval.o(.constdata)
* {& d9 v* h+ Z/ I* c A8 e" u - COM_TX_PIN 0x080034f8 Data 2 stm320518_eval.o(.constdata)% [/ q k& h) H2 O [
- COM_RX_PIN 0x080034fa Data 2 stm320518_eval.o(.constdata)
\% A1 c9 o! s$ f6 ?, Q ?; A. s - COM_TX_PIN_SOURCE 0x080034fc Data 2 stm320518_eval.o(.constdata)8 _- T0 j0 }7 n
- COM_RX_PIN_SOURCE 0x080034fe Data 2 stm320518_eval.o(.constdata); |' X8 j" I% g
- COM_TX_AF 0x08003500 Data 2 stm320518_eval.o(.constdata)
9 x$ J: @2 m [8 j2 ` - COM_RX_AF 0x08003502 Data 2 stm320518_eval.o(.constdata)! a8 V i0 G: [- R8 u+ N j* C L
- Region$Table$Base 0x08003504 Number 0 anon$obj.o(Region$Table)
) Q" f. R+ m* \. M( K r L p% J - Region$Table$Limit 0x08003524 Number 0 anon$obj.o(Region$Table). X" ~ u! l6 m* ~9 ~1 w
- VectorTable 0x20000000 Data 192 main.o(.ARM.__AT_0x20000000) //向量表位置为0x20000000" x& M+ d% `& _8 X" r) H/ c& Y- u
- SystemCoreClock 0x200000c0 Data 4 system_stm32f0xx.o(.data) //其他全局变量的起始位置为0x200000C0
% ~7 e' P( `. p8 o1 S |5 D, I - AHBPrescTable 0x200000c4 Data 16 system_stm32f0xx.o(.data)
. f: c, B5 [2 A8 i( j - GPIO_PORT 0x200000d4 Data 16 stm320518_eval.o(.data)
8 v/ l* ^; _0 I q7 d# M - BUTTON_PORT 0x200000e4 Data 28 stm320518_eval.o(.data): C) N7 N! ~5 i! c) |# g$ F
- COM_USART 0x20000100 Data 4 stm320518_eval.o(.data)' \; N2 r0 i m3 j, v) ~, x
- COM_TX_PORT 0x20000104 Data 4 stm320518_eval.o(.data)
' L# d- ]- F8 @6 e& B- |' p - COM_RX_PORT 0x20000108 Data 4 stm320518_eval.o(.data)
4 l6 j" U4 \9 z* a - __initial_sp 0x20000510 Data 0 startup_stm32f0xx.o(STACK)' Z( L. o0 ?9 o |- ^& H- ?
复制代码 ( W5 | A- o9 t @& l5 _0 S. e
如上所述,中断向量表被编译在0x20000000,内存的起始位置,而system_stm32f0xx.c下的全局变量SystemCoreClock被KEIL编译成放在紧挨着的0x200000C0的位置,与预期完全相符。分别将IAP与APP烧录进FLASH,测试可以正常运行。
% `/ f! e k7 N$ M+ N
7 d. q3 n( I0 P* l注:在KEIL下,必须存在IAP才能调试APP!,这点是与IAR不同的。
6 S, u% w- ~8 N1 _0 ], D5 X5 X6 R( ?/ u8 A, V' \2 E' M
: Z6 u& r$ o9 O' T3 IAR下移植
" M" a. H6 A% F4 r# {在IAR下的IAP没有什么特殊的,主要还是看APP的配置。, Z( p8 H, E8 A/ q
# p9 d' H5 W! p, n8 j8 N5 `使用IAR打开APP工程,修改device为STM32F070:. I3 t3 _# b' s, v" e
. r' U. e0 |' E9 n$ ^
6 l! m; {: H/ }/ \( u1 \0 ^8 B* n0 |9 }
4 Y6 t' C: o6 ]& o+ D" u/ J, t链接配置:
* \" Y; m, |" F
" ?0 ]! Q+ z; {5 G9 Y; T中断向量表:' m% h: Y! ~) K
3 A$ {6 ? T2 r: O7 T3 l4 x. ?8 e* X3 I) m# T0 L( R& n
, w# L1 I- x. o% G" _
内存映射:$ i2 N. x: a6 \+ ]* r8 I. y9 M
: V) f8 v1 f# R2 g7 G! n2 \1 Q$ [& K9 ^( c) O
, S: y" ^/ v+ N8 f0 w# Q* T
. \7 k$ \, X @2 q' n
4 k! ^* V+ c+ a* u* G# c; Y如上,APP存放在FLASH的位置0x8003000,内存还是设置为:0x20000000.( \7 k% |" d& b1 L5 o# O* w
5 f* S. [) D* n( K
编译后,打开对应的map文件如下所示:
9 G. ?$ p. H* _, w& y. v) d
) q' j, G- q4 O/ s8 ` V! b- Entry Address Size Type Object
5 L) V4 V% b+ Y( v; I, ^ - ----- ------- ---- ---- ------
$ M0 Q& ^3 F# E' V4 D9 N4 e- g1 l - .iar.init_table$Base 0x080034fc -- Gb - Linker created -
! T5 T7 c6 W+ F1 U1 s; D1 S, k - .iar.init_table$Limit 0x08003510 -- Gb - Linker created -
* |3 T; F" b$ _: V - ?main 0x08003511 Code Gb cmain.o [4]3 _4 m2 h* J) f( `: M
- CSTACK$Base 0x200000d8 -- Gb - Linker created -
" u/ G' m. p! j+ P6 }4 V - CSTACK$Limit 0x200010d8 -- Gb - Linker created -) Z6 X6 Y2 Y; I! S1 H* m
- Delay 0x080031e3 0x10 Code Gb main.o [1]; F; |; o$ Q$ |% ^4 q
- GPIO_PIN 0x080035a0 0x8 Data Gb stm320518_eval.o [1]% z) ~7 |6 y- o, M! r
- GPIO_PORT 0x200000c0 0x10 Data Gb stm320518_eval.o [1] //stm320518_eval.c文件内的全局变量GPIO_PORT数组存放在0x200000c0
2 u& O% v: |# U0 M8 t - HardFault_Handler 0x08003573 0x4 Code Gb stm32f0xx_it.o [1]
Q" ~+ Y) k3 `* N - NMI_Handler 0x08003571 0x2 Code Gb stm32f0xx_it.o [1]1 J! h7 E! G: C
- NVIC_SetPriority 0x080030c1 0x84 Code Lc main.o [1]
4 e2 O6 Z1 R; h- r% h) L - PendSV_Handler 0x08003579 0x2 Code Gb stm32f0xx_it.o [1]
4 F8 ]3 I; k% W9 F - RCC_APB2PeriphClockCmd 0x08003229 0x20 Code Gb stm32f0xx_rcc.o [1]
. y0 J1 K3 V) G4 B: ~ - Region$Table$Base 0x080034fc -- Gb - Linker created -
1 A$ H: T1 Z" F/ m/ p. R+ Z& G - Region$Table$Limit 0x08003510 -- Gb - Linker created -
, n- k4 P# Y- u6 p+ E/ d - STM_EVAL_LEDToggle 0x08003315 0x26 Code Gb stm320518_eval.o [1]! M( I, n! g8 g0 z3 ^" X# U
- SVC_Handler 0x08003577 0x2 Code Gb stm32f0xx_it.o [1]6 i6 B1 A3 O s4 _& U: S' V
- SYSCFG_MemoryRemapConfig
/ G; F# t8 A( f - 0x0800324d 0x14 Code Gb stm32f0xx_syscfg.o [1]
9 G5 W7 s8 p. N. ~, a - SetSysClock 0x080033b7 0xbe Code Lc system_stm32f0xx.o [1]
X! A5 }* f+ e! ~ - SysTick_Config 0x08003145 0x32 Code Lc main.o [1]
8 M/ [( D; Q7 a4 Q - SysTick_Handler 0x0800357b 0x8 Code Gb stm32f0xx_it.o [1]6 {% E3 Z, Z1 u5 V- k5 p/ a `; s; q2 h
- SystemCoreClock 0x200000d0 0x4 Data Gb system_stm32f0xx.o [1]& I* D; n: K M, \3 z& K
- SystemInit 0x08003349 0x6e Code Gb system_stm32f0xx.o [1]1 g P* G9 j( A, I5 _( W B3 l7 y
- TimingDelay 0x200000d4 0x4 Data Lc main.o [1]
& W/ T# V7 m$ Y6 B: Y - TimingDelay_Decrement 0x080031f3 0x16 Code Gb main.o [1]
6 i, Q, [+ r1 f3 K* K; j9 P4 f- q - VectorTable 0x20000000 0xc0 Data Gb main.o [1] //向量表编译位置为0x200000009 b' D4 @/ r2 J: |
- __aeabi_idiv0 0x08003345 Code Gb IntDivZer.o [4]
' d* K3 f( P+ f( D - __aeabi_uidiv 0x08003265 Code Gb I32DivModFast.o [4]' T" ^2 @6 C" ~9 K- i
- __aeabi_uidivmod 0x08003265 Code Gb I32DivModFast.o [4]+ d* r: {) @% M- J
- __cmain 0x08003511 Code Gb cmain.o [4]1 J* W- P, A4 x/ Q6 ~! k0 d( D1 e
- __exit 0x08003545 0x14 Code Gb exit.o [5]
% k; D. Z5 E$ L- D9 N. @$ Y - __iar_copy_init3 0x080034a5 0x30 Code Gb copy_init3.o [4], a4 b. p- s9 X. L" y k
- __iar_data_init3 0x080034d5 0x28 Code Gb data_init.o [4]
% i5 Y- m3 C4 O' {6 i' n% \- T: \ - __iar_program_start 0x08003595 Code Gb cstartup_M.o [4]
' \, G f4 L' l+ A# Y0 E; \ - __low_level_init 0x0800352b 0x4 Code Gb low_level_init.o [3] t4 I5 |: N4 m6 @- Z6 h* o
- __vector_table 0x08003000 Data Gb startup_stm32f0xx.o [1], t, K! j8 [- J# ?, x1 F# x9 [1 y3 S
- _call_main 0x0800351d Code Gb cmain.o [4]
! N3 k0 M* U7 x3 a) a( O' { - _exit 0x08003539 Code Gb cexit.o [4]. o) L, y% T2 X4 p$ P) v( F6 l
- _main 0x08003527 Code Gb cmain.o [4]5 l+ U. T4 t8 B' \8 `. r: Q
- exit 0x0800352f 0x8 Code Gb exit.o [3]# \+ r3 E% F. u
- 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>
复制代码 ( l/ O; A' T) i9 G0 J
如上所示,在IAR编译下,中断向量表被编译在0x20000000,内存的起始位置,而stm320518_eval.c下的全局变量GPIO_PORT被IAR编译成放在紧挨着的0x200000C0的位置。分别将IAP与APP烧录进FLASH,测试可以正常运行。
1 z; j+ Q- ~2 n3 P; R# y) W2 w0 \$ A4 ~! k9 o- Q, L
注:从IAR工程的链接配置来看,并没有像KEIL那样配置RAM位置为:0x2000000,编译后的结果向量表也不会与其他全局变量相冲突,可见IAR编译器已经自动计算并避免这种冲突,不像KEIL那样会出现链接错误,以此来提示用户。
& m4 o" k0 R9 ]6 s7 I! r
& H8 J2 h; ]- }: _3 g( Q另外:在IAR下,在不存在IAP的情况下也是可以调试APP的,这点是KEIL所不具备的功能,看样子,IAR在细节的处理上比KEIL要好。
5 m& a# B# h3 C( U, A% s/ J& j8 {& ^: T Y$ p: `' M
1 G* Q1 T6 u! p+ S& f& Y
, U1 x, }. h- E8 M6 L
|