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

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

[复制链接]
STMCU小助手 发布时间:2022-8-27 14:12
一、什么是BSS段(ZI段)! t- D- [! R" G" Z% g, V4 N
bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。9 Z* }( ]; g1 l2 M
bss是英文Block Started by Symbol的简称。7 r. `% }) s, F% p
bss段属于静态内存分配。# ~9 A+ I  [0 E& z4 Q" X7 A
7 W+ t' {. r6 e; a8 n& v
二、为什么要复制data段
$ x1 x' {( G4 O这是因为对于在STM32F103这类资源紧缺的单片机芯片中,数据段只是暂时先保存在Flash上,在使用前被复制到内存里,而复制到内存这个过程是需要我们自己实现的。7 b1 Q; Y; P; H( _, f, e! A
0 V0 \* @9 _# N1 F
三、未处理的结果
! S8 e) Y0 R2 ~. i修改main函数如下所示:
. W1 F- V$ [4 |' J% M
) r! @% X8 y! W2 c" D
  1. #include "uart.h"! K, o0 W$ |1 p" T
  2. #include "led.h"" l5 f& m/ r6 @0 K& I
  3. ; e) i  F, l" w1 r
  4. int mydata = 0x32315;! N: M3 \2 |; M. L" T
  5. const int myconst = 0x22315;7 [) i! x( T9 l; T# m% m  Q* F& P
  6. int myzero = 0;# H0 ?5 C+ Z+ s; t. l9 P+ @
  7. int my;5 C, o) V7 p; i7 X
  8. # G" n. s7 m( r) {4 C7 e, ~
  9. int main(void)
    ! T8 c8 u; ]. m" o  Q, a; X! t& W, `
  10. {& y3 B5 f* f2 k& v1 W9 z
  11.     uart_init();
    / k2 v: k( O2 S. k: b) V, p1 I! |
  12.     led_init();& _) z  q' C! L, t+ R/ g* t% w  M
  13.     putstring("stm32f103zet6\r\n");
    & e- e  S# A. I% @! q! K( z
  14.         putstring("mydata\t:");
    7 `8 W$ }' u3 w$ I6 y% |' Q1 Q
  15.     puthex((unsigned int)&mydata);
    9 u# w, \* t+ _0 x- c
  16.     puthex((unsigned int)mydata);- }9 o7 b: E1 Y7 J- N# W
  17.     putstring("\r\nmyconst\t:");
    " s6 ]7 Y7 m7 e& A' t/ g0 G
  18.     puthex((unsigned int)&myconst);
    7 R2 v# j% e4 y8 o3 B/ W) m
  19.     puthex((unsigned int)myconst);
    2 b" _5 o# s! g+ D' S' B
  20.         putstring("\r\nmyzero\t:");0 V/ m, [' h5 F; _3 ?
  21.     puthex((unsigned int)&myzero);0 \( M& v( y3 n; a" ^3 i
  22.     puthex((unsigned int)myzero);
    9 B, t- i4 W, P
  23.     putstring("\r\nmy\t:");
      w- U1 j5 R+ w2 |6 e
  24.     puthex((unsigned int)&my);* h+ G$ u+ y$ h* y7 f0 I: g4 l
  25.     puthex((unsigned int)my);0 Q0 `2 P- w" j6 x% `7 s
  26.     putstring("\r\n");
    - s# ~4 M4 m, ]5 c7 _* R/ {7 m+ P
  27. ( K/ m' v0 K5 `3 K
  28.     while(1)
    - q* z% K; k# o. r1 M# b, B
  29.     {8 R9 j2 ]$ W/ I1 Y, Z' F; Z- @
  30.                 putstring("led on\r\n");' a! {. q$ H: z8 m( }5 F
  31.         led_on();$ l& O6 U4 A- Q9 g4 O
  32.         delay(1000000);/ o; e$ b, B/ A4 t9 V
  33. ! e" v2 R- I( v2 q$ f
  34.                 putstring("led off\r\n");0 v5 Z9 [1 U6 h; M. F3 R
  35.         led_off();
    ; c# a, o$ X; g- F/ ?% _; N
  36.         delay(1000000);
    2 ?3 J) Z9 e; s8 ~8 K
  37.     }+ V; S  c2 Y, t1 h9 f& r" V  {
  38. }
    4 R6 F" [) O" K
