打印
[STM32F1]

帮忙看看这段汇编有没有问题

[复制链接]
2460|22
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xlsbz|  楼主 | 2014-9-23 11:26 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式


想写个软件延时程序。 这段汇编能不能引起什么问题。

引起别的东西异常?
沙发
bhsdlmj| | 2014-9-23 12:36 | 只看该作者
这个程序不错  不用考虑编译器优化级别了。

但是汇编会不会引起别的异常 我就不懂了  

期待高手

使用特权

评论回复
板凳
myxiaonia| | 2014-9-23 13:14 | 只看该作者
你想达到准确的us级延时,可能性不大,在cm系列arm上,影响指令周期因素很多,甚至还受flash等待周期影响

使用特权

评论回复
地板
airwill| | 2014-9-23 23:02 | 只看该作者
大体的思路没有问题,不过有几个小问题和一个大 bug
1。SUBS +BNE 两条指令未必是2个周期吧
2。SUB R0,#3   应该不止3吧,按照指令周期数算,还要加上调用的转移和返回时间呢
3。一个 bug,如果 SUB R0,#3  的 R0 小于等于3 时,会是极其长的时间哦。

使用特权

评论回复
5
airwill| | 2014-9-23 23:05 | 只看该作者
大体的思路没有问题,不过有几个小问题和一个大 bug
1。SUBS +BNE 两条指令未必是2个周期吧
2。SUB R0,#3   应该不止3吧,按照指令周期数算,还要加上调用的转移和返回时间呢
3。一个 bug,如果 SUB R0,#3  的 R0 小于等于3 时,会是极其长的时间哦。

使用特权

评论回复
6
xlsbz|  楼主 | 2014-9-24 09:17 | 只看该作者
airwill 发表于 2014-9-23 23:05
大体的思路没有问题,不过有几个小问题和一个大 bug
1。SUBS +BNE 两条指令未必是2个周期吧
2。SUB R0,#3  ...

多谢斑竹
  
参数usec传递给了r0,那么参数usec我设置大于3就好了。
斑竹,其实我只是想搞个1ms的延时。不用太精确,能在0.9ms~1.1ms就行。
这样的话,1楼的代码能满足要求吧?
---------------------------------------------------------------
我的单片机是STM32F103VGT6,外晶振8M,时钟72M,即用函数SetSysClockTo72(),
此时搞1ms得设置成__asm void Dellayus(1000,48)。
很纳闷明明时钟是72,为什么函数要设置成48?
再次感谢版主
       



使用特权

评论回复
7
xlsbz|  楼主 | 2014-9-24 09:19 | 只看该作者
myxiaonia 发表于 2014-9-23 13:14
你想达到准确的us级延时,可能性不大,在cm系列arm上,影响指令周期因素很多,甚至还受flash等待周期影响 ...

多谢是的。 我也注意到论坛有**《导致STM32芯片指令速度变化的问题分析过程》。于是用汇编了。只是想搞个1ms延时。不用定时器。
希望你也给分析下

使用特权

评论回复
8
yhn1973| | 2014-9-24 09:25 | 只看该作者
跳转指令我印象中跳转是2个周期,不跳转是1个周期吧

使用特权

评论回复
9
airwill| | 2014-9-24 13:25 | 只看该作者
此时搞1ms得设置成__asm void Dellayus(1000,48)。

说明 BNE 指令不是一个周期,而是两个周期。

使用特权

评论回复
10
myxiaonia| | 2014-9-24 13:37 | 只看该作者
xlsbz 发表于 2014-9-24 09:19
多谢是的。 我也注意到论坛有**《导致STM32芯片指令速度变化的问题分析过程》。于是用汇编了。只是想搞 ...

那篇**就是讲到了函数编译后的地址对齐,会对代码执行时间产生影响,你打算指定地址吗

使用特权

评论回复
11
xlsbz|  楼主 | 2014-9-24 18:31 | 只看该作者
myxiaonia 发表于 2014-9-24 13:37
那篇**就是讲到了函数编译后的地址对齐,会对代码执行时间产生影响,你打算指定地址吗 ...

