From da01e97e45189d53b4bc17b1abd559bdd81a1c97 Mon Sep 17 00:00:00 2001 From: richardbarry Date: Fri, 7 Aug 2009 15:30:18 +0000 Subject: [PATCH] Add simple USB CDC task. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@835 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../FreeRTOSConfig.h | 9 +- .../LPCUSB/USB_CDC.c | 459 +++++++++++++++ Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/type.h | 38 ++ .../CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbapi.h | 118 ++++ .../LPCUSB/usbcontrol.c | 246 +++++++++ .../LPCUSB/usbdebug.h | 41 ++ .../LPCUSB/usbhw_lpc.c | 521 ++++++++++++++++++ .../LPCUSB/usbhw_lpc.c.bak | 521 ++++++++++++++++++ .../LPCUSB/usbhw_lpc.h | 149 +++++ .../LPCUSB/usbinit.c | 82 +++ .../LPCUSB/usbstdreq.c | 430 +++++++++++++++ .../LPCUSB/usbstruct.h | 119 ++++ Demo/CORTEX_LPC1768_GCC_Rowley/RTOSDemo.hzp | 9 +- Demo/CORTEX_LPC1768_GCC_Rowley/RTOSDemo.hzs | 7 +- Demo/CORTEX_LPC1768_GCC_Rowley/main.c | 56 +- 15 files changed, 2756 insertions(+), 49 deletions(-) create mode 100644 Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/USB_CDC.c create mode 100644 Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/type.h create mode 100644 Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbapi.h create mode 100644 Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbcontrol.c create mode 100644 Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbdebug.h create mode 100644 Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbhw_lpc.c create mode 100644 Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbhw_lpc.c.bak create mode 100644 Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbhw_lpc.h create mode 100644 Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbinit.c create mode 100644 Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbstdreq.c create mode 100644 Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbstruct.h diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/FreeRTOSConfig.h b/Demo/CORTEX_LPC1768_GCC_Rowley/FreeRTOSConfig.h index a87934814..f0d90fdf4 100644 --- a/Demo/CORTEX_LPC1768_GCC_Rowley/FreeRTOSConfig.h +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/FreeRTOSConfig.h @@ -64,7 +64,7 @@ #define configUSE_IDLE_HOOK 0 #define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 ) #define configUSE_TICK_HOOK 1 -#define configCPU_CLOCK_HZ ( ( unsigned portLONG ) 64000000 ) +#define configCPU_CLOCK_HZ ( ( unsigned portLONG ) 99000000 ) #define configTICK_RATE_HZ ( ( portTickType ) 1000 ) #define configMINIMAL_STACK_SIZE ( ( unsigned portSHORT ) 80 ) #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 19 * 1024 ) ) @@ -133,9 +133,12 @@ to exclude the API function. */ #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( 5 << (8 - configPRIO_BITS) ) /* Priorities passed to NVIC_SetPriority() do not require shifting as the -function does the shifting itself. */ +function does the shifting itself. Note these priorities need to be equal to +or lower than configMAX_SYSCALL_INTERRUPT_PRIORITY - therefore the numeric +value needs to be equal to or greater than 5 (on the Cortex M3 the lower the +numeric value the higher the interrupt priority). */ #define configEMAC_INTERRUPT_PRIORITY 5 - +#define configUSB_INTERRUPT_PRIORITY 6 diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/USB_CDC.c b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/USB_CDC.c new file mode 100644 index 000000000..8b88bef3d --- /dev/null +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/USB_CDC.c @@ -0,0 +1,459 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + Minimal implementation of a USB serial port, using the CDC class. + This example application simply echoes everything it receives right back + to the host. + + Windows: + Extract the usbser.sys file from .cab file in C:\WINDOWS\Driver Cache\i386 + and store it somewhere (C:\temp is a good place) along with the usbser.inf + file. Then plug in the LPC176x and direct windows to the usbser driver. + Windows then creates an extra COMx port that you can open in a terminal + program, like hyperterminal. [Note for FreeRTOS users - the required .inf + file is included in the project directory.] + + Linux: + The device should be recognised automatically by the cdc_acm driver, + which creates a /dev/ttyACMx device file that acts just like a regular + serial port. + +*/ + +#include "FreeRTOS.h" +#include "queue.h" + +#include +#include + +#include "usbapi.h" +#include "usbdebug.h" +#include "usbstruct.h" + +#include "LPC17xx.h" + +#define usbMAX_SEND_BLOCK ( 20 / portTICK_RATE_MS ) +#define usbBUFFER_LEN ( 20 ) + +#define INCREMENT_ECHO_BY 1 +#define BAUD_RATE 115200 + +#define INT_IN_EP 0x81 +#define BULK_OUT_EP 0x05 +#define BULK_IN_EP 0x82 + +#define MAX_PACKET_SIZE 64 + +#define LE_WORD(x) ((x)&0xFF),((x)>>8) + +// CDC definitions +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 + +// data structure for GET_LINE_CODING / SET_LINE_CODING class requests +typedef struct { + unsigned long dwDTERate; + unsigned char bCharFormat; + unsigned char bParityType; + unsigned char bDataBits; +} TLineCoding; + +static TLineCoding LineCoding = {115200, 0, 0, 8}; +static unsigned char abBulkBuf[64]; +static unsigned char abClassReqData[8]; + +static xQueueHandle xRxedChars = NULL, xCharsForTx = NULL; + +// forward declaration of interrupt handler +void USBIntHandler(void); + +static const unsigned char abDescriptors[] = { + +// device descriptor + 0x12, + DESC_DEVICE, + LE_WORD(0x0101), // bcdUSB + 0x02, // bDeviceClass + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + MAX_PACKET_SIZE0, // bMaxPacketSize + LE_WORD(0xFFFF), // idVendor + LE_WORD(0x0005), // idProduct + LE_WORD(0x0100), // bcdDevice + 0x01, // iManufacturer + 0x02, // iProduct + 0x03, // iSerialNumber + 0x01, // bNumConfigurations + +// configuration descriptor + 0x09, + DESC_CONFIGURATION, + LE_WORD(67), // wTotalLength + 0x02, // bNumInterfaces + 0x01, // bConfigurationValue + 0x00, // iConfiguration + 0xC0, // bmAttributes + 0x32, // bMaxPower +// control class interface + 0x09, + DESC_INTERFACE, + 0x00, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x01, // bNumEndPoints + 0x02, // bInterfaceClass + 0x02, // bInterfaceSubClass + 0x01, // bInterfaceProtocol, linux requires value of 1 for the cdc_acm module + 0x00, // iInterface +// header functional descriptor + 0x05, + CS_INTERFACE, + 0x00, + LE_WORD(0x0110), +// call management functional descriptor + 0x05, + CS_INTERFACE, + 0x01, + 0x01, // bmCapabilities = device handles call management + 0x01, // bDataInterface +// ACM functional descriptor + 0x04, + CS_INTERFACE, + 0x02, + 0x02, // bmCapabilities +// union functional descriptor + 0x05, + CS_INTERFACE, + 0x06, + 0x00, // bMasterInterface + 0x01, // bSlaveInterface0 +// notification EP + 0x07, + DESC_ENDPOINT, + INT_IN_EP, // bEndpointAddress + 0x03, // bmAttributes = intr + LE_WORD(8), // wMaxPacketSize + 0x0A, // bInterval +// data class interface descriptor + 0x09, + DESC_INTERFACE, + 0x01, // bInterfaceNumber + 0x00, // bAlternateSetting + 0x02, // bNumEndPoints + 0x0A, // bInterfaceClass = data + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x00, // iInterface +// data EP OUT + 0x07, + DESC_ENDPOINT, + BULK_OUT_EP, // bEndpointAddress + 0x02, // bmAttributes = bulk + LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize + 0x00, // bInterval +// data EP in + 0x07, + DESC_ENDPOINT, + BULK_IN_EP, // bEndpointAddress + 0x02, // bmAttributes = bulk + LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize + 0x00, // bInterval + + // string descriptors + 0x04, + DESC_STRING, + LE_WORD(0x0409), + + 0x0E, + DESC_STRING, + 'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0, + + 0x14, + DESC_STRING, + 'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0, + + 0x12, + DESC_STRING, + 'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0, + +// terminating zero + 0 +}; + + +/** + Local function to handle incoming bulk data + + @param [in] bEP + @param [in] bEPStatus + */ +static void BulkOut(unsigned char bEP, unsigned char bEPStatus) +{ + int i, iLen; + long lHigherPriorityTaskWoken = pdFALSE; + + ( void ) bEPStatus; + + // get data from USB into intermediate buffer + iLen = USBHwEPRead(bEP, abBulkBuf, sizeof(abBulkBuf)); + for (i = 0; i < iLen; i++) { + // put into queue + xQueueSendFromISR( xRxedChars, &( abBulkBuf[ i ] ), &lHigherPriorityTaskWoken ); + } + + portEND_SWITCHING_ISR( lHigherPriorityTaskWoken ); +} + + +/** + Local function to handle outgoing bulk data + + @param [in] bEP + @param [in] bEPStatus + */ +static void BulkIn(unsigned char bEP, unsigned char bEPStatus) +{ + int i, iLen; + long lHigherPriorityTaskWoken = pdFALSE; + + ( void ) bEPStatus; + + if (uxQueueMessagesWaitingFromISR( xCharsForTx ) == 0) { + // no more data, disable further NAK interrupts until next USB frame + USBHwNakIntEnable(0); + return; + } + + // get bytes from transmit FIFO into intermediate buffer + for (i = 0; i < MAX_PACKET_SIZE; i++) { + if( xQueueReceiveFromISR( xCharsForTx, ( &abBulkBuf[i] ), &lHigherPriorityTaskWoken ) != pdPASS ) + { + break; + } + } + iLen = i; + + // send over USB + if (iLen > 0) { + USBHwEPWrite(bEP, abBulkBuf, iLen); + } + + portEND_SWITCHING_ISR( lHigherPriorityTaskWoken ); +} + + +/** + Local function to handle the USB-CDC class requests + + @param [in] pSetup + @param [out] piLen + @param [out] ppbData + */ +static BOOL HandleClassRequest(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData) +{ + switch (pSetup->bRequest) { + + // set line coding + case SET_LINE_CODING: +DBG("SET_LINE_CODING\n"); + memcpy((unsigned char *)&LineCoding, *ppbData, 7); + *piLen = 7; +DBG("dwDTERate=%u, bCharFormat=%u, bParityType=%u, bDataBits=%u\n", + LineCoding.dwDTERate, + LineCoding.bCharFormat, + LineCoding.bParityType, + LineCoding.bDataBits); + break; + + // get line coding + case GET_LINE_CODING: +DBG("GET_LINE_CODING\n"); + *ppbData = (unsigned char *)&LineCoding; + *piLen = 7; + break; + + // set control line state + case SET_CONTROL_LINE_STATE: + // bit0 = DTR, bit = RTS +DBG("SET_CONTROL_LINE_STATE %X\n", pSetup->wValue); + break; + + default: + return FALSE; + } + return TRUE; +} + + +/** + Writes one character to VCOM port + + @param [in] c character to write + @returns character written, or EOF if character could not be written + */ +int VCOM_putchar(int c) +{ +char cc = ( char ) c; + + if( xQueueSend( xCharsForTx, &cc, usbMAX_SEND_BLOCK ) == pdPASS ) + { + return c; + } + else + { + return EOF; + } +} + + +/** + Reads one character from VCOM port + + @returns character read, or EOF if character could not be read + */ +int VCOM_getchar(void) +{ + unsigned char c; + + /* Block the task until a character is available. */ + xQueueReceive( xRxedChars, &c, portMAX_DELAY ); + return c; +} + + +/** + Interrupt handler + + Simply calls the USB ISR + */ +//void USBIntHandler(void) +void USB_IRQHandler(void) +{ + USBHwISR(); +} + + +static void USBFrameHandler(unsigned short wFrame) +{ + ( void ) wFrame; + + if( uxQueueMessagesWaitingFromISR( xCharsForTx ) > 0 ) + { + // data available, enable NAK interrupt on bulk in + USBHwNakIntEnable(INACK_BI); + } +} + +// CodeRed - added CPUcpsie + +unsigned long CPUcpsie(void) +{ + unsigned long ulRet; + + // + // Read PRIMASK and enable interrupts. + // + __asm(" mrs %0, PRIMASK\n" + " cpsie i\n" + " bx lr\n" + : "=r" (ulRet)); + + // + // The return is handled in the inline assembly, but the compiler will + // still complain if there is not an explicit return here (despite the fact + // that this does not result in any code being produced because of the + // naked attribute). + // + return(ulRet); +} + +void vUSBTask( void *pvParameters ) +{ + int c; + + /* Just to prevent compiler warnings about the unused parameter. */ + ( void ) pvParameters; + DBG("Initialising USB stack\n"); + + xRxedChars = xQueueCreate( usbBUFFER_LEN, sizeof( char ) ); + xCharsForTx = xQueueCreate( usbBUFFER_LEN, sizeof( char ) ); + + if( ( xRxedChars == NULL ) || ( xCharsForTx == NULL ) ) + { + /* Not enough heap available to create the buffer queues, can't do + anything so just delete ourselves. */ + vTaskDelete( NULL ); + } + + + // initialise stack + USBInit(); + + // register descriptors + USBRegisterDescriptors(abDescriptors); + + // register class request handler + USBRegisterRequestHandler(REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData); + + // register endpoint handlers + USBHwRegisterEPIntHandler(INT_IN_EP, NULL); + USBHwRegisterEPIntHandler(BULK_IN_EP, BulkIn); + USBHwRegisterEPIntHandler(BULK_OUT_EP, BulkOut); + + // register frame handler + USBHwRegisterFrameHandler(USBFrameHandler); + + // enable bulk-in interrupts on NAKs + USBHwNakIntEnable(INACK_BI); + + DBG("Starting USB communication\n"); + + NVIC_SetPriority( USB_IRQn, configUSB_INTERRUPT_PRIORITY ); + NVIC_EnableIRQ( USB_IRQn ); + + // connect to bus + + DBG("Connecting to USB bus\n"); + USBHwConnect(TRUE); + + // echo any character received (do USB stuff in interrupt) + for( ;; ) + { + c = VCOM_getchar(); + if (c != EOF) + { + // Echo character back with INCREMENT_ECHO_BY offset, so for example if + // INCREMENT_ECHO_BY is 1 and 'A' is received, 'B' will be echoed back. + VCOM_putchar(c + INCREMENT_ECHO_BY ); + } + } +} + diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/type.h b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/type.h new file mode 100644 index 000000000..89d36850a --- /dev/null +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/type.h @@ -0,0 +1,38 @@ +/***************************************************************************** + * type.h: Type definition Header file for NXP LPC17xx Family + * Microprocessors + * + * Copyright(C) 2008, NXP Semiconductor + * All rights reserved. + * + * History + * 2008.08.21 ver 1.00 Prelimnary version, first Release + * +******************************************************************************/ +#ifndef __TYPE_H__ +#define __TYPE_H__ + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef unsigned int BOOL; + +typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus; +typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState; + +/* Pointer to Function returning Void (any number of parameters) */ +typedef void (*PFV)(); + +#endif /* __TYPE_H__ */ diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbapi.h b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbapi.h new file mode 100644 index 000000000..050f0d95b --- /dev/null +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbapi.h @@ -0,0 +1,118 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + @file +*/ + +#include "usbstruct.h" // for TSetupPacket + +/************************************************************************* + USB configuration +**************************************************************************/ + +#define MAX_PACKET_SIZE0 64 /**< maximum packet size for EP 0 */ + +/************************************************************************* + USB hardware interface +**************************************************************************/ + +// endpoint status sent through callback +#define EP_STATUS_DATA (1<<0) /**< EP has data */ +#define EP_STATUS_STALLED (1<<1) /**< EP is stalled */ +#define EP_STATUS_SETUP (1<<2) /**< EP received setup packet */ +#define EP_STATUS_ERROR (1<<3) /**< EP data was overwritten by setup packet */ +#define EP_STATUS_NACKED (1<<4) /**< EP sent NAK */ + +// device status sent through callback +#define DEV_STATUS_CONNECT (1<<0) /**< device just got connected */ +#define DEV_STATUS_SUSPEND (1<<2) /**< device entered suspend state */ +#define DEV_STATUS_RESET (1<<4) /**< device just got reset */ + +// interrupt bits for NACK events in USBHwNakIntEnable +// (these bits conveniently coincide with the LPC176x USB controller bit) +#define INACK_CI (1<<1) /**< interrupt on NACK for control in */ +#define INACK_CO (1<<2) /**< interrupt on NACK for control out */ +#define INACK_II (1<<3) /**< interrupt on NACK for interrupt in */ +#define INACK_IO (1<<4) /**< interrupt on NACK for interrupt out */ +#define INACK_BI (1<<5) /**< interrupt on NACK for bulk in */ +#define INACK_BO (1<<6) /**< interrupt on NACK for bulk out */ + +BOOL USBHwInit (void); +void USBHwISR (void); + +void USBHwNakIntEnable (unsigned char bIntBits); + +void USBHwConnect (BOOL fConnect); + +void USBHwSetAddress (unsigned char bAddr); +void USBHwConfigDevice (BOOL fConfigured); + +// endpoint operations +void USBHwEPConfig (unsigned char bEP, unsigned short wMaxPacketSize); +int USBHwEPRead (unsigned char bEP, unsigned char *pbBuf, int iMaxLen); +int USBHwEPWrite (unsigned char bEP, unsigned char *pbBuf, int iLen); +void USBHwEPStall (unsigned char bEP, BOOL fStall); +unsigned char USBHwEPGetStatus (unsigned char bEP); + +/** Endpoint interrupt handler callback */ +typedef void (TFnEPIntHandler) (unsigned char bEP, unsigned char bEPStatus); +void USBHwRegisterEPIntHandler (unsigned char bEP, TFnEPIntHandler *pfnHandler); + +/** Device status handler callback */ +typedef void (TFnDevIntHandler) (unsigned char bDevStatus); +void USBHwRegisterDevIntHandler (TFnDevIntHandler *pfnHandler); + +/** Frame event handler callback */ +typedef void (TFnFrameHandler)(unsigned short wFrame); +void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler); + + +/************************************************************************* + USB application interface +**************************************************************************/ + +// initialise the complete stack, including HW +BOOL USBInit(void); + +/** Request handler callback (standard, vendor, class) */ +typedef BOOL (TFnHandleRequest)(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData); +void USBRegisterRequestHandler(int iType, TFnHandleRequest *pfnHandler, unsigned char *pbDataStore); +void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler); + +/** Descriptor handler callback */ +typedef BOOL (TFnGetDescriptor)(unsigned short wTypeIndex, unsigned short wLangID, int *piLen, unsigned char **ppbData); + +/** Default standard request handler */ +BOOL USBHandleStandardRequest(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData); + +/** Default EP0 handler */ +void USBHandleControlTransfer(unsigned char bEP, unsigned char bEPStat); + +/** Descriptor handling */ +void USBRegisterDescriptors(const unsigned char *pabDescriptors); +BOOL USBGetDescriptor(unsigned short wTypeIndex, unsigned short wLangID, int *piLen, unsigned char **ppbData); diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbcontrol.c b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbcontrol.c new file mode 100644 index 000000000..18ff180fe --- /dev/null +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbcontrol.c @@ -0,0 +1,246 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** @file + Control transfer handler. + + This module handles control transfers and is normally installed on the + endpoint 0 callback. + + Control transfers can be of the following type: + 0 Standard; + 1 Class; + 2 Vendor; + 3 Reserved. + + A callback can be installed for each of these control transfers using + USBRegisterRequestHandler. + When an OUT request arrives, data is collected in the data store provided + with the USBRegisterRequestHandler call. When the transfer is done, the + callback is called. + When an IN request arrives, the callback is called immediately to either + put the control transfer data in the data store, or to get a pointer to + control transfer data. The data is then packetised and sent to the host. +*/ + +#include "usbdebug.h" + +#include "usbstruct.h" +#include "usbapi.h" + + + +#define MAX_CONTROL_SIZE 128 /**< maximum total size of control transfer data */ +#define MAX_REQ_HANDLERS 4 /**< standard, class, vendor, reserved */ + +static TSetupPacket Setup; /**< setup packet */ + +static unsigned char *pbData; /**< pointer to data buffer */ +static int iResidue; /**< remaining bytes in buffer */ +static int iLen; /**< total length of control transfer */ + +/** Array of installed request handler callbacks */ +static TFnHandleRequest *apfnReqHandlers[4] = {NULL, NULL, NULL, NULL}; +/** Array of installed request data pointers */ +static unsigned char *apbDataStore[4] = {NULL, NULL, NULL, NULL}; + +/** + Local function to handle a request by calling one of the installed + request handlers. + + In case of data going from host to device, the data is at *ppbData. + In case of data going from device to host, the handler can either + choose to write its data at *ppbData or update the data pointer. + + @param [in] pSetup The setup packet + @param [in,out] *piLen Pointer to data length + @param [in,out] ppbData Data buffer. + + @return TRUE if the request was handles successfully + */ +static BOOL _HandleRequest(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData) +{ + TFnHandleRequest *pfnHandler; + int iType; + + iType = REQTYPE_GET_TYPE(pSetup->bmRequestType); + pfnHandler = apfnReqHandlers[iType]; + if (pfnHandler == NULL) { + DBG("No handler for reqtype %d\n", iType); + return FALSE; + } + + return pfnHandler(pSetup, piLen, ppbData); +} + + +/** + Local function to stall the control endpoint + + @param [in] bEPStat Endpoint status + */ +static void StallControlPipe(unsigned char bEPStat) +{ + unsigned char *pb; + int i; + + USBHwEPStall(0x80, TRUE); + +// dump setup packet + DBG("STALL on ["); + pb = (unsigned char *)&Setup; + for (i = 0; i < 8; i++) { + DBG(" %02x", *pb++); + } + DBG("] stat=%x\n", bEPStat); +} + + +/** + Sends next chunk of data (possibly 0 bytes) to host + */ +static void DataIn(void) +{ + int iChunk; + + if( MAX_PACKET_SIZE0 < iResidue ) + { + iChunk = MAX_PACKET_SIZE0; + } + else + { + iChunk = iResidue; + } + + USBHwEPWrite(0x80, pbData, iChunk); + pbData += iChunk; + iResidue -= iChunk; +} + + +/** + * Handles IN/OUT transfers on EP0 + * + * @param [in] bEP Endpoint address + * @param [in] bEPStat Endpoint status + */ +void USBHandleControlTransfer(unsigned char bEP, unsigned char bEPStat) +{ + int iChunk, iType; + + if (bEP == 0x00) { + // OUT transfer + if (bEPStat & EP_STATUS_SETUP) { + // setup packet, reset request message state machine + USBHwEPRead(0x00, (unsigned char *)&Setup, sizeof(Setup)); + DBG("S%x", Setup.bRequest); + + // defaults for data pointer and residue + iType = REQTYPE_GET_TYPE(Setup.bmRequestType); + pbData = apbDataStore[iType]; + iResidue = Setup.wLength; + iLen = Setup.wLength; + + if ((Setup.wLength == 0) || + (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST)) { + // ask installed handler to process request + if (!_HandleRequest(&Setup, &iLen, &pbData)) { + DBG("_HandleRequest1 failed\n"); + StallControlPipe(bEPStat); + return; + } + // send smallest of requested and offered length + if( iLen < Setup.wLength ) + { + iResidue = iLen; + } + else + { + iResidue = Setup.wLength; + } + + // send first part (possibly a zero-length status message) + DataIn(); + } + } + else { + if (iResidue > 0) { + // store data + iChunk = USBHwEPRead(0x00, pbData, iResidue); + if (iChunk < 0) { + StallControlPipe(bEPStat); + return; + } + pbData += iChunk; + iResidue -= iChunk; + if (iResidue == 0) { + // received all, send data to handler + iType = REQTYPE_GET_TYPE(Setup.bmRequestType); + pbData = apbDataStore[iType]; + if (!_HandleRequest(&Setup, &iLen, &pbData)) { + DBG("_HandleRequest2 failed\n"); + StallControlPipe(bEPStat); + return; + } + // send status to host + DataIn(); + } + } + else { + // absorb zero-length status message + iChunk = USBHwEPRead(0x00, NULL, 0); + DBG(iChunk > 0 ? "?" : ""); + } + } + } + else if (bEP == 0x80) { + // IN transfer + // send more data if available (possibly a 0-length packet) + DataIn(); + } + else { + ASSERT(FALSE); + } +} + + +/** + Registers a callback for handling requests + + @param [in] iType Type of request, e.g. REQTYPE_TYPE_STANDARD + @param [in] *pfnHandler Callback function pointer + @param [in] *pbDataStore Data storage area for this type of request + */ +void USBRegisterRequestHandler(int iType, TFnHandleRequest *pfnHandler, unsigned char *pbDataStore) +{ + ASSERT(iType >= 0); + ASSERT(iType < 4); + apfnReqHandlers[iType] = pfnHandler; + apbDataStore[iType] = pbDataStore; +} + diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbdebug.h b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbdebug.h new file mode 100644 index 000000000..4a14862e6 --- /dev/null +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbdebug.h @@ -0,0 +1,41 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// CodeRed - comment out this printf, as will use real one from stdio.h +// to implement output via semihosting + +//int printf(const char *format, ...); +# include + +#ifdef _DEBUG +#define DBG printf +#define ASSERT(x) if(!(x)){DBG("\nAssertion '%s' failed in %s:%s#%d!\n",#x,__FILE__,__FUNCTION__,__LINE__);while(1);} +#else +#define DBG(x ...) +#define ASSERT(x) +#endif + diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbhw_lpc.c b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbhw_lpc.c new file mode 100644 index 000000000..e9bd46015 --- /dev/null +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbhw_lpc.c @@ -0,0 +1,521 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** @file + USB hardware layer + */ + + +#include "usbdebug.h" +#include "usbhw_lpc.h" +#include "usbapi.h" + +/** Installed device interrupt handler */ +static TFnDevIntHandler *_pfnDevIntHandler = NULL; +/** Installed endpoint interrupt handlers */ +static TFnEPIntHandler *_apfnEPIntHandlers[16]; +/** Installed frame interrupt handlers */ +static TFnFrameHandler *_pfnFrameHandler = NULL; + +/** convert from endpoint address to endpoint index */ +#define EP2IDX(bEP) ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7)) +/** convert from endpoint index to endpoint address */ +#define IDX2EP(idx) ((((idx)<<7)&0x80)|(((idx)>>1)&0xF)) + + + +/** + Local function to wait for a device interrupt (and clear it) + + @param [in] dwIntr Bitmask of interrupts to wait for + */ +static void Wait4DevInt(unsigned long dwIntr) +{ + // wait for specific interrupt + while ((USB->USBDevIntSt & dwIntr) != dwIntr); + // clear the interrupt bits + USB->USBDevIntClr = dwIntr; +} + + +/** + Local function to send a command to the USB protocol engine + + @param [in] bCmd Command to send + */ +static void USBHwCmd(unsigned char bCmd) +{ + // clear CDFULL/CCEMTY + USB->USBDevIntClr = CDFULL | CCEMTY; + // write command code + USB->USBCmdCode = 0x00000500 | (bCmd << 16); + Wait4DevInt(CCEMTY); +} + + +/** + Local function to send a command + data to the USB protocol engine + + @param [in] bCmd Command to send + @param [in] bData Data to send + */ +static void USBHwCmdWrite(unsigned char bCmd, unsigned short bData) +{ + // write command code + USBHwCmd(bCmd); + + // write command data + USB->USBCmdCode = 0x00000100 | (bData << 16); + Wait4DevInt(CCEMTY); +} + + +/** + Local function to send a command to the USB protocol engine and read data + + @param [in] bCmd Command to send + + @return the data + */ +static unsigned char USBHwCmdRead(unsigned char bCmd) +{ + // write command code + USBHwCmd(bCmd); + + // get data + USB->USBCmdCode = 0x00000200 | (bCmd << 16); + Wait4DevInt(CDFULL); + return USB->USBCmdData; +} + + +/** + 'Realizes' an endpoint, meaning that buffer space is reserved for + it. An endpoint needs to be realised before it can be used. + + From experiments, it appears that a USB reset causes USBReEP to + re-initialise to 3 (= just the control endpoints). + However, a USB bus reset does not disturb the USBMaxPSize settings. + + @param [in] idx Endpoint index + @param [in] wMaxPSize Maximum packet size for this endpoint + */ +static void USBHwEPRealize(int idx, unsigned short wMaxPSize) +{ + USB->USBReEP |= (1 << idx); + USB->USBEpInd = idx; + USB->USBMaxPSize = wMaxPSize; + Wait4DevInt(EP_RLZED); +} + + +/** + Enables or disables an endpoint + + @param [in] idx Endpoint index + @param [in] fEnable TRUE to enable, FALSE to disable + */ +static void USBHwEPEnable(int idx, BOOL fEnable) +{ + USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA); +} + + +/** + Configures an endpoint and enables it + + @param [in] bEP Endpoint number + @param [in] wMaxPacketSize Maximum packet size for this EP + */ +void USBHwEPConfig(unsigned char bEP, unsigned short wMaxPacketSize) +{ + int idx; + + idx = EP2IDX(bEP); + + // realise EP + USBHwEPRealize(idx, wMaxPacketSize); + + // enable EP + USBHwEPEnable(idx, TRUE); +} + + +/** + Registers an endpoint event callback + + @param [in] bEP Endpoint number + @param [in] pfnHandler Callback function + */ +void USBHwRegisterEPIntHandler(unsigned char bEP, TFnEPIntHandler *pfnHandler) +{ + int idx; + + idx = EP2IDX(bEP); + + ASSERT(idx<32); + + /* add handler to list of EP handlers */ + _apfnEPIntHandlers[idx / 2] = pfnHandler; + + /* enable EP interrupt */ + USB->USBEpIntEn |= (1 << idx); + USB->USBDevIntEn |= EP_SLOW; + + DBG("Registered handler for EP 0x%x\n", bEP); +} + + +/** + Registers an device status callback + + @param [in] pfnHandler Callback function + */ +void USBHwRegisterDevIntHandler(TFnDevIntHandler *pfnHandler) +{ + _pfnDevIntHandler = pfnHandler; + + // enable device interrupt + USB->USBDevIntEn |= DEV_STAT; + + DBG("Registered handler for device status\n"); +} + + +/** + Registers the frame callback + + @param [in] pfnHandler Callback function + */ +void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler) +{ + _pfnFrameHandler = pfnHandler; + + // enable device interrupt + USB->USBDevIntEn |= FRAME; + + DBG("Registered handler for frame\n"); +} + + +/** + Sets the USB address. + + @param [in] bAddr Device address to set + */ +void USBHwSetAddress(unsigned char bAddr) +{ + USBHwCmdWrite(CMD_DEV_SET_ADDRESS, DEV_EN | bAddr); +} + + +/** + Connects or disconnects from the USB bus + + @param [in] fConnect If TRUE, connect, otherwise disconnect + */ +void USBHwConnect(BOOL fConnect) +{ + USBHwCmdWrite(CMD_DEV_STATUS, fConnect ? CON : 0); +} + + +/** + Enables interrupt on NAK condition + + For IN endpoints a NAK is generated when the host wants to read data + from the device, but none is available in the endpoint buffer. + For OUT endpoints a NAK is generated when the host wants to write data + to the device, but the endpoint buffer is still full. + + The endpoint interrupt handlers can distinguish regular (ACK) interrupts + from NAK interrupt by checking the bits in their bEPStatus argument. + + @param [in] bIntBits Bitmap indicating which NAK interrupts to enable + */ +void USBHwNakIntEnable(unsigned char bIntBits) +{ + USBHwCmdWrite(CMD_DEV_SET_MODE, bIntBits); +} + + +/** + Gets the status from a specific endpoint. + + @param [in] bEP Endpoint number + @return Endpoint status byte (containing EP_STATUS_xxx bits) + */ +unsigned char USBHwEPGetStatus(unsigned char bEP) +{ + int idx = EP2IDX(bEP); + + return USBHwCmdRead(CMD_EP_SELECT | idx); +} + + +/** + Sets the stalled property of an endpoint + + @param [in] bEP Endpoint number + @param [in] fStall TRUE to stall, FALSE to unstall + */ +void USBHwEPStall(unsigned char bEP, BOOL fStall) +{ + int idx = EP2IDX(bEP); + + USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0); +} + + +/** + Writes data to an endpoint buffer + + @param [in] bEP Endpoint number + @param [in] pbBuf Endpoint data + @param [in] iLen Number of bytes to write + + @return TRUE if the data was successfully written or <0 in case of error. +*/ +int USBHwEPWrite(unsigned char bEP, unsigned char *pbBuf, int iLen) +{ + int idx; + + idx = EP2IDX(bEP); + + // set write enable for specific endpoint + USB->USBCtrl = WR_EN | ((bEP & 0xF) << 2); + + // set packet length + USB->USBTxPLen = iLen; + + // write data + while (USB->USBCtrl & WR_EN) { + USB->USBTxData = (pbBuf[3] << 24) | (pbBuf[2] << 16) | (pbBuf[1] << 8) | pbBuf[0]; + pbBuf += 4; + } + + // select endpoint and validate buffer + USBHwCmd(CMD_EP_SELECT | idx); + USBHwCmd(CMD_EP_VALIDATE_BUFFER); + + return iLen; +} + + +/** + Reads data from an endpoint buffer + + @param [in] bEP Endpoint number + @param [in] pbBuf Endpoint data + @param [in] iMaxLen Maximum number of bytes to read + + @return the number of bytes available in the EP (possibly more than iMaxLen), + or <0 in case of error. + */ +int USBHwEPRead(unsigned char bEP, unsigned char *pbBuf, int iMaxLen) +{ + unsigned int i, idx; + unsigned long dwData, dwLen; + + idx = EP2IDX(bEP); + + // set read enable bit for specific endpoint + USB->USBCtrl = RD_EN | ((bEP & 0xF) << 2); + + // wait for PKT_RDY + do { + dwLen = USB->USBRxPLen; + } while ((dwLen & PKT_RDY) == 0); + + // packet valid? + if ((dwLen & DV) == 0) { + return -1; + } + + // get length + dwLen &= PKT_LNGTH_MASK; + + // get data + dwData = 0; + for (i = 0; i < dwLen; i++) { + if ((i % 4) == 0) { + dwData = USB->USBRxData; + } + if ((pbBuf != NULL) && ((int)i < iMaxLen)) { + pbBuf[i] = dwData & 0xFF; + } + dwData >>= 8; + } + + // make sure RD_EN is clear + USB->USBCtrl = 0; + + // select endpoint and clear buffer + USBHwCmd(CMD_EP_SELECT | idx); + USBHwCmd(CMD_EP_CLEAR_BUFFER); + + return dwLen; +} + + +/** + Sets the 'configured' state. + + All registered endpoints are 'realised' and enabled, and the + 'configured' bit is set in the device status register. + + @param [in] fConfigured If TRUE, configure device, else unconfigure + */ +void USBHwConfigDevice(BOOL fConfigured) +{ + // set configured bit + USBHwCmdWrite(CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0); +} + + +/** + USB interrupt handler + + @todo Get all 11 bits of frame number instead of just 8 + + Endpoint interrupts are mapped to the slow interrupt + */ +void USBHwISR(void) +{ + unsigned long dwStatus; + unsigned long dwIntBit; + unsigned char bEPStat, bDevStat, bStat; + int i; + unsigned short wFrame; + + // handle device interrupts + dwStatus = USB->USBDevIntSt; + + // frame interrupt + if (dwStatus & FRAME) { + // clear int + USB->USBDevIntClr = FRAME; + // call handler + if (_pfnFrameHandler != NULL) { + wFrame = USBHwCmdRead(CMD_DEV_READ_CUR_FRAME_NR); + _pfnFrameHandler(wFrame); + } + } + + // device status interrupt + if (dwStatus & DEV_STAT) { + /* Clear DEV_STAT interrupt before reading DEV_STAT register. + This prevents corrupted device status reads, see + LPC2148 User manual revision 2, 25 july 2006. + */ + USB->USBDevIntClr = DEV_STAT; + bDevStat = USBHwCmdRead(CMD_DEV_STATUS); + if (bDevStat & (CON_CH | SUS_CH | RST)) { + // convert device status into something HW independent + bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) | + ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) | + ((bDevStat & RST) ? DEV_STATUS_RESET : 0); + // call handler + if (_pfnDevIntHandler != NULL) { + _pfnDevIntHandler(bStat); + } + } + } + + // endpoint interrupt + if (dwStatus & EP_SLOW) { + // clear EP_SLOW + USB->USBDevIntClr = EP_SLOW; + // check all endpoints + for (i = 0; i < 32; i++) { + dwIntBit = (1 << i); + if (USB->USBEpIntSt & dwIntBit) { + // clear int (and retrieve status) + USB->USBEpIntClr = dwIntBit; + Wait4DevInt(CDFULL); + bEPStat = USB->USBCmdData; + // convert EP pipe stat into something HW independent + bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) | + ((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) | + ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) | + ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) | + ((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0); + // call handler + if (_apfnEPIntHandlers[i / 2] != NULL) { + _apfnEPIntHandlers[i / 2](IDX2EP(i), bStat); + } + } + } + } +} + + + +/** + Initialises the USB hardware + + + @return TRUE if the hardware was successfully initialised + */ +BOOL USBHwInit(void) +{ + // P2.9 -> USB_CONNECT + PINCON->PINSEL4 &= ~0x000C0000; + PINCON->PINSEL4 |= 0x00040000; + + // P1.18 -> USB_UP_LED + // P1.30 -> VBUS + PINCON->PINSEL3 &= ~0x30000030; + PINCON->PINSEL3 |= 0x20000010; + + // P0.29 -> USB_D+ + // P0.30 -> USB_D- + PINCON->PINSEL1 &= ~0x3C000000; + PINCON->PINSEL1 |= 0x14000000; + + // enable PUSB + SC->PCONP |= (1 << 31); + + USB->OTGClkCtrl = 0x12; /* Dev clock, AHB clock enable */ + while ((USB->OTGClkSt & 0x12) != 0x12); + + // disable/clear all interrupts for now + USB->USBDevIntEn = 0; + USB->USBDevIntClr = 0xFFFFFFFF; + USB->USBDevIntPri = 0; + + USB->USBEpIntEn = 0; + USB->USBEpIntClr = 0xFFFFFFFF; + USB->USBEpIntPri = 0; + + // by default, only ACKs generate interrupts + USBHwNakIntEnable(0); + + return TRUE; +} + diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbhw_lpc.c.bak b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbhw_lpc.c.bak new file mode 100644 index 000000000..29de3ded9 --- /dev/null +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbhw_lpc.c.bak @@ -0,0 +1,521 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** @file + USB hardware layer + */ + + +#include "usbdebug.h" +#include "usbhw_lpc.h" +#include "usbapi.h" + +/** Installed device interrupt handler */ +static TFnDevIntHandler *_pfnDevIntHandler = NULL; +/** Installed endpoint interrupt handlers */ +static TFnEPIntHandler *_apfnEPIntHandlers[16]; +/** Installed frame interrupt handlers */ +static TFnFrameHandler *_pfnFrameHandler = NULL; + +/** convert from endpoint address to endpoint index */ +#define EP2IDX(bEP) ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7)) +/** convert from endpoint index to endpoint address */ +#define IDX2EP(idx) ((((idx)<<7)&0x80)|(((idx)>>1)&0xF)) + + + +/** + Local function to wait for a device interrupt (and clear it) + + @param [in] dwIntr Bitmask of interrupts to wait for + */ +static void Wait4DevInt(unsigned long dwIntr) +{ + // wait for specific interrupt + while ((USB->USBDevIntSt & dwIntr) != dwIntr); + // clear the interrupt bits + USB->USBDevIntClr = dwIntr; +} + + +/** + Local function to send a command to the USB protocol engine + + @param [in] bCmd Command to send + */ +static void USBHwCmd(unsigned char bCmd) +{ + // clear CDFULL/CCEMTY + USB->USBDevIntClr = CDFULL | CCEMTY; + // write command code + USB->USBCmdCode = 0x00000500 | (bCmd << 16); + Wait4DevInt(CCEMTY); +} + + +/** + Local function to send a command + data to the USB protocol engine + + @param [in] bCmd Command to send + @param [in] bData Data to send + */ +static void USBHwCmdWrite(unsigned char bCmd, unsigned short bData) +{ + // write command code + USBHwCmd(bCmd); + + // write command data + USB->USBCmdCode = 0x00000100 | (bData << 16); + Wait4DevInt(CCEMTY); +} + + +/** + Local function to send a command to the USB protocol engine and read data + + @param [in] bCmd Command to send + + @return the data + */ +static unsigned char USBHwCmdRead(unsigned char bCmd) +{ + // write command code + USBHwCmd(bCmd); + + // get data + USB->USBCmdCode = 0x00000200 | (bCmd << 16); + Wait4DevInt(CDFULL); + return USB->USBCmdData; +} + + +/** + 'Realizes' an endpoint, meaning that buffer space is reserved for + it. An endpoint needs to be realised before it can be used. + + From experiments, it appears that a USB reset causes USBReEP to + re-initialise to 3 (= just the control endpoints). + However, a USB bus reset does not disturb the USBMaxPSize settings. + + @param [in] idx Endpoint index + @param [in] wMaxPSize Maximum packet size for this endpoint + */ +static void USBHwEPRealize(int idx, unsigned short wMaxPSize) +{ + USB->USBReEP |= (1 << idx); + USB->USBEpInd = idx; + USB->USBMaxPSize = wMaxPSize; + Wait4DevInt(EP_RLZED); +} + + +/** + Enables or disables an endpoint + + @param [in] idx Endpoint index + @param [in] fEnable TRUE to enable, FALSE to disable + */ +static void USBHwEPEnable(int idx, BOOL fEnable) +{ + USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA); +} + + +/** + Configures an endpoint and enables it + + @param [in] bEP Endpoint number + @param [in] wMaxPacketSize Maximum packet size for this EP + */ +void USBHwEPConfig(unsigned char bEP, unsigned short wMaxPacketSize) +{ + int idx; + + idx = EP2IDX(bEP); + + // realise EP + USBHwEPRealize(idx, wMaxPacketSize); + + // enable EP + USBHwEPEnable(idx, TRUE); +} + + +/** + Registers an endpoint event callback + + @param [in] bEP Endpoint number + @param [in] pfnHandler Callback function + */ +void USBHwRegisterEPIntHandler(unsigned char bEP, TFnEPIntHandler *pfnHandler) +{ + int idx; + + idx = EP2IDX(bEP); + + ASSERT(idx<32); + + /* add handler to list of EP handlers */ + _apfnEPIntHandlers[idx / 2] = pfnHandler; + + /* enable EP interrupt */ + USB->USBEpIntEn |= (1 << idx); + USB->USBDevIntEn |= EP_SLOW; + + DBG("Registered handler for EP 0x%x\n", bEP); +} + + +/** + Registers an device status callback + + @param [in] pfnHandler Callback function + */ +void USBHwRegisterDevIntHandler(TFnDevIntHandler *pfnHandler) +{ + _pfnDevIntHandler = pfnHandler; + + // enable device interrupt + USB->USBDevIntEn |= DEV_STAT; + + DBG("Registered handler for device status\n"); +} + + +/** + Registers the frame callback + + @param [in] pfnHandler Callback function + */ +void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler) +{ + _pfnFrameHandler = pfnHandler; + + // enable device interrupt + USB->USBDevIntEn |= FRAME; + + DBG("Registered handler for frame\n"); +} + + +/** + Sets the USB address. + + @param [in] bAddr Device address to set + */ +void USBHwSetAddress(unsigned char bAddr) +{ + USBHwCmdWrite(CMD_DEV_SET_ADDRESS, DEV_EN | bAddr); +} + + +/** + Connects or disconnects from the USB bus + + @param [in] fConnect If TRUE, connect, otherwise disconnect + */ +void USBHwConnect(BOOL fConnect) +{ + USBHwCmdWrite(CMD_DEV_STATUS, fConnect ? CON : 0); +} + + +/** + Enables interrupt on NAK condition + + For IN endpoints a NAK is generated when the host wants to read data + from the device, but none is available in the endpoint buffer. + For OUT endpoints a NAK is generated when the host wants to write data + to the device, but the endpoint buffer is still full. + + The endpoint interrupt handlers can distinguish regular (ACK) interrupts + from NAK interrupt by checking the bits in their bEPStatus argument. + + @param [in] bIntBits Bitmap indicating which NAK interrupts to enable + */ +void USBHwNakIntEnable(unsigned char bIntBits) +{ + USBHwCmdWrite(CMD_DEV_SET_MODE, bIntBits); +} + + +/** + Gets the status from a specific endpoint. + + @param [in] bEP Endpoint number + @return Endpoint status byte (containing EP_STATUS_xxx bits) + */ +unsigned char USBHwEPGetStatus(unsigned char bEP) +{ + int idx = EP2IDX(bEP); + + return USBHwCmdRead(CMD_EP_SELECT | idx); +} + + +/** + Sets the stalled property of an endpoint + + @param [in] bEP Endpoint number + @param [in] fStall TRUE to stall, FALSE to unstall + */ +void USBHwEPStall(unsigned char bEP, BOOL fStall) +{ + int idx = EP2IDX(bEP); + + USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0); +} + + +/** + Writes data to an endpoint buffer + + @param [in] bEP Endpoint number + @param [in] pbBuf Endpoint data + @param [in] iLen Number of bytes to write + + @return TRUE if the data was successfully written or <0 in case of error. +*/ +int USBHwEPWrite(unsigned char bEP, unsigned char *pbBuf, int iLen) +{ + int idx; + + idx = EP2IDX(bEP); + + // set write enable for specific endpoint + USB->USBCtrl = WR_EN | ((bEP & 0xF) << 2); + + // set packet length + USB->USBTxPLen = iLen; + + // write data + while (USB->USBCtrl & WR_EN) { + USB->USBTxData = (pbBuf[3] << 24) | (pbBuf[2] << 16) | (pbBuf[1] << 8) | pbBuf[0]; + pbBuf += 4; + } + + // select endpoint and validate buffer + USBHwCmd(CMD_EP_SELECT | idx); + USBHwCmd(CMD_EP_VALIDATE_BUFFER); + + return iLen; +} + + +/** + Reads data from an endpoint buffer + + @param [in] bEP Endpoint number + @param [in] pbBuf Endpoint data + @param [in] iMaxLen Maximum number of bytes to read + + @return the number of bytes available in the EP (possibly more than iMaxLen), + or <0 in case of error. + */ +int USBHwEPRead(unsigned char bEP, unsigned char *pbBuf, int iMaxLen) +{ + unsigned int i, idx; + unsigned long dwData, dwLen; + + idx = EP2IDX(bEP); + + // set read enable bit for specific endpoint + USB->USBCtrl = RD_EN | ((bEP & 0xF) << 2); + + // wait for PKT_RDY + do { + dwLen = USB->USBRxPLen; + } while ((dwLen & PKT_RDY) == 0); + + // packet valid? + if ((dwLen & DV) == 0) { + return -1; + } + + // get length + dwLen &= PKT_LNGTH_MASK; + + // get data + dwData = 0; + for (i = 0; i < dwLen; i++) { + if ((i % 4) == 0) { + dwData = USB->USBRxData; + } + if ((pbBuf != NULL) && (i < iMaxLen)) { + pbBuf[i] = dwData & 0xFF; + } + dwData >>= 8; + } + + // make sure RD_EN is clear + USB->USBCtrl = 0; + + // select endpoint and clear buffer + USBHwCmd(CMD_EP_SELECT | idx); + USBHwCmd(CMD_EP_CLEAR_BUFFER); + + return dwLen; +} + + +/** + Sets the 'configured' state. + + All registered endpoints are 'realised' and enabled, and the + 'configured' bit is set in the device status register. + + @param [in] fConfigured If TRUE, configure device, else unconfigure + */ +void USBHwConfigDevice(BOOL fConfigured) +{ + // set configured bit + USBHwCmdWrite(CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0); +} + + +/** + USB interrupt handler + + @todo Get all 11 bits of frame number instead of just 8 + + Endpoint interrupts are mapped to the slow interrupt + */ +void USBHwISR(void) +{ + unsigned long dwStatus; + unsigned long dwIntBit; + unsigned char bEPStat, bDevStat, bStat; + int i; + unsigned short wFrame; + + // handle device interrupts + dwStatus = USB->USBDevIntSt; + + // frame interrupt + if (dwStatus & FRAME) { + // clear int + USB->USBDevIntClr = FRAME; + // call handler + if (_pfnFrameHandler != NULL) { + wFrame = USBHwCmdRead(CMD_DEV_READ_CUR_FRAME_NR); + _pfnFrameHandler(wFrame); + } + } + + // device status interrupt + if (dwStatus & DEV_STAT) { + /* Clear DEV_STAT interrupt before reading DEV_STAT register. + This prevents corrupted device status reads, see + LPC2148 User manual revision 2, 25 july 2006. + */ + USB->USBDevIntClr = DEV_STAT; + bDevStat = USBHwCmdRead(CMD_DEV_STATUS); + if (bDevStat & (CON_CH | SUS_CH | RST)) { + // convert device status into something HW independent + bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) | + ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) | + ((bDevStat & RST) ? DEV_STATUS_RESET : 0); + // call handler + if (_pfnDevIntHandler != NULL) { + _pfnDevIntHandler(bStat); + } + } + } + + // endpoint interrupt + if (dwStatus & EP_SLOW) { + // clear EP_SLOW + USB->USBDevIntClr = EP_SLOW; + // check all endpoints + for (i = 0; i < 32; i++) { + dwIntBit = (1 << i); + if (USB->USBEpIntSt & dwIntBit) { + // clear int (and retrieve status) + USB->USBEpIntClr = dwIntBit; + Wait4DevInt(CDFULL); + bEPStat = USB->USBCmdData; + // convert EP pipe stat into something HW independent + bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) | + ((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) | + ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) | + ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) | + ((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0); + // call handler + if (_apfnEPIntHandlers[i / 2] != NULL) { + _apfnEPIntHandlers[i / 2](IDX2EP(i), bStat); + } + } + } + } +} + + + +/** + Initialises the USB hardware + + + @return TRUE if the hardware was successfully initialised + */ +BOOL USBHwInit(void) +{ + // P2.9 -> USB_CONNECT + PINCON->PINSEL4 &= ~0x000C0000; + PINCON->PINSEL4 |= 0x00040000; + + // P1.18 -> USB_UP_LED + // P1.30 -> VBUS + PINCON->PINSEL3 &= ~0x30000030; + PINCON->PINSEL3 |= 0x20000010; + + // P0.29 -> USB_D+ + // P0.30 -> USB_D- + PINCON->PINSEL1 &= ~0x3C000000; + PINCON->PINSEL1 |= 0x14000000; + + // enable PUSB + SC->PCONP |= (1 << 31); + + USB->OTGClkCtrl = 0x12; /* Dev clock, AHB clock enable */ + while ((USB->OTGClkSt & 0x12) != 0x12); + + // disable/clear all interrupts for now + USB->USBDevIntEn = 0; + USB->USBDevIntClr = 0xFFFFFFFF; + USB->USBDevIntPri = 0; + + USB->USBEpIntEn = 0; + USB->USBEpIntClr = 0xFFFFFFFF; + USB->USBEpIntPri = 0; + + // by default, only ACKs generate interrupts + USBHwNakIntEnable(0); + + return TRUE; +} + diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbhw_lpc.h b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbhw_lpc.h new file mode 100644 index 000000000..2a4de7949 --- /dev/null +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbhw_lpc.h @@ -0,0 +1,149 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** + Hardware definitions for the LPC176x USB controller + + These are private to the usbhw module +*/ + +// CodeRed - pull in defines from NXP header file +//#include "NXP\LPC17xx\LPC17xx.h" +#include "LPC17xx.h" + + +// CodeRed - these registers have been renamed on LPC176x +#define USBReEP USBReEp +#define OTG_CLK_CTRL USBClkCtrl +#define OTG_CLK_STAT USBClkSt + +/* USBIntSt bits */ +#define USB_INT_REQ_LP (1<<0) +#define USB_INT_REQ_HP (1<<1) +#define USB_INT_REQ_DMA (1<<2) +#define USB_need_clock (1<<8) +#define EN_USB_BITS (1<<31) + +/* USBDevInt... bits */ +#define FRAME (1<<0) +#define EP_FAST (1<<1) +#define EP_SLOW (1<<2) +#define DEV_STAT (1<<3) +#define CCEMTY (1<<4) +#define CDFULL (1<<5) +#define RxENDPKT (1<<6) +#define TxENDPKT (1<<7) +#define EP_RLZED (1<<8) +#define ERR_INT (1<<9) + +/* USBRxPLen bits */ +#define PKT_LNGTH (1<<0) +#define PKT_LNGTH_MASK 0x3FF +#define DV (1<<10) +#define PKT_RDY (1<<11) + +/* USBCtrl bits */ +#define RD_EN (1<<0) +#define WR_EN (1<<1) +#define LOG_ENDPOINT (1<<2) + +/* protocol engine command codes */ + /* device commands */ +#define CMD_DEV_SET_ADDRESS 0xD0 +#define CMD_DEV_CONFIG 0xD8 +#define CMD_DEV_SET_MODE 0xF3 +#define CMD_DEV_READ_CUR_FRAME_NR 0xF5 +#define CMD_DEV_READ_TEST_REG 0xFD +#define CMD_DEV_STATUS 0xFE /* read/write */ +#define CMD_DEV_GET_ERROR_CODE 0xFF +#define CMD_DEV_READ_ERROR_STATUS 0xFB + /* endpoint commands */ +#define CMD_EP_SELECT 0x00 +#define CMD_EP_SELECT_CLEAR 0x40 +#define CMD_EP_SET_STATUS 0x40 +#define CMD_EP_CLEAR_BUFFER 0xF2 +#define CMD_EP_VALIDATE_BUFFER 0xFA + +/* set address command */ +#define DEV_ADDR (1<<0) +#define DEV_EN (1<<7) + +/* configure device command */ +#define CONF_DEVICE (1<<0) + +/* set mode command */ +#define AP_CLK (1<<0) +#define INAK_CI (1<<1) +#define INAK_CO (1<<2) +#define INAK_II (1<<3) +#define INAK_IO (1<<4) +#define INAK_BI (1<<5) +#define INAK_BO (1<<6) + +/* set get device status command */ +#define CON (1<<0) +#define CON_CH (1<<1) +#define SUS (1<<2) +#define SUS_CH (1<<3) +#define RST (1<<4) + +/* get error code command */ +// ... + +/* Select Endpoint command read bits */ +#define EPSTAT_FE (1<<0) +#define EPSTAT_ST (1<<1) +#define EPSTAT_STP (1<<2) +#define EPSTAT_PO (1<<3) +#define EPSTAT_EPN (1<<4) +#define EPSTAT_B1FULL (1<<5) +#define EPSTAT_B2FULL (1<<6) + +/* CMD_EP_SET_STATUS command */ +#define EP_ST (1<<0) +#define EP_DA (1<<5) +#define EP_RF_MO (1<<6) +#define EP_CND_ST (1<<7) + +/* read error status command */ +#define PID_ERR (1<<0) +#define UEPKT (1<<1) +#define DCRC (1<<2) +#define TIMEOUT (1<<3) +#define EOP (1<<4) +#define B_OVRN (1<<5) +#define BTSTF (1<<6) +#define TGL_ERR (1<<7) + + + + + + + + diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbinit.c b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbinit.c new file mode 100644 index 000000000..8bb718317 --- /dev/null +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbinit.c @@ -0,0 +1,82 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** @file + USB stack initialisation + */ + + +#include "usbdebug.h" +#include "usbapi.h" + + +/** data storage area for standard requests */ +static unsigned char abStdReqData[8]; + + +/** + USB reset handler + + @param [in] bDevStatus Device status + */ +static void HandleUsbReset(unsigned char bDevStatus) +{ + if (bDevStatus & DEV_STATUS_RESET) { + DBG("\n!"); + } +} + + +/** + Initialises the USB hardware and sets up the USB stack by + installing default callbacks. + + @return TRUE if initialisation was successful + */ +BOOL USBInit(void) +{ + // init hardware + USBHwInit(); + + // register bus reset handler + USBHwRegisterDevIntHandler(HandleUsbReset); + + // register control transfer handler on EP0 + USBHwRegisterEPIntHandler(0x00, USBHandleControlTransfer); + USBHwRegisterEPIntHandler(0x80, USBHandleControlTransfer); + + // setup control endpoints + USBHwEPConfig(0x00, MAX_PACKET_SIZE0); + USBHwEPConfig(0x80, MAX_PACKET_SIZE0); + + // register standard request handler + USBRegisterRequestHandler(REQTYPE_TYPE_STANDARD, USBHandleStandardRequest, abStdReqData); + + return TRUE; +} + diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbstdreq.c b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbstdreq.c new file mode 100644 index 000000000..05e58b417 --- /dev/null +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbstdreq.c @@ -0,0 +1,430 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** @file + Standard request handler. + + This modules handles the 'chapter 9' processing, specifically the + standard device requests in table 9-3 from the universal serial bus + specification revision 2.0 + + Specific types of devices may specify additional requests (for example + HID devices add a GET_DESCRIPTOR request for interfaces), but they + will not be part of this module. + + @todo some requests have to return a request error if device not configured: + @todo GET_INTERFACE, GET_STATUS, SET_INTERFACE, SYNCH_FRAME + @todo this applies to the following if endpoint != 0: + @todo SET_FEATURE, GET_FEATURE +*/ + +#include "usbdebug.h" +#include "usbstruct.h" +#include "usbapi.h" + +#define MAX_DESC_HANDLERS 4 /**< device, interface, endpoint, other */ + + +/* general descriptor field offsets */ +#define DESC_bLength 0 /**< length offset */ +#define DESC_bDescriptorType 1 /**< descriptor type offset */ + +/* config descriptor field offsets */ +#define CONF_DESC_wTotalLength 2 /**< total length offset */ +#define CONF_DESC_bConfigurationValue 5 /**< configuration value offset */ +#define CONF_DESC_bmAttributes 7 /**< configuration characteristics */ + +/* interface descriptor field offsets */ +#define INTF_DESC_bAlternateSetting 3 /**< alternate setting offset */ + +/* endpoint descriptor field offsets */ +#define ENDP_DESC_bEndpointAddress 2 /**< endpoint address offset */ +#define ENDP_DESC_wMaxPacketSize 4 /**< maximum packet size offset */ + + +/** Currently selected configuration */ +static unsigned char bConfiguration = 0; +/** Installed custom request handler */ +static TFnHandleRequest *pfnHandleCustomReq = NULL; +/** Pointer to registered descriptors */ +static const unsigned char *pabDescrip = NULL; + + +/** + Registers a pointer to a descriptor block containing all descriptors + for the device. + + @param [in] pabDescriptors The descriptor byte array + */ +void USBRegisterDescriptors(const unsigned char *pabDescriptors) +{ + pabDescrip = pabDescriptors; +} + + +/** + Parses the list of installed USB descriptors and attempts to find + the specified USB descriptor. + + @param [in] wTypeIndex Type and index of the descriptor + @param [in] wLangID Language ID of the descriptor (currently unused) + @param [out] *piLen Descriptor length + @param [out] *ppbData Descriptor data + + @return TRUE if the descriptor was found, FALSE otherwise + */ +BOOL USBGetDescriptor(unsigned short wTypeIndex, unsigned short wLangID, int *piLen, unsigned char **ppbData) +{ + unsigned char bType, bIndex; + unsigned char *pab; + int iCurIndex; + + ASSERT(pabDescrip != NULL); + + bType = GET_DESC_TYPE(wTypeIndex); + bIndex = GET_DESC_INDEX(wTypeIndex); + + pab = (unsigned char *)pabDescrip; + iCurIndex = 0; + + while (pab[DESC_bLength] != 0) { + if (pab[DESC_bDescriptorType] == bType) { + if (iCurIndex == bIndex) { + // set data pointer + *ppbData = pab; + // get length from structure + if (bType == DESC_CONFIGURATION) { + // configuration descriptor is an exception, length is at offset 2 and 3 + *piLen = (pab[CONF_DESC_wTotalLength]) | + (pab[CONF_DESC_wTotalLength + 1] << 8); + } + else { + // normally length is at offset 0 + *piLen = pab[DESC_bLength]; + } + return TRUE; + } + iCurIndex++; + } + // skip to next descriptor + pab += pab[DESC_bLength]; + } + // nothing found + DBG("Desc %x not found!\n", wTypeIndex); + return FALSE; +} + + +/** + Configures the device according to the specified configuration index and + alternate setting by parsing the installed USB descriptor list. + A configuration index of 0 unconfigures the device. + + @param [in] bConfigIndex Configuration index + @param [in] bAltSetting Alternate setting number + + @todo function always returns TRUE, add stricter checking? + + @return TRUE if successfully configured, FALSE otherwise + */ +static BOOL USBSetConfiguration(unsigned char bConfigIndex, unsigned char bAltSetting) +{ + unsigned char *pab; + unsigned char bCurConfig, bCurAltSetting; + unsigned char bEP; + unsigned short wMaxPktSize; + + ASSERT(pabDescrip != NULL); + + if (bConfigIndex == 0) { + // unconfigure device + USBHwConfigDevice(FALSE); + } + else { + // configure endpoints for this configuration/altsetting + pab = (unsigned char *)pabDescrip; + bCurConfig = 0xFF; + bCurAltSetting = 0xFF; + + while (pab[DESC_bLength] != 0) { + + switch (pab[DESC_bDescriptorType]) { + + case DESC_CONFIGURATION: + // remember current configuration index + bCurConfig = pab[CONF_DESC_bConfigurationValue]; + break; + + case DESC_INTERFACE: + // remember current alternate setting + bCurAltSetting = pab[INTF_DESC_bAlternateSetting]; + break; + + case DESC_ENDPOINT: + if ((bCurConfig == bConfigIndex) && + (bCurAltSetting == bAltSetting)) { + // endpoint found for desired config and alternate setting + bEP = pab[ENDP_DESC_bEndpointAddress]; + wMaxPktSize = (pab[ENDP_DESC_wMaxPacketSize]) | + (pab[ENDP_DESC_wMaxPacketSize + 1] << 8); + // configure endpoint + USBHwEPConfig(bEP, wMaxPktSize); + } + break; + + default: + break; + } + // skip to next descriptor + pab += pab[DESC_bLength]; + } + + // configure device + USBHwConfigDevice(TRUE); + } + + return TRUE; +} + + +/** + Local function to handle a standard device request + + @param [in] pSetup The setup packet + @param [in,out] *piLen Pointer to data length + @param [in,out] ppbData Data buffer. + + @return TRUE if the request was handled successfully + */ +static BOOL HandleStdDeviceReq(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData) +{ + unsigned char *pbData = *ppbData; + + switch (pSetup->bRequest) { + + case REQ_GET_STATUS: + // bit 0: self-powered + // bit 1: remote wakeup = not supported + pbData[0] = 0; + pbData[1] = 0; + *piLen = 2; + break; + + case REQ_SET_ADDRESS: + USBHwSetAddress(pSetup->wValue); + break; + + case REQ_GET_DESCRIPTOR: + DBG("D%x", pSetup->wValue); + return USBGetDescriptor(pSetup->wValue, pSetup->wIndex, piLen, ppbData); + + case REQ_GET_CONFIGURATION: + // indicate if we are configured + pbData[0] = bConfiguration; + *piLen = 1; + break; + + case REQ_SET_CONFIGURATION: + if (!USBSetConfiguration(pSetup->wValue & 0xFF, 0)) { + DBG("USBSetConfiguration failed!\n"); + return FALSE; + } + // configuration successful, update current configuration + bConfiguration = pSetup->wValue & 0xFF; + break; + + case REQ_CLEAR_FEATURE: + case REQ_SET_FEATURE: + if (pSetup->wValue == FEA_REMOTE_WAKEUP) { + // put DEVICE_REMOTE_WAKEUP code here + } + if (pSetup->wValue == FEA_TEST_MODE) { + // put TEST_MODE code here + } + return FALSE; + + case REQ_SET_DESCRIPTOR: + DBG("Device req %d not implemented\n", pSetup->bRequest); + return FALSE; + + default: + DBG("Illegal device req %d\n", pSetup->bRequest); + return FALSE; + } + + return TRUE; +} + + +/** + Local function to handle a standard interface request + + @param [in] pSetup The setup packet + @param [in,out] *piLen Pointer to data length + @param [in] ppbData Data buffer. + + @return TRUE if the request was handled successfully + */ +static BOOL HandleStdInterfaceReq(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData) +{ + unsigned char *pbData = *ppbData; + + switch (pSetup->bRequest) { + + case REQ_GET_STATUS: + // no bits specified + pbData[0] = 0; + pbData[1] = 0; + *piLen = 2; + break; + + case REQ_CLEAR_FEATURE: + case REQ_SET_FEATURE: + // not defined for interface + return FALSE; + + case REQ_GET_INTERFACE: // TODO use bNumInterfaces + // there is only one interface, return n-1 (= 0) + pbData[0] = 0; + *piLen = 1; + break; + + case REQ_SET_INTERFACE: // TODO use bNumInterfaces + // there is only one interface (= 0) + if (pSetup->wValue != 0) { + return FALSE; + } + *piLen = 0; + break; + + default: + DBG("Illegal interface req %d\n", pSetup->bRequest); + return FALSE; + } + + return TRUE; +} + + +/** + Local function to handle a standard endpoint request + + @param [in] pSetup The setup packet + @param [in,out] *piLen Pointer to data length + @param [in] ppbData Data buffer. + + @return TRUE if the request was handled successfully + */ +static BOOL HandleStdEndPointReq(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData) +{ + unsigned char *pbData = *ppbData; + + switch (pSetup->bRequest) { + case REQ_GET_STATUS: + // bit 0 = endpointed halted or not + pbData[0] = (USBHwEPGetStatus(pSetup->wIndex) & EP_STATUS_STALLED) ? 1 : 0; + pbData[1] = 0; + *piLen = 2; + break; + + case REQ_CLEAR_FEATURE: + if (pSetup->wValue == FEA_ENDPOINT_HALT) { + // clear HALT by unstalling + USBHwEPStall(pSetup->wIndex, FALSE); + break; + } + // only ENDPOINT_HALT defined for endpoints + return FALSE; + + case REQ_SET_FEATURE: + if (pSetup->wValue == FEA_ENDPOINT_HALT) { + // set HALT by stalling + USBHwEPStall(pSetup->wIndex, TRUE); + break; + } + // only ENDPOINT_HALT defined for endpoints + return FALSE; + + case REQ_SYNCH_FRAME: + DBG("EP req %d not implemented\n", pSetup->bRequest); + return FALSE; + + default: + DBG("Illegal EP req %d\n", pSetup->bRequest); + return FALSE; + } + + return TRUE; +} + + +/** + Default handler for standard ('chapter 9') requests + + If a custom request handler was installed, this handler is called first. + + @param [in] pSetup The setup packet + @param [in,out] *piLen Pointer to data length + @param [in] ppbData Data buffer. + + @return TRUE if the request was handled successfully + */ +BOOL USBHandleStandardRequest(TSetupPacket *pSetup, int *piLen, unsigned char **ppbData) +{ + // try the custom request handler first + if ((pfnHandleCustomReq != NULL) && pfnHandleCustomReq(pSetup, piLen, ppbData)) { + return TRUE; + } + + switch (REQTYPE_GET_RECIP(pSetup->bmRequestType)) { + case REQTYPE_RECIP_DEVICE: return HandleStdDeviceReq(pSetup, piLen, ppbData); + case REQTYPE_RECIP_INTERFACE: return HandleStdInterfaceReq(pSetup, piLen, ppbData); + case REQTYPE_RECIP_ENDPOINT: return HandleStdEndPointReq(pSetup, piLen, ppbData); + default: return FALSE; + } +} + + +/** + Registers a callback for custom device requests + + In USBHandleStandardRequest, the custom request handler gets a first + chance at handling the request before it is handed over to the 'chapter 9' + request handler. + + This can be used for example in HID devices, where a REQ_GET_DESCRIPTOR + request is sent to an interface, which is not covered by the 'chapter 9' + specification. + + @param [in] pfnHandler Callback function pointer + */ +void USBRegisterCustomReqHandler(TFnHandleRequest *pfnHandler) +{ + pfnHandleCustomReq = pfnHandler; +} + diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbstruct.h b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbstruct.h new file mode 100644 index 000000000..113e2fef4 --- /dev/null +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/LPCUSB/usbstruct.h @@ -0,0 +1,119 @@ +/* + LPCUSB, an USB device driver for LPC microcontrollers + Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +/** + Definitions of structures of standard USB packets +*/ + +#ifndef _USBSTRUCT_H_ +#define _USBSTRUCT_H_ + +// CodeRed - include the LPCUSB type.h file rather than NXP one directly +#include "type.h" + +/** setup packet definitions */ +typedef struct { + unsigned char bmRequestType; /**< characteristics of the specific request */ + unsigned char bRequest; /**< specific request */ + unsigned short wValue; /**< request specific parameter */ + unsigned short wIndex; /**< request specific parameter */ + unsigned short wLength; /**< length of data transfered in data phase */ +} TSetupPacket; + + +#define REQTYPE_GET_DIR(x) (((x)>>7)&0x01) +#define REQTYPE_GET_TYPE(x) (((x)>>5)&0x03) +#define REQTYPE_GET_RECIP(x) ((x)&0x1F) + +#define REQTYPE_DIR_TO_DEVICE 0 +#define REQTYPE_DIR_TO_HOST 1 + +#define REQTYPE_TYPE_STANDARD 0 +#define REQTYPE_TYPE_CLASS 1 +#define REQTYPE_TYPE_VENDOR 2 +#define REQTYPE_TYPE_RESERVED 3 + +#define REQTYPE_RECIP_DEVICE 0 +#define REQTYPE_RECIP_INTERFACE 1 +#define REQTYPE_RECIP_ENDPOINT 2 +#define REQTYPE_RECIP_OTHER 3 + +/* standard requests */ +#define REQ_GET_STATUS 0x00 +#define REQ_CLEAR_FEATURE 0x01 +#define REQ_SET_FEATURE 0x03 +#define REQ_SET_ADDRESS 0x05 +#define REQ_GET_DESCRIPTOR 0x06 +#define REQ_SET_DESCRIPTOR 0x07 +#define REQ_GET_CONFIGURATION 0x08 +#define REQ_SET_CONFIGURATION 0x09 +#define REQ_GET_INTERFACE 0x0A +#define REQ_SET_INTERFACE 0x0B +#define REQ_SYNCH_FRAME 0x0C + +/* class requests HID */ +#define HID_GET_REPORT 0x01 +#define HID_GET_IDLE 0x02 +#define HID_GET_PROTOCOL 0x03 +#define HID_SET_REPORT 0x09 +#define HID_SET_IDLE 0x0A +#define HID_SET_PROTOCOL 0x0B + +/* feature selectors */ +#define FEA_ENDPOINT_HALT 0x00 +#define FEA_REMOTE_WAKEUP 0x01 +#define FEA_TEST_MODE 0x02 + +/* + USB descriptors +*/ + +/** USB descriptor header */ +typedef struct { + unsigned char bLength; /**< descriptor length */ + unsigned char bDescriptorType; /**< descriptor type */ +} TUSBDescHeader; + +#define DESC_DEVICE 1 +#define DESC_CONFIGURATION 2 +#define DESC_STRING 3 +#define DESC_INTERFACE 4 +#define DESC_ENDPOINT 5 +#define DESC_DEVICE_QUALIFIER 6 +#define DESC_OTHER_SPEED 7 +#define DESC_INTERFACE_POWER 8 + +#define DESC_HID_HID 0x21 +#define DESC_HID_REPORT 0x22 +#define DESC_HID_PHYSICAL 0x23 + +#define GET_DESC_TYPE(x) (((x)>>8)&0xFF) +#define GET_DESC_INDEX(x) ((x)&0xFF) + +#endif /* _USBSTRUCT_H_ */ + diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/RTOSDemo.hzp b/Demo/CORTEX_LPC1768_GCC_Rowley/RTOSDemo.hzp index 3b534ea89..d7e1a8517 100644 --- a/Demo/CORTEX_LPC1768_GCC_Rowley/RTOSDemo.hzp +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/RTOSDemo.hzp @@ -1,7 +1,7 @@ - + @@ -41,6 +41,13 @@ + + + + + + + diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/RTOSDemo.hzs b/Demo/CORTEX_LPC1768_GCC_Rowley/RTOSDemo.hzs index feca37148..5cc8daec4 100644 --- a/Demo/CORTEX_LPC1768_GCC_Rowley/RTOSDemo.hzs +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/RTOSDemo.hzs @@ -22,6 +22,9 @@ + + + @@ -52,7 +55,7 @@ - + - + diff --git a/Demo/CORTEX_LPC1768_GCC_Rowley/main.c b/Demo/CORTEX_LPC1768_GCC_Rowley/main.c index c8c8a2b55..529b498fc 100644 --- a/Demo/CORTEX_LPC1768_GCC_Rowley/main.c +++ b/Demo/CORTEX_LPC1768_GCC_Rowley/main.c @@ -62,6 +62,11 @@ * * "uIP" task - This is the task that handles the uIP stack. All TCP/IP * processing is performed in this task. + * + * "USB" task - Enumerates the USB device as a CDC class, then echoes back all + * received characters with a configurable offset (for example, if the offset + * is 1 and 'A' is received then 'B' will be sent back). A dumb terminal such + * as Hyperterminal can be used to talk to the USB task. */ /* Scheduler includes. */ @@ -116,6 +121,11 @@ static void prvSetupHardware( void ); */ extern void vuIP_Task( void *pvParameters ); +/* + * The task that handles the USB stack. + */ +extern void vUSBTask( void *pvParameters ); + /* * Simply returns the current status message for display on served WEB pages. */ @@ -145,6 +155,9 @@ int main( void ) vStartRecursiveMutexTasks(); vStartLEDFlashTasks( mainFLASH_TASK_PRIORITY ); + /* Create the USB task. */ + xTaskCreate( vUSBTask, ( signed char * ) "USB", configMINIMAL_STACK_SIZE, ( void * ) NULL, tskIDLE_PRIORITY, NULL ); + /* Create the uIP task. The WEB server runs in this task. */ xTaskCreate( vuIP_Task, ( signed char * ) "uIP", mainBASIC_WEB_STACK_SIZE, ( void * ) NULL, mainUIP_TASK_PRIORITY, NULL ); @@ -228,49 +241,6 @@ void prvSetupHardware( void ) /* Disable TPIU. */ PINCON->PINSEL10 = 0; - /* Disconnect the main PLL. */ - SC->PLL0CON &= ~PLLCON_PLLC; - SC->PLL0FEED = PLLFEED_FEED1; - SC->PLL0FEED = PLLFEED_FEED2; - while ((SC->PLL0STAT & PLLSTAT_PLLC) != 0); - - /* Turn off the main PLL. */ - SC->PLL0CON &= ~PLLCON_PLLE; - SC->PLL0FEED = PLLFEED_FEED1; - SC->PLL0FEED = PLLFEED_FEED2; - while ((SC->PLL0STAT & PLLSTAT_PLLE) != 0); - - /* No CPU clock divider. */ - SC->CCLKCFG = 0; - - /* OSCEN. */ - SC->SCS = 0x20; - while ((SC->SCS & 0x40) == 0); - - /* Use main oscillator. */ - SC->CLKSRCSEL = 1; - SC->PLL0CFG = (PLLCFG_MUL16 | PLLCFG_DIV1); - - SC->PLL0FEED = PLLFEED_FEED1; - SC->PLL0FEED = PLLFEED_FEED2; - - /* Activate the PLL by turning it on then feeding the correct - sequence of bytes. */ - SC->PLL0CON = PLLCON_PLLE; - SC->PLL0FEED = PLLFEED_FEED1; - SC->PLL0FEED = PLLFEED_FEED2; - - /* 6x CPU clock divider (64 MHz) */ - SC->CCLKCFG = 5; - - /* Wait for the PLL to lock. */ - while ((SC->PLL0STAT & PLLSTAT_PLOCK) == 0); - - /* Connect the PLL. */ - SC->PLL0CON = PLLCON_PLLC | PLLCON_PLLE; - SC->PLL0FEED = PLLFEED_FEED1; - SC->PLL0FEED = PLLFEED_FEED2; - /* Setup the peripheral bus to be the same as the PLL output (64 MHz). */ SC->PCLKSEL0 = 0x05555555; -- 2.39.5