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