不打算地址对齐。

使用特权

评论回复
12
xlsbz|  楼主 | 2014-9-24 21:59 | 只看该作者
myxiaonia 发表于 2014-9-24 13:37
那篇**就是讲到了函数编译后的地址对齐,会对代码执行时间产生影响,你打算指定地址吗 ...

不想指定地址!想写通用的!

使用特权

评论回复
13
Adu0227| | 2014-9-24 22:20 | 只看该作者
用定时器是最好的方法,当然也可以使用软件仿真的方式用一个大循环,看看循环多少次是1mS,比这个计算指令周期的方法精确多了

使用特权

评论回复
14
xlsbz|  楼主 | 2014-9-25 10:14 | 只看该作者
Adu0227 发表于 2014-9-24 22:20
用定时器是最好的方法,当然也可以使用软件仿真的方式用一个大循环,看看循环多少次是1mS,比这个计算指令 ...

不想用定时器。
软仿真,这招在STM32不好用。我查了些资料说的。

使用特权

评论回复
15
bear1| | 2014-9-25 14:30 | 只看该作者
xlsbz 发表于 2014-9-25 10:14
不想用定时器。
软仿真,这招在STM32不好用。我查了些资料说的。

还是用定时器吧!我是过来人。

使用特权

评论回复
16
prettyxp| | 2014-9-25 14:41 | 只看该作者
跟据arm的体系结构,分为取指令,解释,执行三步,第步有一个时钟周期,因为你在程序中有BX指令,而且没有关中断.进一下中断,什么都黄了.

使用特权

评论回复
17
xlsbz|  楼主 | 2014-9-25 21:05 | 只看该作者
prettyxp 发表于 2014-9-25 14:41
跟据arm的体系结构,分为取指令,解释,执行三步,第步有一个时钟周期,因为你在程序中有BX指令,而且没有关中断. ...

理论上讲,进中断肯定黄,还是可能黄?多谢

使用特权

评论回复
18
xlsbz|  楼主 | 2014-9-25 22:05 | 只看该作者
prettyxp 发表于 2014-9-25 14:41
跟据arm的体系结构,分为取指令,解释,执行三步,第步有一个时钟周期,因为你在程序中有BX指令,而且没有关中断. ...

看这架势,只能用定时器搞死延时了。
本来我这模块要保持不耦合,看样只能若耦合了。

使用特权

评论回复
19
bald| | 2014-9-26 09:45 | 只看该作者
如果有中断源,软件延时很难准确。
bne指令在RAM中运行三个周期没问题。在Flash中运行恐怕不是三个周期,应该与Flash的加速器设置有关。
如果不溢出,合理的顺序应该是先做乘法再除四。

使用特权

评论回复
20
xlsbz|  楼主 | 2014-9-26 16:32 | 只看该作者
bald 发表于 2014-9-26 09:45
如果有中断源,软件延时很难准确。
bne指令在RAM中运行三个周期没问题。在Flash中运行恐怕不是三个周期,应 ...

大侠 不要求太准。20%精度就行。

网上找的代码


另一种方法解决

先上测试代码(普通版)

#include "stm32f10x.h"
#include "core_cm3.h"

__asm int Dellayus(u32 usec)
{
       ALIGN
       PUSH.W {r1}  //2时钟周期
       MOV r1,#18  //1时钟周期
       MUL r0,r1  //1时钟周期
       SUB r0,#3  //1时钟周期
loop
       SUBS r0,#1   //1时钟周期
       BNE loop   //如果跳转则为3个周期,不跳则只有1个周期
       POP {r1}   //2时钟周期
       BX lr    //3个时钟周期
                    //总共所用周期为(usec*4)-4,此处减4主要用于抵消调用此函数的消耗时钟周期(传参1时钟,BLX跳转3时钟)
}

