1 前言STSW-STM32116是ST官网基于标准库的针对STM32F0的USART进口IAP示例程序. Q9 Z- q2 }. E7 j2 K, O5 b
工程原本是针对STM32F051,本文将介绍如何移植到STM32F070,并针对移植的过程中的问题逐个处理。
6 O+ m3 t/ i% ~0 X3 c' I5 {: T: q3 O# o# y4 \
4 m! y0 }4 A0 D& J: N+ D
2 KEIL下移植
7 I' M; Z# G3 {6 H- |; UIAP程序一般分为两个,一个是IAP,一个是APP,IAP存放在内置FLASH的0x8000000的起始位置,而APP则存放在离这个位置一定距离的位置,这个距离一定是大于或等于IAP本身所占空间大小,本例子为0x8003000。 T* r4 |4 l3 D) \1 e+ ^' e3 f& P
- F! T6 ~, Z, z& V
下载资源后,打开STM32F0xx_AN4065_FW_V1.0.0\Project\STM32F0xx_IAP\下的binary_template工程,这个就是APP工程,首先用KEIL打开,修改device为STM32F070,0 _' X, D2 @; Z" B& F0 J
) J- v% U ?% d8 ^1 e. i4 A
! Y: e. ]5 R+ Y2 J _1 E; p' H
4 F/ k0 [, r9 F* N* c. g5 V9 B2 l C
- D+ c2 @/ h2 B/ }) K) C7 [
并编译,结果发现原始的公式是编译不过的,如下错误信息:
* Q7 i9 y2 I3 J# m( x/ y- w/ g4 f/ v$ P5 t. P# o( \+ h4 f
4 h! `# _0 v& O% I* P4 X: O7 n
- Z7 M8 Z+ N; C2 a3 \& H, p0 O0 E+ M# ?) h% ^4 V) T# |" U
从字面上判断为编译system_stm32f0xx.c文件生成的目标文件system_stm32f0xx.o中的数据段(.data)内的RW数据与main.o中的数据在地址0x20000000产生冲突。
0 P' {. I+ F3 U仔细查看代码,发现main函数之前这么一段:
% W9 H5 [& |1 i/ ?* V# ^. v
' Z0 p4 j, ?- g. f, S$ d' _' K5 f* P
; A! \& G N1 m9 o2 K
, a% G I& O& _9 r; P1 g6 `- I可见代码是要将中断向量表VectorTable强制定义在内存0x20000000上,但是此地址与system_stm32f0xx.c定义的全局变量位置有冲突。于是,需要修改避免冲突。中断向量的地址是固定的,但其他全局变量的地址可以相应地移动下,并且APP的烧录位置为0x8003000,如下图:
& g* N+ ^% g7 ~; b0 F
/ {& ~: i& x% x2 z/ M
7 ~9 g/ g7 K. t- X" p7 V; R3 c4 ^1 E n1 O# M
) ?, ]0 G3 c4 w
+ a2 V& ^3 U( W& I, h v再次编译,错误就会消失了。, h. g/ y; _; ^- J0 w. ?, x6 Y- [
5 P7 c6 J/ L# }
另外需要将main函数内前面几行代码做些修改:
1 u8 n' p' Q1 l9 D& X* G- F m* q- int main(void) 4 |' p* U9 j5 J; \2 C4 A2 y
- {
( Y. {$ `& ?* j% W h - uint32_t i = 0;
& `9 V' l9 S% J5 ^6 | -
) [, o+ s6 @% _% Q - /*!< At this stage the microcontroller clock setting is already configured, 4 f' ~1 ]# L% ] w- P* w5 a& t( h
- this is done through SystemInit() function which is called from startup
O" |9 v$ m/ A/ Z% V; l |. d - file (startup_stm32f0xx.s) before to branch to application main.
% w8 x8 K4 G3 f% L2 n - To reconfigure the default setting of SystemInit() function, refer to
9 k$ I% N5 Z/ v - system_stm32f0xx.c file
& A( B$ W* j; Q( H - */ , B1 }& y) t) q
- & `% o# D }: @: v/ e- }
- /* Relocate by software the vector table to the internal SRAM at 0x20000000 ***/ / N7 i* [: o/ ], C
- / Q3 N, r9 Y* `
- /* Copy the vector table from the Flash (mapped at the base of the application ; l% C$ W8 B3 O1 m0 T8 {& r
- load address 0x08003000) to the base address of the SRAM at 0x20000000. */
3 A, I/ a3 o: O/ J% c/ C. z7 T - for(i = 0; i < 48; i++) : Y4 q' i; B$ H9 W
- { : p3 b& t9 W. ~* w0 q- b* E' S
- VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2));
h+ U) n5 I4 e; ^ - } , l9 I+ \" l, ~" [& B
- / [: n, y8 p# _3 k$ b: g
- /* Enable the SYSCFG peripheral clock*/ : d9 x% a9 [ E8 \4 ?6 l+ o! J
- //RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE);
- k- c# `6 F9 s' t* M, Y" S. @ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //需要修改成这样
+ A3 ~. A3 e+ V. r3 l+ G. W - /* Remap SRAM at 0x00000000 */
" B& B3 K3 J5 _& T b& ] - SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
- H# ~3 ~9 _& `/ v4 r - . s# G. F: B0 Q$ j7 Y9 O* K
- /...
c& W+ {$ t6 j r/ X1 z - }
复制代码
6 x) E& G5 V G# i6 {( b( K `" n* n1 b$ g6 c& @1 ]0 `
打开对应的map文件,有如下内容:
. w2 B6 K# z) B2 B3 h- [plain] view plain copy- F M/ M% } Q, k+ p( d0 p
- GPIO_PIN 0x08003470 Data 8 stm320518_eval.o(.constdata)
& m) B3 q! J" ` - GPIO_CLK 0x08003478 Data 16 stm320518_eval.o(.constdata) 0 ?7 V. G' d9 ]% c$ P5 n
- BUTTON_PIN 0x08003488 Data 14 stm320518_eval.o(.constdata) 3 ?( F' q8 V% J* h# R' { Y
- BUTTON_CLK 0x08003498 Data 28 stm320518_eval.o(.constdata)
8 d3 b4 k+ s1 G/ C - BUTTON_EXTI_LINE 0x080034b4 Data 14 stm320518_eval.o(.constdata)
. G3 G1 H5 A! \/ c! t - BUTTON_PORT_SOURCE 0x080034c2 Data 14 stm320518_eval.o(.constdata) $ A: g: V' G0 B# u7 o
- BUTTON_PIN_SOURCE 0x080034d0 Data 14 stm320518_eval.o(.constdata) : L0 a! W3 a; r
- BUTTON_IRQn 0x080034de Data 14 stm320518_eval.o(.constdata) 3 \! g9 E( h E' W
- COM_USART_CLK 0x080034ec Data 4 stm320518_eval.o(.constdata) 6 b i, L, b5 L) c, h
- COM_TX_PORT_CLK 0x080034f0 Data 4 stm320518_eval.o(.constdata)
6 A! v- c) I6 w - COM_RX_PORT_CLK 0x080034f4 Data 4 stm320518_eval.o(.constdata) 8 B+ C" B3 T4 w" i6 b3 G
- COM_TX_PIN 0x080034f8 Data 2 stm320518_eval.o(.constdata)
. S/ m @6 S5 g X; d7 {* y - COM_RX_PIN 0x080034fa Data 2 stm320518_eval.o(.constdata) 5 K4 }2 v( t0 p: l0 T' M
- COM_TX_PIN_SOURCE 0x080034fc Data 2 stm320518_eval.o(.constdata) 0 z: [( ]2 | p! \6 `& i5 Q* `$ j' O$ B
- COM_RX_PIN_SOURCE 0x080034fe Data 2 stm320518_eval.o(.constdata) ( S. g# a( p8 T9 G& k
- COM_TX_AF 0x08003500 Data 2 stm320518_eval.o(.constdata) 9 r4 M \" k0 n! _- v
- COM_RX_AF 0x08003502 Data 2 stm320518_eval.o(.constdata) * x* T! f0 u5 N- d; \" @ U7 f
- Region/ W4 p* n! C, e: f( Z) e1 D6 r
- Base 0x08003504 Number 0 anon
5 g8 h D8 _8 G% H; K1 j5 V1 ^ - Table)
9 U; H" s0 ?6 `, E - Region
0 \9 E7 s8 M( m( a9 U! H/ L - Limit 0x08003524 Number 0 anon. I' r0 |' C/ }; g& i
- Table)
5 z2 H+ l- b; A! W$ e& B6 W' j - VectorTable 0x20000000 Data 192 main.o(.ARM.__AT_0x20000000) //向量表位置为0x20000000 1 w6 z7 B- n8 M- A. I. k @
- SystemCoreClock 0x200000c0 Data 4 system_stm32f0xx.o(.data) //其他全局变量的起始位置为0x200000C0
9 Q/ t. o2 b6 X' Z% P ~, P - AHBPrescTable 0x200000c4 Data 16 system_stm32f0xx.o(.data)
& q! \- ?/ b6 h9 Y4 D3 L2 M! \ - GPIO_PORT 0x200000d4 Data 16 stm320518_eval.o(.data)
# n3 M& l3 C, Q' s& V - BUTTON_PORT 0x200000e4 Data 28 stm320518_eval.o(.data)
9 z* E, P, Z1 V' v5 Y$ E& }' ` - COM_USART 0x20000100 Data 4 stm320518_eval.o(.data)
& ^5 U) L: P( F; @ - COM_TX_PORT 0x20000104 Data 4 stm320518_eval.o(.data)
9 p: m4 b9 {4 z. ^, C$ A4 T! Z$ ^ - COM_RX_PORT 0x20000108 Data 4 stm320518_eval.o(.data) 0 [) ~% j: n# X0 V4 ]: {
- __initial_sp 0x20000510 Data 0 startup_stm32f0xx.o(STACK)
复制代码 $ O0 Q+ |% B4 V$ Q; \
如上所述,中断向量表被编译在0x20000000,内存的起始位置,而system_stm32f0xx.c下的全局变量SystemCoreClock被KEIL编译成放在紧挨着的0x200000C0的位置,与预期完全相符。分别将IAP与APP烧录进FLASH,测试可以正常运行。
* [4 g: Y9 G2 X2 {) B g6 c5 N- W9 V3 f
注:在KEIL下,必须存在IAP才能调试APP!,这点是与IAR不同的。
1 F9 W/ q: E* B$ k2 k: V# i8 L* Q% S' B% p
, Q9 Q, O4 c v3 IAR下移植" U6 b2 k% u o+ u& y
在IAR下的IAP没有什么特殊的,主要还是看APP的配置。 使用IAR打开APP工程,修改device为STM32F070:
p! ? G; E' W" L4 N) D. u# l) m
; A/ D" ]7 A5 C P. a& k4 u4 V
8 x) S, `& |; E, S6 U- v
链接配置: 中断向量表:
5 F6 ~; R5 H0 `
- L/ u3 ~) ?! K' w" }
& k5 b' n3 N6 z; c$ r& S5 X
内存映射:
% J# |. X. I+ f; } P: }
, h/ |& r7 L/ f3 L [$ C* b! d0 l' W, i
如上,APP存放在FLASH的位置0x8003000,内存还是设置为:0x20000000. 编译后,打开对应的map文件如下所示: - Entry Address Size Type Object
5 p5 ?7 g/ _; q) f& P" f5 E( H - ----- ------- ---- ---- ------
+ j/ [+ [' l% z( V0 X4 R" c! }- o - .iar.init_table$Base 0x080034fc -- Gb - Linker created - ' p& Z. F. n3 f2 I5 Y
- .iar.init_table$Limit 0x08003510 -- Gb - Linker created - , S: o+ c5 A/ N& q+ V
- ?main 0x08003511 Code Gb cmain.o [4] . H5 D# q2 a) ]0 ]$ ~) N2 U
- CSTACK$Base 0x200000d8 -- Gb - Linker created -
. ?! B1 E' w, f7 Z4 J, }" ] - CSTACK$Limit 0x200010d8 -- Gb - Linker created - " z8 ]+ F- v, e
- Delay 0x080031e3 0x10 Code Gb main.o [1]
; u" I( s9 h4 p5 \$ d, t - GPIO_PIN 0x080035a0 0x8 Data Gb stm320518_eval.o [1] ; _% K/ T# Q( X) P8 a
- GPIO_PORT 0x200000c0 0x10 Data Gb stm320518_eval.o [1] //stm320518_eval.c文件内的全局变量GPIO_PORT数组存放在0x200000c0 0 V- x# g( P! P0 b. ]
- HardFault_Handler 0x08003573 0x4 Code Gb stm32f0xx_it.o [1] 1 M0 d+ l7 f$ Z; v, ?
- NMI_Handler 0x08003571 0x2 Code Gb stm32f0xx_it.o [1] 9 k. q6 x" {8 \4 V& m6 q
- NVIC_SetPriority 0x080030c1 0x84 Code Lc main.o [1]
: R# b3 Y) p! e N% ^6 ? - PendSV_Handler 0x08003579 0x2 Code Gb stm32f0xx_it.o [1] 0 X- Y3 N6 G' \$ ?
- RCC_APB2PeriphClockCmd 0x08003229 0x20 Code Gb stm32f0xx_rcc.o [1]
) `4 S$ M+ a4 X+ j0 M9 a3 ? - Region
/ V' J# F& Q( H( V. a - Base 0x080034fc -- Gb - Linker created - ) E3 i+ d2 q1 j! i; Q
- Region
0 w/ V1 d! v% [$ o* `; a, c9 n% s - Limit 0x08003510 -- Gb - Linker created -
4 z2 P' D' c( } - STM_EVAL_LEDToggle 0x08003315 0x26 Code Gb stm320518_eval.o [1] w6 _; C, I. @; M& v8 ^
- SVC_Handler 0x08003577 0x2 Code Gb stm32f0xx_it.o [1] * R: I8 B4 z2 a* M9 t
- SYSCFG_MemoryRemapConfig
+ r6 n/ D c4 ^1 B* I) A9 N) R - 0x0800324d 0x14 Code Gb stm32f0xx_syscfg.o [1] 7 U1 @) ^8 d2 ]
- SetSysClock 0x080033b7 0xbe Code Lc system_stm32f0xx.o [1] % o- H& J3 s5 X$ i6 M9 ?
- SysTick_Config 0x08003145 0x32 Code Lc main.o [1] 7 j4 x5 \( z! \: x" f
- SysTick_Handler 0x0800357b 0x8 Code Gb stm32f0xx_it.o [1]
( j) o( z9 ^4 Q) ]: V9 J - SystemCoreClock 0x200000d0 0x4 Data Gb system_stm32f0xx.o [1]
5 d4 Y9 l! i: g7 i9 b3 ? - SystemInit 0x08003349 0x6e Code Gb system_stm32f0xx.o [1]
' ]; ^2 l1 L0 q7 M - TimingDelay 0x200000d4 0x4 Data Lc main.o [1] 9 @/ B" D5 [% v' ` a
- TimingDelay_Decrement 0x080031f3 0x16 Code Gb main.o [1] 5 s4 N1 {7 A J+ J2 ?4 g" p
- VectorTable 0x20000000 0xc0 Data Gb main.o [1] //向量表编译位置为0x20000000 + v. J8 Z8 O: ?# q1 M4 F
- __aeabi_idiv0 0x08003345 Code Gb IntDivZer.o [4] 7 ?( R$ |- p7 r
- __aeabi_uidiv 0x08003265 Code Gb I32DivModFast.o [4] : I2 ~0 u$ y. g/ B0 i
- __aeabi_uidivmod 0x08003265 Code Gb I32DivModFast.o [4] . Q! C B8 J$ ~+ F2 U! D: w
- __cmain 0x08003511 Code Gb cmain.o [4]
$ K) L! Y+ x! K: ~$ ~2 } - __exit 0x08003545 0x14 Code Gb exit.o [5]
9 y& a2 o& e1 q/ E7 i8 x - __iar_copy_init3 0x080034a5 0x30 Code Gb copy_init3.o [4]
6 T7 ?+ n$ [5 y - __iar_data_init3 0x080034d5 0x28 Code Gb data_init.o [4] 9 Q; q- W/ \, g6 l! [$ X3 E1 U- f: u
- __iar_program_start 0x08003595 Code Gb cstartup_M.o [4]
5 |) ~7 s5 J; e# T$ a! U/ T+ A - __low_level_init 0x0800352b 0x4 Code Gb low_level_init.o [3] + K3 ?) V# J1 A+ K9 z, Q
- __vector_table 0x08003000 Data Gb startup_stm32f0xx.o [1] % {9 D+ D( z! B1 u& X' A4 r
- _call_main 0x0800351d Code Gb cmain.o [4] 0 m* t) G% f( m# N
- _exit 0x08003539 Code Gb cexit.o [4]
^; X2 k- C) P* A6 v" J. W" m - _main 0x08003527 Code Gb cmain.o [4]
) R1 |2 y3 m+ z; r0 }3 V( Z - exit 0x0800352f 0x8 Code Gb exit.o [3]
6 V8 a6 C, g. S% E: ]$ ^ W - main 0x08003177 0x6c Code Gb main.o [1] ( [) v. W. `$ i4 `; l# r" E
复制代码
0 N: H; W/ }6 _7 K如上所示,在IAR编译下,中断向量表被编译在0x20000000,内存的起始位置,而stm320518_eval.c下的全局变量GPIO_PORT被IAR编译成放在紧挨着的0x200000C0的位置。分别将IAP与APP烧录进FLASH,测试可以正常运行。
0 k% M6 ^& t2 l. H2 G6 Z. O1 R0 v. e% X( b2 ~% [
注:从IAR工程的链接配置来看,并没有像KEIL那样配置RAM位置为:0x2000000,编译后的结果向量表也不会与其他全局变量相冲突,可见IAR编译器已经自动计算并避免这种冲突,不像KEIL那样会出现链接错误,以此来提示用户。
' p" v& _3 p. c8 K6 G; g8 w ~另外:在IAR下,在不存在IAP的情况下也是可以调试APP的,这点是KEIL所不具备的功能,看样子,IAR在细节的处理上比KEIL要好。
/ e9 Z: w: F6 k1 D- n, N3 U. g* p- O' Y4 s" o
|