打印

请教STM32堆栈的问题

[复制链接]
9600|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
haibao211|  楼主 | 2012-2-13 10:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 haibao211 于 2012-2-13 10:07 编辑

DATA_IN_ExtSRAM EQU 0 ;
Stack_Size EQU 0x00000400 ;
AREA STACK, NOINIT, READWRITE, ALIGN = 3 ;
Stack_Mem SPACE Stack_Size ;
__initial_sp ;
Heap_Size EQU 0x00000400 ;
AREA HEAP, NOINIT, READWRITE, ALIGN = 3 ;
__heap_base ;
Heap_Mem SPACE Heap_Size ;
__heap_limit ;

它定义了堆栈的大小,我现在裸奔,问题是:
沙发
haibao211|  楼主 | 2012-2-13 10:24 | 只看该作者
本帖最后由 haibao211 于 2012-2-13 10:27 编辑

大家别太在意细节啊,可能有的地方不严谨。
int main()
{
     int x1=0;  //问题1: x1 的存储位置是在1楼的栈里面吗?
     while(1)
     {
         a();
         b();
     }
}

int a()
{
   int y1=3;
   int y2=8;
   int y3=4;
   ......
   int y20=1;
   int y =0;
   y = y1+y2;   //假如程序运行到这里,问题二:
  e();        
}
问题2:如果程序运行到这里,那定义的y1,y2...y20这些局部变量是存储在栈空间吗?如果此时来了一个中断(假如是串口中断),那跳到串口中断前 这些y1,y2,....y20需要压入栈里面吗?cpu的寄存器R0,R1,.....R15等 我知道要压入栈空间里面,那y1,y2,和R0等寄存器有什么关系吗?
   
}

使用特权

评论回复
板凳
haibao211|  楼主 | 2012-2-13 10:30 | 只看该作者
问题3: STM32 我使用的是终端嵌套,即抢占模式,那在我串口中断的时候来了一个更高级的定时器终端,那串口中断函数里面的所有变量得压入栈中保存吧,那这个栈是不是还是1楼的那个栈啊?

使用特权

评论回复
地板
香水城| | 2012-2-13 10:59 | 只看该作者
1)是的。
2)不需要,因为y1,y2......已经在栈中。
3)变量不需要压栈。

使用特权

评论回复
5
haibao211|  楼主 | 2012-2-13 11:15 | 只看该作者
谢谢香主!
关于问题2:y1,y2....已经在栈中,不需要压栈了,那需要压栈的是R0.....R15吗?
关于问题3:中断函数里面用到的局部变量不需要压栈,是因为它们也是在栈中吗?这个栈是1楼的那个栈吗?(即主函数用的栈)?如果我多层嵌套中断,那么每一层中断函数里面的变量 都是用1楼的那个栈吗?

使用特权

评论回复
6
香水城| | 2012-2-13 11:19 | 只看该作者
2)如果你使用C,C编译会照顾R0~R15的压栈,不需要你自己考虑。
3)都是同一个栈。

只要使用C,不需要你自己考虑压栈问题。

使用特权

评论回复
7
haibao211|  楼主 | 2012-2-13 11:52 | 只看该作者
谢谢香主!
我裸奔,关于堆栈的大小,那最大的情况是发生在
函数调用到最深处的时候,此时发生了中断,而且巧合的是中断时候又发生中断并且嵌套进去,而且还是要嵌套到最深处,此时的栈是最大的,是吗?如果大于定义的,它就会溢出,造成硬件fault, 如果没有那么多的巧合发生,运行的时候就会没事。
所以有的程序跑着跑着,没准多长时间,可能几分钟,可能几个小时,就会死了,是吗?

使用特权

评论回复
8
香水城| | 2012-2-13 12:00 | 只看该作者
所以你要控制好嵌套的深度、局部变量的数量以及堆栈的大小,保证堆栈始终不会溢出。

使用特权

评论回复
9
haibao211|  楼主 | 2012-2-13 14:44 | 只看该作者
;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
                 IF      :DEF:__MICROLIB           
               
                 EXPORT  __initial_sp
                 EXPORT  __heap_base
                 EXPORT  __heap_limit
               
                 ELSE
               
                 IMPORT  __use_two_region_memory
                 EXPORT  __user_initial_stackheap
                 
