问题描述:
使用MDK4或5编译ST的USB-host库时,里面有个USB_OTG_BSP_uDelay函数,本函数本身在-03级优化下是没有问题的,但我手痒,对里面的变量的定义顺序做了一下修改,结果-o3优化下出问题了(
表现为该延时函数不准确,导致部分U盘枚举失败),请教大师分析一下:
错误改法: 将定义 “const Uint32 u
time = (Uint32)120 * usec / 7;” 放到 “__IO Uint32 uCount = 0;” 代码前面。
我的问题:仅仅是变量定义的顺序不同,为什么优化后结果却不一样(不是存储对齐的问题)?
正常的代码如下:
void USB_OTG_BSP_uDelay(const uint32_t usec)
{
__IO Uint32 uCount = 0;
const Uint32 uTime = (Uint32)120 * usec / 7;
while (1)
{
if (++uCount > uTime)
{
return;
}
}
}
错误的代码如下:
void USB_OTG_BSP_uDelay(const uint32_t usec)
{
const Uint32 uTime = (Uint32)120 * usec / 7;
__IO Uint32 uCount = 0;
while (1)
{
if (++uCount > uTime)
{
return;
}
}
}
附件是正常的与错误的反汇编截图,请大家指点!
本帖最后由 野马-425178 于 2017-5-12 12:51 编辑
做了些实验,发现情况是这样的:
USB_OTG_BSP_uDelay函数在优化后如果有调用LDR汇编指令的时候即满足设计微秒级延时要求,但如果优化后没有调用LDR指令则延时时间被缩短且不符合要求了;
ST库提供的原始代码在优化时刚好有调用LDR指令(因为该变量定义的顺序刚好使MDK优化时认为无法保存寄存器变量,需要每次LDR重载),所以就没有问题;
而我把变量定义顺序修改后,经过MDK优化则把LDR指令去掉了,但是MDK也没有错,因为uTime是const变量,如果优化策略认为不需要每次重载的时候就不需要LDR了,结果导致时间不准确。
实际上,最安全的做法应该是要使用“__IO”来修饰变量“uTime”,而不是用“const”。
版主的回复也是对的,因为这个函数设计的时候就是用const修饰了uTime变量(不一定每次都重新加载),所以LDR被优化掉也算是正常,而我正好又是需要这个指令的运行时间。
在阿莫上刚好有个帖子,关于MDK优化省略了LDR操作的问题,里面描述了和我这个问题很类似。
https://www.amobbs.com/thread-4214047-1-1.html
该网址下以下内容和我的问题类似:
1、你好,我发现如果那个while(unIdleCount!=200); 不是一个空等待的循环,(当然,里面不是的环就不是等待2Ms了,而是在这2MS里一直执行某个操作了),这样的话就不会出现这种情况了,在比较之前
会有一个LDR的操作,保证读取的是RAM里的数据,而这时我并没有用volatile修饰他,而且我的优化等级选的是最高的3也没关系
2、另一个,我发现,只要unIdleCount=0不是紧挨着下面那个判断语句,两句之间隔了一些函数,就算这些函数没有操作unIdleCount,在比较之前也会有那个LDR命令获得unIdleCount最新的值
22: TIM3_Int_Init(500,7199);//10Khz的计数频率,计数到5000为500ms
23:
0x08000A08 8820 LDRH r0,[r4,#0x00] //这条语句是在下面那个判断之前突然出现的,用来获得最新的值
24: while(unIdleCount!=10);
25:
0x08000A0A 280A CMP r0,#0x0A
0x08000A0C D1FD BNE 0x08000A0A
同样,这时我也没有用volatile修饰unIdleCount,那应该就是这时寄存器里面没有保存unIdleCount了,(因为这之前的操作保存不了了),所以会重新读,
3、后来我又脑残的做了几个实验,发现在unIdleCount=0;和while(unIdleCount!=10);之间相隔的有东西的时候,不管是函数(需要跳转)还是简单运算,只要编译器有办法用一个寄存器保存unIdleCount 的值
同时又能完成这之间的运算,他就会直接比较寄存器里面的值,(此时我任然选的是最高优化级别)我的是4.7版本的MDK。
于是我又重复了1里面说的,发现只要while里面有东西,哪怕简单得足以让可以保存unIdleCount的值,但是他也会每次都读取最新的值,
于是我真的有点感慨,真的很智能,(他的理念或许就是这样),完全没意义的事就不用每次都浪费时间和代码空间读取最新的值了,但是
真的有事要做的话就得严谨地每次读取最新的值看是不是满足条件,应不应该执行了,哈哈,说的优点多
一周热门 更多>