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

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

[复制链接]
STMCU小助手 发布时间:2022-8-27 14:12
一、什么是BSS段(ZI段)
bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。
bss是英文Block Started by Symbol的简称。
bss段属于静态内存分配。

二、为什么要复制data段
这是因为对于在STM32F103这类资源紧缺的单片机芯片中,数据段只是暂时先保存在Flash上,在使用前被复制到内存里,而复制到内存这个过程是需要我们自己实现的。

三、未处理的结果
修改main函数如下所示:

  1. #include "uart.h"
  2. #include "led.h"

  3. int mydata = 0x32315;
  4. const int myconst = 0x22315;
  5. int myzero = 0;
  6. int my;

  7. int main(void)
  8. {
  9.     uart_init();
  10.     led_init();
  11.     putstring("stm32f103zet6\r\n");
  12.         putstring("mydata\t:");
  13.     puthex((unsigned int)&mydata);
  14.     puthex((unsigned int)mydata);
  15.     putstring("\r\nmyconst\t:");
  16.     puthex((unsigned int)&myconst);
  17.     puthex((unsigned int)myconst);
  18.         putstring("\r\nmyzero\t:");
  19.     puthex((unsigned int)&myzero);
  20.     puthex((unsigned int)myzero);
  21.     putstring("\r\nmy\t:");
  22.     puthex((unsigned int)&my);
  23.     puthex((unsigned int)my);
  24.     putstring("\r\n");

  25.     while(1)
  26.     {
  27.                 putstring("led on\r\n");
  28.         led_on();
  29.         delay(1000000);

  30.                 putstring("led off\r\n");
  31.         led_off();
  32.         delay(1000000);
  33.     }
  34. }
复制代码

编译烧录运行,可以看到,除了存在Flash的只读全局变量的值正确,其他几个变量的值都是错误的

20210125214800328.png

四、修改链接文件
既然要复制data段和清除BSS段,那么就需要知道如下几个数据

  1. 1、数据段的加载地址,即数据段存放在Flash的哪个位置
  2. 2、数据段的链接地址,即数据段应该复制到在RAM的哪个位置
  3. 3、数据段的长度,应该复制多长的数据从Flash到RAM
  4. 4、BSS段的链接地址,即BSS段应该从何处开始清除
  5. 5、ZI段的长度,应该清除多长的BSS段
复制代码

我们将链接文件修改为如下所示,得到data段的起始加载地址、起始链接地址和结束链接地址,以及bss段的起始链接地址和结束链接地址。其中>RAM AT > FLASH 表示存放时使用RAM地址,存放时使用FLASH地址。

  1. /* 指定内存区域 */
  2. MEMORY
  3. {
  4.     FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 512K
  5.     RAM (xrw)   : ORIGIN = 0x20000000, LENGTH = 64K
  6. }

  7. SECTIONS {

  8.     .text      :
  9.     {
  10.         . = ALIGN(4);
  11.         *start.o (.text)
  12.         *main.o (.text)
  13.         *(.text)
  14.     } > FLASH

  15.     .rodata :
  16.     {
  17.         . = ALIGN(4);
  18.         *(.rodata)         /* .rodata sections (constants, strings, etc.) */
  19.         *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
  20.         . = ALIGN(4);
  21.     } >FLASH

  22.     _sidata = LOADADDR(.data);  /* 获取data段的起始加载地址 */
  23.     .data :
  24.     {
  25.         . = ALIGN(4);
  26.         _sdata = .;        /* 获取data段的起始链接地址 */
  27.         *(.data)           /* .data sections */
  28.         *(.data*)          /* .data* sections */
  29.         . = ALIGN(4);
  30.         _edata = .;        /* 获取data段的结束链接地址 */
  31.     } >RAM AT > FLASH

  32.     . = ALIGN(4);
  33.     .bss :
  34.     {
  35.         _sbss = .;         /* 获取bss段的起始链接地址 */
  36.         *(.bss)
  37.         *(.bss*)
  38.         *(COMMON)

  39.         . = ALIGN(4);
  40.         _ebss = .;         /* 获取bss段的结束链接地址 */
  41.     } >RAM
  42. }
复制代码

五、修改汇编文件
在start.s中加入如下代码复制data段和清除bss段的代码,其中data段的起始加载地址_sidata、起始链接地址_sdata和结束链接地址_edata,以及bss段的起始链接地址_sbss和结束链接地址_ebss,都是从链接脚本中获取的。

  1.   .syntax unified                   /* 指明当前汇编文件的指令是ARM和THUMB通用格式 */
  2.   .cpu cortex-m3                    /* 指明cpu核为cortex-m3 */
  3.   .fpu softvfp                      /* 软浮点 */
  4.   .thumb                            /* thumb指令 */

  5. .global  _start                     /* .global表示Reset_Handler是一个全局符号 */

  6. .word 0x00000000                    /* 当前地址写入一个字(32bit)数据,值为0x00000000,实际上应为栈顶地址 */
  7. .word _start+1                      /* 当前地址写入一个字(32bit)数据, 值为_reset标号代表的地址+1,即程序入口地址*/

  8. _start:                             /* 标签_start,汇编程序的默认入口是_start */
  9.     /* 1、设置栈 */
  10.     LDR SP, =(0x20000000+0x400)

  11.     /* 2、复制data段 */
  12.         movs r1, #0                                                /* r1寄存器用来计数 */
  13.     b LoopCopyDataInit

  14. CopyDataInit:
  15.     ldr r3, =_sidata                                /* 将data段的起始加载地址存入r3寄存器 */
  16.     ldr r3, [r3, r1]                                /* 从Flash取出data段的值存入r3寄存器 */
  17.     str r3, [r0, r1]                                /* 将r3寄存器的值存入RAM中 */
  18.     adds r1, r1, #4                                        /* 每次复制4个字节的data段数据 */

  19. LoopCopyDataInit:
  20.     ldr r0, =_sdata                                        /* 将data段的起始链接地址存入r0寄存器 */
  21.     ldr r3, =_edata                                        /* 将data段的结束链接地址存入r0寄存器 */
  22.     adds r2, r0, r1                                        /* 起始链接地址加上计数,即当前复制地址存入r2寄存器 */
  23.     cmp r2, r3                                                /* 当前复制地址和结束链接地址相比较 */
  24.     bcc CopyDataInit                                /* 如果r2小于等于r3跳转到CopyDataInit标签处,如果大于则往下执行 */

  25.     /* 3、清除bss段 */
  26.         ldr r2, =_sbss                                        /* 将bss段的起始链接地址存入r2寄存器 */
  27.         b LoopFillZerobss

  28. FillZerobss:
  29.         movs r3, #0                                                /* 将0存入r3寄存器 */
  30.         str r3, [r2], #4                                /* 将r3中的值存到r2中的值所指向的地址中, 同时r2中的值加4 */

  31. LoopFillZerobss:
  32.         ldr r3, = _ebss                                        /* 将bss段的结束链接地址存入r3寄存器 */
  33.         cmp r2, r3                                                /* 比较r2和r3内的值,即当前清除地址和结束链接地址相比较 */
  34.           bcc FillZerobss                                        /* 如果r2小于等于r3跳转到FillZerobss标签处,如果大于则往下执行 */

  35.     /* 4、跳转到led函数 */
  36.     BL main
  37.     /* 5、原地循环 */
  38.     B .

复制代码

然后编译运行烧录,这样我们就可以看到变量的值正常了

20210125223543797.png

————————————————
转载:Willliam_william

收藏 评论0 发布时间:2022-8-27 14:12

举报

0个回答

所属标签

相似分享

官网相关资源

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