你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F1系列之复制data段和清除BSS段

[复制链接]
STMCU小助手 发布时间:2022-8-27 14:12
一、什么是BSS段(ZI段)- W& F8 K' Y* `3 g" r
bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。
# \  ]7 p. ^! ]! x1 R- Kbss是英文Block Started by Symbol的简称。
6 x" j0 z' u6 w: R5 v8 bbss段属于静态内存分配。
' _% v! I, S8 C4 X' r) S* G: Z$ [, }% u& w2 v( S& e# @1 G
二、为什么要复制data段
4 r4 a1 o+ {7 W! n4 W# Y这是因为对于在STM32F103这类资源紧缺的单片机芯片中,数据段只是暂时先保存在Flash上,在使用前被复制到内存里,而复制到内存这个过程是需要我们自己实现的。
3 s9 [: p! F" l1 _& u: G
( s5 Y3 N1 \+ S3 @8 X$ c三、未处理的结果
* @( Q, P6 O: E; m* `修改main函数如下所示:
$ F9 F) C3 A. K% R: E) R' t" f0 f5 ]: v$ l' [+ B& M2 A4 k
  1. #include "uart.h"
    / X: E/ U, V, D
  2. #include "led.h"
    9 C, n; Z8 e1 m) z8 ]. h  @/ ?2 U9 n* J
  3. 4 K+ z2 B8 I9 u6 A+ Y9 J2 y8 a
  4. int mydata = 0x32315;
    - o7 t* s" i- x/ w9 v$ s9 Z
  5. const int myconst = 0x22315;# ?) H% t- r) O
  6. int myzero = 0;
    3 }  A/ H- i0 T5 U
  7. int my;
    + L* ~7 S/ e' r5 n; c& i
  8. : a3 v0 x" e& C7 K
  9. int main(void)5 \; L- T/ i: o: |& D
  10. {
    ( B: e; Y% S! N) \5 f
  11.     uart_init();
    5 O0 s5 j. |+ Y! p. @9 n8 q% E
  12.     led_init();/ j8 Q8 q0 ^4 V; j6 ?
  13.     putstring("stm32f103zet6\r\n");
    4 i! o: m8 T8 u* ?0 ?" r+ g% N
  14.         putstring("mydata\t:");- D* ~0 g* a' c! Q
  15.     puthex((unsigned int)&mydata);
    8 d( U0 g8 w5 U1 \
  16.     puthex((unsigned int)mydata);
    $ z8 A" j  i. @+ _3 I0 x
  17.     putstring("\r\nmyconst\t:");
      B. M6 N7 t# S1 w( \6 j; L
  18.     puthex((unsigned int)&myconst);
    + T9 O+ ]5 b3 @
  19.     puthex((unsigned int)myconst);
    * V3 G* l5 a( b7 y$ r
  20.         putstring("\r\nmyzero\t:");
    " R( _' Z3 d& e% B3 S6 W
  21.     puthex((unsigned int)&myzero);
    ) }) ?& t% s1 L7 |
  22.     puthex((unsigned int)myzero);
    / V* _8 X" `+ ?) _
  23.     putstring("\r\nmy\t:");
    4 |3 o2 o( v$ H0 I
  24.     puthex((unsigned int)&my);
    7 T, z; O6 U( p# m& t7 t0 c
  25.     puthex((unsigned int)my);) ]0 l7 C$ |$ [3 u1 A4 c. v
  26.     putstring("\r\n");
    + {8 Y/ G) m0 R$ r" @/ ~5 I

  27. 7 O3 m# J/ i8 u/ H
  28.     while(1)
    . q: ]  p% v) Z" V4 m
  29.     {- K0 A! y7 |& Z# T1 v
  30.                 putstring("led on\r\n");- R1 |( P7 w6 c% `: f) d* B: F
  31.         led_on();
    7 _0 M# N8 p# m; ^; p* A) ^
  32.         delay(1000000);
    4 l7 j$ t2 E$ [. F% w) Z. a
  33. . z; b# \' L4 d) Y$ U
  34.                 putstring("led off\r\n");
    # T# H6 ~. P( A6 C9 t8 w
  35.         led_off();3 S& G3 z$ W9 p1 m
  36.         delay(1000000);
    7 u- [  Q/ T5 V9 P( `
  37.     }8 c6 M* n6 Z: {1 b1 G! S" a: L
  38. }
    6 W/ n1 e% D& Z9 c  y; ~* c! z5 a& C5 n
复制代码
$ B8 ]% }7 k! g. Y! i8 F
编译烧录运行,可以看到,除了存在Flash的只读全局变量的值正确,其他几个变量的值都是错误的
! |- B; ~+ E! o3 n' q9 o1 T' h( _+ ^- B* d% ]0 r, u+ z6 S
20210125214800328.png # `* F, P4 A! B1 C1 W  e) l- @
- }9 _, N' \$ n- M9 E4 v0 J
四、修改链接文件9 q6 d! w% U9 k' @0 S
既然要复制data段和清除BSS段,那么就需要知道如下几个数据" A$ W; f8 f, w! U9 ]6 p, v( V& Z9 t

3 d7 j; \+ n+ h$ X, m
  1. 1、数据段的加载地址,即数据段存放在Flash的哪个位置2 o4 r, Y4 [9 D
  2. 2、数据段的链接地址,即数据段应该复制到在RAM的哪个位置( e9 E4 v) A# x1 F
  3. 3、数据段的长度,应该复制多长的数据从Flash到RAM" P2 G4 h, W6 m1 f( o
  4. 4、BSS段的链接地址,即BSS段应该从何处开始清除
      q- J. D1 D0 S1 A
  5. 5、ZI段的长度,应该清除多长的BSS段
复制代码
9 k/ P- b; z4 q' Q6 k
我们将链接文件修改为如下所示,得到data段的起始加载地址、起始链接地址和结束链接地址,以及bss段的起始链接地址和结束链接地址。其中>RAM AT > FLASH 表示存放时使用RAM地址,存放时使用FLASH地址。
" |- a4 Q7 k# d3 t9 u8 n* `, |/ ?3 n- i; d' q9 {: r
  1. /* 指定内存区域 */
    4 R. C3 Y! G1 H1 t) a/ x2 G5 b
  2. MEMORY6 ^% _& C8 h% X) y$ O  A/ F& H
  3. {
      y' B' l- p7 l9 A  Y3 P
  4.     FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 512K
    ! s$ R) s5 X$ k/ }9 v7 K" E9 S
  5.     RAM (xrw)   : ORIGIN = 0x20000000, LENGTH = 64K
    & C# F- p& Y6 i3 ?
  6. }6 @& m5 C- c2 \8 z
  7. + z3 a& h$ g1 |8 \5 |( u
  8. SECTIONS {
    " H; [& Z  D/ P  |8 _
  9. , R9 i! V! X4 z: d
  10.     .text      :. I# r8 F  Y' O) \9 x
  11.     {6 a/ x4 Q7 m7 j; l
  12.         . = ALIGN(4);- q# \8 m' h4 q9 E8 b7 d# ^9 k
  13.         *start.o (.text)) B; L9 }- A& P/ C; f
  14.         *main.o (.text)& y- s/ x1 g# h" r. M
  15.         *(.text)
    # b% h4 E8 u8 _* x& e- P- M1 U
  16.     } > FLASH0 L- [% P0 D/ T" E* V$ s

  17. : @- k0 k+ g& L
  18.     .rodata :4 T' V  V# v0 Y/ ^4 }  v' n8 D0 T
  19.     {4 q" @5 c( r3 M. d( B0 a- S
  20.         . = ALIGN(4);
    ! @; b, S4 ~2 B1 z- h
  21.         *(.rodata)         /* .rodata sections (constants, strings, etc.) */. m, e# C, O/ H
  22.         *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */4 |+ u' n; _* {7 q) y9 [; Q- o( p
  23.         . = ALIGN(4);0 D3 X* i/ z% f! I; B* w
  24.     } >FLASH1 F8 v$ U6 v8 E- X3 i& \6 T

  25. 5 `" H! r' C: |
  26.     _sidata = LOADADDR(.data);  /* 获取data段的起始加载地址 */
    " _9 A0 q+ o2 ?: S# I( M/ J* M
  27.     .data :
    9 V( u% y% M' F6 M& D: L7 w
  28.     {. j& s- t* G, N6 c% p% P
  29.         . = ALIGN(4);% r; _" A& i; {6 Y6 G3 B5 X4 y
  30.         _sdata = .;        /* 获取data段的起始链接地址 */
    9 L" o: U0 E- |4 m7 W
  31.         *(.data)           /* .data sections */
    , w$ f; i& l7 p9 @
  32.         *(.data*)          /* .data* sections */
    6 i1 s0 j) n* G6 j; y4 u: h
  33.         . = ALIGN(4);
    - V2 s% G/ j. e$ n' W4 l' U- q
  34.         _edata = .;        /* 获取data段的结束链接地址 */* E7 c$ _8 q' A* U, \+ K" P
  35.     } >RAM AT > FLASH. {5 \4 N( H# f" T% v

  36. 8 @5 J( P5 Q9 ]0 c: f
  37.     . = ALIGN(4);) l0 o, g, j- I  g5 ^/ S. f! S3 @
  38.     .bss :/ n9 I% y) @; v( w, l
  39.     {1 Z. M1 ?: T5 L( O) N' W
  40.         _sbss = .;         /* 获取bss段的起始链接地址 */
    , G" o8 U3 [. `6 U
  41.         *(.bss), F8 L0 N3 R8 \" S( Y5 q: \
  42.         *(.bss*)9 ^1 w. c1 T1 @( `0 g& K1 k( h, T
  43.         *(COMMON)0 m" w. x0 t) F- @

  44. ; {0 S/ ?2 T! _$ g
  45.         . = ALIGN(4);; ]) t) a5 W; M9 c, |1 I" w6 l! }3 O
  46.         _ebss = .;         /* 获取bss段的结束链接地址 */
    % ?1 n$ u/ F5 a8 J
  47.     } >RAM/ F. Z! A) L$ H% Z9 O
  48. }
