端点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.
的错误提示。