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

基于STM32的内存管理相关内存架构经验分享

[复制链接]
攻城狮Melo 发布时间:2023-6-12 21:27

使用一个STM32芯片,对于内存而言有两个直观的指标就是 RAM 大小,FLASH大小,比如STM32F103系列(其他系列也是如此):

微信图片_20230612212610.png


6 D+ ?* @' E4 M5 n

那么着两个大小意味着什么?怎么去理解这两个内存,那就得从什么是Flash,什么是RAM说起。

一、FLASH 和 RAM基本概念

先来看一张图:

微信图片_20230612212606.png

- O0 w9 e( g) T4 h1 h) Q) W5 f

1.1 FLASH是什么

通过上图我们可以知道,FLASH属于 非易失性存储器:

扩展一点说,FLASH又称为闪存,不仅具备电子可擦除可编程(EEPROM)的性能,还不会断电丢失数据同时可以快速读取数据,U盘和MP3里用的就是这种存储器。在以前的嵌入式芯片中,存储设备一直使用ROM(EPROM),随着技术的进步,现在嵌入式中基本都是FLASH,用作存储Bootloader以及操作系统或者程序代码或者直接当硬盘使用(U盘)。

然后 Flash 主要有两种NOR Flash和NADN Flash。(对于这两者的区别,下面的话供参考,因为这些介绍都是基于早些年的技术了)

NOR Flash的读取和我们常见的SDRAM的读取是一样,用户可以直接运行装载在NOR FLASH里面的代码,这样可以减少SRAM的容量从而节约了成本。

NAND Flash没有采取内存的随机读取技术,它的读取是以一次读取一块的形式来进行的,通常是一次读取512个字节,采用这种技术的Flash比较廉价。用户不能直接运行NAND Flash上的代码,因此好多使用NAND Flash的开发板除了使用NAND Flah以外,还作上了一块小的NOR Flash来运行启动代码。

STM32单片机内部的FLASH为 NOR FLASH。Flash 相对容量大,掉电数据不丢失,主要用来存储 代码,以及一些掉电不丢失的用户数据。


) W1 l5 W. @! E8 t; m! J8 G

1.2 RAM是什么

RAM 属于易失性存储器:

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的内存管理中会提到)。

STM32单片机内部的 RAM 为  SRAM。RAM相对容量小,速度快,掉电数据丢失,其作用是用来存取各种动态的输入输出数据、中间计算结果以及与外部存储器交换的数据和暂存数据。

# ?7 c9 ~2 G: t: A2 @

二、STM32的内存架构2.1 Cortex-M3的存储器映射分析

在《ARM Cotrex-M3权威指南》中有关 M3的存储器映射表:


2 {4 s# z) [& B+ ^! z: l/ e: W

微信图片_20230612212603.png


8 {+ }) }% B0 p

存储器映射 是用 地址来表示 对象,因为Cortex-M3是32位的单片机,因此其PC指针可以指向2^32=4G的地址空间,也就是图中的 0x00000000到0xFFFFFFFF的区间,也就是将程序存储器、数据存储器、寄存器和输入输出端口被组织在同一个4GB的线性地址空间内,数据字节以小端格式存放在存储器中。

. Q, i6 z2 u1 z2 [) [* [
6 L: I" Q6 r0 _6 I7 i/ e
2.2 STM32 的存储器映射分析

STM32存储器映射表(选用的是STM32F103VE的,不同的型号Flash 和 SRAM 的地址空间不同,起始地址都是一样的):


+ Q& Q- J, {# q3 M4 f8 u/ |

微信图片_20230612212559.png


1 ]* {6 X$ J& m4 ^) G' r0 W

那么我们所需要分析的STM32 内存,就是图中 0X0800 0000开始的 Flash 部分 和 0x2000 0000 开始的SRAM部分,这里还要介绍一个和Flash模块相关的部分:


6 Q% S3 c7 K9 e: w- y9 |# z0 S

微信图片_20230612212556.png

2 Z3 ]- T# d/ r4 i) s# o. g

2.3 STM32的 Flash 组织
0 g$ P9 W2 D  w" E; `& d+ s* w0 t- A+ o% J; ^: `

0 C% k; ~4 K1 N: ?# W" g3 o3 M 微信图片_20230612212552.png
* i, _7 J7 e7 G: L* c& J# A
8 |. l' I! X+ l- P# l
, i- J; ]# r4 i+ ^7 b* w3 _

