范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

深入理解CortexM内存管理(GCC)

  在讨论Cortex-M的内存之前,先来看看Cortex-M的存储器系统,我们知道,Cortex-M系列的处理器,大都可以对32的存储器进行寻址,因此存储器的寻址空间能够达到4G,这就意味着指定和数据共用相同的地址空间,也就是将程序存储器、数据存储器、寄存器和输入输出端口被组织在同一个4GB的线性地址空间内。数据字节以小端格式存放在存储器中。一个字里的最低地址字节被认为是该字的最低有效字节,而最高地址字节是最高有效字节。1 Cortex-M存储器架构
  4G的地址空间就是地址编码的范围。所谓编码就是对每一个程序存储器、数据存储器、寄存器和输入输出端口(一个字节)分配一个唯一的地址号码,这个过程又叫做"编址"或者"地址映射"。这个过程就好像在日常生活中我们给每家每户分配一个地址门牌号。与编码相对应的是"寻址"过程——分配一个地址号码给一个存储单元的目的是为了便于找到它,完成数据的读写,这就是"寻址",因此地址空间有时候又被称作"寻址空间"。
  有了4G的可寻址空间,我们就可通过寻址来操作相应的地址对象。这就需要将程序存储器、数据存储器、寄存器和输入输出端口进行统一编号,也就是存储器映射。
  存储器映射是指把芯片中或芯片外的FLASH,RAM,外设,BOOTBLOCK等进行统一编址。即用地址来表示对象。这个地址绝大多数是由厂家规定好的,用户只能用而不能改。用户只能在挂外部RAM或FLASH的情况下可进行自定义。
  如下图,是Cortex-M3存储器映射结构图。
  Cortex-M3是32位的内核,因此其PC指针可以指向2^32=4G的地址空间,也就是0x0000_0000——0xFFFF_FFFF这一大块空间。根据图中描述,Cortex-M3内核将0x0000_0000——0xFFFF_FFFF这块4G大小的空间分成8大块:代码、SRAM、外设、外部RAM、外部设备、专用外设总线-内部、专用外设总线-外部、特定厂商等,因此使用该内核的设计者必须按照这个进行各自芯片的存储器结构设计。
  首先,我们对比一下Cortex-M3存储器结构和STM32存储器结构:
  图中可以很清晰的看到,STM32的存储器结构和Cortex-M3的很相似,不同的是,STM32加入了很多实际的东西,如:Flash、SRAM等。只有加入了这些东西,才能成为一个拥有实际意义的、可以工作的处理芯片——STM32。
  STM32的存储器地址空间被划分为大小相等的8块区域,每块区域大小为512MB。
  Table 1‑1 存储器地址空间
  地址范围
  描述
  0x0000 0000 ~ 0x2000 0000根据启动引脚的状态决定哪个存储空间被映射到此处。
  片内系统存储区起始地址:0x1fff 0000(2K字节的空间)
  0x2000 0000 ~ 0x4000 0000
  SRAM区,64K,其中位带别名区首地址为:0x2200 0000
  0x4000 0000 ~ 0x6000 0000
  用于片内外设,外设寄存器的别名区首地址:0x4200 0000
  0x6000 0000 ~ 0x8000 0000
  0x8000 0000 ~ 0xa000 0000
  片上flash存储区512M
  0xa000 0000 ~ 0xc000 0000
  0xc000 0000 ~ 0xe000 0000
  0xe000 0000 ~ 0xffff ffff
  对STM32存储器知识的掌握,实际上就是对Flash和SRAM这两个区域知识的掌握。由STM32的系统结构可以看出,Flash和SRAM这两个区域分别由ICode总线和DCode总线与处理器通信,以此完成相应的数据交换。
  当然啦,其他Cortex-M的处理和STM32的也是类似的,比如GD32、CH32等。
  下面将重点描述Flash和SRAM的知识。1.1 Cortex-M的SRAM
  RAM随机存储器(Random Access Memory)表示既可以从中读取数据,也可以写入数据。当机器电源关闭时,存于其中的数据就会丢失。比如电脑的内存条。
  RAM有两大类,一种称为静态RAM(Static RAM/SRAM),SRAM速度非常快,是目前读写最快的存储设备了,但是它也非常昂贵,所以只在要求很苛刻的地方使用,譬如CPU的一级缓冲,二级缓冲。另一种称为动态RAM(Dynamic RAM/DRAM),DRAM保留数据的时间很短,速度也比SRAM慢,不过它还是比任何的ROM都要快,但从价格上来说DRAM相比SRAM要便宜很多,计算机内存就是DRAM的。
  DRAM分为很多种,常见的主要有FPRAM/FastPage、EDORAM、SDRAM、DDR RAM、RDRAM、SGRAM以及WRAM等,这里介绍其中的一种DDR RAM。
  DDR RAM(Date-Rate RAM)也称作DDR SDRAM,这种改进型的RAM和SDRAM是基本一样的,不同之处在于它可以在一个时钟读写两次数据,这样就使得数据传输速度加倍了。这是目前电脑中用得最多的内存,而且它有着成本优势,事实上击败了Intel的另外一种内存标准-Rambus DRAM。在很多高端的显卡上,也配备了高速DDR RAM来提高带宽,这可以大幅度提高3D加速卡的像素渲染能力。
  为什么需要RAM,因为相对FlASH而言,RAM的速度快很多,所有数据在FLASH里面读取太慢了,为了加快速度,就把一些需要和CPU交换的数据读到RAM里来执行。
  STM32单片机内部的 RAM 为 SRAM。不同类型的Cortex-M单片机的SRAM大小是不一样的,但起始地址都是0x2000 0000,终止地址都是0x2000 0000+其固定的容量大小。SRAM相对容量小,速度快,掉电数据丢失,其作用是用来存取各种动态的输入输出数据、中间计算结果以及与外部存储器交换的数据和暂存数据。设备断电后,SRAM中存储的数据就会丢失。1.2 Cortex-M的Flash
  Cortex-M的Flash,严格说,应该是Flash模块。该Flash模块包括:Flash主存储区(Main memory)、Flash信息区(Information block),以及Flash存储接口寄存器区(Flash memory interface)。三个组成部分分别在0x0000 0000——0xFFFF FFFF不同的区域。下面介绍STM32的Flash,如下表所示。
  STM32的闪存模块由:主存储器、信息块和闪存储器块3部分组成。
  主存储器,该部分用来存放代码和数据常数(如加const类型的数据)。对于大容量产品,其被划分为256页,每页2K,注意,小容量和中容量产品则每页只有1K字节。主存储起的起始地址为0X08000000,B0、B1都接GND的时候,就从0X08000000开始运行代码。
  信息块,该部分分为2个部分,其中启动程序代码,是用来存储ST自带的启动程序,用于串口下载,当B0接3.3V,B1接GND时,运行的就这部分代码,用户选择字节,则一般用于配置保护等功能。
  闪存储器块,该部分用于控制闪存储器读取等,是整个闪存储器的控制机构。
  对于主存储器和信息块的写入有内嵌的闪存编程管理;编程与擦除的高压由内部产生。
  在执行闪存写操作时,任何对闪存的读操作都会锁定总线,在写完成后才能正确进行,在进行读取或擦除操作时,不能进行代码或者数据的读取操作。2 C程序内存分析
  在C/C++程序中,编译的程序占用内存分为5个区,分别为栈区、堆区、全局/静态存储区、常量存储区、代码区。
  1.Text段(Code Segment/Text Segment,代码段):通常是指用来存放程序执行代码的一块内存区域,也就是存放CPU执行的机器指令(machine instructions)。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读(某些架构也允许代码段为可写,即允许修改程序)。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
  2.全局初始化数据区/静态数据区(Initialized data segment/Data segment):该区包含了在程序中明确被初始化的全局变量、静态变量(包括全局静态变量和局部静态变量)和常量数据(如字符串常量)。数据段属于静态内存分配。static声明的变量放在data段。
  3.BSS段(Block Started by Symbol):BSS段通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS段属于静态内存分配。
  4.堆(heap):堆是用于存放程序运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。也就是常说的用malloc,calloc, realloc 等函数分配的变量空间是在堆上。当程序调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。
  5.栈(stack):栈又称堆栈,是用户存放程序临时创建的局部变量,也就是说我们函数括弧"{}"中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出(FIFO)特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
  一个程序本质上都是由 bss段、data段、text段三个组成的。
  在C/C++程序编译完成之后,已初始化的全局变量保存在data 段中,未初始化的全局变量保存在bss 段中。
  text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载;而bss段不在可执行文件中,由系统初始化。3 STM32程序的存储分配3.1 程序所占RAM和Flash大小分析
  为例调试方便,这里使用一个裸机串口例子,关于串口的使用请参看笔者博文:
  串口通信:https://bruceou.blog.csdn.net/article/details/79341769
  使用GCC编译代码,编译信息如下:
  其中:text 代表执行的代码,程序中所有的函数都位于此处。当然还包括RO-data(Read Only)代表只读数据,程序中所定义的全局常量数据和字符串都位于此处,如const型。data代表已初始化的读写数据,程序中定义并且初始化的全局变量和静态变量位于此处。bss代表未初始化的读写数据,程序中定义了但没有初始化的全局变量和静态变量位于此处。GCC编译器默认是把你没有初始化的变量都赋值为例0。即上述的bss段。
  值得注意的是,这些参数的单位是Byte。
  text和data两个段需要烧录到FLASH等非易失性器件中。
  data段需要烧录到FLASH中,而bss段则不用,但在运行时,它们都必须装载到可读可写的RAM中。
  因此我们可以计算出FLASH和RAM的大小:
  Flash = test + data
  RAM = data + bss
  这就要涉及到程序的两种状态:加载域和运行域。
  加载域:向Flash中下载程序时,其实仅仅下载的是text+data的内容,意思就是说,在掉电情况下,Flash里面的内存仅包含text+data的内容。
  运行域:当上电后,程序运行时,首先程序会从特定的地址进行启动,启动时会将data的数据加载到SRAM中,单片机的test区域不需要加载到 SRAM,内核直接从 FLASH 读取指令运行。那bss的数据怎么办呢?对于初始值为0全局变量来说,因为要在Code区要调用该全局变量,所以肯定要对其进行描述,程序运行时就知道了,原来你是初始值为0的全局变量呀,然后就在SRAM区给你分配了一段固定区域的地址;对于局部变量来说,会自动分配大小。bss有统计作用,并且SRAM中一段特定的区域是运行bss数据,data +bss就是程序运行总共会占用SRAM的长度,生成局部变量的栈空间包含在bss区的范围。3.2 程序堆栈使用分析
  我们知道,程序运行需要占用的大小是RAM = data + bss,而堆栈的大小是程序开始运行后才能确定的。
  那么堆和栈到底能占用多大呢,堆栈的大小是在STM32F103ZETx_FLASH.ld中设置的,这里以STM32F103ZET6为例进行分析,其内部栈的大小为1KB,堆的大小为0.5KB。
  使用objdump查看elf文件:
  堆栈段起始地址为0x2000 002c,大小为0x604,这0x4又是怎么来的?这里查看map文件。
  堆占用了0x200字节,栈占用了0x400字节,而剩下的0x4字节来自于 ALIGN(0x8),即8字节对齐,因为堆栈段紧跟.bss段之后,那首地址应该是0x2000 0070,但是规定了8字节对齐,所以最小为32,即需要补上4个字节,所以堆栈段起始地址应该是0x2000 00F4。
  【注】栈:向低地址扩展,堆:向高地址扩展。如果依次定义变量,先定义的栈变量的内存地址比后定义的栈变量的内存地址要大,先定义的堆变量的内存地址比后定义的堆变量的内存地址要小。
  【Tips】
  1、堆栈的大小在编译器编译之后是不知道的,只有运行的时候才知道,所以需要注意一点,就是别造成堆栈溢出了,不然就会发生hard fault错误。
  2、所有在处理的函数,包括函数嵌套,递归,等等,都是从这个"栈"里面,来分配的。所以,如果栈大小为2K,一个函数的局部变量过多,比如在函数里面定义一个char buf[512],这一下就占了1/4的栈大小了,再在其他函数里面来搞两下,程序崩溃是很容易的事情,这时候,一般你会进入到hardfault…。
  3、STM32的栈,是向下生长的。事实上,一般CPU的栈增长方向,都是向下的。而堆的生长方向,都是向上的。堆和栈,只是他们各自的起始地址和增长方向不同,他们没有一个固定的界限,所以一旦堆栈冲突,系统就到了崩溃的时候了。
  4、程序中的常量,如果没加const也会编译到SRAM里,加了const会被编译到flash中。3.3 实例代码分析
  前面分析了那么多,下面通过一个实例来验证前面的分析。
  main.c函数代码如下:/* Includes ------------------------------------------------------------------*/ #include "main.h"  /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include  #include  /* USER CODE END Includes */  /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */  /* USER CODE END PTD */  /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */  /* USER CODE END PD */  /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */  /* USER CODE END PM */  /* Private variables ---------------------------------------------------------*/ UART_HandleTypeDef huart1;  /* USER CODE BEGIN PV */ uint8_t buffer[10];//声明了一个初始化为0的全局数组 uint8_t data = 1;//初始化的全局变量  /* USER CODE END PV */  /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART1_UART_Init(void); /* USER CODE BEGIN PFP */  /* USER CODE END PFP */  /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */  /* USER CODE END 0 */  /**   * @brief  The application entry point.   * @retval int   */ int main(void) {   /* USER CODE BEGIN 1 */   uint8_t stack_i; //未初始化的局部变量,   uint8_t stack_j = 1; //初始化的局部变量    uint8_t *pHeap1 = (uint8_t *)malloc(10);//指针pHeap指向堆区分配了一个uint8_t类型10大小的空间   uint8_t *pHeap2 = (uint8_t *)malloc(10);    /* USER CODE END 1 */    /* MCU Configuration--------------------------------------------------------*/    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */   HAL_Init();    /* USER CODE BEGIN Init */    /* USER CODE END Init */    /* Configure the system clock */   SystemClock_Config();    /* USER CODE BEGIN SysInit */    /* USER CODE END SysInit */    /* Initialize all configured peripherals */   MX_GPIO_Init();   MX_USART1_UART_Init();   /* USER CODE BEGIN 2 */       printf("First address of uninitialized global variable buffer: %pr ", buffer);   printf("Address of initialized global variable data: %pr ", &data);   printf("Address of uninitialized local variable stack_i: %pr ", &stack_i);   printf("Address of uninitialized local variable stack_j: %pr ", &stack_j);        printf("The first address of pHeap1 in the heap: %pr ", pHeap1);   printf("The first address of pHeap2 in the heap: %pr ", pHeap2);    free(pHeap1);   free(pHeap2);    /* USER CODE END 2 */    /* Infinite loop */   /* USER CODE BEGIN WHILE */   while (1)   {     /* USER CODE END WHILE */      /* USER CODE BEGIN 3 */     HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);     HAL_Delay(500);   }   /* USER CODE END 3 */ }
  编译后内存分配如下:
  运行程序,打印信息如下:
  data是初始化的全局变量,在.data区;buffer是未初始化的全局变量,在.bss区;pHeap是通过malloc分配的空间,在堆区,逐渐增加;局部变量都在栈区,增加减小。

