本帖最后由 aimejia 于 2018-5-24 10:25 编辑
2 V/ j: e- S- A3 R/ H' b6 l$ S- e) h* l0 ^. G
1 前言
& o4 A4 U' A' c. ~5 w1 P+ r( u; A- _. K STSW-STM32116是ST官网基于标准库的针对STM32F0的USART进口IAP示例程序,下载链接:https://www.stmcu.org.cn/document/detail/index/id-213120
" i" D- i3 t1 S2 ~+ l6 {+ k; C& S 工程原本是针对STM32F051,本文将介绍如何移植到STM32F070,并针对移植的过程中的问题逐个处理。
4 b6 R9 H1 a3 ~8 @7 r. J- w1 M
2 KEIL下移植
8 ?- B2 t/ D" Q: X IAP程序一般分为两个,一个是IAP,一个是APP,IAP存放在内置FLASH的0x8000000的起始位置,而APP则存放在离这个位置一定距离的位置,这个距离一定是大于或等于IAP本身所占空间大小,本例子为0x8003000。' V6 J0 o7 E* Y+ D
5 p9 ?# D x% Z: ] 下载资源后,打开STM32F0xx_AN4065_FW_V1.0.0\Project\STM32F0xx_IAP\下的binary_template工程,这个就是APP工程,首先用KEIL打开,修改device为STM32F070,& u. @- I. Z) o7 e9 b
# ]1 }3 l5 P8 R% Z; Y
8 K3 X3 B6 c$ G: @0 t/ |; v# H4 W 并编译,结果发现原始的公式是编译不过的,如下错误信息:
; h3 U7 S! a) j- <font face="Tahoma" size="2">[plain] view plain copy
5 ^9 f% I- C0 N4 F- K0 I. _ - linking...
+ f; j5 J/ B& \ }3 a2 ^* S v - .\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 ^4 D1 _' m( n5 W: O$ \7 ? - Not enough information to list image symbols. # c8 t; K- Q6 [* a
- Finished: 1 information, 0 warning and 1 error messages. 8 O% o6 c' ]' G' R+ C0 M/ N
- ".\STM320518_EVAL\STM320518_EVAL.axf" - 1 Error(s), 0 Warning(s). 9 ~/ v9 x8 p" H& m* D
- Target not created. , ^3 O# e9 z" ~ L3 Q, t" S9 f
- Build Time Elapsed: 00:00:08 </font>
复制代码 从字面上判断为编译system_stm32f0xx.c文件生成的目标文件system_stm32f0xx.o中的数据段(.data)内的RW数据与main.o中的数据在地址0x20000000产生冲突。9 M$ E1 I. g5 c. }
7 l8 l3 f0 _ F% @0 G3 y 仔细查看代码,发现main函数之前这么一段:
' y$ W/ Q& J1 f& V- a( l- <font face="Tahoma" size="2">[cpp] view plain copy0 G/ W& c5 {* L6 Y
- #if (defined ( __CC_ARM )) 6 [9 X' b: X# X5 S) j" [& ^6 @
- __IO uint32_t VectorTable[48] __attribute__((at(0x20000000))); 5 l8 w* f: v; p9 Y1 f
- #elif (defined (__ICCARM__)) # e4 W! B. O R. g5 C5 T1 v
- #pragma location = 0x20000000
* Y! Q; G. D8 z! [8 E - __no_init __IO uint32_t VectorTable[48]; ) z& b" z2 t3 g- s- o( V; g9 ?
- #elif defined ( __GNUC__ ) 2 v" M( w/ r1 ]* @# @2 z+ `' {( c3 @
- __IO uint32_t VectorTable[48] __attribute__((section(".RAMVectorTable"))); 1 A0 {% |: x6 ~* A6 G
- #elif defined ( __TASKING__ ) & I3 O) e# \: i6 K( M4 |
- __IO uint32_t VectorTable[48] __at(0x20000000); ( r: r$ V8 N. I% g: o
- #endif </font>
复制代码 可见代码是要将中断向量表VectorTable强制定义在内存0x20000000上,但是此地址与system_stm32f0xx.c定义的全局变量位置有冲突。于是,需要修改避免冲突。中断向量的地址是固定的,但其他全局变量的地址可以相应地移动下,并且APP的烧录位置为0x8003000,如下图:8 u! D& y. N% z
# h7 X C2 z7 m, A
- x% n! s$ e( w: V! W9 h$ t2 q D 再次编译,错误就会消失了。; C$ y7 {1 z' D8 \: }9 T# A
M. W: ~' B' q4 Q5 F! N' [ Z
另外需要将main函数内前面几行代码做些修改:
% `# C- j- K3 _, v! S# @- <font face="Tahoma" size="2">[cpp] view plain copy: R: k4 Z4 t# `0 \# j
- int main(void)
% z+ C# _) U# H6 i - { / v8 C! N( c$ l
- uint32_t i = 0; ( k' J- H1 ^# w1 |- ^: t
- ( _6 U/ B$ C# H
- /*!< At this stage the microcontroller clock setting is already configured, * ^& }/ z5 r. Y6 S3 e" ^# L% a
- this is done through SystemInit() function which is called from startup ( a# c6 ^: [8 m- l
- file (startup_stm32f0xx.s) before to branch to application main. # [& q7 [2 u2 E% ~' Z
- To reconfigure the default setting of SystemInit() function, refer to
( b1 s4 i3 }3 ~$ E* S5 |7 C - system_stm32f0xx.c file 1 v( `0 D) h7 M: G
- */ + [% e3 Y! Z( i* X* {
-
- H3 p7 o7 S) k* ^ - /* Relocate by software the vector table to the internal SRAM at 0x20000000 ***/
' V5 [6 M$ p" i# d2 _4 y& q# M; j - / H4 f% Y1 Q& T( n
- /* Copy the vector table from the Flash (mapped at the base of the application
+ k" O5 y8 g! q0 s2 P' S - load address 0x08003000) to the base address of the SRAM at 0x20000000. */ % @( Q% q" B2 ?$ p
- for(i = 0; i < 48; i++)
" i$ R+ O6 Y: s3 {" d4 J - {
, G& T1 m) p' J6 p+ o - VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2));
2 W% @, @* \7 e8 ^! a6 \- f; b" S - } 7 t) @; C. l' }; U. M3 d
- U: j; n: {) M8 a6 y: S
- /* Enable the SYSCFG peripheral clock*/
/ v& R) N2 O$ F {; W# x5 @ - //RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);
. p$ k7 I" F# L0 d - RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //需要修改成这样 , W1 U8 i8 y5 r! j0 Z6 T
- /* Remap SRAM at 0x00000000 */
$ V4 {0 E* G$ H; a3 T4 w# Z" n - SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
& G* \: `8 r2 [$ a( C, R) w -
' i3 f9 x/ n, G$ i R - /... 1 s* i. V1 U3 w
- } </font>
复制代码 打开对应的map文件,有如下内容:4 |1 G' D4 f) K: l* z
- <font face="Tahoma" size="2">[plain] view plain copy3 @, {0 z( a& E( D
- GPIO_PIN 0x08003470 Data 8 stm320518_eval.o(.constdata)
/ B" Z: ~% k" I - GPIO_CLK 0x08003478 Data 16 stm320518_eval.o(.constdata)
; W7 H5 T3 }2 T - BUTTON_PIN 0x08003488 Data 14 stm320518_eval.o(.constdata) ( T5 x* P2 c. }- }2 m, _9 Y* w1 H
- BUTTON_CLK 0x08003498 Data 28 stm320518_eval.o(.constdata)
5 T$ `) F2 v% R' _3 g - BUTTON_EXTI_LINE 0x080034b4 Data 14 stm320518_eval.o(.constdata) 6 t+ f+ t y7 T& v$ W
- BUTTON_PORT_SOURCE 0x080034c2 Data 14 stm320518_eval.o(.constdata)
) z! u; [( ?) o" y) b8 Y9 |' k - BUTTON_PIN_SOURCE 0x080034d0 Data 14 stm320518_eval.o(.constdata) 4 i' ~& p8 x; ]( d0 K7 ^
- BUTTON_IRQn 0x080034de Data 14 stm320518_eval.o(.constdata)
: o/ }% m& T% E3 | t2 }7 X6 R - COM_USART_CLK 0x080034ec Data 4 stm320518_eval.o(.constdata)
$ M& U* d v* f( q# l, C! \0 L* S - COM_TX_PORT_CLK 0x080034f0 Data 4 stm320518_eval.o(.constdata)
% L6 K" q/ e; l! f$ L, f* \8 r - COM_RX_PORT_CLK 0x080034f4 Data 4 stm320518_eval.o(.constdata) . m% A, ~+ Q j7 y. G9 I
- COM_TX_PIN 0x080034f8 Data 2 stm320518_eval.o(.constdata) 8 ~+ w5 o. E8 B) {+ Z$ Z) v. i
- COM_RX_PIN 0x080034fa Data 2 stm320518_eval.o(.constdata) % Y7 B, |( b, l+ `; M" {( Z
- COM_TX_PIN_SOURCE 0x080034fc Data 2 stm320518_eval.o(.constdata) # b4 T1 _" G [3 s) V% ^: x: G
- COM_RX_PIN_SOURCE 0x080034fe Data 2 stm320518_eval.o(.constdata) ! V! [* ~8 ?) ?8 [8 e
- COM_TX_AF 0x08003500 Data 2 stm320518_eval.o(.constdata)
7 P1 \* e3 \* x' b0 r8 } - COM_RX_AF 0x08003502 Data 2 stm320518_eval.o(.constdata)
$ I. l( b& p3 H8 ~! F S - Region- c2 e: g- L- d0 z
- Table" ^! r( k% V; S: O& l. m' [( ]! ~
- Base 0x08003504 Number 0 anon9 N! [% G: x+ S1 A4 T6 G& U
- obj.o(Region7 I6 z4 d% z* J; x* Q: F8 k5 ]
- Table) 7 c/ P& t$ ]' X' y; \0 M0 J. s
- Region
/ A: S' b, R, x9 ` - Table/ E. I2 C* a. |" Q
- Limit 0x08003524 Number 0 anon5 w, p( \1 C; j' c" v" d" W) L4 L3 f4 E
- obj.o(Region
! Z# c8 ?, w+ k& v. T6 G - Table) , n A4 n% N( H0 d/ U/ K
- VectorTable 0x20000000 Data 192 main.o(.ARM.__AT_0x20000000) //向量表位置为0x20000000 , p( N( C! q9 R t3 G" t5 h0 ]+ L
- SystemCoreClock 0x200000c0 Data 4 system_stm32f0xx.o(.data) //其他全局变量的起始位置为0x200000C0
% B F$ [5 x% l0 I% y - AHBPrescTable 0x200000c4 Data 16 system_stm32f0xx.o(.data)
" w# j7 z1 h; }! C - GPIO_PORT 0x200000d4 Data 16 stm320518_eval.o(.data) ( j( S* `$ p$ C( i. g
- BUTTON_PORT 0x200000e4 Data 28 stm320518_eval.o(.data) : u) |0 G2 a }9 i7 P/ a) z
- COM_USART 0x20000100 Data 4 stm320518_eval.o(.data)
- E5 u9 O" R0 q. S( t - COM_TX_PORT 0x20000104 Data 4 stm320518_eval.o(.data)
. P$ A. Z7 l& e$ k9 c- _1 p9 s - COM_RX_PORT 0x20000108 Data 4 stm320518_eval.o(.data)
2 Y0 A; c" H. D* t5 G - __initial_sp 0x20000510 Data 0 startup_stm32f0xx.o(STACK) </font>
复制代码 如上所述,中断向量表被编译在0x20000000,内存的起始位置,而system_stm32f0xx.c下的全局变量SystemCoreClock被KEIL编译成放在紧挨着的0x200000C0的位置,与预期完全相符。分别将IAP与APP烧录进FLASH,测试可以正常运行。
) ~# o( r2 x8 y: ~1 b
; Y, n+ D6 M: g- p5 I6 c, S1 Y 注:在KEIL下,必须存在IAP才能调试APP!,这点是与IAR不同的。
; ~8 ^( l7 k; K
9 w# ]/ N1 r5 i9 d/ @3 IAR下移植
& P; G. s: ^, w, P 在IAR下的IAP没有什么特殊的,主要还是看APP的配置。' X2 i- H5 I1 n, }9 p0 A
6 q3 I6 s6 V7 Y; r4 _ 使用IAR打开APP工程,修改device为STM32F070:9 q/ N. n5 [6 ]; J$ f4 V8 f
# F9 @) U6 V1 G$ O, S$ k4 o' N5 d2 \
链接配置: h6 m% W+ _* U4 D% E) o d
' w$ V& t* {9 W0 |% K0 d) A
中断向量表:
. V4 e' S2 O3 {# @8 O+ G
2 c$ Y' f ]# K% K8 @8 u; p) u" q- I5 y0 e2 m
# K5 W! X% T* q1 I2 O F+ F
内存映射:
9 H) }. g2 h" @; h2 l; T2 T e0 y$ C9 l
. ~+ K9 e9 B* {# |6 k) [$ _3 [ 如上,APP存放在FLASH的位置0x8003000,内存还是设置为:0x20000000.
3 F9 [4 M. z1 a0 T3 o
0 l5 E" x/ Z7 L/ a7 s% @ 编译后,打开对应的map文件如下所示:
; ]$ {. f! h1 \( m- <font face="Tahoma" size="2">[plain] view plain copy
. m+ @% H. k1 e - Entry Address Size Type Object
( i5 g6 s( s1 }( f; p - ----- ------- ---- ---- ------
, O6 J. O- @! g. |3 u; _ - .iar.init_table$Base 0x080034fc -- Gb - Linker created -
* o! [# c! V# |: H/ i - .iar.init_table$Limit 0x08003510 -- Gb - Linker created - ' r( r- a3 P9 H/ a, m/ |: f
- ?main 0x08003511 Code Gb cmain.o [4] 1 q/ A% b1 T6 C# h+ r, x3 r
- CSTACK$Base 0x200000d8 -- Gb - Linker created - / G1 n; H2 Q W* x
- CSTACK$Limit 0x200010d8 -- Gb - Linker created - * ~+ x8 s& @& J7 P8 V$ }0 _
- Delay 0x080031e3 0x10 Code Gb main.o [1]
2 i9 ?. V+ i, r - GPIO_PIN 0x080035a0 0x8 Data Gb stm320518_eval.o [1] ( h) I" r6 x, U3 t3 E
- GPIO_PORT 0x200000c0 0x10 Data Gb stm320518_eval.o [1] //stm320518_eval.c文件内的全局变量GPIO_PORT数组存放在0x200000c0 5 L" g+ b G/ C* v
- HardFault_Handler 0x08003573 0x4 Code Gb stm32f0xx_it.o [1] + M- h3 X1 W# d! ~$ N
- NMI_Handler 0x08003571 0x2 Code Gb stm32f0xx_it.o [1]
; ?- j+ d7 \) Y- O! F - NVIC_SetPriority 0x080030c1 0x84 Code Lc main.o [1]
* w% W. n3 Z( c - PendSV_Handler 0x08003579 0x2 Code Gb stm32f0xx_it.o [1] ) D$ m. H/ Q- b7 c/ D6 X( D
- RCC_APB2PeriphClockCmd 0x08003229 0x20 Code Gb stm32f0xx_rcc.o [1] l7 R4 Z2 V8 s" @ E- i( k2 p& G
- Region
0 i/ J; B; G$ U! }& I0 V - Table
) Y/ \$ d7 m" V8 e& j; P4 e# t - Base 0x080034fc -- Gb - Linker created -
# l% W6 G t3 { - Region& A. z: e% |8 n, A& E& O
- Table
8 L" \1 L( ~4 w9 v. \1 O' s4 W1 S9 _ - Limit 0x08003510 -- Gb - Linker created - ; g( t2 k6 O t1 O# @- V
- STM_EVAL_LEDToggle 0x08003315 0x26 Code Gb stm320518_eval.o [1]
l: c4 B% v5 }4 V; w+ u - SVC_Handler 0x08003577 0x2 Code Gb stm32f0xx_it.o [1]
& {* q7 \, ~# G7 ? - SYSCFG_MemoryRemapConfig & u+ w3 c1 p# v/ Z1 g r A5 U
- 0x0800324d 0x14 Code Gb stm32f0xx_syscfg.o [1] 4 Y! u. t. F2 w R
- SetSysClock 0x080033b7 0xbe Code Lc system_stm32f0xx.o [1] 5 x) O+ T* [* }5 W! ]& {) l
- SysTick_Config 0x08003145 0x32 Code Lc main.o [1]
* k D# B$ [! B. k2 [' _' Y9 {! j - SysTick_Handler 0x0800357b 0x8 Code Gb stm32f0xx_it.o [1] ! ]" v; z+ l3 w$ o: L- q
- SystemCoreClock 0x200000d0 0x4 Data Gb system_stm32f0xx.o [1]
% S/ {1 L+ B+ y3 r" A& O - SystemInit 0x08003349 0x6e Code Gb system_stm32f0xx.o [1]
* M) a( _3 j/ W8 l# f7 n - TimingDelay 0x200000d4 0x4 Data Lc main.o [1] . }$ O5 X4 k+ l2 g$ u
- TimingDelay_Decrement 0x080031f3 0x16 Code Gb main.o [1] . s0 s s! {( [
- VectorTable 0x20000000 0xc0 Data Gb main.o [1] //向量表编译位置为0x20000000 7 h1 E, Q" l3 {, d' D
- __aeabi_idiv0 0x08003345 Code Gb IntDivZer.o [4] 2 g2 ?6 X A0 j% J5 J
- __aeabi_uidiv 0x08003265 Code Gb I32DivModFast.o [4]
/ {, o P% z% _ - __aeabi_uidivmod 0x08003265 Code Gb I32DivModFast.o [4]
; `4 t, s& t, p, o* f" k - __cmain 0x08003511 Code Gb cmain.o [4]
% j& [; o$ w8 |( g - __exit 0x08003545 0x14 Code Gb exit.o [5] ) `, E6 ]3 N" |5 R2 S _! b. u
- __iar_copy_init3 0x080034a5 0x30 Code Gb copy_init3.o [4]
" f M% a8 q0 T - __iar_data_init3 0x080034d5 0x28 Code Gb data_init.o [4] : R% }: o2 ?0 w: C" k: X' {: ?
- __iar_program_start 0x08003595 Code Gb cstartup_M.o [4] 3 g8 L- P* r$ k
- __low_level_init 0x0800352b 0x4 Code Gb low_level_init.o [3]
$ Y8 G, l A, G$ E. f - __vector_table 0x08003000 Data Gb startup_stm32f0xx.o [1] + r7 z. D! X4 g# M. _ p/ e; I2 Z
- _call_main 0x0800351d Code Gb cmain.o [4]
( `2 I6 E# \6 Y: y - _exit 0x08003539 Code Gb cexit.o [4]
5 r2 s6 S2 S2 H H! F' I* K2 R - _main 0x08003527 Code Gb cmain.o [4] ( C' m* ^+ ~ `
- exit 0x0800352f 0x8 Code Gb exit.o [3] 4 [. o; y& z5 @' l r3 o8 o& q
- main 0x08003177 0x6c Code Gb main.o [1] </font>
复制代码 如上所示,在IAR编译下,中断向量表被编译在0x20000000,内存的起始位置,而stm320518_eval.c下的全局变量GPIO_PORT被IAR编译成放在紧挨着的0x200000C0的位置。分别将IAP与APP烧录进FLASH,测试可以正常运行。
" g. D5 G7 i g* U0 s1 t3 ?, E/ l, q& Q" H
注:从IAR工程的链接配置来看,并没有像KEIL那样配置RAM位置为:0x2000000,编译后的结果向量表也不会与其他全局变量相冲突,可见IAR编译器已经自动计算并避免这种冲突,不像KEIL那样会出现链接错误,以此来提示用户。+ Z: ~4 b0 P; s" d6 d; Y
9 g: S1 q. o1 \9 V
另外:在IAR下,在不存在IAP的情况下也是可以调试APP的,这点是KEIL所不具备的功能,看样子,IAR在细节的处理上比KEIL要好。
" R) H+ B# q" Y8 i" `1 p1 ^2 s3 h
7 N! B) M2 a0 l5 a9 S) _" G# Q7 Q
转载自FD6 b5 C9 I& b. R: \5 x; w
# h7 I4 Q+ Q, {5 u' [- f3 z6 d+ t |