STM32的Flash,严格说,应该是Flash模块。该Flash模块包括:Flash主存储区(Main memory)、Flash信息区(Informationblock),以及Flash存储接口寄存器区(Flash memory interface)。

主存储器,该部分用来存放代码和数据常数(如加const类型的数据)。对于大容量产品,其被划分为256页,每页2K,小容量和中容量产品则每页只有1K字节。主存储起的起始地址为0X08000000,B0、B1都接GND的时候,就从0X08000000开始运行代码。

信息块,该部分分为2个部分,其中启动程序代码,是用来存储ST自带的启动程序,用于下载,当B0接3.3V,B1接GND时,运行的就这部分代码,用户选择字节,则一般用于配置保护等功能。

闪存储器块,该部分用于控制闪存储器读取等,是整个闪存储器的控制机构。

对于主存储器和信息块的写入有内嵌的闪存编程管理;编程与擦除的高压由内部产生。

在执行闪存写操作时,任何对闪存的读操作都会锁定总线,在写完成后才能正确进行,在进行读取或擦除操作时,不能进行代码或者数据的读取操作。

7 M$ a6 n& K; P2 y: p! r" D

三、STM32 的内存管理

STM32 的内存管理起始就是对 0X8000 0000 开始的 Flash 部分 和 0x2000 0000 开始的 SRAM 部分使用管理


9 l! p$ d8 W4 j7 H- u" l6 Q+ D' f

3.1 C/C++ 程序编译后的存储数据段

参考博文:STM32内存结构介绍

在了解如何使用内存管理之前,先得理解一下 6 个储存数据段 和 3种存储属性区 的概念:

