STM32学习笔记-STM32堆栈区(二)

发布者:superstar11最新更新时间:2020-01-16 来源: eefocus关键字:STM32  堆栈区  分区 手机看文章 扫描二维码
随时随地手机看文章

STM32的分区


STM32的分区从0x2000 0000(0x2000 0000是SRAM的起始地址,由此可知,堆栈等都是在RAM中的)开始。静态区,堆,栈。所有的全局变量,包括静态变量之类的,全部存储在静态存储区。 紧跟静态存储区之后的,是堆区(如没用到malloc,则没有该区),之后是栈区,栈在程序中存储局部变量。


先看启动文件startup_stm32f10x_md.s的定义:

;

Amount of memory (in bytes) allocated for Stack 


; Tailor this value to your application needs 


; Stack Configuration 


; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> 


;


Stack_Size

EQU 0x00000400


AREA

STACK, NOINIT, READWRITE, ALIGN=3 


Stack_Mem SPACE Stack_Size 


__initial_sp


; Heap Configuration 


; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> 


;


Heap_Size

EQU 0x00000200


AREA

HEAP, NOINIT, READWRITE, ALIGN=3 


__heap_base 


Heap_Mem SPACE Heap_Size 


__heap_limit


这里定义了堆栈各自大小,堆:512bytes 栈1k;

所以栈区大小有限制,我们在局部变量中不要定义大数组否则容易溢出。


再看下code ro rw zi


Code指存储到flash【Rom】中的程序代码。


ZI英语是zero initial,就是程序中用到的变量并且被系统初始化为0的变量的字节数,keil编译器默认是把你没有初始化的变量都赋值一个0,这些变量在程序运行时是保存在RAM中的。


RW是可读可写变量,就是初始化时候就已经赋值了的,RW + ZI就是你的程序总共使用的RAM字节数。


RO是程序中的指令和常量,这些值是被保存到Rom中的。


Total ROM Size (Code +RO Data + RW Data)这样所写的程序占用的ROM的字节总数,也就是说程序所下载到ROM flash 中的大小。为什么Rom中还要存RW,因为掉电后RAM中所有数据都丢失了,每次上电RAM中的数据是被重新赋值的,每次这些固定的值就是存储在Rom中的,为什么不包含ZI段呢,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。包含进去反而浪费存储空间。


实际上,ROM中的指令至少应该有这样的功能:


将RW从ROM中搬到RAM中,因为RW是变量,变量不能存在ROM中。

将ZI所在的RAM区域全部清零,因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI地址及大小来将相应得RAM区域清零。ZI中也是变量,同理:变量不能存在ROM中。

例子:


1,首先来看:栈(STACK)的问题.


函数的局部变量,都是存放在“栈”里面,栈的英文是:STACK。STACK的大小,我们可以在stm32的启动文件里面设置,在startup_stm32f10x_hd.s里面,开头就有:


Stack_Size     EQU     0x00000800


表示栈大小是0X800,也就是2048字节,这样,CPU处理任务的时候,函数局部变量过多可占用的大小就是:2048字节。注意:是所有在处理的函数,包括函数嵌套,递归,等等,都是从这个“栈”里面,来分配的。


所以,如果一个函数的局部变量过多,比如在函数里面定义一个u8 buf[512],这一下就占了1/4的栈大小了,再在其他函数里面来搞两下,程序崩溃是很容易的事情,这时候,一般你会进入到hardfault…


这是初学者非常容易犯的一个错误.切记不要在函数里面放N多局部变量,尤其有大数组的时候!


对于栈区,一般栈顶,也就是MSP,在程序刚运行的时候,指向程序所占用内存的最高地址。比如附件里面的这个程序序,内存占用如下图:

在这里插入图片描述

图中,我们可以看到,程序总共占用内存:20+2348字节=2368=0X940


那么程序刚开始运行的时候:MSP=0X2000 0000+0X940=0X2000 0940.

事实上,也是如此,如图:

在这里插入图片描述

图中,MSP就是:0X2000 0940,程序运行后,MSP就是从这个地址开始,往下给函数的局部变量分配地址。