复制代码

/ @; z& `% k" B- E# t" {编译烧录运行,可以看到,除了存在Flash的只读全局变量的值正确,其他几个变量的值都是错误的
4 |  ~) G1 \9 g8 l
* q& \3 G2 W9 ^+ u, X' O- }* r 20210125214800328.png
# F, s  M: |2 R( u+ F/ m7 M* B  \3 p1 h% k* X9 O' N
四、修改链接文件6 b2 L! E( s& e
既然要复制data段和清除BSS段,那么就需要知道如下几个数据. }5 X, p5 G- W% U! u  \

, D- V4 n: Q! P4 x1 O
  1. 1、数据段的加载地址,即数据段存放在Flash的哪个位置
    + v) \( ~* @1 n
  2. 2、数据段的链接地址,即数据段应该复制到在RAM的哪个位置' T. R! g0 J" o; e5 i. g6 T5 B8 B) i4 y
  3. 3、数据段的长度,应该复制多长的数据从Flash到RAM, m  V) {: k  l3 n
  4. 4、BSS段的链接地址,即BSS段应该从何处开始清除; u& {8 L& x1 n' e" W9 w
  5. 5、ZI段的长度,应该清除多长的BSS段
复制代码
7 f  r0 z' }9 @+ d4 s
我们将链接文件修改为如下所示,得到data段的起始加载地址、起始链接地址和结束链接地址,以及bss段的起始链接地址和结束链接地址。其中>RAM AT > FLASH 表示存放时使用RAM地址,存放时使用FLASH地址。
- j/ e) L. f5 ~9 u& E( o- @+ L/ s0 e1 s
  1. /* 指定内存区域 */
    9 \: U, v+ a- l) m. \3 ^
  2. MEMORY1 |* q+ m6 W1 F0 _0 _/ K7 x
  3. {/ g& B0 l( i  r  [4 s! M0 d
  4.     FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 512K+ t- i7 S( A4 S/ j
  5.     RAM (xrw)   : ORIGIN = 0x20000000, LENGTH = 64K* K6 T2 K9 m1 u' v: {4 m# R
  6. }
    ( v0 n& R3 ?' c7 q
  7. 9 Q' @, N& K/ n/ K
  8. SECTIONS {/ J6 M3 s$ H* i

  9. 4 h6 a4 _8 Z1 D2 N$ M0 ^
  10.     .text      :
    ) s8 s  h' j0 T  T9 O
  11.     {
    ! a. W( Q9 u  U! c
  12.         . = ALIGN(4);
      M8 X) B4 ~, c* u! s+ @' K4 Z7 }
  13.         *start.o (.text)4 u- y5 w5 P: Y
  14.         *main.o (.text), v& p6 @# Z9 X/ m+ s# Y
  15.         *(.text)
    ( ~. ]8 C+ Y: ~" x: z: ~7 m
  16.     } > FLASH$ f, L2 [. W6 a( v, y: X2 r
  17. ) a+ F& _& |8 G  t
  18.     .rodata :8 c4 b. ]7 h/ U5 O
  19.     {
    . v% l- {! s% w* _
  20.         . = ALIGN(4);
      O( y8 l: ?0 L8 a# G  ^0 ^9 n
  21.         *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    1 ?6 L0 Z1 P/ t
  22.         *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */3 t5 V6 {5 ]# ]- K5 g8 }  K3 V1 ^# C
  23.         . = ALIGN(4);
      }1 ~- [5 ]4 ?
  24.     } >FLASH9 R" z* {0 X3 y. b4 W; l

  25. % l) ]5 {, Z" }9 [
  26.     _sidata = LOADADDR(.data);  /* 获取data段的起始加载地址 */
    $ p$ y" t5 p/ e! ~& c6 v* j
  27.     .data :
    $ \$ S: m- I  L4 L' t4 \
  28.     {/ ~7 F, Y4 J5 x$ K6 h6 C0 Q4 x
  29.         . = ALIGN(4);* E7 a4 I: B8 q: k7 y& }1 Y
  30.         _sdata = .;        /* 获取data段的起始链接地址 */% x0 K8 K2 u' A* g  ?
  31.         *(.data)           /* .data sections */
    % a7 Y/ M4 b" L/ b+ Z1 d
  32.         *(.data*)          /* .data* sections */
    6 E6 q# V  n  |
  33.         . = ALIGN(4);
    # w7 e' F8 W& n# }: g
  34.         _edata = .;        /* 获取data段的结束链接地址 */0 o$ X1 T& d1 Y: }
  35.     } >RAM AT > FLASH
    / l! H$ i1 S% F  c3 }
  36. 6 |: f2 U4 y4 Y* u
  37.     . = ALIGN(4);8 D% `' q5 S$ ], d# N' N. Z) _
  38.     .bss :! d+ N3 n3 O; k8 l% b
  39.     {5 W( S5 k% U* [+ H' h4 u) ~
  40.         _sbss = .;         /* 获取bss段的起始链接地址 */
    % n  `! m' f! Z2 |& A$ H
  41.         *(.bss)
    2 _. d0 R9 u2 B. E' h
  42.         *(.bss*)
    # h. K! ]+ ]# G
  43.         *(COMMON)
    1 y- d% B, J# ?% e6 y0 }- b* h
  44. * f- l- n7 P2 n7 ?
  45.         . = ALIGN(4);
    9 L2 p& ]# d& W
  46.         _ebss = .;         /* 获取bss段的结束链接地址 */7 K5 J) j7 t6 [+ Y
  47.     } >RAM* H! l, D- `- _, {( e) v% ^
  48. }
复制代码
* l/ G- Y$ m' Z  Z' b" s! k4 x, b
五、修改汇编文件# @* Z$ K) w- ?4 Y% @: r9 o2 \
在start.s中加入如下代码复制data段和清除bss段的代码,其中data段的起始加载地址_sidata、起始链接地址_sdata和结束链接地址_edata,以及bss段的起始链接地址_sbss和结束链接地址_ebss,都是从链接脚本中获取的。" q+ y+ P8 q; t
  1. 9 G* J7 E/ \' _  o
  2.   .syntax unified                   /* 指明当前汇编文件的指令是ARM和THUMB通用格式 */
    9 C; ^. I: G- `  X: |7 ]
  3.   .cpu cortex-m3                    /* 指明cpu核为cortex-m3 */, [2 \. O$ A- G1 o4 F$ _( f
  4.   .fpu softvfp                      /* 软浮点 */
    ! U' o9 R5 r3 Z1 g) m4 H
  5.   .thumb                            /* thumb指令 */
    + N7 t4 @' v3 F. m9 i; f

  6. 4 g7 S/ [  ~- R  z
  7. .global  _start                     /* .global表示Reset_Handler是一个全局符号 */
    / B) L; h& @  g; a5 A6 w" {
  8. : {! @7 p/ D( n' h$ H1 J
  9. .word 0x00000000                    /* 当前地址写入一个字(32bit)数据,值为0x00000000,实际上应为栈顶地址 */
    # {0 ?3 u% H( p" ]0 f# @- F
  10. .word _start+1                      /* 当前地址写入一个字(32bit)数据, 值为_reset标号代表的地址+1,即程序入口地址*/
    , l. |% J/ l3 \' I0 b
  11. ! G1 [8 H9 A- o/ D! X
  12. _start:                             /* 标签_start,汇编程序的默认入口是_start */$ b. z; `4 L/ C
  13.     /* 1、设置栈 */
    : ]' ^- `! R8 h! S
  14.     LDR SP, =(0x20000000+0x400)3 R6 w- q0 D! M( M. I2 w2 X4 g+ H3 X
  15. % D8 Y' w/ B+ e
  16.     /* 2、复制data段 */3 S" M. g: ]1 [; h6 d( ]) R
  17.         movs r1, #0                                                /* r1寄存器用来计数 */
    # ]$ x. w2 R0 x1 b: M5 m+ c
  18.     b LoopCopyDataInit
    2 \" ~+ @3 _5 n5 s

  19. 2 U! x  D' P0 T; k9 i; C+ U. \
  20. CopyDataInit:
    * Y+ ~0 }) J+ n" }! P6 L9 }. j
  21.     ldr r3, =_sidata                                /* 将data段的起始加载地址存入r3寄存器 */, q+ I1 `8 a& M; U% x
  22.     ldr r3, [r3, r1]                                /* 从Flash取出data段的值存入r3寄存器 */
    2 S$ s' _2 Q) C# }2 P* i5 g
  23.     str r3, [r0, r1]                                /* 将r3寄存器的值存入RAM中 */
    : O; y" p: p0 |; y" n. ?! f$ p
  24.     adds r1, r1, #4                                        /* 每次复制4个字节的data段数据 */
    3 N" B5 q' s5 Z* C1 e6 s# p+ ]9 [
  25. . ~* \8 K* y& T4 n7 ^
  26. LoopCopyDataInit:
      u$ k) j' k% T. e# j
  27.     ldr r0, =_sdata                                        /* 将data段的起始链接地址存入r0寄存器 */
    3 i( a1 p% _' a' ?* F% m  [
  28.     ldr r3, =_edata                                        /* 将data段的结束链接地址存入r0寄存器 */
    ! \  P' I9 G- h7 T4 Y9 }$ k& R2 B& L
  29.     adds r2, r0, r1                                        /* 起始链接地址加上计数,即当前复制地址存入r2寄存器 */' d8 q# S3 ?2 W, ^3 |, H2 u2 m
  30.     cmp r2, r3                                                /* 当前复制地址和结束链接地址相比较 */% F. }( K; k5 a$ F. ~! `
  31.     bcc CopyDataInit                                /* 如果r2小于等于r3跳转到CopyDataInit标签处,如果大于则往下执行 */
      U, g) o; {; d* _9 Z
  32. $ P3 |# o- a! a" j. Z+ w# T
  33.     /* 3、清除bss段 */- B, }7 k- l: J$ z
  34.         ldr r2, =_sbss                                        /* 将bss段的起始链接地址存入r2寄存器 */
    ( W' S& \& e' X- \
  35.         b LoopFillZerobss& ~' I. Z+ v, y

  36. : H6 X+ ^' K+ L" H, g
  37. FillZerobss:) D2 m% J, {4 t' [$ n" E
  38.         movs r3, #0                                                /* 将0存入r3寄存器 */
    7 e6 E' X5 l3 }* |) E5 Q) K
  39.         str r3, [r2], #4                                /* 将r3中的值存到r2中的值所指向的地址中, 同时r2中的值加4 */0 h: q% v* s4 e
  40. ) p% r& p$ j2 W3 M$ H1 L4 y! Y. d
  41. LoopFillZerobss:
    9 t3 d; [0 C4 }3 k+ H& }* X, M
  42.         ldr r3, = _ebss                                        /* 将bss段的结束链接地址存入r3寄存器 */
    - D9 m- `7 t. L4 m+ J2 }# D9 L
  43.         cmp r2, r3                                                /* 比较r2和r3内的值,即当前清除地址和结束链接地址相比较 */9 V3 D$ M3 C$ y8 {& u( j
  44.           bcc FillZerobss                                        /* 如果r2小于等于r3跳转到FillZerobss标签处,如果大于则往下执行 */- F, Q+ [) [, g6 V/ {

  45. 8 }) Q3 m2 k  Q  Z
  46.     /* 4、跳转到led函数 */& v' w" s8 ]* |0 y2 x
  47.     BL main: {+ `/ S! l7 v# c; ^
  48.     /* 5、原地循环 */7 G/ H* D' O" g  X4 |5 ~
  49.     B .& s$ r6 {8 L0 g$ ~! B. M7 w

  50. , Y* ]' o: W$ }, C. g
复制代码

9 @( t! C) b+ L2 h然后编译运行烧录,这样我们就可以看到变量的值正常了
1 o' H5 S$ w0 O. E" K) v4 @4 S0 n2 n+ X" y" j
20210125223543797.png # r7 v& L/ c& J# _
  [2 t0 \0 t& ~# W$ L! _
————————————————
! a+ I9 ~* l  i  d2 ?% F4 p转载:Willliam_william
* T3 Q9 {0 X9 [; |& E. M; x
2 @: B  E* A. X2 [9 B6 P
收藏 评论0 发布时间:2022-8-27 14:12

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版