& d9 [( g& m% @! G1 `- s* w+ A4 u


; {- l% q; Y- [


3 m0 I/ E" A- q6 S, v

.data

数据段,储存已初始化且不为0的全局变量和静态变量(全局静态变量和局部静态变量)。static声明的变量放在data段。数据段属于静态内存分配,所以放在RAM里,准确来说,是在程序运行的时候需要在RAM中运行。


- A! K+ U$ B3 y6 l) ?

.BSS

Block Started by Symbol。储存未初始化的,或初始化为0的全局变量和静态变量。BSS段属于静态内存分配,所以放在RAM里。


1 ]2 ]* v5 W2 n, N

.text(CodeSegment/Text Segment)

代码段,储存程序代码。也就是存放CPU执行的机器指令(machineinstructions)。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读(某些架构也允许代码段为可写,即允许修改程序)。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。放在Flash里。

! ]4 ^: }, O5 c& X* E$ \& j

.constdata

储存只读常量。const修饰的常量,不管是在局部还是全局放在Flash 里。所以为了节省 RAM,把常量的字符串,数据等 用const声明

8 P1 C' E2 U, K- G) `+ g# @

heap(堆)

堆是用于存放进程运行中被动态分配的内存段。他的大小并不固定,可动态扩张或者缩减,由程序员使用malloc()和free()函数进行分配和释放。当调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。放在RAM里其可用大小定义在启动文件startup_stm32fxx.s中。


* D, C8 F( {+ t+ N5 J, X

stack(栈)

栈又称堆栈,是用户存放程序临时创建的局部变量,由系统自动分配和释放。可存放局部变量、函数的参数和返回值(但不包括static声明的变量,static意味着 放在 data 数据段中)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。???由于栈的先进先出(FIFO)特点???上面这句话正确吗?Cortex-M3/M4的堆栈是向下生长,第一个入栈的元素应该是最后一个才能出来??所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。放在RAM里其大小定义在启动文件startup_stm32fxx.s中。

+ G  K1 p2 N& e, z8 X+ T, E( l

3.2 STM32 程序编译后的内存占用情况

7 a( n( r# q& z* E% p4 b% E0 {3.2.1 MDK 编译

MDK编译后的结果:


5 c- J/ A3 v( A: V

微信图片_20230612212546.png

5 L' B! @/ p9 L; K3 P+ W4 o

Code:程序代码部分。.text 段放在ROM里面,就是Flash,需要占用flash空间

RO-data(Read Only)只读数据 程序定义的常量,只读数据,字符串常量(const修饰的).constdata 段放在flash里面,需要占用flash空间

RW-data(Read Write)可读可写数据 已经初始化的全局变量和静态变量(就是static修饰的变量);.data 段需要在 RAM里面运行,但是起初需要保存在 Flash里面,程序运行后复制到 RAM里面运行,需要占用Flash空间

ZI-data(Zero Initialize)未初始化的全局变量和静态变量,以及初始化为0的变量;.BSS段ZI的数据全部是0,没必要开始就包含,只要程序运行之前将ZI数据所在的区域(RAM里面)一律清 0,不占用Flash,运行时候占用RAM.

heap 和 stack 其实也属于 ZI,只不过他不是程序编译就能确定大小的,必须在运行中才会有大小,而是是变化的

因为RAM掉电丢失,所以 RW-data 数据也得下载到ROM(flash) 中,在运行的时候复制到 RAM中运行,如下图所示:

. F) K9 g3 R& P1 `

微信图片_20230612212543.png


4 f) n5 n0 ^) C/ k2 Z2 C' L( \! I8 ?

由上我们得知:

程序占用   Flash = Code + RO data + RW data

程序运行时候占用   RAM = RW data + ZI data

Code + RO data + RW data 的大小也是生成的 bin 文件的大小


" {7 @7 \+ y" b4 l8 W- U* i1 R0 y+ W

3.2.1 GCC 编译

GCC编译结果:


" B1 y# w0 \- f0 y

微信图片_20230612212540.png


. |5 J/ ^" `/ P; R3 r

GCC编译, 图中红色的部分是占用 Flash 的大小:Flash = text + data 。蓝色部分是运行时候占用 RAM大小:RAM = data + bss

7 V& v. Z$ T% Q

3.3 STM32 程序的内存分配

我们前面说到的 stack(栈) 和 heap(堆),程序编译完成以后并不能知道运行时候实际占用RAM 大小。但是我们可以知道的是  stack(栈) 和 heap(堆)的起始地址,和能够使用的最大空间,我们先看能够使用的空间大小。


* L* I) h; ?% H5 A6 z& q

3.3.1 MDK 环境

MDK是在 startup_stm32fxxx.s 中定义的:

2 P4 d% ~- J6 o

微信图片_20230612212537.png

& B, p) Q. L, v9 ~( U8 @  E4 x

在 startup_stm32fxxx.s 中我们可以看到关于 Stack_Size 和 Heap_Size的定义,图中的定义就是规定本程序中 栈 的大小为 1K, 堆的大小为 0.5K。

startup_stm32fxxx.s文件是系统的启动文件,startup_stm32fxxx.s主要完成三个工作:栈和堆的初始化、定位中断向量表、调用Reset Handler。(关于STM32的启动文件,我们有单独的一篇文章,请查看另一篇博文    STM32的启动过程(startup_xxxx.s文件解析))

我们在生成的.map文件可以看到 HEAP 和 STACK的起始地址(不懂的可以先看博文下面一节的内容——四、MDK生成的.map文件简析),我们要注意的是:堆使用时候从起始地址开始,往上加栈使用时候从结束地址,就是__initial_sp(栈顶指针的地址)开始,往下减他们的空间大小定义好了,如果入栈元素过大,使得元素减到了堆的地址范围,就是栈溢出,这会导致改变堆中相应地址元素的值。同样的,当申请的动态内存过大,使得堆的变量加到了栈的地址范围,就是堆溢出。

在实际项目中,如果程序复杂,中断嵌套太多,栈需要多设置一点空间如果你使用裸机程序,从来不使用标准库的malloc,heap可以没有,因为永远不会用到,还一直占用着一片RAM区。

所以在我们知道了以上的知识后,我们可以按照自己的工程需求,定义Stack_Size 和 Heap_Size。

0 z& p; s: R- O

3.3.2 GCC 环境

如果是在GCC编译器下面,关于 Stack_Size 和 Heap_Size的定义如下图:

- g! o* W1 a7 t( |% J3 l; I

微信图片_20230612212533.png

- D/ P$ }, j& g7 B! H& [

四、MDK生成的.map文件简析

为了更深层次的理解上述内容,我们还有必要分析一下MDK生成的  .map 文件, 那么既然要分析,除了我们关注的flash 和 ram部分的内容,其他的地方也稍微做一下笔记:

  U0 ~! `4 ~9 h* {! ^& @

4.1  Section Cross References

主要是不同文件中函数的调用关系:


+ t. u8 K/ Q3 z6 X8 n3 X" a$ `6 j6 ~

微信图片_20230612212526.png

2 ]* E+ K& z. B) L6 @0 |( n

我们查看一下 clock.c 文件下的 rt_tick_increase函数:


' @3 L. P* K7 i: K' c+ `5 m4 ~& |

微信图片_20230612212519.png


: K5 O* T% c( k4 i" K- `1 z( i

4.2  Removing Unused input sections from the image

被删除的冗余函数:


& E: L* z' i1 C, h

微信图片_20230612212512.png


6 i- }3 s& `1 n$ y2 A( |" t

删除函数功能在MDK的配置中可以设置,勾选以后删除得多,不勾选删除得少,如下图:

" D, Y. e" b) b- x. {

微信图片_20230612212507.png


! }; {, o* ~" D

在 Removing Unused input sections from the image 的最后会列出删除的冗余函数的大小,如果在MDK上改变上图所示的配置,下图中的删除总代码可以看到变化:

- F2 n& V; r3 e( r6 L0 y( _' a" P* g

微信图片_20230612212503.png


2 {1 [4 r- c' P0 B, q

4.3 Image Symbol Table

5 W) p5 |, n4 [1 z+ }4.3.1 Local Symbols

局部标号, 用Static声明的全局变量地址和大小, C文件中函数的地址和用static声明的函数代码大小, 汇编文件中的标号地址(作用域限本文件):

- |: Z" Z" b+ U

微信图片_20230612212459.png

. k/ `  T$ z- i, r* M; s

我们找个占用内存地址的地方看一下:

; p, p* f% O7 g# T9 n( J; t2 |! H

微信图片_20230612212453.png

" j2 ^! R8 L6 @, d. ^6 }" a/ s  \

我们在 startup_stm32f103xg.s ,可以看到RESET函数:我们继续往下看:


. Q  n5 G, C* L, ]0 G0 y

微信图片_20230612212445.png


' q5 y9 K7 d/ e4 w" l' N

上图中的 i.RCC_Delay 下面跟了一个 RCC_Delay,说明这个函数是用static修饰的,我们找到 stm32f1xx_hal_rcc.c下的RCC_Delay  如图:


6 H9 {# O4 @7 T# u3 ^1 w

微信图片_20230612212431.png

4 }" o, t7 ^$ N- F

我们接着看到 SRAM区:


7 `2 l3 K- l7 p' k- d" V  C8 S

微信图片_20230612212427.png

2 C& o, s% q% ?: n% R2 b

我们继续看到后面的.bss段,包括了 HEAP 和 STACK区域:


- \2 d) N; l  M/ e, y

微信图片_20230612212422.png

( K. m2 f+ d, C2 r" U/ X' ?

通过上图中我们可以看到 HEAP 的起始地址为 0x20002338, ram从 0x2000 0000开始存放的依次为 .data、.bss、HEAP、STACK。HEAP在 startup_stm32fxxx.s 中定义过大小为 0x200, 所以结束地址为0x20002538, HEAP 是和 STACK连接在一起的,所以STACK的起始地址为 0x20002538,大小 0X400,结束地址为  0x20002938。最后我们可以看到 __initial_sp 指向的是 0x20002938,入栈从高地址开始入栈,地址越来越小。


7 f9 K( T" W/ V! K+ L

4.3.2 Global Symbols

全局标号, 全局变量的地址和大小, C文件中函数的地址及其代码大小, 汇编文件中的标号地址(作用域全工程):


; ~+ @7 R9 o* e( d( S( O

微信图片_20230612212420.png


( T# w/ s, t) F! P" `# R3 q6 B. ]

我们找到Flash地址开始的部分:


4 f# e# X& \5 N2 U, p: k

微信图片_20230612212416.png


3 |" X0 t( A6 G3 p' O) [

在 startup_stm32fxxx.s 能看到对应的部分:


9 q/ c) b, z; S+ ?  O

微信图片_20230612212413.png

) }$ r7 {4 j$ @0 |. n6 S

看到最后的 RAM区,注意下图中标出的两行的功能:

! `8 X, ?5 E( s" A- h" A


# G: M3 f: L- A0 D! b: O

4.4  Memory Map of the image

映像文件可以分为加载域(Load Region)和运行域(Execution Region):加载域反映了ARM可执行映像文件各个段存放在存储器中时的位置关系。

: F$ t+ s+ ^" ^8 o

微信图片_20230612212404.png

' j$ S, [5 m1 L8 c

其中还能看出来 Flash中存放的都是 code,和 RO_Data:

. S' ?/ E( [2 T  k# `" B+ a' q

微信图片_20230612212401.png

6 u3 c# S% H" m5 g- J

我们看看SRAM部分:


" m1 W0 z8 L; p% H' r" g: o

微信图片_20230612212353.png

! e# \. Q" n7 {4 x* K: ^

需要注意一下,我们前面代码he 数据部分都是4字节对齐,PAD一般都是补充2个字节,到了栈部分,需要8字节对齐:

/ H" i  ?2 {# V. q

微信图片_20230612212349.png

: d8 Z" E5 I8 C0 M

4.5  Image component sizes

存储组成大小 这部分的内容就比较直观

  }" C0 S3 X" E5 A

微信图片_20230612212345.png

/ H& p) l, X/ P, Y

最后就是我们熟悉的部分:

! x3 a' a  z7 r7 {1 b7 {

微信图片_20230612212327.png


; m! V& N: z/ a1 J

五、一些相关的补充内容5.1 STM32 的启动方式

! \) I4 ~. ^- N+ b0 i. r' F. Q8 n# _% B2 W
BOOT0
BOOT1
启动模式
0XUser Flash memory(从闪存存储器启动)
10System memory(从系统存储器启动)
11Embedded SRAM(从内嵌SRAM启动)

) d3 R# R4 h$ M( e, J  p

