📄 usb in a nutshell - chapter 7 - pdiusbd11 and pic16f87x example.htm
字号:
packet and issue an ACK before we can change the address. Otherwise
the device may never see the IN token being sent on the default
address. </P>
<P>The completion of the status stage is signalled by an interrupt on
EP0 IN. In order to differentiate between a set address response and a
normal EP0_IN interrupt we set a variable, CtlTransferInProgress to
PROGRESS_ADDRESS. In the EP0 IN handler a check is made of
CtlTransferInProgress. If it equals PROGRESS_ADDRESS then the Set
Address Enable command is issued to the PDIUSBD11 and
CtlTransferInProgress is set to PROGRESS_IDLE. The host gives 2ms for
the device to change its address before the next command is sent. </P><PRE> case GET_DESCRIPTOR:
GetDescriptor(&SetupPacket);
break;
case GET_CONFIGURATION:
D11WriteEndpoint(D11_ENDPOINT_EP0_IN, &DeviceConfigured, 1);
break;
case SET_CONFIGURATION:
printf("Set Configuration\n\r");
DeviceConfigured = SetupPacket.wValue & 0xFF;
D11WriteEndpoint(D11_ENDPOINT_EP0_IN, NULL, 0);
if (DeviceConfigured) {
RB3 = 0;
printf("\n\r *** Device Configured *** \n\r");
}
else {
RB3 = 1; /* Device Not Configured */
printf("\n\r ** Device Not Configured *** \n\r");
}
break;
//case SET_DESCRIPTOR:
default:
/* Unsupported - Request Error - Stall */
ErrorStallControlEndPoint();
break;
}
break;
</PRE>
<P>The Get Configuration and Set Configuration is used to "enable" the
USB device allowing data to be transferred on endpoints other than
endpoint zero. Set Configuration should be issued with wValue equal to
that of a bConfigurationValue of the configuration you want to enable.
In our case we only have one configuration, configuration 1. A zero
configuration value means the device is not configured while a
non-zero configuration value indicates the device is configured. The
code does not fully type check the configuration value, it only copies
it into a local storage variable, DeviceConfigured. If the value in
wValue does not match the bConfigurationValue of a Configuration, it
should return with a USB Request Error. </P><PRE> case STANDARD_INTERFACE_REQUEST:
printf("Standard Interface Request\n\r");
switch (SetupPacket.bRequest) {
case GET_STATUS:
/* Get Status Request to Interface should return */
/* Zero, Zero (Reserved for future use) */
Buffer[0] = 0x00;
Buffer[1] = 0x00;
D11WriteEndpoint(D11_ENDPOINT_EP0_IN, Buffer, 2);
break;
case SET_INTERFACE:
/* Device Only supports default setting, Stall may be */
/* returned in the status stage of the request */
if (SetupPacket.wIndex == 0 && SetupPacket.wValue == 0)
/* Interface Zero, Alternative Setting = 0 */
D11WriteEndpoint(D11_ENDPOINT_EP0_IN, NULL, 0);
else ErrorStallControlEndPoint();
break;
case GET_INTERFACE:
if (SetupPacket.wIndex == 0) { /* Interface Zero */
Buffer[0] = 0; /* Alternative Setting */
D11WriteEndpoint(D11_ENDPOINT_EP0_IN, Buffer, 1);
break;
} /* else fall through as RequestError */
//case CLEAR_FEATURE:
//case SET_FEATURE:
/* Interface has no defined features. Return RequestError */
default:
ErrorStallControlEndPoint();
break;
}
break;
</PRE>
<P>Of the Standard Interface Requests, none perform any real function.
The Get Status request must return a word of zero and is reserved for
future use. The Set Interface and Get Interface requests are used with
alternative Interface Descriptors. We have not defined any alternative
Interface Descriptors so Get Interface returns zero and any request to
Set an interface other than to set interface zero with an alternative
setting of zero is processed with a Request Error. </P><PRE> case STANDARD_ENDPOINT_REQUEST:
printf("Standard Endpoint Request\n\r");
switch (SetupPacket.bRequest) {
case CLEAR_FEATURE:
case SET_FEATURE:
/* Halt(Stall) feature required to be implemented on all Interrupt and */
/* Bulk Endpoints. It is not required nor recommended on the Default Pipe */
if (SetupPacket.wValue == ENDPOINT_HALT)
{
if (SetupPacket.bRequest == CLEAR_FEATURE) Buffer[0] = 0x00;
else Buffer[0] = 0x01;
switch (SetupPacket.wIndex & 0xFF) {
case 0x01 : D11CmdDataWrite(D11_SET_ENDPOINT_STATUS + \
D11_ENDPOINT_EP1_OUT, Buffer, 1);
break;
case 0x81 : D11CmdDataWrite(D11_SET_ENDPOINT_STATUS + \
D11_ENDPOINT_EP1_IN, Buffer, 1);
break;
case 0x02 : D11CmdDataWrite(D11_SET_ENDPOINT_STATUS + \
D11_ENDPOINT_EP2_OUT, Buffer, 1);
break;
case 0x82 : D11CmdDataWrite(D11_SET_ENDPOINT_STATUS + \
D11_ENDPOINT_EP2_IN, Buffer, 1);
break;
case 0x03 : D11CmdDataWrite(D11_SET_ENDPOINT_STATUS + \
D11_ENDPOINT_EP3_OUT, Buffer, 1);
break;
case 0x83 : D11CmdDataWrite(D11_SET_ENDPOINT_STATUS + \
D11_ENDPOINT_EP3_IN, Buffer, 1);
break;
default : /* Invalid Endpoint - RequestError */
ErrorStallControlEndPoint();
break;
}
D11WriteEndpoint(D11_ENDPOINT_EP0_IN, NULL, 0);
} else {
/* No other Features for Endpoint - Request Error */
ErrorStallControlEndPoint();
}
break;
</PRE>
<P>The Set Feature and Clear Feature requests are used to set endpoint
specific features. The standard defines one endpoint feature selector,
ENDPOINT_HALT. We check what endpoint the request is directed to and
set/clear the STALL bit accordingly. This HALT feature is not required
on the default endpoints. </P><PRE> case GET_STATUS:
/* Get Status Request to Endpoint should return */
/* Halt Status in D0 for Interrupt and Bulk */
switch (SetupPacket.wIndex & 0xFF) {
case 0x01 : D11CmdDataRead(D11_READ_ENDPOINT_STATUS + \
D11_ENDPOINT_EP1_OUT, Buffer, 1);
break;
case 0x81 : D11CmdDataRead(D11_READ_ENDPOINT_STATUS + \
D11_ENDPOINT_EP1_IN, Buffer, 1);
break;
case 0x02 : D11CmdDataRead(D11_READ_ENDPOINT_STATUS + \
D11_ENDPOINT_EP2_OUT, Buffer, 1);
break;
case 0x82 : D11CmdDataRead(D11_READ_ENDPOINT_STATUS + \
D11_ENDPOINT_EP2_IN, Buffer, 1);
break;
case 0x03 : D11CmdDataRead(D11_READ_ENDPOINT_STATUS + \
D11_ENDPOINT_EP3_OUT, Buffer, 1);
break;
case 0x83 : D11CmdDataRead(D11_READ_ENDPOINT_STATUS + \
D11_ENDPOINT_EP3_IN, Buffer, 1);
break;
default : /* Invalid Endpoint - RequestError */
ErrorStallControlEndPoint();
break;
}
if (Buffer[0] & 0x08) Buffer[0] = 0x01;
else Buffer[0] = 0x00;
Buffer[1] = 0x00;
D11WriteEndpoint(D11_ENDPOINT_EP0_IN, Buffer, 2);
break;
default:
/* Unsupported - Request Error - Stall */
ErrorStallControlEndPoint();
break;
}
break;
</PRE>
<P>The Get Status request when directed to the endpoint returns the
status of the endpoint, ie. if it is halted or not. Like the Set/Clear
feature request ENDPOINT_HALT, we only need to report the status of
the generic endpoints. </P>
<P>Any undefined Standard Endpoint Requests are handled by USB Request
Error. </P><PRE> case VENDOR_DEVICE_REQUEST:
case VENDOR_ENDPOINT_REQUEST:
printf("Vendor Device bRequest = 0x%X, wValue = 0x%X, wIndex = 0x%X\n\r", \
SetupPacket.bRequest, SetupPacket.wValue, SetupPacket.wIndex);
switch (SetupPacket.bRequest) {
case VENDOR_GET_ANALOG_VALUE:
printf("Get Analog Value, Channel %x :",SetupPacket.wIndex & 0x07);
ADCON0 = 0xC1 | (SetupPacket.wIndex & 0x07) << 3;
/* Wait Acquistion time of Sample and Hold */
for (a = 0; a <= 255; a++);
ADGO = 1;
while(ADGO);
Buffer[0] = ADRESL;
Buffer[1] = ADRESH;
a = (Buffer[1] << 8) + Buffer[0];
a = (a * 500) / 1024;
printf(" Value = %d.%02d\n\r",(unsigned int)a/100,(unsigned int)a%100);
D11WriteEndpoint(D11_ENDPOINT_EP0_IN, Buffer, 2);
break;
</PRE>
<P>Now comes the functional parts of the USB device. The Vendor
Requests can be dreamed up by the designer. We have dreamed up two
requests, VENDOR_GET_ANALOG_VALUE and VENDOR_SET_RB_HIGH_NIBBLE.
VENDOR_GET_ANALOG_VALUE reads the 10-bit Analog Value on Channel x
dictated by wIndex. This is ANDed with 0x07 to allow 8 possible
channels, supporting the larger PIC16F877 if required. The analog
value is returned in a two byte data packet. </P><PRE> case VENDOR_SET_RB_HIGH_NIBBLE:
printf("Write High Nibble of PORTB\n\r");
PORTB = (PORTB & 0x0F) | (SetupPacket.wIndex & 0xF0);
D11WriteEndpoint(D11_ENDPOINT_EP0_IN, NULL, 0);
break;
default:
ErrorStallControlEndPoint();
break;
}
break;
</PRE>
<P>The VENDOR_SET_RB_HIGH_NIBBLE can be used to set the high nibble
bits of PORTB[3:7]. </P><PRE> default:
printf("UnSupported Request Type 0x%X\n\r",SetupPacket.bmRequestType);
ErrorStallControlEndPoint();
break;
}
} else {
printf("Data Packet?\n\r");
/* This is a Data Packet */
}
}
</PRE>
<P>Any unsupported request types such as class device request, class
interface request etc is dealt with by a USB Request Error. </P><PRE>void GetDescriptor(PUSB_SETUP_REQUEST SetupPacket)
{
switch((SetupPacket->wValue & 0xFF00) >> 8) {
case TYPE_DEVICE_DESCRIPTOR:
printf("\n\rDevice Descriptor: Bytes Asked For %d, Size of Descriptor %d\n\r", \
SetupPacket->wLength,DeviceDescriptor.bLength);
pSendBuffer = (const unsigned char *)&DeviceDescriptor;
BytesToSend = DeviceDescriptor.bLength;
if (BytesToSend > SetupPacket->wLength)
BytesToSend = SetupPacket->wLength;
WriteBufferToEndPoint();
break;
case TYPE_CONFIGURATION_DESCRIPTOR:
printf("\n\rConfiguration Descriptor: Bytes Asked For %d, Size of Descriptor %d\n\r", \
SetupPacket->wLength, sizeof(ConfigurationDescriptor));
pSendBuffer = (const unsigned char *)&ConfigurationDescriptor;
BytesToSend = sizeof(ConfigurationDescriptor);
if (BytesToSend > SetupPacket->wLength)
BytesToSend = SetupPacket->wLength;
WriteBufferToEndPoint();
break;
</PRE>
<P>The Get Descriptor requests involve responses greater than the 8
byte maximum packet size limit of the endpoint. Therefore they must be
broken up into 8 byte chunks. Both the Device and Configuration
requests load the address of the relevant descriptors into pSendBuffer
and sets the BytesToSend to the length of the descriptor. The request
will also specify a descriptor length in wLength specifying the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -