[ZLG-MCU] 汇编压栈问题

[复制链接]
4288|11
 楼主| zlgarm 发表于 2008-4-10 15:31 | 显示全部楼层 |阅读模式
&nbsp;&nbsp;&nbsp;&nbsp;近日使用汇编写电机变频器的算法,uCOS-II写的汇编函数。一不留神忘记在汇编函数里把要使用的寄存器压堆,导致电机经常停转。由于程序巨大,调了半天才找出这个小BUG。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;网上有人说C调用子函数前,编译器会自动加入PUSH指令,把子函数要使用的寄存器压堆,返回后又自动加入POP指令出栈。如果子函数是C语言写的,那是正确的,但如果是汇编写的,那就只对一半!如果编译不优化,那么编译器把汇编函数当成C函数,会加入压栈和出堆指令;但如果选择优化,那么编译器有可能把汇编函数的代码,直接复制到调用它的地方,不按调用函数的流程,更不会加入压栈和出堆指令,如果汇编函数没有自我压栈,那程序会跑飞!我的变频器算法就是这样。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;另外,uCOS官方的移植模板触法任务调度的函数是这样写的:<br />OSCtxSw<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R4,&nbsp;=NVIC_INT_CTRL&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;trigger&nbsp;the&nbsp;PendSV<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R5,&nbsp;=NVIC_PENDSVSET<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;STR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R5,&nbsp;[R4]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LR&nbsp;<br />如果选择优化编译,这段代码就有可能使单片机跑飞!正确的写法应该是(不管编译器会不会加入压栈和出堆指令):<br />OSCtxSw<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PUSH&nbsp;&nbsp;&nbsp;&nbsp;{R4,&nbsp;R5}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R4,&nbsp;=NVIC_INT_CTRL&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;trigger&nbsp;the&nbsp;PendSV<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LDR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R5,&nbsp;=NVIC_PENDSVSET<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;STR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;R5,&nbsp;[R4]<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;POP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{R4,&nbsp;R5}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LR&nbsp;<br /><br />(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函数”。<br /><br />(zlgarm_zsg)
 楼主| zlgarm 发表于 2008-4-11 13:58 | 显示全部楼层

小心R0-R3

&nbsp;&nbsp;&nbsp;&nbsp;在Keil或IAR下编Cortex-M3时,如果汇编函数用到了R0-R3,调用前都会自动加入压堆指令(如果有需要的话)。但ADS编译ARM7时好像不会加入的,也没听说过编译器一定都会自动压R0-R3。安全的做法是,不管编译器怎么处理,对于汇编函数要用的寄存器都要自己先压堆。<br /><br />(zlgarm_zsg)
HWM 发表于 2008-4-12 08:09 | 显示全部楼层

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

  
grant_jx 发表于 2008-4-12 13:14 | 显示全部楼层

有个概念的疑问

“:&nbsp;小心R0-R3&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;在Keil或IAR下编Cortex-M3时,如果汇编函数用到了R0-R3,调用前都会自动加入压堆指令(如果有需要的话)。但ADS编译ARM7时好像不会加入的,也没听说过编译器一定都会自动压R0-R3。安全的做法是,不管编译器怎么处理,对于汇编函数要用的寄存器都要自己先压堆。<br /><br />(zlgarm_zsg)&nbsp;<br />&nbsp;<br />”<br /><br />Cortex-M3&nbsp;Technical&nbsp;Reference&nbsp;Manual&nbsp;第5章&nbsp;Exception&nbsp;第5.5.1章节&nbsp;Stacking<br /><br />https://bbs.21ic.com/upfiles/img/20084/2008412125357155.jpg<br /><br /><br />1、当处理器进入异常模式时,M3是自动压栈!看清楚这里是自动压栈!当异常到来时,M3会去自动压栈,保护R0~R3等一共8个寄存器。这个动作不是编译器能决定的,是由异常的处理机制决定。要按你的说法,不相信编译器能做,恐怕你还得麻烦将xPSR、LR、PC、R12也得保存一下,要不可能你用汇编写ISR,恐怕会出现退出ISR,无法返回正确地址!不是吗?&nbsp;&nbsp;&nbsp;<br /><br />https://bbs.21ic.com/upfiles/img/20084/20084121327854.jpg<br /><br /><br />因为概念问题,被混淆了容易误导大众,顺便提提。<br /><br />很不巧的是,最近我也在花时间理解STM32上FOC方式控制PMSM的数学算法实现上,刚好也在ISR处理这部分。<br /><br /><br /><br /><br />补充:看了楼下8楼的回答提示,发现我理解错了顶楼的帖子,人家说的是一般函数,我理解成了ISR函数。<br /><br />刚才也看了一下EWARM&nbsp;Compiler&nbsp;Reference里关于一般功能函数的章节,&nbsp;确有提到R0~R3会做为隐形的型参传递,没有找到明确的提示R0~R3会自动压栈的说明。<br /><br /><br /><br />调试电机在ISR设置断点也没什么大不了的,关键是看使用的MCU是否支持在设置断点的时候,代码运行到断点位置,马达输出在硬件上是否能提供保护功能。<br /><br /><br />
grant_jx 发表于 2008-4-12 13:16 | 显示全部楼层

晕倒,21ic有抽筋了?

怎么又不能贴图了。
HWM 发表于 2008-4-12 13:54 | 显示全部楼层

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

  
mohanwei 发表于 2008-4-12 14:36 | 显示全部楼层

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

强悍
 楼主| zlgarm 发表于 2008-4-12 21:24 | 显示全部楼层

PWM

1.&nbsp;Lumiary的PWM可被设置&nbsp;在单步调试时强行设为高电平或低电平.<br />2.&nbsp;我使用了错误中断,里面把PWM设为无效电平,程序跑飞了就进去关电机.<br />这些特点使调试电机比较安全.<br /><br />(ZLGARM_ZSG)
computer00 发表于 2008-4-13 01:07 | 显示全部楼层

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

Assembler&nbsp;functions&nbsp;may&nbsp;destroy&nbsp;the&nbsp;contents&nbsp;of&nbsp;R0—R3,&nbsp;R8-R12,&nbsp;and&nbsp;R14.&nbsp;When&nbsp;invoking&nbsp;a&nbsp;C&nbsp;function&nbsp;from&nbsp;assembly,&nbsp;you&nbsp;must&nbsp;assume&nbsp;that&nbsp;these&nbsp;registers&nbsp;are&nbsp;destroyed.<br /><br />不知道这是一个对ARM&nbsp;C语言的一个行业规定还是KEIL自己定义的,就不清楚了。<br />谁能找找权威的资料有这方面的介绍或者约定就好了……这样可以避免一些不必要的重复操作。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

11

主题

2820

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部