STM32 KEIL下的堆栈设置问题
深入理解STM32双堆栈机制
深入理解STM32双堆栈机制堆栈堆栈,「堆」和「栈」经过无数技术书籍,以及各类技术博主苦口婆心的提醒,恐怕没几个人会再把堆和栈混为一谈,精明的开发者都明白,堆栈堆栈,「堆」和「栈」是不同的两种数据结构,具有各自的内存分配和使用方式。
众所周知,栈由编译器自动分配释放,堆由程序员手动分配释放,栈存放函数形参、局部变量,堆内存申请了记得释放……诸如此类,老生常谈。
众所不周知,在不同的体系结构、裸机/操作系统下,堆栈在内存中的分配方式、内存布局、空间大小、存储内容也存在差异。
本文以 STM32 系列芯片(Cortex-M3 内核)和 RT-Thread 操作系统为例,梳理嵌入式开发过程中,与 MCU 堆栈有关的概念,然而堆栈涉及的知识太多,本文只侧重从内存分布角度阐述,帮助读者整体把握相关技术。
程序为什么需要堆栈堆栈是程序访问内存的一种方式。
程序员在编程处理应用数据时,往往要使用大块连续的内存空间。
程序指令在执行运算的过程中,也有大量中间结果需要临时保存,显然这些数据都是存放在内存当中,堆和栈便提供了这样一种机制:将内存分类管理,提供不同的访问方式。
堆和栈的使用更具体表现为,编程中使用的malloc()函数从堆内存分配空间,利用指针数组或内存函数使用。
程序编译后所包含的大量PUSH和POP指令操作,系统根据SP(堆栈指针)寄存器访问当前对应栈内存,通过栈保存临时数据。
堆和栈在内存中的具体位置,是接下面篇幅中讨论的重点。
当然,内存空间只是连续字节数据的抽象,本身并不区分堆和栈的概念,它做的只是存储和读写信息。
因此,如何定义堆栈、初始化建立堆栈环境,在嵌入式软件运行前便显得尤为重要。
这涉及到处理器提供的堆栈机制、操作系统内存管理和进程切换等方方面面。
程序内存布局在芯片内部存储器中,包含了代码、数据、堆栈等信息,存放在 Flash 和 SRAM 当中,这里有必要说明一下众多内存类型的地址空间分布,其中包含我们的主角 —— 堆栈。
stm32堆栈如何设置,地址如何分配
stm32堆栈如何设置,地址如何分配用IAR的,打开icf文件/*###ICF### Section handled by ICF editor, don't touch! *** *//*-Editor annotation file-*//* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0 .xml" *//*-Specials-*/define symbol __ICFEDIT_intvec_start__ = 0x08000000;/*-Memory Regions-*/define symbol __ICFEDIT_region_ROM_start__ = 0x0800000 0 ;define symbol __ICFEDIT_region_ROM_end__ = 0x0807FF FF;define symbol __ICFEDIT_region_RAM_start__ = 0x2000000 0;define symbol __ICFEDIT_region_RAM_end__ = 0x2000FFF F;/*-Sizes-*/define symbol __ICFEDIT_size_cstack__ = 0x400;define symbol __ICFEDIT_size_heap__ = 0x200;/**** End of ICF editor section. ###ICF###*/define memory mem with size = 4G;define region ROM_region = mem:[from __ICFEDIT_region_ ROM_start__ to __ICFEDIT_region_ROM_end__];define region RAM_region = mem:[from __ICFEDIT_region_ RAM_start__ to __ICFEDIT_region_RAM_end__];define block CSTACK with alignment = 8, size = __ICFEDIT _size_cstack__ { };define block HEAP with alignment = 8, size = __ICFEDIT_ size_heap__ { };initialize by copy { readwrite };do not initialize { section .noinit };place at address mem:__ICFEDIT_intvec_start__ { readonly se ction .intvec };place in ROM_region { readonly };place in RAM_region { readwrite,block CSTACK, block HEAP };直接改define symbol __ICFEDIT_size_cstack__ = 0x400;define symbol __ICFEDIT_size_heap__ = 0x200;即可,MDK也简单,找到stm32f10x_vector.s; If you need to use external SRAM mounted on STM3210E-EVAL board as data memory,; change the following define value to '1' (or choose ENABL E in Configuration Wizard window);// <o> External SRAM Configuration <0=> DISABLE <1= > ENABLEDATA_IN_ExtSRAM EQU 0; Amount of memory (in bytes) allocated for Stack; Tailor this value to your application needs;// <h> Stack Configuration;// <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>;// </h>Stack_Size EQU 0x00000400AREA STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem SPACE Stack_Size__initial_sp; If you need to use external SRAM mounted on STM3210E-EVAL board as data memory; and internal SRAM for Stack, uncomment the following lin e and comment the line above;__initial_sp EQU 0x20000000 + Stack_Size ; "Use MicroLIB " must be checked in; the Project->Options->Target window; Amount of memory (in bytes) allocated for Heap; Tailor this value to your application needs;// <h> Heap Configuration;// <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>;// </h>Heap_Size EQU 0x00000400AREA HEAP, NOINIT, READWRITE, ALIGN=3__heap_baseHeap_Mem SPACE Heap_Size__heap_limit两种方法都可以通过IDE的对话框了更改参数。
STM32外扩RAM做变量定义与内部RAM做堆栈的设置
STM32外扩RAM做变量定义与内部RAM做堆栈的设置说明:当STM32上运行UC/OSII和UC/GUI时,STM32内部自带的RAM可能不够用,这就需要STM32的外扩RAM功能,内部RAM作为中断服务程序的堆栈使用,而外部RAM 作为存放临时变量的地方和UC/OSII的任务切换用堆栈,具体配置如下:1.修改启动代码我使用的开发板外扩了512K字节的RAM,分配的地址为BANK1的第3个区,即起始地址为0x68000000,大小为0x80000启动代码如下:;******************** (C) COPYRIGHT 2009 STMicroelectronics ********************;* File Name : startup_stm32f10x_hd.s;* Author : MCD Application Team;* Version : V3.1.0;* Date : 06/19/2009;* Description : STM32F10x High Density Devices vector table for RVMDK;* toolchain.;* This module performs:;* - Set the initial SP;* - Set the initial PC == Reset_Handler;* - Set the vector table entries with the exceptions ISR address;* - Configure external SRAM mounted on STM3210E-EV AL board;* to be used as data memory (optional, to be enabled by user);* - Branches to __main in the C library (which eventually;* calls main()).;* After Reset the CortexM3 processor is in Thread mode,;* priority is Privileged, and the Stack is set to Main.;* <<< Use Configuration Wizard in Context Menu >>>;****************************************************************************** *; THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS; WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SA VE TIME.; AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,; INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE; CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING; INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.;****************************************************************************** *; If you need to use external SRAM mounted on STM3210E-EV AL board as data memory,; change the following define value to '1' (or choose ENABLE in Configuration Wizard window) ;// <o> External SRAM Configuration <0=> DISABLE <1=> ENABLEDATA_IN_ExtSRAM EQU 1; Amount of memory (in bytes) allocated for Stack; Tailor this value to your application needs;// <h> Stack Configuration;// <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>;// </h>Stack_Size EQU 0x00000400AREA STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem SPACE Stack_Size;__initial_sp; If you need to use external SRAM mounted on STM3210E-EV AL board as data memory; and internal SRAM for Stack, uncomment the following line and comment the line above__initial_sp EQU 0x20000000 + Stack_Size ; "Use MicroLIB" must be checked in; the Project->Options->Target window; Amount of memory (in bytes) allocated for Heap; Tailor this value to your application needs;// <h> Heap Configuration;// <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>;// </h>Heap_Size EQU 0x00000400AREA HEAP, NOINIT, READWRITE, ALIGN=3__heap_baseHeap_Mem SPACE Heap_Size__heap_limitTHUMBPRESERVE8; Vector Table Mapped to Address 0 at ResetAREA RESET, DATA, READONLYEXPORT __VectorsEXPORT __Vectors_EndEXPORT __Vectors_Size__Vectors DCD __initial_sp ; Top of StackDCD Reset_Handler ; Reset HandlerDCD NMI_Handler ; NMI HandlerDCD HardFault_Handler ; Hard Fault HandlerDCD MemManage_Handler ; MPU Fault HandlerDCD BusFault_Handler ; Bus Fault HandlerDCD UsageFault_Handler ; Usage Fault HandlerDCD 0 ; ReservedDCD 0 ; ReservedDCD 0 ; ReservedDCD 0 ; ReservedDCD SVC_Handler ; SVCall HandlerDCD DebugMon_Handler ; Debug Monitor HandlerDCD 0 ; ReservedDCD PendSV_Handler ; PendSV HandlerDCD SysTick_Handler ; SysTick Handler; External InterruptsDCD WWDG_IRQHandler ; Window WatchdogDCD PVD_IRQHandler ; PVD through EXTI Line detectDCD TAMPER_IRQHandler ; TamperDCD RTC_IRQHandler ; RTCDCD FLASH_IRQHandler ; FlashDCD RCC_IRQHandler ; RCCDCD EXTI0_IRQHandler ; EXTI Line 0DCD EXTI1_IRQHandler ; EXTI Line 1DCD EXTI2_IRQHandler ; EXTI Line 2DCD EXTI3_IRQHandler ; EXTI Line 3DCD EXTI4_IRQHandler ; EXTI Line 4DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7DCD ADC1_2_IRQHandler ; ADC1 & ADC2DCD USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TXDCD USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0DCD CAN1_RX1_IRQHandler ; CAN1 RX1DCD CAN1_SCE_IRQHandler ; CAN1 SCEDCD EXTI9_5_IRQHandler ; EXTI Line 9..5DCD TIM1_BRK_IRQHandler ; TIM1 BreakDCD TIM1_UP_IRQHandler ; TIM1 UpdateDCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and CommutationDCD TIM1_CC_IRQHandler ; TIM1 Capture CompareDCD TIM2_IRQHandler ; TIM2DCD TIM3_IRQHandler ; TIM3DCD TIM4_IRQHandler ; TIM4DCD I2C1_EV_IRQHandler ; I2C1 EventDCD I2C1_ER_IRQHandler ; I2C1 ErrorDCD I2C2_EV_IRQHandler ; I2C2 EventDCD I2C2_ER_IRQHandler ; I2C2 ErrorDCD SPI1_IRQHandler ; SPI1DCD SPI2_IRQHandler ; SPI2DCD USART1_IRQHandler ; USART1DCD USART2_IRQHandler ; USART2DCD USART3_IRQHandler ; USART3DCD EXTI15_10_IRQHandler ; EXTI Line 15..10DCD RTCAlarm_IRQHandler ; RTC Alarm through EXTI LineDCD USBWakeUp_IRQHandler ; USB Wakeup from suspendDCD TIM8_BRK_IRQHandler ; TIM8 BreakDCD TIM8_UP_IRQHandler ; TIM8 UpdateDCD TIM8_TRG_COM_IRQHandler ; TIM8 Trigger and CommutationDCD TIM8_CC_IRQHandler ; TIM8 Capture CompareDCD ADC3_IRQHandler ; ADC3DCD FSMC_IRQHandler ; FSMCDCD SDIO_IRQHandler ; SDIODCD TIM5_IRQHandler ; TIM5DCD SPI3_IRQHandler ; SPI3DCD UART4_IRQHandler ; UART4DCD UART5_IRQHandler ; UART5DCD TIM6_IRQHandler ; TIM6DCD TIM7_IRQHandler ; TIM7DCD DMA2_Channel1_IRQHandler ; DMA2 Channel1DCD DMA2_Channel2_IRQHandler ; DMA2 Channel2DCD DMA2_Channel3_IRQHandler ; DMA2 Channel3DCD DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5 __Vectors_End__Vectors_Size EQU __Vectors_End - __VectorsAREA |.text|, CODE, READONLY; Reset handler routineReset_Handler PROCEXPORT Reset_HandlerIF DATA_IN_ExtSRAM == 1; FSMC Bank1 NOR/SRAM3 is used for the STM3210E-EV AL, if another Bank is ; required, then adjust the Register Addresses; Enable FSMC clockLDR R0,= 0x00000114LDR R1,= 0x40021014STR R0,[R1]; Enable GPIOD, GPIOE, GPIOF and GPIOG clocksLDR R0,= 0x000001E0LDR R1,= 0x40021018STR R0,[R1]; SRAM Data lines, NOE and NWE configuration; SRAM Address lines configuration; NOE and NWE configuration; NE3 configuration; NBL0, NBL1 configurationLDR R0,= 0x44BB44BBLDR R1,= 0x40011400STR R0,[R1]LDR R0,= 0xBBBBBBBBLDR R1,= 0x40011404STR R0,[R1]LDR R0,= 0xB44444BBLDR R1,= 0x40011800STR R0,[R1]LDR R0,= 0xBBBBBBBBLDR R1,= 0x40011804STR R0,[R1]LDR R0,= 0x44BBBBBBLDR R1,= 0x40011C00STR R0,[R1]LDR R0,= 0xBBBB4444LDR R1,= 0x40011C04STR R0,[R1]LDR R0,= 0x44BBBBBBLDR R1,= 0x40012000STR R0,[R1]LDR R0,= 0x44444B44LDR R1,= 0x40012004STR R0,[R1]; FSMC Configuration; Enable FSMC Bank1_SRAM BankLDR R0,= 0x00001011LDR R1,= 0xA0000010STR R0,[R1]LDR R0,= 0x00000200LDR R1,= 0xA0000014STR R0,[R1]ENDIFIMPORT __mainLDR R0, =__mainBX R0ENDP; Dummy Exception Handlers (infinite loops which can be modified)NMI_Handler PROCEXPORT NMI_Handler [WEAK]B .ENDPHardFault_Handler\PROCEXPORT HardFault_Handler [WEAK]B .ENDPMemManage_Handler\PROCEXPORT MemManage_Handler [WEAK]B .ENDPBusFault_Handler\PROCEXPORT BusFault_Handler [WEAK]B .ENDPUsageFault_Handler\PROCEXPORT UsageFault_Handler [WEAK]B .ENDPSVC_Handler PROCEXPORT SVC_Handler [WEAK]B .ENDPDebugMon_Handler\PROCEXPORT DebugMon_Handler [WEAK]B .ENDPPendSV_Handler PROCEXPORT PendSV_Handler [WEAK]B .ENDPSysTick_Handler PROCEXPORT SysTick_Handler [WEAK]B .ENDPDefault_Handler PROCEXPORT WWDG_IRQHandler [WEAK]EXPORT PVD_IRQHandler [WEAK]EXPORT TAMPER_IRQHandler [WEAK]EXPORT RTC_IRQHandler [WEAK]EXPORT FLASH_IRQHandler [WEAK]EXPORT RCC_IRQHandler [WEAK]EXPORT EXTI0_IRQHandler [WEAK]EXPORT EXTI2_IRQHandler [WEAK]EXPORT EXTI3_IRQHandler [WEAK]EXPORT EXTI4_IRQHandler [WEAK]EXPORT DMA1_Channel1_IRQHandler [WEAK]EXPORT DMA1_Channel2_IRQHandler [WEAK]EXPORT DMA1_Channel3_IRQHandler [WEAK]EXPORT DMA1_Channel4_IRQHandler [WEAK]EXPORT DMA1_Channel5_IRQHandler [WEAK]EXPORT DMA1_Channel6_IRQHandler [WEAK]EXPORT DMA1_Channel7_IRQHandler [WEAK]EXPORT ADC1_2_IRQHandler [WEAK]EXPORT USB_HP_CAN1_TX_IRQHandler [WEAK] EXPORT USB_LP_CAN1_RX0_IRQHandler [WEAK]EXPORT CAN1_RX1_IRQHandler [WEAK]EXPORT CAN1_SCE_IRQHandler [WEAK]EXPORT EXTI9_5_IRQHandler [WEAK]EXPORT TIM1_BRK_IRQHandler [WEAK]EXPORT TIM1_UP_IRQHandler [WEAK]EXPORT TIM1_TRG_COM_IRQHandler [WEAK]EXPORT TIM1_CC_IRQHandler [WEAK]EXPORT TIM2_IRQHandler [WEAK]EXPORT TIM3_IRQHandler [WEAK]EXPORT TIM4_IRQHandler [WEAK]EXPORT I2C1_EV_IRQHandler [WEAK]EXPORT I2C1_ER_IRQHandler [WEAK]EXPORT I2C2_EV_IRQHandler [WEAK]EXPORT I2C2_ER_IRQHandler [WEAK]EXPORT SPI1_IRQHandler [WEAK]EXPORT SPI2_IRQHandler [WEAK]EXPORT USART1_IRQHandler [WEAK]EXPORT USART2_IRQHandler [WEAK]EXPORT USART3_IRQHandler [WEAK]EXPORT EXTI15_10_IRQHandler [WEAK]EXPORT RTCAlarm_IRQHandler [WEAK]EXPORT USBWakeUp_IRQHandler [WEAK]EXPORT TIM8_BRK_IRQHandler [WEAK]EXPORT TIM8_UP_IRQHandler [WEAK]EXPORT TIM8_TRG_COM_IRQHandler [WEAK]EXPORT TIM8_CC_IRQHandler [WEAK]EXPORT ADC3_IRQHandler [WEAK]EXPORT FSMC_IRQHandler [WEAK]EXPORT SDIO_IRQHandler [WEAK]EXPORT TIM5_IRQHandler [WEAK]EXPORT UART4_IRQHandler [WEAK]EXPORT UART5_IRQHandler [WEAK]EXPORT TIM6_IRQHandler [WEAK]EXPORT TIM7_IRQHandler [WEAK]EXPORT DMA2_Channel1_IRQHandler [WEAK]EXPORT DMA2_Channel2_IRQHandler [WEAK]EXPORT DMA2_Channel3_IRQHandler [WEAK]EXPORT DMA2_Channel4_5_IRQHandler [WEAK]WWDG_IRQHandlerPVD_IRQHandlerTAMPER_IRQHandlerRTC_IRQHandlerFLASH_IRQHandlerRCC_IRQHandlerEXTI0_IRQHandlerEXTI1_IRQHandlerEXTI2_IRQHandlerEXTI3_IRQHandlerEXTI4_IRQHandlerDMA1_Channel1_IRQHandlerDMA1_Channel2_IRQHandlerDMA1_Channel3_IRQHandlerDMA1_Channel4_IRQHandlerDMA1_Channel5_IRQHandlerDMA1_Channel6_IRQHandlerDMA1_Channel7_IRQHandlerADC1_2_IRQHandlerUSB_HP_CAN1_TX_IRQHandlerUSB_LP_CAN1_RX0_IRQHandlerCAN1_RX1_IRQHandlerCAN1_SCE_IRQHandlerEXTI9_5_IRQHandlerTIM1_BRK_IRQHandlerTIM1_UP_IRQHandlerTIM1_TRG_COM_IRQHandlerTIM1_CC_IRQHandlerTIM2_IRQHandlerTIM3_IRQHandlerTIM4_IRQHandlerI2C1_EV_IRQHandlerI2C1_ER_IRQHandlerI2C2_EV_IRQHandlerI2C2_ER_IRQHandlerSPI1_IRQHandlerSPI2_IRQHandlerUSART1_IRQHandlerUSART2_IRQHandlerUSART3_IRQHandlerEXTI15_10_IRQHandlerRTCAlarm_IRQHandlerUSBWakeUp_IRQHandlerTIM8_BRK_IRQHandlerTIM8_UP_IRQHandlerTIM8_TRG_COM_IRQHandlerTIM8_CC_IRQHandlerADC3_IRQHandlerFSMC_IRQHandlerSDIO_IRQHandlerTIM5_IRQHandlerSPI3_IRQHandlerUART4_IRQHandlerUART5_IRQHandlerTIM6_IRQHandlerTIM7_IRQHandlerDMA2_Channel1_IRQHandlerDMA2_Channel2_IRQHandlerDMA2_Channel3_IRQHandlerDMA2_Channel4_5_IRQHandlerB .ENDPALIGN;****************************************************************************** *; User Stack and Heap initialization;****************************************************************************** *IF :DEF:__MICROLIBEXPORT __initial_spEXPORT __heap_baseEXPORT __heap_limitELSEIMPORT __use_two_region_memoryEXPORT __user_initial_stackheap__user_initial_stackheapLDR R0, = Heap_MemLDR R1, =(Stack_Mem + Stack_Size)LDR R2, = (Heap_Mem + Heap_Size)LDR R3, = Stack_MemBX LRALIGNENDIFEND;******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE*****2.设置目标选项1)打开目标选项框设置入图所示,注:一定要勾选“Use MicroLIB”选项通过以上的设置,堆栈就定义在内部RAM,而其他定义的变量就在外扩的RAM分配了。
一文解析STM32内存管理和堆栈的认知与理解
一文解析STM32内存管理和堆栈的认知与理解本文主要介绍了STM32内存管理和堆栈的认知与理解,首先介绍的是内存管理的实现原理及分配、释放原理,其次介绍了stm32的存储器结构,最后阐述了堆栈的认知与理解,具体的跟随小编一起来了解一下吧。
STM32内存管理详解内存管理,是指软件运行时对计算机内存资源的分配和使用的技术。
其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源。
内存管理的实现方法有很多种,他们其实最终都是要实现2 个函数:malloc 和free;malloc 函数用于内存申请,free 函数用于内存释放。
内存管理的实现原理从上图可以看出,分块式内存管理由内存池和内存管理表两部分组成。
内存池被等分为n 块,对应的内存管理表,大小也为n,内存管理表的每一个项对应内存池的一块内存。
内存管理表的项值代表的意义为:当该项值为0 的时候,代表对应的内存块未被占用,当该项值非零的时候,代表该项对应的内存块已经被占用,其数值则代表被连续占用的内存块数。
比如某项值为10,那么说明包括本项对应的内存块在内,总共分配了10 个内存块给外部的某个指针。
内寸分配方向如图所示到低位地址)即首先从最末端开始找空内存。
当内存管理刚初始化的时候,内存表全部清零,表示没有任何内存块被占用。
分配原理当指针p 调用malloc 申请内存的时候,先判断p 要分配的内存块数(m),然后从第n 项开始,向下查找,直到找到m 块连续的空内存块(即对应内存管理表项为0),然后将这m 个内存管理表项的值都设置为m(标记被占用),最后,把最后的这个空内存块的地址返回指针p,完成一次分配。
注意,如果当内存不够的时候(找到最后也没找到连续的m 块空闲内存),则返回NULL 给p,表示分配失败。
释放原理。
学习STM32(二)之STM32内存管理(三)STM32内存管理以及堆和栈的理解
学习STM32(⼆)之STM32内存管理(三)STM32内存管理以及堆和栈的理解⾸先,先看⼀下stm32的存储器结构。
以下两种说法都⼀样的,各有着重⽽已,可单看第⼀个说法,第⼆个知道就⾏第⼀个说法:原⽂ :STM32的存储器映射详解存储器映射是指把芯⽚中或芯⽚外的FLASH,,外设,BOOT,BLOCK等进⾏统⼀编址。
即⽤地址来表⽰对象。
这个地址绝⼤多数是由⼚家规定好的,⽤户只能⽤⽽不能改。
⽤户只能在挂外部RAM或FLASH的情况下可进⾏⾃定义。
Corx-M3⽀持4GB的存储空间,它的存储系统采⽤统⼀编址的⽅式; 程序存储器、数据存储器、被组织在4GB的线性地址空间内,以⼩端格式(little-endian)存放。
由于Cortex-M3是32位的内核,因此其PC指针可以指向2^32=4G的地址空间,也就是0x0000_0000——0xFFFF_FFFF这⼀⼤块空间。
见图1:图1:Cortex-M3的存储器映射Cortex-M3内核将0x0000_0000——0xFFFF_FFFF这块4G⼤⼩的空间分成8⼤块:代码、SRAM、外设、外部RAM、外部设备、专⽤外设总线-内部、专⽤外设总线-外部、特定⼚商(见图1)。
这就导致了,使⽤该内核的芯⽚⼚家必须按照这个进⾏各⾃芯⽚的存储器结构设计,如。
图2:Cortex-M3与中密度stm32的存储器映射对⽐图三:图2中可以很清晰的看到,STM32的存储器结构和Cortex-M3的很相似(这是因为stm32本来就是按照cortex_m3内核来设计硬件的),不同的是,STM32加⼊了很多实际的东西,如:Flash、SRAM等。
只有加⼊了这些东西,才能成为⼀个拥有实际意义的、可以⼯作的处理芯⽚——STM32。
STM32的存储器地址空间被划分为⼤⼩相等的8块区域,每块区域⼤⼩为512MB(如:0x20000000~0x40000000)。
对STM32存储器知识的掌握,实际上就是对Flash和SRAM这两个区域知识的掌握。
用Keil环境编程发现STM32内存管理的一个问题
用Keil环境编程发现STM32内存管理的一个问题非常简单的一个工程,没有用到任何IO操作,与STM32有关的仅仅只有芯片的选择,即其SRAM大小有区别。
图1是工程示意图,从图中可以看出,除了自己编写的代码外,仅仅增加了2个文件,即system_stm32f10x.c和startup_stm32f10x_hd.s,其中为了对startup_stm32f10x_hd.s进行修改,将其从库文件夹复制到了项目文件夹中。
图1代码1int main(){int a,b,c,d;a=10;b=20;c=a+b;for(;;);}myex1.c(3): warning: #550-D: variable 'c' was set but never usedlinking...Program Size: Code=796 RO-data=336 RW-data=20 ZI-data=1636FromELF: creating hex file...'myex1.axf' - 0 Error(s), 1 Warning(s).代码2int main(){ const int x=16;int a,b,c,d;a=10;b=20;c=a+b;for(;;);}myex1.c(2): warning: #177-D: variable 'x' was declared but never referencedmyex1.c(3): warning: #550-D: variable 'c' was set but never usedlinking...Program Size: Code=800 RO-data=336 RW-data=20 ZI-data=1636FromELF: creating hex file...'myex1.axf' - 0 Error(s), 2 Warning(s).说明:(1)Code增加了4字节(2)其余没有任何变化代码3int main(){ const int x=16;int myArry[100];int i;int a,b,c,d;a=10;b=20;c=a+b;for(i=0;i<>myArry[i]=i;for(;;);}myex1.c(2): warning: #177-D: variable 'x' was declared but never referencedmyex1.c(3): warning: #550-D: variable 'myArry' was set but never usedmyex1.c(5): warning: #550-D: variable 'c' was set but never usedmyex1.c(5): warning: #177-D: variable 'd' was declared but never referencedlinking...Program Size: Code=816 RO-data=336 RW-data=20 ZI-data=1636FromELF: creating hex file...'myex1.axf' - 0 Error(s), 4 Warning(s).分析:程序中增加了数组myArry,Code增加为816字节,但是RO-data等仍未变化代码4int main(){ const int x=16;int myArry[100]={1,2,3,4,5,6};int i;int a,b,c,d;a=10;b=20;c=a+b;for(i=0;i<>myArry[i]=i;for(;;);}myex1.c(2): warning: #177-D: variable 'x' was declared butnever referencedmyex1.c(3): warning: #550-D: variable 'myArry' was set but never usedmyex1.c(5): warning: #550-D: variable 'c' was set but never usedmyex1.c(5): warning: #177-D: variable 'd' was declared but never referencedlinking...Program Size: Code=1024 RO-data=360 RW-data=20 ZI-data=1636FromELF: creating hex file...'myex1.axf' - 0 Error(s), 4 Warning(s).分析:(1)由于myArry作了初始化,因此RO-data增加了360-336=24字节。
问个只要用Cortex-M单片机都会遇到的问题,关于堆栈的!!
问个只要用Cortex-M单片机都会遇到的问题,关于堆栈的!!下面一段话是看本论坛上的一位大侠说的:MSP的位置= 全局变量数+HEAP_SIZE+Stack_Size。
KEIL编译器对RAM的排列方式(地址由低到高):1、全局变量(包括已初始化的变量和没初始化的变量);2、Heap所占的空间;3、主Stack所占空间;首先,我认为这段话肯定是对的,应该没有问题,,,可是,我不明白的是:编译器根据下面两段代码,就能知道我定义的存储区是堆栈吗Stack_Size EQU 0x0200;AREA STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem SPACE Stack_Size__initial_spHeap_Size EQU 0x000;AREA HEAP, NOINIT, READWRITE, ALIGN=3__heap_baseHeap_Mem SPACE Heap_Size__heap_limitSPACE伪指令是汇编语言中用于定义内存空间的,可是,编译器怎么知道我定义的Stack_Mem存储区是栈空间呢难道是根据这个存储区的名字叫:Stack_Mem来判断的吗发完帖子就发现,自己问了一个愚蠢的问题:AREA STACK, NOINIT, READWRITE, ALIGN=3AREA HEAP, NOINIT, READWRITE, ALIGN=3这个问题一点也不愚蠢啊,反倒是红色的两个名字会愚弄人呢!是时候揭开它们的假面具了。
STACK, HEAP只是两个section的名字。
程序就是由各种代码和数据section组成的,最后由链接器排开并生成一个映像文件。
这两个名字没有特殊的法力,很有欺骗性啊。
不信的话,你把它改成你和你女朋友的名字也可以的!不是因为名字叫"STACK", "HEAP"就人如其名了。
事实上,关键的一句是__initial_sp (顶格写的,而且必须顶格写)这个标号,它最终会被链接器解析成这个名为STACK的section 结束后的地址。
STM32堆栈整理
STM32内存编程在startup_stm32f10x_md.s文件中,它的前面几行就有以上定义,;栈=1KStack_Size EQU 0x00000400;堆=512BHeap_Size EQU 0x00000200Stack_Size不影响Hex,更不影响Hex怎么运行的,只是在Debug调试时会提示错。
栈溢出也有是超过了国界进行活动,只要老外没有意见,你可以接着玩,有老外不让你玩,你就的得死,或是大家都死(互相撕杀),有的人写单片机代码在函数里定义一个大数组int buf[8192],栈要是小于8192是会死的很惨。
Heap_Size可为0,即不使用动态分配。
Heap_Size的大小与malloc所分配的内存有关,当连续分配而又不释放,会导致满堆或内存泄露。
本文源起的诉求,即在object过多的情况下进行解析,程序需要N多次的动态内存分配,而Heap_Size太小,导致无法分配内存。
通过修改Heap_Size的大小解决了诉求。
STM32的内存分配规律从0X20000000开始依次为:静态存储区+堆区(可有可无)+栈区所有的全局变量,包括静态变量之类的,全部存储在静态存储区。
紧跟静态存储区之后的,是堆区(如没用到malloc,则没有该区),之后是栈区。
附录STM32内存地址说明在MDK编译过程中,内存的划分如下:Code是存储程序代码的。
RO-data是存储const常量和指令。
RW-data是存储初始化值不为0的全局变量。
ZI-data是存储未初始化的全局变量或初始化值为0的全局变量。
Flash=Code + RO Data + RW Data;RAM= RW-data+ZI-data;此内存划分暂未包括堆栈,堆栈会在程序运行时,占用RAM。
堆栈的内存占用就是MDK里,RAM分配给RW-data+ZI-data之后的地址开始分配的。
---------------------STM32的堆栈大小在官方文件已经定义好了,分别是:Heap_Size EQU 0x00000200 一共512字节Stack_Size EQU 0x00000400 一共1K字节/***********************************************************************************/但是STM32在keil环境下每次编译后的堆栈起始地址并不是固定的(就算事先已经定义好了堆栈的大小),因为栈的起始地址是由用户程序中事先定义好的变量数目决定的(实测是如此)。
stm32 单机程序栈保护机制
stm32 单机程序栈保护机制
STM32单片机的程序栈保护机制是一种用于保护程序运行时堆栈空间的技术。
在STM32单片机中,堆栈保护可以通过使用硬件和软件相结合的方式来实现。
下面我将从硬件和软件两个方面来介绍STM32单片机的程序栈保护机制。
硬件方面:
STM32单片机的硬件提供了一些特性来保护程序的堆栈空间。
其中最常见的是硬件堆栈保护功能。
在STM32单片机中,可以通过设置相关的寄存器来启用硬件堆栈保护。
这样可以防止堆栈溢出和堆栈破坏,提高系统的稳定性和安全性。
另外,STM32单片机还提供了一些特殊的寄存器和机制,用于监控堆栈的使用情况,比如堆栈指针寄存器(SP)和堆栈溢出检测机制等。
这些硬件特性可以帮助开发人员及时发现和处理堆栈相关的问题,保障程序的正常运行。
软件方面:
除了硬件保护机制,STM32单片机的程序堆栈还可以通过软件
来进行保护。
比如,开发人员可以在编写程序时,合理规划堆栈的
大小,避免出现堆栈溢出的情况。
此外,还可以通过编写堆栈溢出
检测的代码来监控堆栈的使用情况,及时发现并处理堆栈溢出的问题。
另外,开发人员还可以通过使用一些静态分析工具或者动态调
试工具来检测程序中可能存在的堆栈问题,及时进行修复和优化。
总结:
综上所述,STM32单片机的程序堆栈保护机制包括硬件和软件
两个方面。
通过合理配置硬件保护特性和编写规范的软件代码,可
以有效保护程序的堆栈空间,提高系统的稳定性和安全性。
开发人
员在使用STM32单片机时,应该充分了解和掌握这些堆栈保护技术,以确保程序的正常运行。
keil堆栈溢出函数 -回复
keil堆栈溢出函数-回复什么是Keil堆栈溢出函数?回答:Keil堆栈溢出函数是指在Keil开发平台上出现的一种错误,当程序在执行时使用了超过函数栈所能容纳的内存空间时,就会发生堆栈溢出。
堆栈溢出会导致程序崩溃或出现未定义的行为,严重的情况下甚至可能导致系统死机。
本文将详细讨论Keil堆栈溢出函数的原因、影响和解决方法。
首先,我们需要了解什么是堆栈以及它在编程中的作用。
堆栈(Stack)是一种内存存储区域,用于临时保存函数运行时的数据,如局部变量、函数参数、返回地址等。
每当一个函数被调用时,系统都会为该函数分配一块内存空间作为函数栈帧,在函数执行完毕后,该内存空间将会被释放。
由于函数栈帧的大小是有限的,当某个函数使用的内存超过了栈帧的大小,就会发生堆栈溢出。
那么,Keil堆栈溢出函数会带来什么影响?首先,堆栈溢出会导致程序崩溃或出现未定义的行为。
当函数使用了超过栈帧大小的内存空间时,它会覆盖栈上其他函数的数据,包括局部变量和返回地址等信息。
这可能导致被覆盖的函数出现错误的值或无法正确返回,从而引发程序错误。
此外,堆栈溢出还可能导致系统死机或重启,因为堆栈溢出可能导致系统的关键数据被破坏,进而影响系统的正常运行。
那么,如何解决Keil堆栈溢出函数问题呢?以下是一些常用的解决方法:1. 增加堆栈大小:Keil开发平台允许用户在配置文件中调整堆栈大小。
通过增加堆栈大小,可以提供更多的内存空间用于函数执行,从而减少堆栈溢出的可能性。
2. 优化代码:一些堆栈溢出问题是由于函数内部使用了大量的局部变量或递归调用导致的。
通过优化代码,减少局部变量的使用和递归调用的层数,可以减少堆栈的使用,从而降低堆栈溢出的风险。
3. 使用动态内存分配:在一些情况下,函数需要使用大量的内存空间,而静态分配的堆栈大小无法满足需求。
这时可以考虑使用动态内存分配,如malloc函数,在堆上动态分配内存,从而避免堆栈溢出的问题。
4. 检查递归调用:递归调用是一种常见的堆栈溢出的原因。
STM32分配堆栈空间不足问题原因及解决方法
STM32 分配堆栈空间不足问题原因及解决方法
在开发过程中,我们有时候可能会遇到数据错误的情况,而这个情况发生多数是由于堆栈溢出导致,这里我们将详细讲解复现堆栈溢出会导致的问题及提供相应的解决方法。
先说结论,以STM32F103RCT6 为例,初始的栈空间是1KB,堆空
间是512Byte。
如果动态内存分配需求过多时,需要手动调节堆空间。
在启
动文件startup_stm32f103xe.s 的开头就可以设置堆栈空间大小。
同样,在
STM32CubeMX 中也可对堆栈大小进行修改,在Project -》SetTIngs 选项中
可以对Minimum Heap Size 大小进行更改。
扩大之后即可解决堆栈空间不足
的问题。
遇到的问题
今天在STM32F103RCT6 上,使用malloc()为链表分配内存空间
时,忽然遇到一次分配内存过多而死机的问题。
查阅官方文档发现此型号的单片机FLASH 256KB,RAM 48KB。
我链表的结构体定义如下:
typedef struct LNode{。
keil堆栈溢出函数 -回复
keil堆栈溢出函数-回复问题是什么?问题是关于Keil堆栈溢出函数的。
堆栈溢出是一种常见的程序错误,它产生于栈内存被超出其边界的操作所引发的情况。
Keil是一种常用的嵌入式开发环境,堆栈溢出函数是在Keil中用于检测和处理堆栈溢出错误的函数。
什么是堆栈溢出?堆栈是一种内存区域,用于存储程序执行时的临时数据。
它以先进后出的方式组织数据,类似于一个弹簧床垫。
当程序调用一个函数时,当前函数的局部变量、函数参数和返回地址等信息都会被压入堆栈中。
当函数执行完毕后,这些信息会被弹出堆栈,将控制权返回给调用函数。
堆栈溢出是指程序在使用堆栈时超出了其分配的边界。
这种情况可能导致数据损坏、程序崩溃、安全漏洞等问题。
堆栈溢出的原因通常包括递归函数调用、过多的局部变量、未经充分验证的用户输入等。
Keil堆栈溢出函数是什么?Keil堆栈溢出函数是Keil开发环境中提供的一种工具,用于检测和处理堆栈溢出错误。
它能够通过监控程序使用的堆栈空间,识别并报告堆栈溢出的情况,从而帮助开发人员及时修复问题。
Keil堆栈溢出函数的实现原理是利用了硬件中断机制。
当堆栈溢出错误发生时,硬件中断会被触发,从而启动Keil堆栈溢出函数的执行。
该函数会终止当前执行的任务,并将有关错误信息输出到终端或者日志文件中。
如何使用Keil堆栈溢出函数?以下是一步一步使用Keil堆栈溢出函数的示例过程:1. 打开Keil开发环境,并导入你的项目。
2. 在主函数(或其他函数)的开头处插入以下代码:cinclude <RTX51TNY.H>extern void _task_stack_overflow(unsigned char taskid);void main(void) {声明一个任务ID变量unsigned char taskID;创建一个任务taskID = os_tsk_create(_task_stack_overflow, 3);死循环,避免程序退出while(1);}这段代码引入了Keil堆栈溢出函数的头文件,并声明了一个任务ID变量和一个主函数。
STM32如何定义堆栈地址到RAM区顶端
STM32如何定义堆栈地址到RAM区顶端本设置针对stm32f103rbt6的设置,该芯⽚RAM⼤⼩为20kB,故RAM区地址范围为0x20000000—0x20005000,芯⽚信息如下图所⽰;第⼀步:设置.sct⽂件;; *************************************************************; *** Scatter-Loading Description File generated by uVision ***; *************************************************************LR_IROM1 0x08000000 0x00020000 { ; load region size_regionER_IROM1 0x08000000 0x00020000 { ; load address = execution address*.o (RESET, +First)*(InRoot$$Sections).ANY (+RO)}RW_IRAM1 0x20000000 0x00005000 { ; RW data.ANY (+RW +ZI)}RW_IRAM2 0x20004800 UNINIT 0x00000800 { ; STACK ADDRESSstartup_stm32f10x_md.o (STACK)}RW_IRAM3 0x20004600 UNINIT 0x00000200 { ; HEAP ADDRESSstartup_stm32f10x_md.o (HEAP)}}RW_IRAM2 0x20004800 UNINIT 0x00000800 //设置栈起始地址为0x20004800,栈⼤⼩为0x00000800RW_IRAM3 0x20004600 UNINIT 0x00000200 //设置堆起始地址为0x20004600,堆⼤⼩为0x00000200第⼆步:在启动⽂件中设置堆栈⼤⼩;此处设置的堆栈⼤⼩要与第⼀步⼀致,否则将会以这次设置的⼤⼩为准,第⼀步设置的堆栈⼤⼩将失效;第三步:设置存储区分配地址⽅式;如下图所⽰设置,Scatter file选择第⼀步设置好的.sct⽂件;第四步:查看⽣成的.map⽂件如下图所⽰,表⽰起始的堆栈地址已设置到RAM顶端第五步:测试验证;如下图所⽰,测试验证成功,开始时堆栈地址指向RAM的顶端,即R13的值为0x20005000关注微信公众号:嵌⼊式STM32软硬件开发,来学习更多STM32开发的深⼊知识。
STM32内存管理以及STM32中的堆栈
STM32内存管理以及STM32中的堆栈
今天仔细读了一下内存管理的代码,然后还有看了堆栈的相关知识,把以前不太明白的一些东西想通了。
首先,先看一下stm32的存储器结构。
Flash,SRAM寄存器和输入输出端口被组织在同一个4GB的线性地址空间内。
可访问的存储器空间被分成8个主要块,每个块为512MB。
FLASH存储下载的程序。
SRAM是存储运行程序中的数据。
所以,只要你不外扩存储器,写完的程序中的所有东西也就会出现在这两个存储器中。
这是一个前提!
堆栈的认知
1. STM32中的堆栈。
这个我产生过混淆,导致了很多逻辑上的混乱。
首先要说明的是单片机是一种集成电路芯片,集成CPU、RAM、ROM、多种I/O口和中断系统、定时器/计数器等功能。
CPU中包括了各种总线电路,计算电路,逻辑电路,还有各种寄存器。
Stm32有通用寄存器R0‐R15 以及一些特殊功能寄存器,其中包括了堆栈指针寄存器。
当stm32正常运行程序的时候,来了一个中断,CPU就需要将寄存器中的值压栈到RAM里,然后将数据所在的地址存放在堆栈寄存器中。
等中断处理完成退出时,再将数据出栈到之前的寄存器中,这个在C语言里是自动完成的。
2. 编程中的堆栈。
在编程中很多时候会提到堆栈这个东西,准确的说这个就是RAM中的一个区域。
我们先来了解几个说明:
(1) 程序中的所有内容最终只会出现在flash,ram里(不外扩)。
(2) 段的划分,是将类似数据种类存储在一个区域里,方便管理,但正如上面所说,不管。
keil堆栈溢出函数
keil堆栈溢出函数
在Keil开发环境中,堆栈溢出是指当函数调用层级过多或者函
数内部使用的局部变量过多导致堆栈空间不足,进而发生数据覆盖
或程序崩溃的情况。
为了避免堆栈溢出,我们可以采取以下几种方法:
1. 优化代码结构,合理设计函数调用层级,避免过多的嵌套调用。
可以通过拆分复杂函数、合并冗余函数等方式来减少函数调用
层级,从而减少堆栈的使用。
2. 减少局部变量的使用,局部变量在函数调用时会在堆栈上分
配空间,过多的局部变量会导致堆栈空间不足。
因此,可以考虑减
少或优化局部变量的使用,尽量使用全局变量或静态变量来代替。
3. 增加堆栈大小,在Keil中,可以通过调整堆栈大小来解决
堆栈溢出的问题。
在工程的链接脚本文件中(一般是以.ld结尾的
文件),可以找到堆栈的定义位置,根据实际需求增加堆栈的大小。
4. 使用动态内存分配,动态内存分配(如malloc、free等函数)可以在堆上分配内存,而不是在堆栈上分配。
这样可以避免堆
栈溢出的问题。
但是需要注意合理释放动态分配的内存,避免内存泄漏。
5. 避免递归调用,递归调用是一种函数自身调用自身的方式,如果递归层级过深,会导致堆栈溢出。
可以考虑使用迭代方式替代递归,或者优化递归算法,减少递归层级。
总结来说,避免堆栈溢出需要优化代码结构、减少局部变量使用、增加堆栈大小、使用动态内存分配和避免递归调用。
通过这些方法,可以有效地预防和解决Keil中的堆栈溢出问题。
STM32堆栈大小详解以及变量存储位置
STM32堆栈大小详解以及变量存储位置栈增长和大端/小端问题是和CPU相关的两个问题.1,首先来看:栈(STACK)的问题.函数的局部变量,都是存放在'栈'里面,栈的英文是:STACK.STACK的大小,我们可以在stm32的启动文件里面设置,以战舰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就是从这个地址开始,往下给函数的局部变量分配地址.再说说栈的增长方向,我们可以用如下代码测试://保存栈增长方向//0,向下增长;1,向上增长.static u8 stack_dir;//查找栈增长方向,结果保存在stack_dir里面.void find_stack_direction(void){static u8 *addr=NULL; //用于存放第一个dummy的地址。
STM32IAP堆栈问题
STM32IAP堆栈问题Question:最近在搞STM32 的IAP。
发现一个很奇怪的问题。
在程序A里面,跳转到程序B执行。
A存放在0x08000000,B存放在0x0800e000.起初,B使用的内存大概6K,其中堆栈使用了4K。
此时如果从程序A跳到程序B,B出现死机。
但是如果用仿真器直接运行B是可以运行的。
实在不知道什么问题,后来B的堆栈改小,设为1K,这是就正常了。
能从程序A跳转到程序B,并且B也能正常运行。
请问这是什么原因?程序B的运行为什么后它的内存大小的影响呢?片子是STM32F103R8T6.望高手解答!!谢谢了。
----------------------------------------------------------------------------------Answer:感觉是你在跳转到B的时候没有把程序B的主堆栈进行初始化,这样程序B在运行的时候还在使用程序A的堆栈指针,很可能会与程序B的全局变量区混到一起了,执行情况就没法预知了,会有某些奇怪现象发生。
----------------------------------------------------------------------------------A程序用了ucos2,而且不是在中断里跳转到B,那应该是在某个任务里跳转的吧。
ucos2的官方移植版本,任务里使用的堆栈指针是PSP,如果你的A 程序是在使用PSP的任务里跳转到B程序的,那么函数void JumpBootloaderProgram(void)中的__set_MSP(*(volatile unsigned int*) ApplicationAddress)函数并没有使跳转到B后的堆栈指针初始化为主堆栈指针,即跳转到B后还是使用的程序A的PSP,问题可能会出在这里。
----------------------------------------------------------------------------------还得再啰嗦几句,楼主所说的“把PSP和MSP都重新设置”指的是在函数JumpBootloaderProgram中又加入了一句__set_PSP(*(volatile unsigned int*) ApplicationAddress)吗?如果是这样,貌似跳转到B之后还有隐患,因为由A跳到B后,主程序用的是PSP,而中断服务程序仍要使用MSP,因为CM3的中断服务是“处理模式”,只能使用MSP。
STM32堆栈分析
三、STM32堆栈区预备知识:一个由C/C++编译的程序占用的内存分为以下几个部分:●栈区(stack):编译器自动分配释放,存放函数的参数值,局部变量的值等。
操作方式类似于数据结构中的栈。
●堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
●全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
程序结束后由系统释放。
●文字常量区—常量字符串就是放在这里的。
程序结束后由系统释放●程序代码区—存放函数体的二进制代码编译后,各个区存储内容举例说明如下://main.cppint a = 0; 全局初始化区char *p1; 全局未初始化区main(){int b; 栈char s[] = “abc”; 栈char *p2; 栈char *p3 = “123456”; 123456\0在常量区,p3在栈上static int c =0;全局(静态)初始化区p1 = (char *)malloc(10);p2 = (char *)malloc(20);分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}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; <h> Stack Configuration; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>; </h>Stack_Size EQU 0x00000400AREA STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem SPACE Stack_Size__initial_sp; <h> Heap Configuration; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>; </h>Heap_Size EQU 0x00000200AREA HEAP, NOINIT, READWRITE, ALIGN=3__heap_baseHeap_Mem SPACE Heap_Size__heap_limit这里定义了堆栈各自大小,堆:512bytes 栈1k;所以栈区大小有限制,我们在局部变量中不要定义大数组否则容易溢出。
基于STM32分析栈、堆、全局区、常量区、代码区
基于STM32分析栈、堆、全局区、常量区、代码区在一个STM32程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全局区中高地址分布着.bss段,低地址分布着.data段。
总的分布如下所示:内存高地址栈区堆区.bss段.data段常量区内存低地址代码区一、栈区(stack)临时创建的局部变量存放在栈区。
函数调用时,其入口参数存放在栈区。
函数返回时,其返回值存放在栈区。
const定义的局部变量存放在栈区。
2、堆区(heap)堆区用于存放程序运行中被动态分布的内存段,可增可减。
可以有malloc等函数实现动态分布内存。
有malloc函数分布的内存,必须用free进行内存释放,否则会造成内存泄漏。
3、全局区(静态区)全局区有.bss段和.data段组成,可读可写。
4、.bss段未初始化的全局变量存放在.bss段。
初始化为0的全局变量和初始化为0的静态变量存放在.bss段。
.bss段不占用可执行文件空间,其内容有操作系统初始化。
5、.data段已经初始化的全局变量存放在.data段。
静态变量存放在.data段。
.data段占用可执行文件空间,其内容有程序初始化。
const定义的全局变量存放在.rodata段。
6、常量区字符串存放在常量区。
常量区的内容不可以被修改。
7、代码区程序执行代码存放在代码区。
字符串常量也有可能存放在代码区。
通过上面的介绍,可能你对各个数据的存储位置还是很模糊,下面通过一个简单的程序,再来体会理解一下。
通过上面的介绍,可能你对各个数据的存储位置还是很模糊,下面通过一个简单的程序,再来体会理解一下【多余一段】#include <stdio.h>static unsigned int val1 = 1; //val1存放在.data段unsigned int val2 = 1; //初始化的全局变量存放在.data段unsigned int val3 ; //未初始化的全局变量存放在.bss段const unsigned int val4 = 1; //val4存放在.rodata(只读数据段)unsigned char Demo(unsigned int num) //num 存放在栈区{ char*var = "123456"; //var存放在栈区,"123456"存放在常量区unsigned int num1 = 1 ; //num1存放在栈区static unsigned int num2 = 0; //num2存放在.data段constunsigned int num3 = 7; //num3存放在栈区void*p; p = malloc(8); //p存放在堆区free(p); return1;}void main(){ unsigned int num = 0; num = Demo(num); //Demo()函数的返回值存放在栈区。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
STM32 KEIL下的堆栈设置问题
刚接手STM32时,你只编写一个
int main()
{
while(1);
}
BUILD://Program Size: Code=340 RO-data=252 RW-data=0 ZI-data=1632
编译后,就会发现这么个程序已用了1600多的RAM,要是在51单片机上,会心疼死了,这1600多的RAM跑哪儿去了,分析map,你会发现是堆和栈占用的在startup_stm32f10x_md.s文件中,它的前面几行就有以上定义,这下该明白了吧。
Stack_Size EQU 0x00000400
Heap_Size EQU 0x00000200
顺便记号,关注此帖:
以下引用网上资料理解堆和栈的区别
(1)栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似
于数据结构中的栈。
(2)堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。
分配
方式类似于数据结构中的链表。
(3)全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
程序结束后由系统自动释放。
(4)文字常量区:常量字符串就是存放在这里的。
(5)程序代码区:存放函数体的二进制代码。
例如:
int a=0; //全局初始化区
char *p1; //全局未初始化区
main()
{
int b; //栈
char s[]="abc"; //栈
char *p3= "1234567"; //在文字常量区
static int c =0 ; //静态初始化区
p1= (char *)malloc(10); //堆区
strcpy(p1,"123456"); //"123456"放在常量区
}
所以堆和栈的区别:
stack的空间由操作系统自动分配/释放,heap上的空间手动分配/释放。
stack的空间有限,heap是很大的自由存储区。
程序在编译期和函数分配内存都是在栈上进行,且程序运行中函数调用时参数的传递也是在栈上进行。
STM32单片机中文官网
意法半导体/ST/STM。