原来发表于21ic,近期在重新整理并搬家,利用下EDN的博客备份,呵呵, 为了技术的完整性,顺便把香帅的讲解也拷贝过来了
以前只是和朋友合作写过USB的PC端应用层软件, 对USB的协议层及管道只是有一些基本的认识, 近期拿到了一个STM32的最小系统,也接一下USB出来学学固件制作,呵呵 看STM32的USB驱动,首先从中断服务函数看起, void USB_Istr(void) wIstr = _GetISTR(); // 取到USB中断的标志位 共处理了8个标志位,依次如下: #define ISTR_CTR (0x8000) /* Correct TRansfer (clear-only bit) */ 这里特别要一提的是:清除中断标志的方法,不能采用"读--修改--写"的办法: Read-modify-write cycles should be avoided because between the read and the write operations another bit could be set by the hardware and the next write will clear it before the microprocessor has the time to serve the event. it is recommended to clear them with a load instruction where all bits which must not be altered are written with 1, and all bits to be cleared are written with ‘0’ (为什么可以这样写呢?不会形成软件中断吗?-----当然不会,因为这个寄存器的位不是RW的,呵呵,而是RC的,我仔细看了好一会儿才发现的) ST的usb库为了与用户的应用衔接,采用了C的结构体+函数指针,这样应用时只需要接口DEVICE_PROP Device_Property 的函数,将这个函数填充完整后,即可更改应用了,,这样做一个很大好处时,应用时如果没有特别的应用,不用去关心USB的底层实现,在USB的库之上做应用是可行的.(不过,如果库本身有缺陷,那就郁闷了,偶初学,还是先看看再说) ,在USB的库里都是通过指针DEVICE_PROP *pProperty;来调用Device_Property里的函数实现的,该指针是在USB_Init()里初始化的. 初学嘛,异常的中断处理先略过了,直接看下正常的通信处理吧,都在函数:void CTR_LP(void)中实现, 这里发现了一个问题, _SetISTR((u16)CLR_CTR); /* clear CTR flag */ 这个位不是只读的吗?难不成是我的RM0008Reference manual太旧了??有空去查查了。 先往下看: EPindex = (u8)(wIstr & ISTR_EP_ID);得到端点号,这个可是很重要的噢,看USB一定要搞清楚什么是端点。 接下当然就是依端点的不同,进行不同的处理啦, 端点0一般用来做一些设置等,这是由协议保留确定的, 其他的都可以拿来做别的应用了,同样,这里还是用函数指针对应用留了接口: void (*pEpInt_OUT[7])(void) ; 根据你的需求去填写吧,嘿嘿。。 -----附注:目前我已经把USB的虚拟串口移植到我的STM32控制台上了 |
博主的判断是对的,你发现的问题确实存在,USB_ISTR的CTR位是只读位,_SetISTR((u16)CLR_CTR)这句话没有用。 实际上CTR位也不能在这个位置被清除,否则后面如何判断发生中断的端点号呢? 真正的清除中断是在随后读出EPindex,调用_ClearEP_CTR_TX或_ClearEP_CTR_RX的时候。 <><><><><><><><><><><><><><><><><><><><> 再看你发现的问题,这句话实际上可以被去掉,没用! 在内部,CTR位是所有端点的中断标志"或"起来得到的,接收端点的中断标志为USB_EPnR中CTR_RX,发送端点的中断标志为USB_EPnR中CTR_TX。 <><><><><><><><><><><><><><><><><><><><> 估计写这个库函数的工程师对这个USB设备还理解不够深入,所以出现了这样的错误。整个这个库的架构是十年前我们在第二个USB单片机(ST92163)时就确定的,以后一直延续到ST7的USB库、STR7和STR9的USB库,直至现在的STM32;多年下来证明这个架构是非常好用的。 |
用户94692 2008-7-30 11:47