第一种启动方式是最常用的用户FLASH启动,正常工作就在这种模式下,STM32的FLASH可以擦出10万次,所以不用担心芯片哪天会被擦爆!

第二种启动方式是系统存储器启动方式,即我们常说的串口下载方式(ISP),不建议使用这种,速度比较慢。STM32 中自带的BootLoader就是在这种启动方式中,如果出现程序硬件错误的话可以切换BOOT0/1到该模式下重新烧写Flash即可恢复正常。

第三种启动方式是STM32内嵌的SRAM启动。该模式用于调试。 用jlink在线仿真,则是下载到SRAM中。

以上三种启动方式我们都很熟悉,但是他的究竟是如何实现的呢?

我们先来看看《Cortex-M3权威指南》关于CM3复位后的动作:


( e. s; S, T# V( e

微信图片_20230612212323.png

/ P" K+ _% p  o8 F/ n9 H0 [8 f

当选择相应的启动方式时,对应的存储器空间被映射到启动空间(0x00000000)。

从闪存存储器启动:主闪存存储器被映射到启动空间(0x0000 0000) ,也就是0x08000000被映射到0x00000000。

从内嵌SRAM启动 :SRAM起始地址 0x2000 0000 被映射到0x00000000。

从系统存储器启动:系统存储器被映射到启动空间(0x0000 0000),也就是0x1FFF F000被映射到0x00000000。(为什么是0x1FFF F000 可以查阅上文中的  2.2小节  STM32 的存储器映射分析,STM32互联型产品这个地址不一样,此地址由ST官方写入了一段BootLoader代码,可以通过官方BootLoader升级MCU固件,无法修改)。

, V, n. D( M4 P; E  D. \

5.2 STM32启动地址和 Bootloader 说明

通过上面的内容,我们现在知道STM32 从Flash程序启动以后会从 0X08000000 开始运行,那么他这个地址是否可以修改,答案是当然的!但是单独的改他的启动地址,没有任何意义,一般都是需要使用到 Bootloader 才会使得应用程序的地址发生变化。

在 0x1FFF F000 这个地址上官方写入了一段 BootLoader 用户使用,我们也可以自己写一段 BootLoader 程序方便自己使用,因为是自己写的,他还是用户程序,只是我们自己把程序分成了 BootLoader部分和 应用程序部分,大概的意思如下图所示:

8 U5 P4 k4 B) ]/ t

