1.首先,强烈建议按如下规则执行定义和赋值(越是新的编译器越是会消弱这种规则,比如MDK-ARM V5):1.1.在块开始的地方,首先定义变量,既在做任何赋值运算前定义完所有变量!
1.2.注意是块,没说是一定是函数头,但函数头确实是一个块开始的地方。另外,凡是左花括号“{”开始的地方都是块开始的地方。
在块开始的地方先定义变量,再执行赋值语句。
2.如下图:
uCount是定义时给了初值,这是定义不是赋值。uTime是在定义时有个计算过程,usec不是确定的值,在翻译为汇编时必然有个计算过程,语法看起来是定义时给了初值,但其中有个计算过程,这个计算过程如果在定义uCount之前执行的话,就违反了上述的第1条。所以请按照第1条写代码。
3.如下图:
看为什么会出错(我的理解,可以讨论)!
在0x08024984地址处的代码是往r1写了0,然后在0x08024986地址处存入内存该r1=0;在0x08024988地址处执行了r1+=1;此时r1=1,接着在0x0802498a地址处存入内存该r1,此时存入内存内r1=1;然后在0x0802498c地址处判断r1和r0,r0既是uTime的值;显然r1小于r0,在0x0802498e地址处跳到了0x08024988地址处,此时r1=2,再在0x0802498a地址处存入内存!和正确的汇编代码比较后你会发现此错误的汇编总是存入内存而没有从内存读!没有读内存也没什么问题,因为r1总是正确的加1了,只是缺少了一个从内存中读出r1再加的过程,这个看似“多此一举”的动作为什么会那么重要呢?
显然“错误”的汇编没有按照__IO(既:volatile)的属性来处理r1(只完成了一半:存)!
按照volatile的规则,每次都需要从ram中(而不是寄存器中)读写数据,那么按此规则执行一定是正确的,否则可能会出现问题。
楼主可以再看下,该delay函数退出时r1的值是多少?以及谁会打断该函数?
最后,建议使用最新的编译器和ST官方的代码!!
HAL最新的usb-host中没有该USB_OTG_BSP_uDelay函数的使用,都是用的HAL_DELAY函数:
使用HAL_Delay:
本帖最后由 野马-425178 于 2017-5-12 15:10 编辑
moyanming2013 发表于 2017-5-12 13:55
1.首先,强烈建议按如下规则执行定义和赋值(越是新的编译器越是会消弱这种规则,比如MDK-ARM V5):1.1.在 ...
解释的非常精辟,感谢高手指点,我还以为自己找到原因了,看来还得继续深究:)
1:USB_OTG_BSP_uDelay函数退出时uTime=0x33,uCount=0x34;
2:因为项目移植HAL库改动较多风险也较大,所以暂时沿用标准库。
3:项目中我使用2个USB分别作为host和device,这2个USB都使用这个延时函数,是否会重入还不确定,另外中断源较多,运行中被中断基本是必然的,但只要时间不缩短是没有问题。
4:对于你的分析,我的问题是既然uCount是__IO,为什么MDK在优化后只存不取呢?(是因为没有按照你说的1.1,1.2规则来写代码引起的吗)?
也就是说,如果没有按照那个规则来定义变量,MDK就可能忽略这个__IO要求(我目前使用的是MDK5.23.0)?
严格的函数写法应该如下,对么?
void USB_OTG_BSP_uDelay(const uint32_t usec)
{
__IO Uint32 uTime, uCount;
uCount = 0;
uTime = (Uint32)120 * usec / 7;
do
{
if (++uCount > uTime)
{
return;
}
}
while (1);
}
下面是这个改法后的反汇编截图:
野马-425178 发表于 2017-5-12 14:56
解释的非常精辟,感谢高手指点,我还以为自己找到原因了,看来还得继续深究:)
1:USB_OTG_BSP_uDelay函 ...
显然的,你这么写后,47EE处开始的代码和其循环,总是把值从ram中取出,然后加,又存到了ram,最后比较,如此循环,这个是没问题的。 我想请教一下楼主keil优化等级选择3稳定吗?产品中应该选几
页:
1
[2]