下面象城管一樣,逐一分拆每戶。
wIstr=_GetISTR();得到中斷的原因,這個根本不是函數(shù),而是得到ISTR的值。
由于我們沒有外掛復(fù)位,故外掛的復(fù)位就不進行了。我們只處理這個:voidVirtual_Com_Port_Reset(void),這個函數(shù)在usb_prop.c這個文件中。它的目的是恢復(fù)上電時的缺省設(shè)置。這個我們就不去深究了。因為好象也沒有必要。
首先將全局變量pInformation(它定義在初始化中usb_init.c)中的配置值置為0表示設(shè)備還沒配置過。(這個變量猜想應(yīng)該在枚舉之類的地方用于判斷是否已枚舉過)其次將當前的特征值賦值Virtual_Com_Port_ConfigDescriptor[7]。(含義先不管它)然后再將當前的通訊口設(shè)為端口0即pInformation-》Current_Interface=0;端口0大約就是控制口吧。
接下來設(shè)置緩沖表的地址或寄存器為00。這個我們暫不管它含義是什么放一邊去。
再接下來,初始化三個端口,它們是端口0,1和2。其中端口0是控制口,端口1是發(fā)送口,端口3是接收口。
在.h中定義了緩沖區(qū)表的基地址為00,而端口0收為0x40,端口0的發(fā)為0x80,端口1的發(fā)地址為0xC0.端口2的發(fā)地址為0x100.端3的收地址為0x110.可以看到其緩沖區(qū)端口2的為16字節(jié),其它的都為64字節(jié)。感覺ST公司太節(jié)省了點吧。這么短的包,如果用480M的超速的話怎么夠?
最后一句:bDeviceState=ATTACHED;表示USB進入一個新狀態(tài)。
接下來,看中斷是否響應(yīng)DMA上溢下溢,錯誤處理,喚醒、掛起中斷我們都沒有用到,故全部不看它?,F(xiàn)在主要要看的一個終于出現(xiàn)了,它就是我們?nèi)齻€要響應(yīng)的中斷之一(三個中斷分別是復(fù)位中斷,幀頭SOF中斷,正確收發(fā)中斷)SOF中斷。這個表示幀的起始中斷。不過這個中斷的處理卻是異常的簡單,就是將這個SOF標志清除后再bIntPackSOF++;即可
當然最重要的總是在總后的,接下來的一個中斷可要費點周章了。它就是正確的收發(fā)到數(shù)據(jù)的中斷,它調(diào)用了CTR_LP()函數(shù),這個函數(shù)它定義在usb_int.c中。我們重點解讀它:這個程序名為低優(yōu)先級正確接收中斷
★首先這個中斷是一個循環(huán),它一直在等ISTR_CTR==0為止。因為當它等于0時,表示里面的數(shù)據(jù)已經(jīng)全部取完。沒取完它是不會罷休的。就象強盜進了金庫要將它搬空為止,結(jié)果是阿里巴巴勝出一樣。
★清除這個CTR標志位,為了這個,我們?nèi)タ匆幌聰?shù)據(jù)手冊,慶幸是中文的看得快一點(如果老是這么想,也許是不幸的開始)。發(fā)現(xiàn)CTR標志位只是一個只讀的位,要清除它,它能是去清除USB_EpnR中的對應(yīng)位。所以為什么用一個while()的原因是中斷一個處理完后,可能還有其它的中斷未處理完,如果是這樣的話,這個CTR位就一直是高電平。可是程序中卻將ISTR的CTR位清除(在數(shù)據(jù)手冊中它被說明為只讀位)難道這是ST的一個小失誤?別人不信,反正我是信了。
★根據(jù)端點的ID號(ISTR寄存器)決定它是控制端點0的響應(yīng)呢還是其它端點的響應(yīng)。原來控制端點0的響應(yīng)在這里,估計枚舉就在這里進行的吧。不過枚舉過程我暫不想看,因為我相信ST會把所有的過程都給搞定的。讀程序時,如果過分的分支再分支,最后就一無所有,有時要反復(fù)4~5遍才知道,如此就只好先舍去一些確定性的,象兩平行線一定不相交的證明就不要看了。先看與要達到的目的密切相關(guān)的才行。如果要看枚舉過程,“圈圈的教我玩USB”寫得非常好,完全是由淺入深,建議買這本書看一看(贊一個,盡管不很深入,談到教書育人,比清華的教授要強得多了,某些教授就是只會騙國家經(jīng)費,找學(xué)生做事,大學(xué)搞出來的科研成果99%沒有價值)。
★重點看其它端點的響應(yīng)中斷由于前面我們已經(jīng)得知了ID號,我們就到對應(yīng)的端點寄存器中去找,即臂如是端點2的響應(yīng),我們就到端點2的USB_EP2R中去找??此前l(fā)送中斷還是接收中斷。它是B15位就是它的CTR_RX,如果不等于0說明它就是該端點的接收中斷。
★接收中斷處理的過程:
_ClearEP_CTR_RX(EPindex);///清除這個接收標志
?。?pEpInt_OUT[EPindex-1])();///調(diào)用相應(yīng)的接收中斷的處理函數(shù)
注意這個函數(shù)數(shù)組的用法。它的定義如下:void(*pEpInt_OUT[7])(void)={
EP1_OUT_Callback,EP2_OUT_Callback,EP3_OUT_Callback,。。。
};回憶一下,大學(xué)C語言學(xué)過的函數(shù)的定義:void*function(void)學(xué)的時候沒用功吧。其實,要是我來做的話,還不如用幾個if語句來得簡明。
★所幸,我們在這里只用到兩個回調(diào)函數(shù),只需看2個即可,一個是EP1_IN_Callback()另一個是EP3_OUT_Callback()
而EP1這個,只是執(zhí)行這么簡單的一句:count_in=0;這個是當串口向USB發(fā)時時,串口的數(shù)據(jù),在串口中斷中已經(jīng)做了處理。它就是我們前面看過的:
buffer_in[count_in]=USART_ReceiveData(USART1);count_in++;
UserToPMABufferCopy(buffer_in,ENDP1_TXADDR,count_in);SetEPTxCount(ENDP1,count_in);SetEPTxValid(ENDP1);
如果串口上我們連一個鍵盤,當敲打它時,就產(chǎn)生了串口中斷,這個中斷中將數(shù)據(jù)接收好,然后拷到緩沖區(qū)中(這是一個64字節(jié)的緩沖區(qū))然后只需設(shè)置EP1的長度,開始發(fā)送就可以了。注意到這個發(fā)送字節(jié)的個數(shù)的寄存器在緩沖區(qū)中的某個地方。它在[USB_BTABLE]+n×16+4處。這點還請參考數(shù)據(jù)手冊。
SetEPTxValid(ENDP1)這個函數(shù)還有點煩。要是將它全面解剖開來,就有下列東東:(為簡化起見,中間的一些變量我用實際的數(shù)表表示了)#define_SetEPTxStatus(1,0x0030){\////我們這里是將兩位都置為11
registeru16_wRegVal;\
_wRegVal=_GetENDPOINT(1)&EPTX_DTOGMASK;\///這個數(shù)就是0x0030/*togglefirstbit?*/\if((EPTX_DTOG1&wState)!=0)\///如果原來的值不為0_wRegVal^=EPTX_DTOG1;
\///異或一下即原來如果為0則變?yōu)?而如果已經(jīng)是1了就變?yōu)?---已經(jīng)為1就不能再發(fā)了
/*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發(fā)送就成功了。而如果原來就是11,則置為00。意味著發(fā)送就失敗了。原來為01就變?yōu)?0,原來為10就變?yōu)?1。而01代表的是STALL。10代表的是NAK。具體為什么要這樣,這個STALL,NAK在USB中的含義到現(xiàn)在有點模糊,可參考圈圈的書。但精確的在這里的含義還有待以后再弄清楚
評論