微信图片_20230612212317.png

( a- \  B2 H# k2 a; N; o4 s

为什么要使用用户 BootLoader :

在有些项目中,可能因为某些原因需要经常更换 程序,如果每次都是重新烧录,特别的麻烦,那么我们就可以自己设计一个 BootLoader,通过 SD卡进行升级:上电后先运行 BootLoader,BootLoader主要工作是检测是否有SD卡,SD卡中是否有需要的BIn文件, 如果检测到就将其复制到 应用程序区域 使得程序得以更新,更新结束以后跳转到应用程序执行;如果没检测到相应的SD卡,就说明程序不需要更新,也跳转到应用程序执行;

以上主要是说明使用 BootLoader 的思路与适用场合,至于具体的实现其实网上有很多教程,如果有机会我也会补充或者单独写一篇文章总结一下

(说明:下面是零碎的笔记,还没整理完,仅供参考 stm32 FLASH的起始地址是0x08000000,当然也可以自定义起始地址,不过记得在main函数中定义变量后加一句SCB->VTOR=FLASH_BASE | OFFSET;OFFSET是想要偏移的量,可宏定义或直接0xXX。当然也可以调用库函数 NVIC_SetVectorTable()进行偏移,效果一样。IAP升级这样用的多)

: Z9 n- S1 [5 b1 C0 X

5.3  单片机和 x86cpu运行程序的不同

参考博文:cpu运行时程序是在flash中还是在RAM呢?x86的pc机cpu在运行的时候程序是存储在RAM中的,而单片机等嵌入式系统则是存于flash中

x86cpu和单片机读取程序的具体途径:pc机在运行程序的时候将程序从外存(硬盘)中,调入到RAM中运行,cpu从RAM中读取程序和数据
8 k4 U6 o6 W. f, I- G2 E而单片机的程序则是固化在flash中,cpu运行时直接从flash中读取程序,从RAM中读取数据

原因分析 :x86构架的cpu是基于冯.诺依曼体系的,即数据和程序存储在一起,而且pc机的RAM资源相当丰富,从几十M到几百M甚至是几个G,客观上能够承受大量的程序数据。9 B* r# @8 [* r9 G
单片机的构架大多是哈弗体系的,即程序和数据分开存储,而且单片的片内RAM资源是相当有限的,内部的RAM过大会带来成本的大幅度提高。

冯.诺依曼体系与哈佛体系的区别:二者的区别就是程序空间和数据空间是否是一体的。早期的微处理器大多采用冯诺依曼结构,典型代表是Intel公司的X86微处理器。取指令和取操作数都在同一总线上,通过分时复用的方式进行的。缺点是在高速运行时,不能达到同时取指令和取操作数,从而形成了传输过程的瓶颈。3 t$ N# g4 G! E
哈佛总线技术应用是以DSP和ARM为代表的。采用哈佛总线体系结构的芯片内部程序空间和数据空间是分开的,这就允许同时取指令和取操作数,从而大大提高了运算能力。

  M" N5 N! D1 b

5.4  ARM 和 x86cpu 指令集RISC和CISC说明

(此部分是学习了韦东山老师的视频后来记录的,原视频可以在韦东山老师官网里面找到:百问网)

ARM芯片属于精简指令集计算机(RISC:Reduced Instruction Set Computing),它所用的指令比较简单,有如下特点:① 对内存只有读、写指令 ② 对于数据的运算是在CPU内部实现 ③ 使用RISC指令的CPU复杂度小一点,易于设计

. U" q/ ]7 s4 ?; n$ @

微信图片_20230612212313.png

5 @+ q: i% @+ }7 p8 A/ D

在ARM架构中,对于乘法运算a = a * b, 在RISC中要使用4条汇编指令:① 读内存a ② 读内存b ③ 计算a*b ④ 把结果写入内存

x86属于复杂指令集计算机(CISC:Complex Instruction Set Computing), 它所用的指令比较复杂,比如某些复杂的指令,它是通过“微程序”来实现的。

/ g! m, K7 J/ R. q

微信图片_20230612212306.png


+ k5 g' Q+ E( r# e1 \) A: t

比如执行乘法指令时,实际上会去执行一个“微程序”, 一样是去执行这4步操作:① 读内存a ② 读内存b ③ 计算a*b ④ 把结果写入内存


. Z7 ]' ^. u4 p0 @% K! H

