本帖最后由 Simon21ic 于 2013-6-10 17:56 编辑
貌似之前我提到的BUG还原封不动,经过一年多了,不确定有多少人理解这个BUG,那就公布这个BUG的原理吧。
原帖在这里:https://bbs.21ic.com/forum.php?mod=viewthread&tid=305774
首先,看一下USB endpoint寄存器的定义:
在看一下ST最新版本的库中的代码:
#define _ClearEP_CTR_RX(bEpNum) (_SetENDPOINT(bEpNum,\
_GetENDPOINT(bEpNum) & 0x7FFF & EPREG_MASK))
#define _ClearEP_CTR_TX(bEpNum) (_SetENDPOINT(bEpNum,\
_GetENDPOINT(bEpNum) & 0xFF7F & EPREG_MASK))
#define _SetENDPOINT(bEpNum,wRegValue) (*(EP0REG + bEpNum)= \
(uint16_t)wRegValue)
#define _GetENDPOINT(bEpNum) ((uint16_t)(*(EP0REG + bEpNum)))
#define EPREG_MASK (EP_CTR_RX|EP_SETUP|EP_T_FIELD|EP_KIND|EP_CTR_TX|EPADDR_FIELD)
拿_ClearEP_CTR_RX举例,按照代码,貌似这个宏的功能是清零CTR_RX位,并且需要把toggle的位清零(因为写1toggle)。
当然,第一个问题,wRegValue没有加括号,如果由于这个产生问题,相信你会相当郁闷,呵呵,不过,关键还不在这里。
关键问题在于,标准的“读-修改-写”的问题。
首先,会读取USB_EPnR寄存器,假定读取到的CTR_RX为1,CTR_TX为0。
之后处理后,调用_ClearEP_CTR_RX来清零CTR_RX位,貌似都很正常。
但是,如果之后把修改好的值写回USB_EPnR寄存器的时候,USB外设把CTR_TX置1了,那这个写操作会把CTR_TX也清零,并且实际数据都没有处理,现象就是TX端口死了,在USB中断不能及时得到相应的时候,这个问题会以一个比较小的概率出现,测试时间长的话,几乎肯定会碰到。
由于CTR_TX是写0清零,写1没有影响,那么实际的定义应该为:
#define _ClearEP_CTR_RX(bEpNum) (_SetENDPOINT(bEpNum,\
(_GetENDPOINT(bEpNum) & 0x7FFF & EPREG_MASK) | EP_CTR_TX))
|