2 FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
\r
5 ***************************************************************************
\r
7 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
8 * Complete, revised, and edited pdf reference manuals are also *
\r
11 * Purchasing FreeRTOS documentation will not only help you, by *
\r
12 * ensuring you get running as quickly as possible and with an *
\r
13 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
14 * the FreeRTOS project to continue with its mission of providing *
\r
15 * professional grade, cross platform, de facto standard solutions *
\r
16 * for microcontrollers - completely free of charge! *
\r
18 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
20 * Thank you for using FreeRTOS, and thank you for your support! *
\r
22 ***************************************************************************
\r
25 This file is part of the FreeRTOS distribution.
\r
27 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
28 the terms of the GNU General Public License (version 2) as published by the
\r
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
30 >>>NOTE<<< The modification to the GPL is included to allow you to
\r
31 distribute a combined work that includes FreeRTOS without being obliged to
\r
32 provide the source code for proprietary components outside of the FreeRTOS
\r
33 kernel. FreeRTOS is distributed in the hope that it will be useful, but
\r
34 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
35 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
36 more details. You should have received a copy of the GNU General Public
\r
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
\r
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
\r
39 by writing to Richard Barry, contact details for whom are available on the
\r
44 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
47 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
50 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
51 licensing and training services.
\r
55 Sample interrupt driven USB device driver. This is a minimal implementation
\r
56 for demonstration only. Although functional, it is not a full and compliant
\r
59 The USB device enumerates as a simple 3 axis joystick, and once configured
\r
60 transmits 3 axis of data which can be viewed from the USB host machine.
\r
62 This file implements the USB interrupt service routine, and a demo FreeRTOS
\r
63 task. The interrupt service routine handles the USB hardware - taking a
\r
64 snapshot of the USB status at the point of the interrupt. The task receives
\r
65 the status information from the interrupt for processing at the task level.
\r
67 See the FreeRTOS.org WEB documentation for more information.
\r
73 + Descriptors that have a length that is an exact multiple of usbFIFO_LENGTH
\r
74 can now be transmitted. To this end an extra parameter has been
\r
75 added to the prvSendControlData() function, and the state
\r
76 eSENDING_EVEN_DESCRIPTOR has been introduced. Thanks to Scott Miller for
\r
77 assisting with this contribution.
\r
81 + Replaced the duplicated RX_DATA_BK0 in the interrupt mask with the
\r
85 /* Standard includes. */
\r
88 /* Demo board includes. */
\r
91 /* Scheduler includes. */
\r
92 #include "FreeRTOS.h"
\r
97 /* Descriptor type definitions. */
\r
98 #define usbDESCRIPTOR_TYPE_DEVICE ( 0x01 )
\r
99 #define usbDESCRIPTOR_TYPE_CONFIGURATION ( 0x02 )
\r
100 #define usbDESCRIPTOR_TYPE_STRING ( 0x03 )
\r
102 /* USB request type definitions. */
\r
103 #define usbGET_REPORT_REQUEST ( 0x01 )
\r
104 #define usbGET_IDLE_REQUEST ( 0x02 )
\r
105 #define usbGET_PROTOCOL_REQUEST ( 0x03 )
\r
106 #define usbSET_REPORT_REQUEST ( 0x09 )
\r
107 #define usbSET_IDLE_REQUEST ( 0x0A )
\r
108 #define usbSET_PROTOCOL_REQUEST ( 0x0B )
\r
109 #define usbGET_CONFIGURATION_REQUEST ( 0x08 )
\r
110 #define usbGET_STATUS_REQUEST ( 0x00 )
\r
111 #define usbCLEAR_FEATURE_REQUEST ( 0x01 )
\r
112 #define usbSET_FEATURE_REQUEST ( 0x03 )
\r
113 #define usbSET_ADDRESS_REQUEST ( 0x05 )
\r
114 #define usbGET_DESCRIPTOR_REQUEST ( 0x06 )
\r
115 #define usbSET_CONFIGURATION_REQUEST ( 0x09 )
\r
116 #define usbGET_INTERFACE_REQUEST ( 0x0A )
\r
117 #define usbSET_INTERFACE_REQUEST ( 0x0B )
\r
120 /* Misc USB definitions. */
\r
121 #define usbDEVICE_CLASS_VENDOR_SPECIFIC ( 0xFF )
\r
122 #define usbBUS_POWERED ( 0x80 )
\r
123 #define usbHID_REPORT_DESCRIPTOR ( 0x22 )
\r
124 #define AT91C_UDP_TRANSCEIVER_ENABLE ( *( ( unsigned long * ) 0xfffb0074 ) )
\r
126 /* Index to the various string. */
\r
127 #define usbLANGUAGE_STRING ( 0 )
\r
128 #define usbMANUFACTURER_STRING ( 1 )
\r
129 #define usbPRODUCT_STRING ( 2 )
\r
130 #define usbCONFIGURATION_STRING ( 3 )
\r
131 #define usbINTERFACE_STRING ( 4 )
\r
133 /* Data indexes for reading the request from the xISRStatus.ucFifoData[]
\r
134 into xUSB_REQUEST. The data order is designed for speed - so looks a
\r
136 #define usbREQUEST_TYPE_INDEX ( 7 )
\r
137 #define usbREQUEST_INDEX ( 6 )
\r
138 #define usbVALUE_HIGH_BYTE ( 4 )
\r
139 #define usbVALUE_LOW_BYTE ( 5 )
\r
140 #define usbINDEX_HIGH_BYTE ( 2 )
\r
141 #define usbINDEX_LOW_BYTE ( 3 )
\r
142 #define usbLENGTH_HIGH_BYTE ( 0 )
\r
143 #define usbLENGTH_LOW_BYTE ( 1 )
\r
145 /* Misc application definitions. */
\r
146 #define usbINTERRUPT_PRIORITY ( 3 )
\r
147 #define usbQUEUE_LENGTH ( 0x3 ) /* Must have all bits set! */
\r
148 #define usbFIFO_LENGTH ( ( unsigned long ) 8 )
\r
149 #define usbEND_POINT_0 ( 0 )
\r
150 #define usbEND_POINT_1 ( 1 )
\r
151 #define usbXUP ( 1 )
\r
152 #define usbXDOWN ( 2 )
\r
153 #define usbYUP ( 3 )
\r
154 #define usbYDOWN ( 4 )
\r
155 #define usbMAX_COORD ( 120 )
\r
156 #define usbMAX_TX_MESSAGE_SIZE ( 128 )
\r
157 #define usbRX_COUNT_MASK ( ( unsigned long ) 0x7ff )
\r
158 #define AT91C_UDP_STALLSENT AT91C_UDP_ISOERROR
\r
159 #define usbSHORTEST_DELAY ( ( portTickType ) 1 )
\r
160 #define usbINIT_DELAY ( ( portTickType ) 500 / portTICK_RATE_MS )
\r
161 #define usbSHORT_DELAY ( ( portTickType ) 50 / portTICK_RATE_MS )
\r
162 #define usbEND_POINT_RESET_MASK ( ( unsigned long ) 0x0f )
\r
163 #define usbDATA_INC ( ( char ) 5 )
\r
164 #define usbEXPECTED_NUMBER_OF_BYTES ( ( unsigned long ) 8 )
\r
166 /* Control request types. */
\r
167 #define usbSTANDARD_DEVICE_REQUEST ( 0 )
\r
168 #define usbSTANDARD_INTERFACE_REQUEST ( 1 )
\r
169 #define usbSTANDARD_END_POINT_REQUEST ( 2 )
\r
170 #define usbCLASS_INTERFACE_REQUEST ( 5 )
\r
172 /*-----------------------------------------------------------*/
\r
174 /* Structure used to take a snapshot of the USB status from within the ISR. */
\r
175 typedef struct X_ISR_STATUS
\r
177 unsigned long ulISR;
\r
178 unsigned long ulCSR0;
\r
179 unsigned char ucFifoData[ 8 ];
\r
182 /* Structure used to hold the received requests. */
\r
185 unsigned char ucReqType;
\r
186 unsigned char ucRequest;
\r
187 unsigned short usValue;
\r
188 unsigned short usIndex;
\r
189 unsigned short usLength;
\r
198 eSENDING_EVEN_DESCRIPTOR,
\r
202 /* Structure used to control the data being sent to the host. */
\r
205 unsigned char ucTxBuffer[ usbMAX_TX_MESSAGE_SIZE ];
\r
206 unsigned long ulNextCharIndex;
\r
207 unsigned long ulTotalDataLength;
\r
210 /*-----------------------------------------------------------*/
\r
213 * The USB interrupt service routine. This takes a snapshot of the USB
\r
214 * device at the time of the interrupt, clears the interrupts, and posts
\r
215 * the data to the USB processing task.
\r
217 __arm void vUSB_ISR( void );
\r
220 * Called after the bus reset interrupt - this function readies all the
\r
221 * end points for communication.
\r
223 static void prvResetEndPoints( void );
\r
226 * Setup the USB hardware, install the interrupt service routine and
\r
227 * initialise all the state variables.
\r
229 static void vInitUSBInterface( void );
\r
232 * Decode and act upon an interrupt generated by the control end point.
\r
234 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage );
\r
237 * For simplicity requests are separated into device, interface, class
\r
238 * interface and end point requests.
\r
240 * Decode and handle standard device requests originating on the control
\r
243 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest );
\r
246 * For simplicity requests are separated into device, interface, class
\r
247 * interface and end point requests.
\r
249 * Decode and handle standard interface requests originating on the control
\r
252 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
255 * For simplicity requests are separated into device, interface, class
\r
256 * interface and end point requests.
\r
258 * Decode and handle standard end point requests originating on the control
\r
261 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest );
\r
264 * For simplicity requests are separated into device, interface, class
\r
265 * interface and end point requests.
\r
267 * Decode and handle the class interface requests.
\r
269 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest );
\r
272 * Setup the Tx buffer to send data in response to a control request.
\r
274 * The data to be transmitted is buffered, the state variables are updated,
\r
275 * then prvSendNextSegment() is called to start the transmission off. Once
\r
276 * the first segment has been sent the remaining segments are transmitted
\r
277 * in response to TXCOMP interrupts until the entire buffer has been
\r
280 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthLeftToSend, long lSendingDescriptor );
\r
283 * Examine the Tx buffer to see if there is any more data to be transmitted.
\r
285 * If there is data to be transmitted then send the next segment. A segment
\r
286 * can have a maximum of 8 bytes (this is defined as the maximum for the end
\r
287 * point by the descriptor). The final segment may be less than 8 bytes if
\r
288 * the total data length was not an exact multiple of 8.
\r
290 static void prvSendNextSegment( void );
\r
293 * A stall condition is forced each time the host makes a request that is not
\r
294 * supported by this minimal implementation.
\r
296 * A stall is forced by setting the appropriate bit in the end points control
\r
297 * and status register.
\r
299 static void prvSendStall( void );
\r
302 * A NULL (or zero length packet) is transmitted in acknowledge the reception
\r
303 * of certain events from the host.
\r
305 static void prvUSBTransmitNull( void );
\r
308 * When the host requests a descriptor this function is called to determine
\r
309 * which descriptor is being requested and start its transmission.
\r
311 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest );
\r
314 * This demo USB device enumerates as a simple 3 axis joystick. Once
\r
315 * configured this function is periodically called to generate some sample
\r
318 * The x and y axis are made to move in a square. The z axis is made to
\r
319 * repeatedly increment up to its maximum.
\r
321 static void prvTransmitSampleValues( void );
\r
324 * The created task to handle the USB demo functionality.
\r
326 void vUSBDemoTask( void *pvParameters );
\r
328 /*-----------------------------------------------------------*/
\r
331 - DESCRIPTOR DEFINITIONS -
\r
334 /* String descriptors used during the enumeration process.
\r
335 These take the form:
\r
338 Length of descriptor,
\r
343 const char pxLanguageStringDescriptor[] =
\r
346 usbDESCRIPTOR_TYPE_STRING,
\r
350 const char pxManufacturerStringDescriptor[] =
\r
353 usbDESCRIPTOR_TYPE_STRING,
\r
365 const char pxProductStringDescriptor[] =
\r
368 usbDESCRIPTOR_TYPE_STRING,
\r
393 const char pxConfigurationStringDescriptor[] =
\r
396 usbDESCRIPTOR_TYPE_STRING,
\r
418 const char pxInterfaceStringDescriptor[] =
\r
421 usbDESCRIPTOR_TYPE_STRING,
\r
439 /* Enumeration descriptors. */
\r
440 const char pxReportDescriptor[] =
\r
442 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
\r
443 0x09, 0x04, /* USAGE (Joystick) */
\r
444 0xa1, 0x01, /* COLLECTION (Application) */
\r
445 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
\r
446 0x09, 0x01, /* USAGE (Pointer) */
\r
447 0xa1, 0x00, /* COLLECTION (Physical) */
\r
448 0x09, 0x30, /* USAGE (X) */
\r
449 0x09, 0x31, /* USAGE (Y) */
\r
450 0x09, 0x32, /* USAGE (Z) */
\r
451 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */
\r
452 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */
\r
453 0x75, 0x08, /* REPORT_SIZE (8) */
\r
454 0x95, 0x03, /* REPORT_COUNT (3) */
\r
455 0x81, 0x02, /* INPUT (Data,Var,Abs) */
\r
456 0xc0, /* END_COLLECTION */
\r
457 0xc0 /* END_COLLECTION */
\r
460 const char pxDeviceDescriptor[] =
\r
462 /* Device descriptor */
\r
463 0x12, /* bLength */
\r
464 0x01, /* bDescriptorType */
\r
465 0x10, 0x01, /* bcdUSBL */
\r
466 usbDEVICE_CLASS_VENDOR_SPECIFIC, /* bDeviceClass: */
\r
467 0x00, /* bDeviceSubclass: */
\r
468 0x00, /* bDeviceProtocol: */
\r
469 0x08, /* bMaxPacketSize0 */
\r
470 0xFF, 0xFF, /* idVendorL */
\r
471 0x01, 0x00, /* idProductL */
\r
472 0x00, 0x01, /* bcdDeviceL */
\r
473 usbMANUFACTURER_STRING, /* iManufacturer */
\r
474 usbPRODUCT_STRING, /* iProduct */
\r
475 0x00, /* SerialNumber */
\r
476 0x01 /* bNumConfigs */
\r
479 const char pxConfigDescriptor[] = {
\r
480 /* Configuration 1 descriptor */
\r
481 0x09, /* CbLength */
\r
482 0x02, /* CbDescriptorType */
\r
483 0x22, 0x00, /* CwTotalLength 2 EP + Control */
\r
484 0x01, /* CbNumInterfaces */
\r
485 0x01, /* CbConfigurationValue */
\r
486 usbCONFIGURATION_STRING,/* CiConfiguration */
\r
487 usbBUS_POWERED, /* CbmAttributes Bus powered + Remote Wakeup*/
\r
488 0x32, /* CMaxPower: 100mA */
\r
490 /* Joystick Interface Descriptor Requirement */
\r
491 0x09, /* bLength */
\r
492 0x04, /* bDescriptorType */
\r
493 0x00, /* bInterfaceNumber */
\r
494 0x00, /* bAlternateSetting */
\r
495 0x01, /* bNumEndpoints */
\r
496 0x03, /* bInterfaceClass: HID code */
\r
497 0x00, /* bInterfaceSubclass */
\r
498 0x00, /* bInterfaceProtocol */
\r
499 usbINTERFACE_STRING,/* iInterface */
\r
501 /* HID Descriptor */
\r
502 0x09, /* bLength */
\r
503 0x21, /* bDescriptor type: HID Descriptor Type */
\r
504 0x00, 0x01, /* bcdHID */
\r
505 0x00, /* bCountryCode */
\r
506 0x01, /* bNumDescriptors */
\r
507 usbHID_REPORT_DESCRIPTOR, /* bDescriptorType */
\r
508 sizeof( pxReportDescriptor ), 0x00, /* wItemLength */
\r
510 /* Endpoint 1 descriptor */
\r
511 0x07, /* bLength */
\r
512 0x05, /* bDescriptorType */
\r
513 0x81, /* bEndpointAddress, Endpoint 01 - IN */
\r
514 0x03, /* bmAttributes INT */
\r
515 0x03, 0x00, /* wMaxPacketSize: 3 bytes (x, y, z) */
\r
516 0x0A /* bInterval */
\r
519 /*-----------------------------------------------------------*/
\r
521 /* File scope state variables. */
\r
522 static unsigned char ucUSBConfig = ( unsigned char ) 0;
\r
523 static unsigned long ulReceivedAddress = ( unsigned long ) 0;
\r
524 static eDRIVER_STATE eDriverState = eNOTHING;
\r
526 /* Array in which the USB interrupt status is passed between the ISR and task. */
\r
527 static xISRStatus xISRMessages[ usbQUEUE_LENGTH + 1 ];
\r
529 /* Structure used to control the characters being sent to the host. */
\r
530 static xTX_MESSAGE pxCharsForTx;
\r
532 /* Queue used to pass messages between the ISR and the task. */
\r
533 static xQueueHandle xUSBInterruptQueue;
\r
535 /* ISR entry has to be written in the asm file as we want a context switch
\r
536 to occur from within the ISR. See the port documentation on the FreeRTOS.org
\r
537 WEB site for more information. */
\r
538 extern void vUSBISREntry( void );
\r
540 /*-----------------------------------------------------------*/
\r
542 /* Macros to manipulate the control and status registers. These registers
\r
543 cannot be accessed using a direct read modify write operation outside of the
\r
544 ISR as some bits are left unchanged by writing with a 0, and some are left
\r
545 unchanged by writing with a 1. */
\r
547 #define usbINT_CLEAR_MASK (AT91C_UDP_TXCOMP | AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP | AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 )
\r
549 #define usbCSR_SET_BIT( pulValueNow, ulBit ) \
\r
551 /* Set TXCOMP, RX_DATA_BK0, RXSETUP, */ \
\r
552 /* STALLSENT and RX_DATA_BK1 to 1 so the */ \
\r
553 /* write has no effect. */ \
\r
554 ( * ( ( unsigned long * ) pulValueNow ) ) |= ( unsigned long ) 0x4f; \
\r
556 /* Clear the FORCE_STALL and TXPKTRDY bits */ \
\r
557 /* so the write has no effect. */ \
\r
558 ( * ( ( unsigned long * ) pulValueNow ) ) &= ( unsigned long ) 0xffffffcf; \
\r
560 /* Set whichever bit we want set. */ \
\r
561 ( * ( ( unsigned long * ) pulValueNow ) ) |= ( ulBit ); \
\r
564 #define usbCSR_CLEAR_BIT( pulValueNow, ulBit ) \
\r
566 /* Set TXCOMP, RX_DATA_BK0, RXSETUP, */ \
\r
567 /* STALLSENT and RX_DATA_BK1 to 1 so the */ \
\r
568 /* write has no effect. */ \
\r
569 ( * ( ( unsigned long * ) pulValueNow ) ) |= ( unsigned long ) 0x4f; \
\r
571 /* Clear the FORCE_STALL and TXPKTRDY bits */ \
\r
572 /* so the write has no effect. */ \
\r
573 ( * ( ( unsigned long * ) pulValueNow ) ) &= ( unsigned long ) 0xffffffcf; \
\r
575 /* Clear whichever bit we want clear. */ \
\r
576 ( * ( ( unsigned long * ) pulValueNow ) ) &= ( ~ulBit ); \
\r
579 /*-----------------------------------------------------------*/
\r
581 __arm void vUSB_ISR( void )
\r
583 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
584 static volatile unsigned long ulNextMessage = 0;
\r
585 xISRStatus *pxMessage;
\r
586 unsigned long ulTemp, ulRxBytes;
\r
588 /* Take the next message from the queue. Note that usbQUEUE_LENGTH *must*
\r
589 be all 1's, as in 0x01, 0x03, 0x07, etc. */
\r
590 pxMessage = &( xISRMessages[ ( ulNextMessage & usbQUEUE_LENGTH ) ] );
\r
593 /* Take a snapshot of the current USB state for processing at the task
\r
595 pxMessage->ulISR = AT91C_BASE_UDP->UDP_ISR;
\r
596 pxMessage->ulCSR0 = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
598 /* Clear the interrupts from the ICR register. The bus end interrupt is
\r
599 cleared separately as it does not appear in the mask register. */
\r
600 AT91C_BASE_UDP->UDP_ICR = AT91C_BASE_UDP->UDP_IMR | AT91C_UDP_ENDBUSRES;
\r
602 /* If there are bytes in the FIFO then we have to retrieve them here.
\r
603 Ideally this would be done at the task level. However we need to clear the
\r
604 RXSETUP interrupt before leaving the ISR, and this may cause the data in
\r
605 the FIFO to be overwritten. Also the DIR bit has to be changed before the
\r
606 RXSETUP bit is cleared (as per the SAM7 manual). */
\r
607 ulTemp = pxMessage->ulCSR0;
\r
609 /* Are there any bytes in the FIFO? */
\r
610 ulRxBytes = ulTemp >> 16;
\r
611 ulRxBytes &= usbRX_COUNT_MASK;
\r
613 /* With this minimal implementation we are only interested in receiving
\r
614 setup bytes on the control end point. */
\r
615 if( ( ulRxBytes > 0 ) && ( ulTemp & AT91C_UDP_RXSETUP ) )
\r
617 /* Take off 1 for a zero based index. */
\r
618 while( ulRxBytes > 0 )
\r
621 pxMessage->ucFifoData[ ulRxBytes ] = AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ];
\r
624 /* The direction must be changed first. */
\r
625 usbCSR_SET_BIT( &ulTemp, ( AT91C_UDP_DIR ) );
\r
626 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
629 /* Must write zero's to TXCOMP, STALLSENT, RXSETUP, and the RX DATA
\r
630 registers to clear the interrupts in the CSR register. */
\r
631 usbCSR_CLEAR_BIT( &ulTemp, usbINT_CLEAR_MASK );
\r
632 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
634 /* Also clear the interrupts in the CSR1 register. */
\r
635 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
636 usbCSR_CLEAR_BIT( &ulTemp, usbINT_CLEAR_MASK );
\r
637 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
639 /* The message now contains the entire state and optional data from
\r
640 the USB interrupt. This can now be posted on the Rx queue ready for
\r
641 processing at the task level. */
\r
642 xQueueSendFromISR( xUSBInterruptQueue, &pxMessage, &xHigherPriorityTaskWoken );
\r
644 /* We may want to switch to the USB task, if this message has made
\r
645 it the highest priority task that is ready to execute. */
\r
646 portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
\r
648 /* Clear the AIC ready for the next interrupt. */
\r
649 AT91C_BASE_AIC->AIC_EOICR = 0;
\r
651 /*-----------------------------------------------------------*/
\r
653 void vUSBDemoTask( void *pvParameters )
\r
655 xISRStatus *pxMessage;
\r
657 /* The parameters are not used in this task. */
\r
658 ( void ) pvParameters;
\r
660 /* Init USB device */
\r
661 portENTER_CRITICAL();
\r
662 vInitUSBInterface();
\r
663 portEXIT_CRITICAL();
\r
665 /* Process interrupts as they arrive. The ISR takes a snapshot of the
\r
666 interrupt status then posts the information on this queue for processing
\r
667 at the task level. This simple demo implementation only processes
\r
668 a few interrupt sources. */
\r
671 if( xQueueReceive( xUSBInterruptQueue, &pxMessage, usbSHORT_DELAY ) )
\r
673 if( pxMessage->ulISR & AT91C_UDP_EPINT0 )
\r
675 /* Process end point 0 interrupt. */
\r
676 prvProcessEndPoint0Interrupt( pxMessage );
\r
679 if( pxMessage->ulISR & AT91C_UDP_ENDBUSRES )
\r
681 /* Process an end of bus reset interrupt. */
\r
682 prvResetEndPoints();
\r
687 /* The ISR did not post any data for us to process on the queue, so
\r
688 just generate and send some sample data. */
\r
689 if( eDriverState == eREADY_TO_SEND )
\r
691 prvTransmitSampleValues();
\r
696 /*-----------------------------------------------------------*/
\r
698 static void prvTransmitSampleValues( void )
\r
700 unsigned long ulStatus;
\r
701 static long lState = usbXUP;
\r
703 /* Variables to hold dummy x, y and z joystick axis data. */
\r
704 static signed char x = 0, y = 0, z = 0;
\r
706 /* Generate some sample data in the x and y axis - draw a square. */
\r
709 case usbXUP : x += usbDATA_INC;
\r
710 if( x >= usbMAX_COORD )
\r
716 case usbXDOWN : x -= usbDATA_INC;
\r
717 if( x <= -usbMAX_COORD )
\r
723 case usbYUP : y += usbDATA_INC;
\r
724 if( y >= usbMAX_COORD )
\r
730 case usbYDOWN : y -= usbDATA_INC;
\r
731 if( y <= -usbMAX_COORD )
\r
738 /* Just make the z axis go up and down. */
\r
741 /* Can we place data in the fifo? */
\r
742 if( !( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] & AT91C_UDP_TXPKTRDY ) )
\r
744 /* Write our sample data to the fifo. */
\r
745 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = x;
\r
746 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = y;
\r
747 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_1 ] = z;
\r
749 /* Send the data. */
\r
750 portENTER_CRITICAL();
\r
752 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
753 usbCSR_SET_BIT( &ulStatus, ( AT91C_UDP_TXPKTRDY ) );
\r
754 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulStatus;
\r
756 portEXIT_CRITICAL();
\r
759 /*-----------------------------------------------------------*/
\r
761 static void prvUSBTransmitNull( void )
\r
763 unsigned long ulStatus;
\r
765 /* Wait until the FIFO is free - even though we are not going to use it.
\r
766 THERE IS NO TIMEOUT HERE! */
\r
767 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
769 vTaskDelay( usbSHORTEST_DELAY );
\r
772 portENTER_CRITICAL();
\r
774 /* Set the length of data to send to equal the index of the next byte
\r
775 to send. This will prevent the ACK to this NULL packet causing any
\r
776 further data transmissions. */
\r
777 pxCharsForTx.ulTotalDataLength = pxCharsForTx.ulNextCharIndex;
\r
779 /* Set the TXPKTRDY bit to cause a transmission with no data. */
\r
780 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
781 usbCSR_SET_BIT( &ulStatus, ( AT91C_UDP_TXPKTRDY ) );
\r
782 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
784 portEXIT_CRITICAL();
\r
786 /*-----------------------------------------------------------*/
\r
788 static void prvSendStall( void )
\r
790 unsigned long ulStatus;
\r
792 portENTER_CRITICAL();
\r
794 /* Force a stall by simply setting the FORCESTALL bit in the CSR. */
\r
795 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
796 usbCSR_SET_BIT( &ulStatus, AT91C_UDP_FORCESTALL );
\r
797 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
799 portEXIT_CRITICAL();
\r
801 /*-----------------------------------------------------------*/
\r
803 static void prvResetEndPoints( void )
\r
805 unsigned long ulTemp;
\r
807 eDriverState = eJUST_RESET;
\r
809 /* Reset all the end points. */
\r
810 AT91C_BASE_UDP->UDP_RSTEP = usbEND_POINT_RESET_MASK;
\r
811 AT91C_BASE_UDP->UDP_RSTEP = ( unsigned long ) 0x00;
\r
813 /* Enable data to be sent and received. */
\r
814 AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
\r
816 /* Repair the configuration end point. */
\r
817 portENTER_CRITICAL();
\r
819 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
820 usbCSR_SET_BIT( &ulTemp, ( ( unsigned long ) ( AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL ) ) );
\r
821 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulTemp;
\r
822 AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT0 );
\r
824 portEXIT_CRITICAL();
\r
826 /*-----------------------------------------------------------*/
\r
828 static void prvProcessEndPoint0Interrupt( xISRStatus *pxMessage )
\r
830 if( pxMessage->ulCSR0 & AT91C_UDP_RX_DATA_BK0 )
\r
832 /* We only expect to receive zero length data here as ACK's.
\r
833 Set the data pointer to the end of the current Tx packet to
\r
834 ensure we don't send out any more data. */
\r
835 pxCharsForTx.ulNextCharIndex = pxCharsForTx.ulTotalDataLength;
\r
838 if( pxMessage->ulCSR0 & AT91C_UDP_TXCOMP )
\r
840 /* We received a TX complete interrupt. What we do depends on
\r
841 what we sent to get this interrupt. */
\r
843 if( eDriverState == eJUST_GOT_CONFIG )
\r
845 /* We sent an acknowledgement of a SET_CONFIG request. We
\r
846 are now at the end of the enumeration. */
\r
847 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_CONFG;
\r
849 /* Read the end point for data transfer. */
\r
850 portENTER_CRITICAL();
\r
852 unsigned long ulTemp;
\r
854 ulTemp = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ];
\r
855 usbCSR_SET_BIT( &ulTemp, AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN );
\r
856 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_1 ] = ulTemp;
\r
857 AT91F_UDP_EnableIt( AT91C_BASE_UDP, AT91C_UDP_EPINT1 );
\r
859 portEXIT_CRITICAL();
\r
861 eDriverState = eREADY_TO_SEND;
\r
863 else if( eDriverState == eJUST_GOT_ADDRESS )
\r
865 /* We sent an acknowledgement of a SET_ADDRESS request. Move
\r
866 to the addressed state. */
\r
867 if( ulReceivedAddress != ( unsigned long ) 0 )
\r
869 AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
\r
873 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
876 AT91C_BASE_UDP->UDP_FADDR = ( AT91C_UDP_FEN | ulReceivedAddress );
\r
877 eDriverState = eNOTHING;
\r
881 /* The TXCOMP was not for any special type of transmission. See
\r
882 if there is any more data to send. */
\r
883 prvSendNextSegment();
\r
887 if( pxMessage->ulCSR0 & AT91C_UDP_RXSETUP )
\r
889 xUSB_REQUEST xRequest;
\r
890 unsigned char ucRequest;
\r
891 unsigned long ulRxBytes;
\r
893 /* A data packet is available. */
\r
894 ulRxBytes = pxMessage->ulCSR0 >> 16;
\r
895 ulRxBytes &= usbRX_COUNT_MASK;
\r
897 if( ulRxBytes >= usbEXPECTED_NUMBER_OF_BYTES )
\r
899 /* Create an xUSB_REQUEST variable from the raw bytes array. */
\r
901 xRequest.ucReqType = pxMessage->ucFifoData[ usbREQUEST_TYPE_INDEX ];
\r
902 xRequest.ucRequest = pxMessage->ucFifoData[ usbREQUEST_INDEX ];
\r
904 /* NOT PORTABLE CODE! */
\r
905 xRequest.usValue = pxMessage->ucFifoData[ usbVALUE_HIGH_BYTE ];
\r
906 xRequest.usValue <<= 8;
\r
907 xRequest.usValue |= pxMessage->ucFifoData[ usbVALUE_LOW_BYTE ];
\r
909 xRequest.usIndex = pxMessage->ucFifoData[ usbINDEX_HIGH_BYTE ];
\r
910 xRequest.usIndex <<= 8;
\r
911 xRequest.usIndex |= pxMessage->ucFifoData[ usbINDEX_LOW_BYTE ];
\r
913 xRequest.usLength = pxMessage->ucFifoData[ usbLENGTH_HIGH_BYTE ];
\r
914 xRequest.usLength <<= 8;
\r
915 xRequest.usLength |= pxMessage->ucFifoData[ usbLENGTH_LOW_BYTE ];
\r
917 /* Manipulate the ucRequestType and the ucRequest parameters to
\r
918 generate a zero based request selection. This is just done to
\r
919 break up the requests into subsections for clarity. The
\r
920 alternative would be to have more huge switch statement that would
\r
921 be difficult to optimise. */
\r
922 ucRequest = ( ( xRequest.ucReqType & 0x60 ) >> 3 );
\r
923 ucRequest |= ( xRequest.ucReqType & 0x03 );
\r
925 switch( ucRequest )
\r
927 case usbSTANDARD_DEVICE_REQUEST:
\r
928 /* Standard Device request */
\r
929 prvHandleStandardDeviceRequest( &xRequest );
\r
932 case usbSTANDARD_INTERFACE_REQUEST:
\r
933 /* Standard Interface request */
\r
934 prvHandleStandardInterfaceRequest( &xRequest );
\r
937 case usbSTANDARD_END_POINT_REQUEST:
\r
938 /* Standard Endpoint request */
\r
939 prvHandleStandardEndPointRequest( &xRequest );
\r
942 case usbCLASS_INTERFACE_REQUEST:
\r
943 /* Class Interface request */
\r
944 prvHandleClassInterfaceRequest( &xRequest );
\r
947 default: /* This is not something we want to respond to. */
\r
953 /*-----------------------------------------------------------*/
\r
955 static void prvGetStandardDeviceDescriptor( xUSB_REQUEST *pxRequest )
\r
957 /* The type is in the high byte. Return whatever has been requested. */
\r
958 switch( ( pxRequest->usValue & 0xff00 ) >> 8 )
\r
960 case usbDESCRIPTOR_TYPE_DEVICE:
\r
961 prvSendControlData( ( unsigned char * ) &pxDeviceDescriptor, pxRequest->usLength, sizeof( pxDeviceDescriptor ), pdTRUE );
\r
964 case usbDESCRIPTOR_TYPE_CONFIGURATION:
\r
965 prvSendControlData( ( unsigned char * ) &( pxConfigDescriptor ), pxRequest->usLength, sizeof( pxConfigDescriptor ), pdTRUE );
\r
968 case usbDESCRIPTOR_TYPE_STRING:
\r
970 /* The index to the string descriptor is the lower byte. */
\r
971 switch( pxRequest->usValue & 0xff )
\r
973 case usbLANGUAGE_STRING:
\r
974 prvSendControlData( ( unsigned char * ) &pxLanguageStringDescriptor, pxRequest->usLength, sizeof(pxLanguageStringDescriptor), pdTRUE );
\r
977 case usbMANUFACTURER_STRING:
\r
978 prvSendControlData( ( unsigned char * ) &pxManufacturerStringDescriptor, pxRequest->usLength, sizeof( pxManufacturerStringDescriptor ), pdTRUE );
\r
981 case usbPRODUCT_STRING:
\r
982 prvSendControlData( ( unsigned char * ) &pxProductStringDescriptor, pxRequest->usLength, sizeof( pxProductStringDescriptor ), pdTRUE );
\r
985 case usbCONFIGURATION_STRING:
\r
986 prvSendControlData( ( unsigned char * ) &pxConfigurationStringDescriptor, pxRequest->usLength, sizeof( pxConfigurationStringDescriptor ), pdTRUE );
\r
989 case usbINTERFACE_STRING:
\r
990 prvSendControlData( ( unsigned char * ) &pxInterfaceStringDescriptor, pxRequest->usLength, sizeof( pxInterfaceStringDescriptor ), pdTRUE );
\r
994 /* Don't know what this string is. */
\r
1002 /* We are not responding to anything else. */
\r
1007 /*-----------------------------------------------------------*/
\r
1009 static void prvHandleStandardDeviceRequest( xUSB_REQUEST *pxRequest )
\r
1011 unsigned short usStatus = 0;
\r
1013 switch( pxRequest->ucRequest )
\r
1015 case usbGET_STATUS_REQUEST:
\r
1016 /* Just send two byte dummy status. */
\r
1017 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
1020 case usbGET_DESCRIPTOR_REQUEST:
\r
1021 /* Send device descriptor */
\r
1022 prvGetStandardDeviceDescriptor( pxRequest );
\r
1025 case usbGET_CONFIGURATION_REQUEST:
\r
1026 /* Send selected device configuration */
\r
1027 prvSendControlData( ( unsigned char * ) &ucUSBConfig, sizeof( ucUSBConfig ), sizeof( ucUSBConfig ), pdFALSE );
\r
1030 case usbSET_FEATURE_REQUEST:
\r
1031 prvUSBTransmitNull();
\r
1034 case usbSET_ADDRESS_REQUEST:
\r
1036 /* Acknowledge the SET_ADDRESS, but (according to the manual) we
\r
1037 cannot actually move to the addressed state until we get a TXCOMP
\r
1038 interrupt from this NULL packet. Therefore we just remember the
\r
1039 address and set our state so we know we have received the address. */
\r
1040 prvUSBTransmitNull();
\r
1041 eDriverState = eJUST_GOT_ADDRESS;
\r
1042 ulReceivedAddress = ( unsigned long ) pxRequest->usValue;
\r
1045 case usbSET_CONFIGURATION_REQUEST:
\r
1047 /* Acknowledge the SET_CONFIGURATION, but (according to the manual)
\r
1048 we cannot actually move to the configured state until we get a
\r
1049 TXCOMP interrupt from this NULL packet. Therefore we just remember the
\r
1050 config and set our state so we know we have received the go ahead. */
\r
1051 ucUSBConfig = ( unsigned char ) ( pxRequest->usValue & 0xff );
\r
1052 eDriverState = eJUST_GOT_CONFIG;
\r
1053 prvUSBTransmitNull();
\r
1058 /* We don't answer to anything else. */
\r
1063 /*-----------------------------------------------------------*/
\r
1065 static void prvHandleClassInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
1067 switch( pxRequest->ucRequest )
\r
1069 case usbSET_IDLE_REQUEST:
\r
1070 prvUSBTransmitNull();
\r
1073 /* This minimal implementation ignores these. */
\r
1074 case usbGET_REPORT_REQUEST:
\r
1075 case usbGET_IDLE_REQUEST:
\r
1076 case usbGET_PROTOCOL_REQUEST:
\r
1077 case usbSET_REPORT_REQUEST:
\r
1078 case usbSET_PROTOCOL_REQUEST:
\r
1085 /*-----------------------------------------------------------*/
\r
1087 static void prvGetStandardInterfaceDescriptor( xUSB_REQUEST *pxRequest )
\r
1089 switch( ( pxRequest->usValue & ( unsigned short ) 0xff00 ) >> 8 )
\r
1091 case usbHID_REPORT_DESCRIPTOR:
\r
1092 prvSendControlData( ( unsigned char * ) pxReportDescriptor, pxRequest->usLength, sizeof( pxReportDescriptor ), pdTRUE );
\r
1097 /* Don't expect to send any others. */
\r
1102 /*-----------------------------------------------------------*/
\r
1104 static void prvHandleStandardInterfaceRequest( xUSB_REQUEST *pxRequest )
\r
1106 unsigned short usStatus = 0;
\r
1108 switch( pxRequest->ucRequest )
\r
1110 case usbGET_STATUS_REQUEST:
\r
1111 /* Send dummy 2 bytes. */
\r
1112 prvSendControlData( ( unsigned char * ) &usStatus, sizeof( usStatus ), sizeof( usStatus ), pdFALSE );
\r
1115 case usbGET_DESCRIPTOR_REQUEST:
\r
1116 prvGetStandardInterfaceDescriptor( pxRequest );
\r
1119 /* This minimal implementation does not respond to these. */
\r
1120 case usbGET_INTERFACE_REQUEST:
\r
1121 case usbSET_FEATURE_REQUEST:
\r
1122 case usbSET_INTERFACE_REQUEST:
\r
1129 /*-----------------------------------------------------------*/
\r
1131 static void prvHandleStandardEndPointRequest( xUSB_REQUEST *pxRequest )
\r
1133 switch( pxRequest->ucRequest )
\r
1135 /* This minimal implementation does not expect to respond to these. */
\r
1136 case usbGET_STATUS_REQUEST:
\r
1137 case usbCLEAR_FEATURE_REQUEST:
\r
1138 case usbSET_FEATURE_REQUEST:
\r
1145 /*-----------------------------------------------------------*/
\r
1147 static void vInitUSBInterface( void )
\r
1149 volatile unsigned long ulTemp;
\r
1151 /* Create the queue used to communicate between the USB ISR and task. */
\r
1152 xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );
\r
1154 /* Initialise a few state variables. */
\r
1155 pxCharsForTx.ulNextCharIndex = ( unsigned long ) 0;
\r
1156 ucUSBConfig = ( unsigned char ) 0;
\r
1157 eDriverState = eNOTHING;
\r
1159 /* HARDWARE SETUP */
\r
1161 /* Set the PLL USB Divider */
\r
1162 AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
\r
1164 /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock. */
\r
1165 AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
\r
1166 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
\r
1168 /* Setup the PIO for the USB pull up resistor. */
\r
1169 AT91F_PIO_CfgOutput(AT91C_BASE_PIOA,AT91C_PIO_PA16);
\r
1171 /* Start without the pullup - this will get set at the end of this
\r
1173 AT91F_PIO_SetOutput( AT91C_BASE_PIOA, AT91C_PIO_PA16 );
\r
1175 /* When using the USB debugger the peripheral registers do not always get
\r
1176 set to the correct default values. To make sure set the relevant registers
\r
1178 AT91C_BASE_UDP->UDP_IDR = ( unsigned long ) 0xffffffff;
\r
1179 AT91C_BASE_UDP->UDP_ICR = ( unsigned long ) 0xffffffff;
\r
1180 AT91C_BASE_UDP->UDP_CSR[ 0 ] = ( unsigned long ) 0x00;
\r
1181 AT91C_BASE_UDP->UDP_CSR[ 1 ] = ( unsigned long ) 0x00;
\r
1182 AT91C_BASE_UDP->UDP_GLBSTATE = 0;
\r
1183 AT91C_BASE_UDP->UDP_FADDR = 0;
\r
1185 /* Enable the transceiver. */
\r
1186 AT91C_UDP_TRANSCEIVER_ENABLE = 0;
\r
1188 /* Enable the USB interrupts - other interrupts get enabled as the
\r
1189 enumeration process progresses. */
\r
1190 AT91F_AIC_ConfigureIt( AT91C_BASE_AIC, AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, ( void (*)( void ) ) vUSBISREntry );
\r
1191 AT91F_AIC_EnableIt( AT91C_BASE_AIC, AT91C_ID_UDP );
\r
1193 /* Wait a short while before making our presence known. */
\r
1194 vTaskDelay( usbINIT_DELAY );
\r
1195 AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, AT91C_PIO_PA16 );
\r
1197 /*-----------------------------------------------------------*/
\r
1199 static void prvSendControlData( unsigned char *pucData, unsigned short usRequestedLength, unsigned long ulLengthToSend, long lSendingDescriptor )
\r
1201 if( ( ( unsigned long ) usRequestedLength < ulLengthToSend ) )
\r
1203 /* Cap the data length to that requested. */
\r
1204 ulLengthToSend = ( unsigned short ) usRequestedLength;
\r
1206 else if( ( ulLengthToSend < ( unsigned long ) usRequestedLength ) && lSendingDescriptor )
\r
1208 /* We are sending a descriptor. If the descriptor is an exact
\r
1209 multiple of the FIFO length then it will have to be terminated
\r
1210 with a NULL packet. Set the state to indicate this if
\r
1212 if( ( ulLengthToSend % usbFIFO_LENGTH ) == 0 )
\r
1214 eDriverState = eSENDING_EVEN_DESCRIPTOR;
\r
1218 /* Here we assume that the previous message has been sent. THERE IS NO
\r
1219 BUFFER OVERFLOW PROTECTION HERE.
\r
1221 Copy the data to send into the buffer as we cannot send it all at once
\r
1222 (if it is greater than 8 bytes in length). */
\r
1223 memcpy( pxCharsForTx.ucTxBuffer, pucData, ulLengthToSend );
\r
1225 /* Reinitialise the buffer index so we start sending from the start of
\r
1227 pxCharsForTx.ulTotalDataLength = ulLengthToSend;
\r
1228 pxCharsForTx.ulNextCharIndex = ( unsigned long ) 0;
\r
1230 /* Send the first 8 bytes now. The rest will get sent in response to
\r
1231 TXCOMP interrupts. */
\r
1232 prvSendNextSegment();
\r
1234 /*-----------------------------------------------------------*/
\r
1236 static void prvSendNextSegment( void )
\r
1238 volatile unsigned long ulNextLength, ulStatus, ulLengthLeftToSend;
\r
1240 /* Is there any data to send? */
\r
1241 if( pxCharsForTx.ulTotalDataLength > pxCharsForTx.ulNextCharIndex )
\r
1243 ulLengthLeftToSend = pxCharsForTx.ulTotalDataLength - pxCharsForTx.ulNextCharIndex;
\r
1245 /* We can only send 8 bytes to the fifo at a time. */
\r
1246 if( ulLengthLeftToSend > usbFIFO_LENGTH )
\r
1248 ulNextLength = usbFIFO_LENGTH;
\r
1252 ulNextLength = ulLengthLeftToSend;
\r
1255 /* Wait until we can place data in the fifo. THERE IS NO TIMEOUT
\r
1257 while( AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] & AT91C_UDP_TXPKTRDY )
\r
1259 vTaskDelay( usbSHORTEST_DELAY );
\r
1262 /* Write the data to the FIFO. */
\r
1263 while( ulNextLength > ( unsigned long ) 0 )
\r
1265 AT91C_BASE_UDP->UDP_FDR[ usbEND_POINT_0 ] = pxCharsForTx.ucTxBuffer[ pxCharsForTx.ulNextCharIndex ];
\r
1268 pxCharsForTx.ulNextCharIndex++;
\r
1271 /* Start the transmission. */
\r
1272 portENTER_CRITICAL();
\r
1274 ulStatus = AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ];
\r
1275 usbCSR_SET_BIT( &ulStatus, ( ( unsigned long ) 0x10 ) );
\r
1276 AT91C_BASE_UDP->UDP_CSR[ usbEND_POINT_0 ] = ulStatus;
\r
1278 portEXIT_CRITICAL();
\r
1282 /* There is no data to send. If we were sending a descriptor and the
\r
1283 descriptor was an exact multiple of the max packet size then we need
\r
1284 to send a null to terminate the transmission. */
\r
1285 if( eDriverState == eSENDING_EVEN_DESCRIPTOR )
\r
1287 prvUSBTransmitNull();
\r
1288 eDriverState = eNOTHING;
\r