乡村爱情15定档0112,谢刘赵宋搞事业,共建共享农庄有乡村爱情追的春节才圆满,因为它可以给观众带来欢乐。乡村爱情15定档0112,我很开心。这一季仍然是以象牙山F4中的谢刘赵宋为主,但不再是打打杀杀,而是比拼着搞事业,共建共享农庄。琉璃6璇玑吃醋司凤偷乐,高能名场面笑不停,2人助攻是亮点头条创作挑战赛文丨娱乐小暴风由成毅和袁冰妍领衔主演的琉璃,简直是太上头了。虽说早已大结局,但不妨碍我二刷三刷和N刷,可谓是一入坑中深似海。早期的璇玑六识残缺,不通情爱之事,整体表现2023辽宁春晚阵容强大,铠甲一号直击彩排现场,带你提前剧透2023年元旦已过,距离春节越来越近,除央视春晚正在彩排之外,其他各大卫视春晚也都正在紧张的筹备和录制。其中在2022年春节期间获省级卫视春晚收视第一位的辽宁春晚,成为备受观众期待变形金刚7擎天柱5大谜题揭秘,它的武器系统到底做了哪些更改你知道擎天柱最厉害的招数是什么吗what只要使用了这一招,99的情况下,它都可以做到力挽狂澜,只有一次失败了。本期笔者就来与大家揭秘,变形金刚7新擎天柱的5个疑问与谜题。最新的形态超越班后有客栈,吴彤综艺的量产秘诀犀牛娱乐原创文方正编辑朴芳2023国综仍绕不开吴彤这个名字。开年,TVB整顿内娱的抓马综艺无限超越班尚在热播中,由吴彤制片的我们的客栈又强势上线,甭管口碑如何两极,唐嫣首档常驻综艺蕾哈娜和黑人男友闪耀金球奖!穿低胸装霸气如女王,福娃发型亮了当了妈妈后的蕾哈娜成了十足的辣妈,而在周二举行的金球奖颁奖典礼上,天后蕾哈娜没有赶得上红毯,红毯结束后她才赶到,但是一点都不影响她抢了其他明星的风头,照样惊艳全场。一蕾哈娜穿低胸裙消消乐9关怎么破解破解方法如下首先打通普通关卡,开启精英789关,点击9关。接着点击开始,进入精英第9关。然后9关的通关方法为获得金豆荚,但金豆荚被方块堵住了。接着破解9关很简单,放导弹,围绕导弹消被执行827万!WBG与RNG母公司合同纠纷案一审结果出炉不知道大家是否还记得,在S12全球总决赛八强赛RNG惨遭T1淘汰后,网上便传出了WBG所属公司因合同纠纷而起诉了RNG。而在近日,这个WBG与RNG母公司的合同纠纷案一审结果已经出暴雪网易复合不可能不降低标准正和新代理商谈判之前暴雪宣布与网易终止合作,包括魔兽世界炉石传说守望先锋暗黑破坏神3星际争霸2等暴雪游戏国服都将于1月24日正式关服。最近网上有传闻称,暴雪已经降低标准重新与网易谈判,希望继续合作这些传奇即将增强!实况足球国服大更后建议入手的十大传奇盘点!从v5。10。0的版本序列号可以推测,国服手游即将进行的升级,只是一次赛季小更,而非同步国际服的赛季大更。但由于国服新引擎调整说明中,官方将国服新引擎更新时间定在了2023年的上半冬日战火点燃巅峰对决,2022TGG冬季杯全国总决赛圆满落幕冬日战火点燃巅峰对决!1月8日,由世纪天成主办的2022TGG冬季杯全国总决赛正式拉开帷幕。尽管由于疫情原因本次决赛现场没有设置现场观众,但比赛的紧张刺激随着线上观众的热情席卷了总
香江洋面孔香港洋主厨西式创新菜融入东方味蕾同期理查德埃克布斯荷兰籍米其林大厨香港是一座非常国际化的都市,是一座非常包容的城市。我在这里已经18年了,这里是我的家。同期理查德埃克布斯荷兰籍米其林大厨我叫理查德埃克布斯,我是香湖南省学生资助工作负面清单发布,15个严禁5个不得近日,湖南省学生资助工作负面清单出炉(下称负面清单),将进一步加强学生资助工作全周期管理。负面清单从对象认定资金发放监督管理政策宣传4个方面20个条例进行了规定。对象认定严禁随意变空军航空兵某旅实战化飞行训练影像鹰击长空鏖战云端缑鹏涛解放军报特约通讯员崔保亮摄影报道双机加力升空。飞行员起飞前检查战机。战机飞赴训练空域。旭日初升,战机接续起飞。旭日初升,西北某军用机场引擎轰鸣。数架战机加力升空,奔赴预定空域李梦再遭爆料,男主张隆发文力挺李梦,其中有何内情?前一阵的瓜还没消化完,李梦又端来一盘生猛大瓜。其实很多人不想吃这盘瓜,甚至连看都不愿看到。因为李梦一直是大伙喜闻乐见的重量级女神。李梦1995年生于辽宁沈阳,身高1米82,最初练游吉大师院附小教育集团附属小学开展红领巾劳动种植实践活动红网时刻新闻3月21日讯(通讯员张靖岚张亦欣)双减政策实施以来,吉大师院附小教育集团附属小学通过一系列举措,让劳动精神真正扎根在学生心间。3月20日,学校部分学生来到新开辟的校内劳打造绿美广东样板间21地市掀起绿美广东生态建设高潮,启动林业生态项目超570个南方财经全媒体记者梁施婷喻淑琴河源报道3月21日是第11个国际森林日,广东省21市同心聚力,共建绿美广东主题宣传主会场活动在河源市正式启动,全省21个地市60余个县(区)同步联动多襄阳市落马贪官神操作3800元买的古董600万卖给开发商王士金的个人资料王士金,1966年1月出生,山东泗水人,大学,工学学士。1986年8月开始工作,并于1998年12月加入中国共产党。曾任湖北省襄阳市襄州区区委副书记区长(正县级)。输掉国家德比后,只有这步妙招可以立即使国际米兰解危脱困被尤文双杀,与其归于伤病满营实力不济,不如归于老天报应。足球也是有灵性的。当初苏宁夺冠即解散,欠俱乐部球员的薪水不发,玩赖至今。球员相对于俱乐部来说处于弱势地位,高智商的敬畏父子利放弃中国国籍,以体育之名叛逃,体育界3位叛徒如今结局如何提到著名诗人艾青的那句为什么我的双眼常含泪水,因为我对这土地爱得深沉,大家一定很熟悉,这句诗歌也表达出了作者一种刻骨铭心至死不渝的最伟大最深沉的爱国主义感情!在体育赛场,当五星红旗重大失误!中国队世界冠军组合爆冷丢冠,仅排第14,教练不知所措日前,2023年全国跳水冠军赛正如火如荼进行。在四个双人奥运项目中,练俊杰和杨昊获得男子双人十米台金牌,全红婵和陈芋汐以绝对优势拿下女子双人十米台冠军。女子双人3米板决赛,世界冠军图集备战亚洲杯瞄准亚运会中国女子垒球队在广东黄村训练基地集训中国体育讯3月20日,中国女子垒球队在广东省黄村训练基地展开集训。3月底,队伍将前往韩国征战亚洲杯,回国后将全力备战9月下旬的杭州亚运会,届时中国女垒队将由东道主身份出战。由于20