2,再来说说,堆(HEAP)的问题.

全局变量,静态变量,以及内存管理所用的内存,都是属于“堆"区”,英文名:“HEAP”,与栈区不同,堆区,则从内存区域的起始地址开始分配给各个全局变量和静态变量。

堆的生长方向,都是向上的。在程序里面,所有的内存分为:堆+栈,只是他们各自的起始地址和增长方向不同,他们没有一个固定的界限,所以一旦堆栈冲突,系统就到了崩溃的时候了。

3,再说说,大小端的问题


大端模式:低位字节存在高地址上,高位字节存在低地址上

小端模式:高位字节存在高地址上,低位字节存在低地址上

STM32属于小端模式,简单的说,比如u32 temp=0X12345678;

假设temp地址在0X2000 0010.

那么在内存里面,存放就变成了:

地址

| HEX |


0X2000 0010 | 78 56 43 12 |

关键字:STM32  堆栈区  分区 引用地址:STM32学习笔记-STM32堆栈区(二)

上一篇:STM32 keil4 extern问题
下一篇:关于STM32堆栈方面知识点

推荐阅读最新更新时间:2024-11-07 19:07

经典_STM32_ADC多通道采样的例子
STM32 ADC多通道转换 描述:用ADC连续采集11路模拟信号,并由DMA传输到内存。ADC配置为扫描并且连续转换模式,ADC的时钟配置为12MHZ。在每次转换结束后,由DMA循环将转换的数据传输到内存中。ADC可以连续采集N次求平均值。最后通过串口传输出最后转换的结果。 程序如下: #i nclude stm32f10x.h //这个头文件包括STM32F10x所有外围寄存器、位、内存映射的定义 #i nclude eval.h //头文件(包括串口、按键、LED的函数声明) #i nclude SysTickDelay.h #i nclude UART_INTERFACE.h #i nclude stdio.h #d
[单片机]
STM32时钟系统与时钟启动顺序详解
概念基础: STM32时钟系统基本一致,不同系列之间有细微差别。此文档主要针对STM32F446的时钟系统进行介绍。 1. 时钟树概述 为何不是采用一个系统时钟?如51 因为STM32本身非常复杂,外设非常多,但是并非所有外设都需要系统时钟这么高的频率,比如看门狗和RTC只需要几十K的时钟即可。同一个电路,时钟越快,功耗越大,同时抗电磁干扰能力也会越弱,所以对于较为复杂的MCU一般采用多时钟源的方法来解决这些问题。 主要时钟源: 5个最主要的时钟源: 高速时钟源:HSI、HSE、PLL 低速时钟源:LSI、LSE 其中PLL实际又分为3个时钟源:主PLL、I2S部分专用PLLI2S、SAI部分专用PLLASI。 详解: LS
[单片机]
<font color='red'>STM32</font>时钟系统与时钟启动顺序详解
STM32 启动代码分析详解
1、堆栈存储器 堆栈存储区是在片上存储器中的SRAM(或RAM)中由用户自行开辟的一片数据存储区域,并且堆栈区的大小可根据用户的需要任意指定(只要不超过SRAM或RAM的大小),而堆栈区的位置由编译器指定分配。 Cortex-M3/M4处理器的堆栈指针SP是“满递减,空递增”,呈现向下逆生长的特点。 堆栈区数据的存储特点是“先进后出,后进先出”。 这种特点是由堆栈指针的移动方式决定的,先入栈的数据对应的指针值比较大,后入栈的数据对应的指针值比较小,而出栈时堆栈指针的值是递增的,所以指针值大的数据当然后出栈。 堆栈的作用: 局部变量的存储、函数调用时函数或子程序间数据的传递(形参的保存,其实函数调用一旦结束被
[单片机]
STM32 GPIO的工作模式
一、前言 在之前围绕STM32的GPIO的基本结构进行了介绍,图1为STM32的5V容忍的GPIO口内部基本结构图,图2为GPIO的基本结构中各个模块部分的概述。 阅读GPIO基本结构的内容能够对GPIO的工作模式有更深的了解。 正是由于GPIO的结构中包含了多样性的电路和模块,因此进行合理的配置组合,就可以使得GPIO应用在不同的工作模式下进行工作。 图1 STM32的5V容忍的GPIO内部基本结构 图2 GPIO基本结构包含的功能概述 二、工作模式概述 图3为STM32的GPIO工作模式概述图,从图中可以看出,GPIO端口的静态特征就是指芯片可供你选择的该GPIO的配置,只有通过对使用的GPIO端口进行合理的配置,
[单片机]
<font color='red'>STM32</font> GPIO的工作模式
基于STM32的LF RFID识别系统设计
射频识别技术(Radio Frequency Identification,RFID)是从八十年代起走向成熟的一项自动识别技术。RFID利用射频方式进行非接触双向通信,以达到识别目的并交换数据,主要通过空间耦合(交变磁场或电磁场)实现无接触信息传递并通过所传递的信息达到识别目的。 RFID技术在近年取得了长足的发展,目前已广泛应用的频段分布在LF、HF、UHF和徽波频段,各频段的RFID系统均有各自的优点和相应的应用范围。对于LF频段的RFID系统而言,最明显的优点在于拥有很好的穿透性能,如可穿透液体物质,建筑物,人体等,且各种动物体细胞和各种气体分子对LF频段的能量吸收很小。 可见LF RFID系统可以在需要良好穿透性,需要
[单片机]
基于<font color='red'>STM32</font>的LF RFID识别系统设计
STM32单片机的学习经验
随便写写,关于stm32 最近在学习stm32,写点东西,虽然简单,但都是原创啊 开发板是前辈画的,好像是用来测试一个3G功能的,不过对于我来说太远;我要来了3个,自己焊了一个最小系统,好在公司资源还是不错的,器件芯片有,还可以问问前辈--对公司还是比较满意的,虽然工资少了点,但学东西第一位O( _ )O~。 最开始当然是建工程了,这个真不太会,前前后后竟用了一周(时间真长,别见笑啊),上网查资料, 问前辈,自己琢磨。。。总算搞定,然后从GPIO开始学,开始还真没什么头绪(虽然在大学学点51,但完全没有真正应用,顶多是跑马灯实验),开始纠结是从寄存器开始学还是从库函数开始学,后来看到一句 用库函数入门,用寄存器提高 于是
[单片机]
STM32开发笔记13: 在keil中使用不初始化变量
单片机型号:STM32F030R8 我们进行程序设计的时候,都会知道,系统上电或复位时,会执行变量初始化操作,但是有些情况下,我们并不希望变量初始化,例如,在系统异常复位发生后,我们希望系统能够迅速恢复复位前的现场状况,这样就希望变量能够保留原先的值,而不被初始化。实际上,大家都知道,变量是存储在RAM中的,只要不掉电,变量的数值是不会改变的,只要我们不让系统进行初始化操作就可以了。 不同的编译环境,有不同的设置方法,本文介绍在Keil中设置不初始化变量的方法。在这里需要说明的是,网上介绍了许多的设置方法,但并不是所有的方法都起作用,本文将介绍一种最为直接的方法。 1、打开Options for Targe
[单片机]
<font color='red'>STM32</font>开发笔记13: 在keil中使用不初始化变量
STM32多机通信
从机io口设置 多机通信系统中,从机采用漏级开路方式连接,从设备的串口必须配置为漏极开路,不能是推挽方式,推挽方式的高、低电平的驱动能力很强,如果将两个不同电平的io口连接在一起,会导致灌电流过大烧坏io口,漏极开路的漏级有上拉电阻会限制电流的大小。 一主多从的硬件连接方式 主机的TX输出与从机的RX端口直接相连,从机的TX端口经过与门与主机的RX端口相连接。由于输出口为推挽输出,直接将从机的Tx与主机的RX相连即可。 通信机制 多机通信机制是使从机处于静默状态,从机发送指令唤醒从机,然后发送数据。 静默状态的特点 (1)所有接收状态都不会被置为1。 (2)所有的接收中断都被禁止。 (3)USART_CR1寄存器中的RWU被置为1
[单片机]
<font color='red'>STM32</font>多机通信
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved