打印
[开发工具]

求助关于MDK编译 # pramga unroll指令

[复制链接]
1044|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xlsbz|  楼主 | 2014-9-19 12:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
想一个延时函数
for (i=0;i<10000;i++)

想在不用优化级别下都延时相同的时间。查到可用unroll 和unroll_completely
但是但不怎么起作用啊

求大侠帮忙解答
沙发
xlsbz|  楼主 | 2014-9-23 09:52 | 只看该作者
另一种方法解决

先上测试代码(普通版)

#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

粉丝