打印
[ZLG-MCU]

汇编压栈问题

[复制链接]
3091|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zlgarm|  楼主 | 2008-4-10 15:31 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    近日使用汇编写电机变频器的算法,uCOS-II写的汇编函数。一不留神忘记在汇编函数里把要使用的寄存器压堆,导致电机经常停转。由于程序巨大,调了半天才找出这个小BUG。
     网上有人说C调用子函数前,编译器会自动加入PUSH指令,把子函数要使用的寄存器压堆,返回后又自动加入POP指令出栈。如果子函数是C语言写的,那是正确的,但如果是汇编写的,那就只对一半!如果编译不优化,那么编译器把汇编函数当成C函数,会加入压栈和出堆指令;但如果选择优化,那么编译器有可能把汇编函数的代码,直接复制到调用它的地方,不按调用函数的流程,更不会加入压栈和出堆指令,如果汇编函数没有自我压栈,那程序会跑飞!我的变频器算法就是这样。

      另外,uCOS官方的移植模板触法任务调度的函数是这样写的:
OSCtxSw
        LDR     R4, =NVIC_INT_CTRL    ; trigger the PendSV
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]
        BX      LR 
如果选择优化编译,这段代码就有可能使单片机跑飞!正确的写法应该是(不管编译器会不会加入压栈和出堆指令):
OSCtxSw
        PUSH    {R4, R5}
        LDR     R4, =NVIC_INT_CTRL    ; trigger the PendSV
        LDR     R5, =NVIC_PENDSVSET
        STR     R5, [R4]
        POP     {R4, R5}
        BX      LR 

(zlgarm_zsg)

相关帖子

沙发
computer00| | 2008-4-10 15:37 | 只看该作者

好象编译器只会自动保护R0~R3……其它的需要用户自己保护

R0~R3可以在汇编里面随便用,用其它的话,必须要自己保护起来。

使用特权

评论回复
板凳
HWM| | 2008-4-10 15:38 | 只看该作者

编译并不会莫名其妙地把汇编函数当成C函数

使用特权

评论回复
地板
zlgarm|  楼主 | 2008-4-10 15:59 | 只看该作者

说得不准确

谢谢HWM。说得不准确,不是“当成C函数”。

(zlgarm_zsg)

使用特权

评论回复
5
zlgarm|  楼主 | 2008-4-11 13:58 | 只看该作者

小心R0-R3

    在Keil或IAR下编Cortex-M3时,如果汇编函数用到了R0-R3,调用前都会自动加入压堆指令(如果有需要的话)。但ADS编译ARM7时好像不会加入的,也没听说过编译器一定都会自动压R0-R3。安全的做法是,不管编译器怎么处理,对于汇编函数要用的寄存器都要自己先压堆。

(zlgarm_zsg)

使用特权

评论回复
6
HWM| | 2008-4-12 08:09 | 只看该作者

用汇编做子程序(和C连接)绝对要保护寄存器,除非不用它

使用特权

评论回复
7
grant_jx| | 2008-4-12 13:14 | 只看该作者

有个概念的疑问

“: 小心R0-R3 

    在Keil或IAR下编Cortex-M3时,如果汇编函数用到了R0-R3,调用前都会自动加入压堆指令(如果有需要的话)。但ADS编译ARM7时好像不会加入的,也没听说过编译器一定都会自动压R0-R3。安全的做法是,不管编译器怎么处理,对于汇编函数要用的寄存器都要自己先压堆。

(zlgarm_zsg) 
 


Cortex-M3 Technical Reference Manual 第5章 Exception 第5.5.1章节 Stacking

https://bbs.21ic.com/upfiles/img/20084/2008412125357155.jpg


1、当处理器进入异常模式时,M3是自动压栈!看清楚这里是自动压栈!当异常到来时,M3会去自动压栈,保护R0~R3等一共8个寄存器。这个动作不是编译器能决定的,是由异常的处理机制决定。要按你的说法,不相信编译器能做,恐怕你还得麻烦将xPSR、LR、PC、R12也得保存一下,要不可能你用汇编写ISR,恐怕会出现退出ISR,无法返回正确地址!不是吗?   

https://bbs.21ic.com/upfiles/img/20084/20084121327854.jpg


因为概念问题,被混淆了容易误导大众,顺便提提。

很不巧的是,最近我也在花时间理解STM32上FOC方式控制PMSM的数学算法实现上,刚好也在ISR处理这部分。




补充:看了楼下8楼的回答提示,发现我理解错了顶楼的帖子,人家说的是一般函数,我理解成了ISR函数。

刚才也看了一下EWARM Compiler Reference里关于一般功能函数的章节, 确有提到R0~R3会做为隐形的型参传递,没有找到明确的提示R0~R3会自动压栈的说明。



调试电机在ISR设置断点也没什么大不了的,关键是看使用的MCU是否支持在设置断点的时候,代码运行到断点位置,马达输出在硬件上是否能提供保护功能。


使用特权

评论回复
8
grant_jx| | 2008-4-12 13:16 | 只看该作者

晕倒,21ic有抽筋了?

怎么又不能贴图了。

使用特权

评论回复
9
HWM| | 2008-4-12 13:54 | 只看该作者

7楼:ISR可不等于一般函数喔

使用特权

评论回复
10
mohanwei| | 2008-4-12 14:36 | 只看该作者

一不留神……电机停转……这种东西也能随便调试……

强悍

使用特权

评论回复
11
zlgarm|  楼主 | 2008-4-12 21:24 | 只看该作者

PWM

1. Lumiary的PWM可被设置 在单步调试时强行设为高电平或低电平.
2. 我使用了错误中断,里面把PWM设为无效电平,程序跑飞了就进去关电机.
这些特点使调试电机比较安全.

(ZLGARM_ZSG)

使用特权

评论回复
12
computer00| | 2008-4-13 01:07 | 只看该作者

看到KEIL的CARM编译器说明里,有这样一句:

Assembler functions may destroy the contents of R0—R3, R8-R12, and R14. When invoking a C function from assembly, you must assume that these registers are destroyed.

不知道这是一个对ARM C语言的一个行业规定还是KEIL自己定义的,就不清楚了。
谁能找找权威的资料有这方面的介绍或者约定就好了……这样可以避免一些不必要的重复操作。

使用特权

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

本版积分规则

11

主题

2820

帖子

0

粉丝