下面象城管一樣,逐一分拆每戶。
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上溢下溢,錯誤處理,喚醒、掛起中斷我們都沒有用到,故全部不看它?,F在主要要看的一個終于出現了,它就是我們三個要響應的中斷之一(三個中斷分別是復位中斷,幀頭SOF中斷,正確收發中斷)SOF中斷。這個表示幀的起始中斷。不過這個中斷的處理卻是異常的簡單,就是將這個SOF標志清除后再bIntPackSOF++;即可
當然最重要的總是在總后的,接下來的一個中斷可要費點周章了。它就是正確的收發到數據的中斷,它調用了CTR_LP()函數,這個函數它定義在usb_int.c中。我們重點解讀它:這個程序名為低優先級正確接收中斷
★首先這個中斷是一個循環,它一直在等ISTR_CTR==0為止。因為當它等于0時,表示里面的數據已經全部取完。沒取完它是不會罷休的。就象強盜進了金庫要將它搬空為止,結果是阿里巴巴勝出一樣。
★清除這個CTR標志位,為了這個,我們去看一下數據手冊,慶幸是中文的看得快一點(如果老是這么想,也許是不幸的開始)。發現CTR標志位只是一個只讀的位,要清除它,它能是去清除USB_EpnR中的對應位。所以為什么用一個while()的原因是中斷一個處理完后,可能還有其它的中斷未處理完,如果是這樣的話,這個CTR位就一直是高電平??墒浅绦蛑袇s將ISTR的CTR位清除(在數據手冊中它被說明為只讀位)難道這是ST的一個小失誤?別人不信,反正我是信了。
★根據端點的ID號(ISTR寄存器)決定它是控制端點0的響應呢還是其它端點的響應。原來控制端點0的響應在這里,估計枚舉就在這里進行的吧。不過枚舉過程我暫不想看,因為我相信ST會把所有的過程都給搞定的。讀程序時,如果過分的分支再分支,最后就一無所有,有時要反復4~5遍才知道,如此就只好先舍去一些確定性的,象兩平行線一定不相交的證明就不要看了。先看與要達到的目的密切相關的才行。如果要看枚舉過程,“圈圈的教我玩USB”寫得非常好,完全是由淺入深,建議買這本書看一看(贊一個,盡管不很深入,談到教書育人,比清華的教授要強得多了,某些教授就是只會騙國家經費,找學生做事,大學搞出來的科研成果99%沒有價值)。
★重點看其它端點的響應中斷由于前面我們已經得知了ID號,我們就到對應的端點寄存器中去找,即臂如是端點2的響應,我們就到端點2的USB_EP2R中去找??此前l送中斷還是接收中斷。它是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中的含義到現在有點模糊,可參考圈圈的書。但精確的在這里的含義還有待以后再弄清楚
評論
查看更多