控制传输分为三个阶段。
1、SETUP阶段,通过SETUPDAT的8字节寄存器进行,
SETUPDAT[0] = bmRequestType
SETUPDAT[1] = bmRequest
SETUPDAT[2:3] = wValue //CyConsole之EZ-USB界面时,为低位在后,高位在前。
SETUPDAT[4:5] = wIndex //CyConsole之EZ-USB界面时,为低位在后,高位在前。
SETUPDAT[6:7] = wLength
传输我们自定义的命令时,bmRequestType不用处理;bmRequest为我们自定义的命令,上位机和下位机统一即可;wValue和wIndex我们可以自由使用,共4个字节;wLength为接下来的“数据阶段”的数据长度。
2、数据阶段。本阶段是可选的,如果我们传输的数据wValue和wIndex容纳不下,或者需要从设备读取信息,就需要通过数据阶段进行,数据阶段通过EP0BUF、EP0BCH、EP0BCL寄存器进行,数据阶段一次可以传输64字节的数据。
本阶段常常被错误的使用,特别是从上位机传输数据到下位机时,错误使用造成一个奇怪的现象:需要连续传输两次才能在缓冲区中得到正确的数据。以下是错误使用的例子:
//R1项目68013a固件。主正小角。
case 0xCA:
{
Degree_Count = EP0BUF[0]*0x10000+EP0BUF[1]*0x100+EP0BUF[2];
CW_Fine();
EP0BUF[0] = 0x10;
EP0BUF[1] = 0x24;
EP0BCH = 0;
EP0BCL = 2;
}
break;
这本意是从上位机得到Degree_Count,并且返回0x1024,但实际上,这会导致上述的问题。仔细看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,以启动数据阶段!改为下述代码:
//R1项目68013a固件。主正小角。
case 0xCA:
{
//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);
}
Degree_Count = (EP0BUF[0]<<16)|(EP0BUF[1]<<8)|EP0BUF[2];
CW_Fine();
EP0BUF[0] = 10;
EP0BUF[1] = 24;
EP0BCH = 0;
EP0BCL = 3;
}
另外,无数据阶段的传输不需要在最后使用EP0BCH = 0; EP0BCL = 0来“告诉ez-usb已经读取完毕”。
3、状态阶段。通过EP0CS寄存器,告知上位机命令是否处理等信息。如果未处理,通过EZUSB_STALL_EP0()告知上位机;通过EP0CS |= bmHSNAK;发送ack进行确认。(此阶段不需我们处理,fw.c中已处理)
When the firmware completes its housekeeping operations, it clears the HSNAK bit (by writing ‘1’ to it), which instructs the EZ-USB to ACK the STATUS stage, terminating the transfer. This handshake prevents the host from attempting to use an interface before it is fully configured. [2]
[1] EZ-USB TRM 7.2, P115
[2] EZ-USB TRM 2.2, P37