端點0是用來測試驅動最好的方法,我稍後會把linux下面的驅動心得放上來,這個哥們寫了如何發送資料:http://www.lcsky.org/2.0/node/43
控制傳輸在交換少量控制資訊的時候很有用,例如傳送指令、擷取下位機狀态等,通過Cypress标準固件架構可以很友善的使用控制傳輸,僅需在DR_VendorCmnd中加入自己的處理過程即可。如:
BOOL DR_VendorCmnd(void) {
switch(SETUPDAT[1]) {
case VR_1: //自定義指令1
do_something();
break;
case VR_2: //自定義指令2
do_something_else();
break;
default:
return(TRUE);
}
return(FALSE); // no error; command handled OK
}
控制傳輸分為三個階段。
1、SETUP階段,通過SETUPDAT的8位元組寄存器進行,
SETUPDAT[0] = bmRequestType
SETUPDAT[1] = bmRequest
SETUPDAT[2:3] = wValue
SETUPDAT[4:5] = wIndex
SETUPDAT[6:7] = wLength
傳輸我們自定義的指令時,bmRequestType不用處理;bmRequest為我們自定義的指令,上位機和下位機統一即可;wValue和wIndex我們可以自由使用,共4個位元組;wLength為接下來的“資料階段”的資料長度。
2、資料階段。本階段是可選的,如果我們傳輸的資料wValue和wIndex容納不下,或者需要從裝置讀取資訊,就需要通過資料階段進行,資料階段通過EP0BUF、EP0BCH、EP0BCL寄存器進行,資料階段一次可以傳輸64位元組的資料。
本階段常常被錯誤的使用,特别是從上位機傳輸資料到下位機時,錯誤使用造成一個奇怪的現象:需要連續傳輸兩次才能在緩沖區中得到正确的資料。以下是錯誤使用的例子:
case VR_1:
a = EP0BUF[0];
b = EP0BUF[1];
c = EP0BUF[2];
d = EP0BUF[3];
EP0BCH = 0;
SYNCDELAY;
EP0BCL = 0;
SYNCDELAY;
break;
這本意是從上位機得到一些資料,并且通過最後的EP0BCH = 0;EP0BCL = 0;告訴ez-usb已經讀取完畢,但實際上,這會導緻上述的問題。仔細看TRM,發現如下的一段話:
Some CONTROL transfers do not have a DATA stage. Therefore the 8051 code that processes the SETUP data should check the length field in the SETUP data (in the 8-byte buffer at SETUPDAT) and arm endpoint zero for the DATA phase (by loading IN0BC or OUT0BC) only if the length is non-zero.[1]
至此,傳輸兩次才能得到正确資料的疑惑解開了——下行資料需要通過EP0BCH和EP0BCL告知ez-usb,以啟動資料階段!改為下述代碼:
case VR_1:
//start data phase, see TRM 7.2
if (SETUPDAT[7] != 0 || SETUPDAT[6] != 0) {
EP0BCH = SETUPDAT[7];
SYNCDELAY;
EP0BCL = SETUPDAT[6];
SYNCDELAY;
while(EP0CS & bmEPBUSY);
}
a = EP0BUF[0];
b = EP0BUF[1];
c = EP0BUF[2];
d = EP0BUF[3];
break;
另外,無資料階段的傳輸不需要在最後使用EP0BCH = 0; EP0BCL = 0來“告訴ez-usb已經讀取完畢”。
3、狀态階段。通過EP0CS寄存器,告知上位機指令是否處理等資訊。如果未處理,通過EZUSB_STALL_EP0()告知上位機;通過EP0CS |= bmHSNAK;發送ack進行确認。(此階段不需我們處理,fw.c中已處理)
我補充下如何接收資料:
if(SETUPDAT[1]==0xd2) //自定義接收資料指令
{
for(j=0;j<64;j++)
EP0BUF[j]= 0x11;
for(j=0;j<10;j++)
EP0BUF[j]=j<5?0x55:0xAA;
for(;j<20;j++)
EP0BUF[j]=0xcc;
for(;j<30;j++)
EP0BUF[j]=0x88;
//
EP0BCH = 0;
EP0BCL = 40; //要發送的個數,最大隻有64個
return FALSE;
}
return TRUE;
注意:處理完非标準請求指令後要傳回false,否則固件會調用EZUSB_STALL_EP0(); 而電腦認為無效,出現類似:
Vendor Request failed
A device attached to the system is not functioning.
的錯誤提示。