RISC和CISC的区别:

  • CISC的指令能力强,单多数指令使用率低却增加了CPU的复杂度,指令是可变长格式;
  • RISC的指令大部分为单周期指令,指令长度固定,操作寄存器,对于内存只有Load/Store操作
  • CISC支持多种寻址方式;RISC支持的寻址方式
  • CISC通过微程序控制技术实现;
  • RISC增加了通用寄存器,硬布线逻辑控制为主,采用流水线
  • CISC的研制周期长
  • RISC优化编译,有效支持高级语言9 r6 g# I  @7 ]  U1 _* n# m! S" y- L

##六、  GCC下生成的.map文件 我们知道了MDK下的.map文件,GCC下的.map文件基本上也可以看懂了,这里添加GCC下.map文件关于RAM的部分:

: z: d0 C6 y- J  d% _8 E

6.1 RAM部分

RAM部分从0x2000 0000开始,首先存放的是.data部分:

3 d: v6 e. ]! _. ~8 I

微信图片_20230612212302.png


% T! O% \; o6 t( k0 x

接下来是.bss段:

* x# R$ G+ _+ [# Y2 n

微信图片_20230612212258.png


- X3 G- g* |! q. j9 n6 U# R% G8 D

如果使用了FreeRTOS,那么在.bbs段后面会有关于FreeRTOS部分的数据:


% y- j9 I3 v1 r

微信图片_20230612212252.png

! i6 t0 E" A9 N$ `

最后才到了heap和stack:

0 J2 d% S% j; R3 s3 s

微信图片_20230612212245.png

: j7 q& [- {5 @

如有侵权请联系删除

转载自:矜辰所致2 _! {1 Q2 X! ]: M8 M


0 T8 \& F: ~7 ~3 P8 d

: }) i3 @5 C$ \

4 S1 A7 H1 a1 w% q
微信图片_20230612212409.png
微信图片_20230612212440.png
微信图片_20230612212549.png
收藏 1 评论0 发布时间:2023-6-12 21:27

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版