复制代码
9 ^7 J8 S2 C$ X$ Y# O
五、修改汇编文件6 Z; l- Q' W& F+ i+ e6 e0 U3 U! j
在start.s中加入如下代码复制data段和清除bss段的代码,其中data段的起始加载地址_sidata、起始链接地址_sdata和结束链接地址_edata,以及bss段的起始链接地址_sbss和结束链接地址_ebss,都是从链接脚本中获取的。! F7 E5 ]& P7 @! Z

  1. 4 h5 z2 x8 H# W& t
  2.   .syntax unified                   /* 指明当前汇编文件的指令是ARM和THUMB通用格式 */
    5 A  W. r" z* \
  3.   .cpu cortex-m3                    /* 指明cpu核为cortex-m3 */
    ' m) M. w% F3 J8 h3 q
  4.   .fpu softvfp                      /* 软浮点 */% S  r9 t+ |! r) A3 [9 h
  5.   .thumb                            /* thumb指令 */
    ! T# Q- B7 G) N

  6. 3 [3 V- g# d2 y0 b; w( B8 }) n8 [
  7. .global  _start                     /* .global表示Reset_Handler是一个全局符号 */
    9 M# T8 w: U# l) G. J
  8. 9 K% p) c' |) @
  9. .word 0x00000000                    /* 当前地址写入一个字(32bit)数据,值为0x00000000,实际上应为栈顶地址 */
    ' T* ~6 S. |% Q3 W/ H
  10. .word _start+1                      /* 当前地址写入一个字(32bit)数据, 值为_reset标号代表的地址+1,即程序入口地址*/
    . P& i$ J3 _% c* X3 B% r& Z3 X
  11. ! L5 l! {9 M4 p
  12. _start:                             /* 标签_start,汇编程序的默认入口是_start */$ v' m# P: \+ ?
  13.     /* 1、设置栈 */+ Q# c/ s. U% b
  14.     LDR SP, =(0x20000000+0x400)) V* [" D2 o/ t8 e  e  b- W  d
  15. . [, \5 q# J+ M2 X* M: g/ V
  16.     /* 2、复制data段 */
    % w( q5 o  e( o8 ~
  17.         movs r1, #0                                                /* r1寄存器用来计数 */4 E  F5 M* e0 X
  18.     b LoopCopyDataInit: M5 g- u* w: ?" F0 y6 x

  19. * u6 d6 I3 \: J5 B
  20. CopyDataInit:
    1 M# w* `2 P6 o2 X. u& b
  21.     ldr r3, =_sidata                                /* 将data段的起始加载地址存入r3寄存器 */, e3 ]7 r* m/ }1 \
  22.     ldr r3, [r3, r1]                                /* 从Flash取出data段的值存入r3寄存器 */
    / Y. l7 q* F$ k8 Q; f1 Y, `
  23.     str r3, [r0, r1]                                /* 将r3寄存器的值存入RAM中 */4 m" A+ X/ p+ y& L
  24.     adds r1, r1, #4                                        /* 每次复制4个字节的data段数据 */
    - D. S! L# o/ D) e* V

  25. 7 u/ r' n3 S( e/ ~& _
  26. LoopCopyDataInit:  P7 {# `) K, G/ Y1 e5 h: g1 k
  27.     ldr r0, =_sdata                                        /* 将data段的起始链接地址存入r0寄存器 *// y9 f& k; O! E: u5 N) T
  28.     ldr r3, =_edata                                        /* 将data段的结束链接地址存入r0寄存器 */
    7 i  P0 P5 v& Z- j- }" T
  29.     adds r2, r0, r1                                        /* 起始链接地址加上计数,即当前复制地址存入r2寄存器 */
    + t2 v. v" T: }- B$ x  X4 M
  30.     cmp r2, r3                                                /* 当前复制地址和结束链接地址相比较 */
    0 R1 ?: J3 ~8 p
  31.     bcc CopyDataInit                                /* 如果r2小于等于r3跳转到CopyDataInit标签处,如果大于则往下执行 */  S+ N$ Q. M6 X- {
  32. 2 \& i2 L# \5 O- b
  33.     /* 3、清除bss段 */
    1 b3 [, r- Z" G+ t  p+ e+ r
  34.         ldr r2, =_sbss                                        /* 将bss段的起始链接地址存入r2寄存器 */
      B4 Z9 \& O( h6 l: R: m6 u
  35.         b LoopFillZerobss
    & b- s1 V4 A6 m8 o' G" S
  36. % o8 f% u' ]& b, ?
  37. FillZerobss:1 z- I$ w! n: D* j! {* |% {
  38.         movs r3, #0                                                /* 将0存入r3寄存器 */& Y% R6 P+ C2 K
  39.         str r3, [r2], #4                                /* 将r3中的值存到r2中的值所指向的地址中, 同时r2中的值加4 */3 J' }) l" z* G4 o2 k: B
  40. & u6 l# w; t( c
  41. LoopFillZerobss:4 T3 a7 W3 r/ l$ ]
  42.         ldr r3, = _ebss                                        /* 将bss段的结束链接地址存入r3寄存器 */* Z1 M% M  o/ B7 y- k* W
  43.         cmp r2, r3                                                /* 比较r2和r3内的值,即当前清除地址和结束链接地址相比较 */
    ) K, M5 A  r& U
  44.           bcc FillZerobss                                        /* 如果r2小于等于r3跳转到FillZerobss标签处,如果大于则往下执行 */- f* C& z0 Z; |2 t

  45. , u* N, U" l# Z% x) z1 w$ Y1 Z% g
  46.     /* 4、跳转到led函数 */
    6 y5 h6 o0 O, R1 r5 ]
  47.     BL main6 o5 T4 I$ b& H7 `5 |7 [2 k
  48.     /* 5、原地循环 */- r' @1 o, P5 W4 |
  49.     B .
    9 i$ F5 N' |9 V- _5 |. f8 W' T4 d
  50. $ Q* j+ a$ l) L) d, ~* h  D
复制代码
7 w( T9 Z: B" R( U2 g
然后编译运行烧录,这样我们就可以看到变量的值正常了
4 U$ h8 f; y/ C" R
/ ~8 k. {* a; j* }! s: E/ A 20210125223543797.png
  t& Y8 y0 R! }6 ?3 J3 t/ y3 }
$ x3 n: }! N1 `- S————————————————
0 r( O% d$ Q- t) ^! `) G# U. A/ Y* [转载:Willliam_william
7 o9 Y7 s& I5 d/ y. Z% h
$ i7 a6 K/ u! ^2 v( M
赞 收藏 评论0 发布时间:2022-8-27 14:12

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版