int main(void)
{
       while(1)
       {
            //运行到此处时32.93us,第1379时钟周期
            Dellayus(100);
            //运行到此处时132.93us,第8579时钟周期,运行上条指令共花8579-1379=7200时钟周期
            //因系统时钟为72MHz,所以每72时钟周期所花时间为1微妙,上条指令所花时间
            //等于7200 ÷ 72 = 100微妙,延时完全准确
            Dellayus(100);
            //运行到此处时232.93us,第15779时钟周期,同样验证上面的结论
       }
}


调试:

第一个100微妙延时函数运行前






第一个100微妙延时函数运行后







所花系统时钟周期8579-1379=7200个系统时钟,时间精确为0.00013293-0.0003293=0.0001秒,
也就是100微秒。延时函数通过软件模拟以及硬件调试同样精确,如果延时参数大于255微秒,调用
时会多耗两个时钟周期(0.028微秒)用于从代码段加载常数。可以修改代码修正误差。最大定时不能
超过(232-1) ÷  18 ≈ 238.6秒。

以上方法可以节约系统定时器资源,避免和其他代码争用定时器。通常用于微秒級延时。



--------------------------------------------------------------------------------



--------------------------------------------------------------------------------



版主的建议非常好,是该增加时钟参数以适应不同的时钟频率,改了一下代码,目前软件仿真测试没问题,等晚上再用JLink
测试一下(理论上应该没问题,已经考虑了闪存预取优化)。

#include "stm32f10x.h"
#include "core_cm3.h"

__asm void Dellayus(u32 usec,u8 freq)  //freq参数为系统时钟频率(SYSCLK),单位MHz,且必须能被4整除,且必须大    于等于16,常用的
{           //有24,36,48,56,72,如果一定要使用8MHz则必须满足延时时间大于2微秒,但freq一定不要
             //小于8MHz,否则函数将出现混乱。条件为 ((usec >= 1) && (freq >=16)) ||  ((usec >= 2) && (freq >= 8))
   ALIGN
   LSR r1,r1,#2  //1时钟周期,除以单次循环所用的时钟数(4个)即得到延时1微妙所需的循环数
   MUL r0,r1  //1时钟周期
   SUB r0,#3  //1时钟周期
   NOP    //用于匹配延时周期以及使loop循环处指令在8字节边界对齐,提高精度(因为指令预取单元一次预取8字节指令)
   NOP    //所以循环时都不用再从闪存内取指令,避免闪存延时影响延时精度
loop
   SUBS r0,#1   //1时钟周期
   BNE loop   //延时循环,每次4个时钟周期,最后一次只需两个时钟周期(如果跳转则为3个周期,不跳则只有1个周期)
   NOP
   BX lr    //3个时钟周期
        //本函数内总共所用周期为usec*(freq/4)-2 +9,调用此函数的消耗5个时钟周期(传参2时钟,BLX跳转3时钟)
}      //函数最低耗时11个时钟周期,上面usec*(freq/4) - 2为循环代码的耗时(此处减2是因为最后一次循环BNE没有跳转,只消耗1个时钟比跳转的3个时钟节约2个所以减去2才是最终循环的耗时),9就是其它代码的耗时

//比如频率为8MHz时延时2微秒所需延时周期数为2*8=16个时钟,将值带入上面的公式即为 2 * (8 / 4) - 2 + 9 =11            即为函数体耗时,再加上5个周期的调用开销最终消耗16个时钟周期,同时这也是最低延时周期数。

int main(void)
{
   while(1)
   {
    //运行到此处时32.93us,第1379时钟周期
    Dellayus(100,72);
    //运行到此处时132.93us,第8579时钟周期,运行上条指令共花8579-1379=7200时钟周期
    //因系统时钟为72MHz,所以每72时钟周期所花时间为1微妙,上条指令所花时间
    //等于7200 ÷ 72 = 100微妙,延时完全准确
    Dellayus(100,72);
    //运行到此处时232.93us,第15779时钟周期,同样验证上面的结论
   }
}

使用特权

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

本版积分规则

190

主题

1614

帖子

4

粉丝