下面象城管一样,逐一分拆每户。
wIstr=_GetISTR();得到中断的原因,这个根本不是函数,而是得到ISTR的值。
由于我们没有外挂复位,故外挂的复位就不进行了。我们只处理这个:voidVirtual_Com_Port_Reset(void),这个函数在usb_prop.c这个文件中。它的目的是恢复上电时的缺省设置。这个我们就不去深究了。因为好象也没有必要。
首先将全局变量pInformation(它定义在初始化中usb_init.c)中的配置值置为0表示设备还没配置过。(这个变量猜想应该在枚举之类的地方用于判断是否已枚举过)其次将当前的特征值赋值Virtual_Com_Port_ConfigDescriptor[7]。(含义先不管它)然后再将当前的通讯口设为端口0即pInformation-》Current_Interface=0;端口0大约就是控制口吧。
接下来设置缓冲表的地址或寄存器为00。这个我们暂不管它含义是什么放一边去。
再接下来,初始化三个端口,它们是端口0,1和2。其中端口0是控制口,端口1是发送口,端口3是接收口。
在.h中定义了缓冲区表的基地址为00,而端口0收为0x40,端口0的发为0x80,端口1的发地址为0xC0.端口2的发地址为0x100.端3的收地址为0x110.可以看到其缓冲区端口2的为16字节,其它的都为64字节。感觉ST公司太节省了点吧。这么短的包,如果用480M的超速的话怎么够?
最后一句:bDeviceState=ATTACHED;表示USB进入一个新状态。
接下来,看中断是否响应DMA上溢下溢,错误处理,唤醒、挂起中断我们都没有用到,故全部不看它。现在主要要看的一个终于出现了,它就是我们三个要响应的中断之一(三个中断分别是复位中断,帧头SOF中断,正确收发中断)SOF中断。这个表示帧的起始中断。不过这个中断的处理却是异常的简单,就是将这个SOF标志清除后再bIntPackSOF++;即可
当然最重要的总是在总后的,接下来的一个中断可要费点周章了。它就是正确的收发到数据的中断,它调用了CTR_LP()函数,这个函数它定义在usb_int.c中。我们重点解读它:这个程序名为低优先级正确接收中断
★首先这个中断是一个循环,它一直在等ISTR_CTR==0为止。因为当它等于0时,表示里面的数据已经全部取完。没取完它是不会罢休的。就象强盗进了金库要将它搬空为止,结果是阿里巴巴胜出一样。
★清除这个CTR标志位,为了这个,我们去看一下数据手册,庆幸是中文的看得快一点(如果老是这么想,也许是不幸的开始)。发现CTR标志位只是一个只读的位,要清除它,它能是去清除USB_EpnR中的对应位。所以为什么用一个while()的原因是中断一个处理完后,可能还有其它的中断未处理完,如果是这样的话,这个CTR位就一直是高电平。可是程序中却将ISTR的CTR位清除(在数据手册中它被说明为只读位)难道这是ST的一个小失误?别人不信,反正我是信了。
★根据端点的ID号(ISTR寄存器)决定它是控制端点0的响应呢还是其它端点的响应。原来控制端点0的响应在这里,估计枚举就在这里进行的吧。不过枚举过程我暂不想看,因为我相信ST会把所有的过程都给搞定的。读程序时,如果过分的分支再分支,最后就一无所有,有时要反复4~5遍才知道,如此就只好先舍去一些确定性的,象两平行线一定不相交的证明就不要看了。先看与要达到的目的密切相关的才行。如果要看枚举过程,“圈圈的教我玩USB”写得非常好,完全是由浅入深,建议买这本书看一看(赞一个,尽管不很深入,谈到教书育人,比清华的教授要强得多了,某些教授就是只会骗国家经费,找学生做事,大学搞出来的科研成果99%没有价值)。
★重点看其它端点的响应中断由于前面我们已经得知了ID号,我们就到对应的端点寄存器中去找,即臂如是端点2的响应,我们就到端点2的USB_EP2R中去找。看它是发送中断还是接收中断。它是B15位就是它的CTR_RX,如果不等于0说明它就是该端点的接收中断。
★接收中断处理的过程:
_ClearEP_CTR_RX(EPindex);///清除这个接收标志
(*pEpInt_OUT[EPindex-1])();///调用相应的接收中断的处理函数
注意这个函数数组的用法。它的定义如下:void(*pEpInt_OUT[7])(void)={
EP1_OUT_Callback,EP2_OUT_Callback,EP3_OUT_Callback,。。。
};回忆一下,大学C语言学过的函数的定义:void*function(void)学的时候没用功吧。其实,要是我来做的话,还不如用几个if语句来得简明。
★所幸,我们在这里只用到两个回调函数,只需看2个即可,一个是EP1_IN_Callback()另一个是EP3_OUT_Callback()
而EP1这个,只是执行这么简单的一句:count_in=0;这个是当串口向USB发时时,串口的数据,在串口中断中已经做了处理。它就是我们前面看过的:
buffer_in[count_in]=USART_ReceiveData(USART1);count_in++;
UserToPMABufferCopy(buffer_in,ENDP1_TXADDR,count_in);SetEPTxCount(ENDP1,count_in);SetEPTxValid(ENDP1);
如果串口上我们连一个键盘,当敲打它时,就产生了串口中断,这个中断中将数据接收好,然后拷到缓冲区中(这是一个64字节的缓冲区)然后只需设置EP1的长度,开始发送就可以了。注意到这个发送字节的个数的寄存器在缓冲区中的某个地方。它在[USB_BTABLE]+n×16+4处。这点还请参考数据手册。
SetEPTxValid(ENDP1)这个函数还有点烦。要是将它全面解剖开来,就有下列东东:(为简化起见,中间的一些变量我用实际的数表表示了)#define_SetEPTxStatus(1,0x0030){\////我们这里是将两位都置为11
registeru16_wRegVal;\
_wRegVal=_GetENDPOINT(1)&EPTX_DTOGMASK;\///这个数就是0x0030/*togglefirstbit?*/\if((EPTX_DTOG1&wState)!=0)\///如果原来的值不为0_wRegVal^=EPTX_DTOG1;
\///异或一下即原来如果为0则变为1而如果已经是1了就变为0---已经为1就不能再发了
/*togglesecondbit?*/\if((EPTX_DTOG2&wState)!=0)\///第5位也是如此做_wRegVal^=EPTX_DTOG2;\_SetENDPOINT(bEpNum,_wRegVal);\}
于我我们就知道,如果原来的STAT_TX[1:0](位于第5,4位就是0x0030处)就是为00的,则我们就置这个STAT_TX[1:0]=11发送就成功了。而如果原来就是11,则置为00。意味着发送就失败了。原来为01就变为10,原来为10就变为01。而01代表的是STALL。10代表的是NAK。具体为什么要这样,这个STALL,NAK在USB中的含义到现在有点模糊,可参考圈圈的书。但精确的在这里的含义还有待以后再弄清楚
评论