__user_initial_stackheap

                 LDR     R0, =  Heap_Mem
                 LDR     R1, =(Stack_Mem + Stack_Size)
                 LDR     R2, = (Heap_Mem +  Heap_Size)
                 LDR     R3, = Stack_Mem
                 BX      LR

                 ALIGN

                 ENDIF

                 END

;******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE*****
谢谢香主!
启动代码段最后一部分,这一部分好像没有用啊?
因为程序好像先运行以下代码,运行完了之后直接跳到主函数去了
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

使用特权

评论回复
10
airwill| | 2012-2-13 15:48 | 只看该作者
关于局部变量, 编译器通常首先将其分配在寄存器里, 放不下了, 直接分配的堆栈中.
对于在堆栈中的变量, 编译器使用 sp 相关的指令 (基址寻址) 读写. 所以一直存在于堆栈中.
对于中断服务, 编译器会对其服务函数里使用的所有寄存器都堆栈现场保护, 所以根本不要理会中断服务的影响.

使用特权

评论回复
11
香水城| | 2012-2-13 15:55 | 只看该作者
9楼的代码是从哪里抄来的?与LZ的问题有什么关系?

使用特权

评论回复
12
haibao211|  楼主 | 2012-2-13 16:06 | 只看该作者
本帖最后由 haibao211 于 2012-2-13 16:07 编辑

代码是ST的固件库中 startup_stm32f2xx.s 中的。
硬件设计中如果外加SRAM,启动代码就需要改变,如果上FREERTOS,启动代码又变了,现在的情况是,固件库中有外加SRAM的startup_stm32f2xx.s  , 也有FREERTOS 的 startup_stm32f2xx.s  , 但是没有两个一起上的,而我想既上FREERTOS ,硬件上又要加SRAM,所以只得自己写,但不知道怎么修改,所以提问。
香主千万不要误会啊!

另外感谢airwill,我终于明白了压栈R0和局部变量之间的关系是怎么回事。

使用特权

评论回复
13
香水城| | 2012-2-13 16:25 | 只看该作者
代码是ST的固件库中 startup_stm32f2xx.s 中的。
硬件设计中如果外加SRAM,启动代码就需要改变,如果上FREERTOS,启动代码又变了,现在的情况是,固件库中有外加SRAM的startup_stm32f2xx.s  , 也有FREERTOS 的 start ...
haibao211 发表于 2012-2-13 16:06


硬件设计中如果外加SRAM,并不需要改变启动代码。系统启动之后,进入main的时候,完全可以不考虑外加SRAM;有关外加SRAM的使用,还是在进入main之后再处理为好。

另一方面,因为局部变量都是放在堆栈中,程序运行中需要频繁地访问这些局部变量,所以还是把堆栈放到内部SRAM中效率更高。

外加SRAM一般只做大容量缓冲使用。

使用特权

评论回复
14
sf116| | 2014-12-17 09:36 | 只看该作者
学习了

使用特权

评论回复
15
karaxiaoyu| | 2016-1-8 13:36 | 只看该作者
学习了

使用特权

评论回复
16
lvenic| | 2017-11-21 14:58 | 只看该作者
学习了
总于明白了
堆栈

使用特权

评论回复
17
kingkits| | 2017-11-21 15:54 | 只看该作者
堆和栈是不同的。
函数调用时,或者中断时,压栈用的是栈
定义函数中临时变量时,用的是堆
一个向下生长,一个向上生长,如果堆栈空间不够,就会发生冲突

使用特权

评论回复
18
feelhyq| | 2017-11-21 17:22 | 只看该作者
kingkits 发表于 2017-11-21 15:54
堆和栈是不同的。
函数调用时,或者中断时,压栈用的是栈
定义函数中临时变量时,用的是堆

定义函数的临时变量用的也是栈,栈的生长方向跟处理器体系结构有关,51单片的的栈就是向上生长的

使用特权

评论回复
19
kingkits| | 2017-11-22 09:53 | 只看该作者
你不理解堆栈的定义,实际上堆栈是同一段RAM空间,栈向下生长,堆向上生长

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

20

主题

283

帖子

0

粉丝