Committer:
chris
Date:
Fri Oct 21 23:02:16 2011 +0000
Revision:
1:4d08e0ebf5dd
Parent:
0:e98d1c2b16c6

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
chris 0:e98d1c2b16c6 1 /* USBBusInterface_LPC17_LPC23.c */
chris 0:e98d1c2b16c6 2 /* USB Bus Interface for NXP LPC1768 and LPC2368 */
chris 0:e98d1c2b16c6 3 /* Copyright (c) 2011 ARM Limited. All rights reserved. */
chris 0:e98d1c2b16c6 4
chris 0:e98d1c2b16c6 5 #ifdef TARGET_LPC1768
chris 0:e98d1c2b16c6 6
chris 0:e98d1c2b16c6 7 #include "USBBusInterface.h"
chris 0:e98d1c2b16c6 8 #include "USBEvents.h"
chris 0:e98d1c2b16c6 9
chris 0:e98d1c2b16c6 10
chris 0:e98d1c2b16c6 11 /* Get endpoint direction */
chris 0:e98d1c2b16c6 12 #define IN_EP(endpoint) ((endpoint) & 1U ? true : false)
chris 0:e98d1c2b16c6 13 #define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)
chris 0:e98d1c2b16c6 14
chris 0:e98d1c2b16c6 15 /* Convert physical endpoint number to register bit */
chris 0:e98d1c2b16c6 16 #define EP(endpoint) (1UL<<endpoint)
chris 0:e98d1c2b16c6 17
chris 0:e98d1c2b16c6 18 /* Power Control for Peripherals register */
chris 0:e98d1c2b16c6 19 #define PCUSB (1UL<<31)
chris 0:e98d1c2b16c6 20
chris 0:e98d1c2b16c6 21 /* USB Clock Control register */
chris 0:e98d1c2b16c6 22 #define DEV_CLK_EN (1UL<<1)
chris 0:e98d1c2b16c6 23 #define AHB_CLK_EN (1UL<<4)
chris 0:e98d1c2b16c6 24
chris 0:e98d1c2b16c6 25 /* USB Clock Status register */
chris 0:e98d1c2b16c6 26 #define DEV_CLK_ON (1UL<<1)
chris 0:e98d1c2b16c6 27 #define AHB_CLK_ON (1UL<<4)
chris 0:e98d1c2b16c6 28
chris 0:e98d1c2b16c6 29 /* USB Device Interupt registers */
chris 0:e98d1c2b16c6 30 #define FRAME (1UL<<0)
chris 0:e98d1c2b16c6 31 #define EP_FAST (1UL<<1)
chris 0:e98d1c2b16c6 32 #define EP_SLOW (1UL<<2)
chris 0:e98d1c2b16c6 33 #define DEV_STAT (1UL<<3)
chris 0:e98d1c2b16c6 34 #define CCEMPTY (1UL<<4)
chris 0:e98d1c2b16c6 35 #define CDFULL (1UL<<5)
chris 0:e98d1c2b16c6 36 #define RxENDPKT (1UL<<6)
chris 0:e98d1c2b16c6 37 #define TxENDPKT (1UL<<7)
chris 0:e98d1c2b16c6 38 #define EP_RLZED (1UL<<8)
chris 0:e98d1c2b16c6 39 #define ERR_INT (1UL<<9)
chris 0:e98d1c2b16c6 40
chris 0:e98d1c2b16c6 41 /* USB Control register */
chris 0:e98d1c2b16c6 42 #define RD_EN (1<<0)
chris 0:e98d1c2b16c6 43 #define WR_EN (1<<1)
chris 0:e98d1c2b16c6 44 #define LOG_ENDPOINT(endpoint) ((endpoint>>1)<<2)
chris 0:e98d1c2b16c6 45
chris 0:e98d1c2b16c6 46 /* USB Receive Packet Length register */
chris 0:e98d1c2b16c6 47 #define DV (1UL<<10)
chris 0:e98d1c2b16c6 48 #define PKT_RDY (1UL<<11)
chris 0:e98d1c2b16c6 49 #define PKT_LNGTH_MASK (0x3ff)
chris 0:e98d1c2b16c6 50
chris 0:e98d1c2b16c6 51 /* Serial Interface Engine (SIE) */
chris 0:e98d1c2b16c6 52 #define SIE_WRITE (0x01)
chris 0:e98d1c2b16c6 53 #define SIE_READ (0x02)
chris 0:e98d1c2b16c6 54 #define SIE_COMMAND (0x05)
chris 0:e98d1c2b16c6 55 #define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16))
chris 0:e98d1c2b16c6 56
chris 0:e98d1c2b16c6 57 /* SIE Command codes */
chris 0:e98d1c2b16c6 58 #define SIE_CMD_SET_ADDRESS (0xD0)
chris 0:e98d1c2b16c6 59 #define SIE_CMD_CONFIGURE_DEVICE (0xD8)
chris 0:e98d1c2b16c6 60 #define SIE_CMD_SET_MODE (0xF3)
chris 0:e98d1c2b16c6 61 #define SIE_CMD_READ_FRAME_NUMBER (0xF5)
chris 0:e98d1c2b16c6 62 #define SIE_CMD_READ_TEST_REGISTER (0xFD)
chris 0:e98d1c2b16c6 63 #define SIE_CMD_SET_DEVICE_STATUS (0xFE)
chris 0:e98d1c2b16c6 64 #define SIE_CMD_GET_DEVICE_STATUS (0xFE)
chris 0:e98d1c2b16c6 65 #define SIE_CMD_GET_ERROR_CODE (0xFF)
chris 0:e98d1c2b16c6 66 #define SIE_CMD_READ_ERROR_STATUS (0xFB)
chris 0:e98d1c2b16c6 67
chris 0:e98d1c2b16c6 68 #define SIE_CMD_SELECT_ENDPOINT(endpoint) (0x00+endpoint)
chris 0:e98d1c2b16c6 69 #define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+endpoint)
chris 0:e98d1c2b16c6 70 #define SIE_CMD_SET_ENDPOINT_STATUS(endpoint) (0x40+endpoint)
chris 0:e98d1c2b16c6 71
chris 0:e98d1c2b16c6 72 #define SIE_CMD_CLEAR_BUFFER (0xF2)
chris 0:e98d1c2b16c6 73 #define SIE_CMD_VALIDATE_BUFFER (0xFA)
chris 0:e98d1c2b16c6 74
chris 0:e98d1c2b16c6 75 /* SIE Device Status register */
chris 0:e98d1c2b16c6 76 #define SIE_DS_CON (1<<0)
chris 0:e98d1c2b16c6 77 #define SIE_DS_CON_CH (1<<1)
chris 0:e98d1c2b16c6 78 #define SIE_DS_SUS (1<<2)
chris 0:e98d1c2b16c6 79 #define SIE_DS_SUS_CH (1<<3)
chris 0:e98d1c2b16c6 80 #define SIE_DS_RST (1<<4)
chris 0:e98d1c2b16c6 81
chris 0:e98d1c2b16c6 82 /* SIE Device Set Address register */
chris 0:e98d1c2b16c6 83 #define SIE_DSA_DEV_EN (1<<7)
chris 0:e98d1c2b16c6 84
chris 0:e98d1c2b16c6 85 /* SIE Configue Device register */
chris 0:e98d1c2b16c6 86 #define SIE_CONF_DEVICE (1<<0)
chris 0:e98d1c2b16c6 87
chris 0:e98d1c2b16c6 88 /* Select Endpoint register */
chris 0:e98d1c2b16c6 89 #define SIE_SE_FE (1<<0)
chris 0:e98d1c2b16c6 90 #define SIE_SE_ST (1<<1)
chris 0:e98d1c2b16c6 91 #define SIE_SE_STP (1<<2)
chris 0:e98d1c2b16c6 92 #define SIE_SE_PO (1<<3)
chris 0:e98d1c2b16c6 93 #define SIE_SE_EPN (1<<4)
chris 0:e98d1c2b16c6 94 #define SIE_SE_B_1_FULL (1<<5)
chris 0:e98d1c2b16c6 95 #define SIE_SE_B_2_FULL (1<<6)
chris 0:e98d1c2b16c6 96
chris 0:e98d1c2b16c6 97 /* Set Endpoint Status command */
chris 0:e98d1c2b16c6 98 #define SIE_SES_ST (1<<0)
chris 0:e98d1c2b16c6 99 #define SIE_SES_DA (1<<5)
chris 0:e98d1c2b16c6 100 #define SIE_SES_RF_MO (1<<6)
chris 0:e98d1c2b16c6 101 #define SIE_SES_CND_ST (1<<7)
chris 0:e98d1c2b16c6 102
chris 0:e98d1c2b16c6 103 static uint32_t endpointStallState;
chris 0:e98d1c2b16c6 104
chris 0:e98d1c2b16c6 105 static int epComplete = 0;
chris 0:e98d1c2b16c6 106 /*
chris 0:e98d1c2b16c6 107 * Serial Interface Engine commands
chris 0:e98d1c2b16c6 108 */
chris 0:e98d1c2b16c6 109
chris 0:e98d1c2b16c6 110 static void SIECommand(uint32_t command)
chris 0:e98d1c2b16c6 111 {
chris 0:e98d1c2b16c6 112 /* The command phase of a SIE transaction */
chris 0:e98d1c2b16c6 113 LPC_USB->USBDevIntClr = CCEMPTY;
chris 0:e98d1c2b16c6 114 LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_COMMAND, command);
chris 0:e98d1c2b16c6 115 while (!(LPC_USB->USBDevIntSt & CCEMPTY));
chris 0:e98d1c2b16c6 116 }
chris 0:e98d1c2b16c6 117
chris 0:e98d1c2b16c6 118 static void SIEWriteData(uint8_t data)
chris 0:e98d1c2b16c6 119 {
chris 0:e98d1c2b16c6 120 /* The data write phase of a SIE transaction */
chris 0:e98d1c2b16c6 121 LPC_USB->USBDevIntClr = CCEMPTY;
chris 0:e98d1c2b16c6 122 LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_WRITE, data);
chris 0:e98d1c2b16c6 123 while (!(LPC_USB->USBDevIntSt & CCEMPTY));
chris 0:e98d1c2b16c6 124 }
chris 0:e98d1c2b16c6 125
chris 0:e98d1c2b16c6 126 static uint8_t SIEReadData(uint32_t command)
chris 0:e98d1c2b16c6 127 {
chris 0:e98d1c2b16c6 128 /* The data read phase of a SIE transaction */
chris 0:e98d1c2b16c6 129 LPC_USB->USBDevIntClr = CDFULL;
chris 0:e98d1c2b16c6 130 LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_READ, command);
chris 0:e98d1c2b16c6 131 while (!(LPC_USB->USBDevIntSt & CDFULL));
chris 0:e98d1c2b16c6 132 return (uint8_t)LPC_USB->USBCmdData;
chris 0:e98d1c2b16c6 133 }
chris 0:e98d1c2b16c6 134
chris 0:e98d1c2b16c6 135 static void SIEsetDeviceStatus(uint8_t status)
chris 0:e98d1c2b16c6 136 {
chris 0:e98d1c2b16c6 137 /* Write SIE device status register */
chris 0:e98d1c2b16c6 138 SIECommand(SIE_CMD_SET_DEVICE_STATUS);
chris 0:e98d1c2b16c6 139 SIEWriteData(status);
chris 0:e98d1c2b16c6 140 }
chris 0:e98d1c2b16c6 141
chris 0:e98d1c2b16c6 142 static uint8_t SIEgetDeviceStatus(void)
chris 0:e98d1c2b16c6 143 {
chris 0:e98d1c2b16c6 144 /* Read SIE device status register */
chris 0:e98d1c2b16c6 145 SIECommand(SIE_CMD_GET_DEVICE_STATUS);
chris 0:e98d1c2b16c6 146 return SIEReadData(SIE_CMD_GET_DEVICE_STATUS);
chris 0:e98d1c2b16c6 147 }
chris 0:e98d1c2b16c6 148
chris 0:e98d1c2b16c6 149 void SIEsetAddress(uint8_t address)
chris 0:e98d1c2b16c6 150 {
chris 0:e98d1c2b16c6 151 /* Write SIE device address register */
chris 0:e98d1c2b16c6 152 SIECommand(SIE_CMD_SET_ADDRESS);
chris 0:e98d1c2b16c6 153 SIEWriteData((address & 0x7f) | SIE_DSA_DEV_EN);
chris 0:e98d1c2b16c6 154 }
chris 0:e98d1c2b16c6 155
chris 0:e98d1c2b16c6 156 static uint8_t SIEselectEndpoint(uint8_t endpoint)
chris 0:e98d1c2b16c6 157 {
chris 0:e98d1c2b16c6 158 /* SIE select endpoint command */
chris 0:e98d1c2b16c6 159 SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint));
chris 0:e98d1c2b16c6 160 return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint));
chris 0:e98d1c2b16c6 161 }
chris 0:e98d1c2b16c6 162
chris 0:e98d1c2b16c6 163 static uint8_t SIEclearBuffer(void)
chris 0:e98d1c2b16c6 164 {
chris 0:e98d1c2b16c6 165 /* SIE clear buffer command */
chris 0:e98d1c2b16c6 166 SIECommand(SIE_CMD_CLEAR_BUFFER);
chris 0:e98d1c2b16c6 167 return SIEReadData(SIE_CMD_CLEAR_BUFFER);
chris 0:e98d1c2b16c6 168 }
chris 0:e98d1c2b16c6 169
chris 0:e98d1c2b16c6 170 static void SIEvalidateBuffer(void)
chris 0:e98d1c2b16c6 171 {
chris 0:e98d1c2b16c6 172 /* SIE validate buffer command */
chris 0:e98d1c2b16c6 173 SIECommand(SIE_CMD_VALIDATE_BUFFER);
chris 0:e98d1c2b16c6 174 }
chris 0:e98d1c2b16c6 175
chris 0:e98d1c2b16c6 176 static void SIEsetEndpointStatus(uint8_t endpoint, uint8_t status)
chris 0:e98d1c2b16c6 177 {
chris 0:e98d1c2b16c6 178 /* SIE set endpoint status command */
chris 0:e98d1c2b16c6 179 SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint));
chris 0:e98d1c2b16c6 180 SIEWriteData(status);
chris 0:e98d1c2b16c6 181 }
chris 0:e98d1c2b16c6 182
chris 0:e98d1c2b16c6 183 static uint16_t SIEgetFrameNumber(void) __attribute__ ((unused));
chris 0:e98d1c2b16c6 184 static uint16_t SIEgetFrameNumber(void)
chris 0:e98d1c2b16c6 185 {
chris 0:e98d1c2b16c6 186 /* Read current frame number */
chris 0:e98d1c2b16c6 187 uint16_t lowByte;
chris 0:e98d1c2b16c6 188 uint16_t highByte;
chris 0:e98d1c2b16c6 189
chris 0:e98d1c2b16c6 190 SIECommand(SIE_CMD_READ_FRAME_NUMBER);
chris 0:e98d1c2b16c6 191 lowByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
chris 0:e98d1c2b16c6 192 highByte = SIEReadData(SIE_CMD_READ_FRAME_NUMBER);
chris 0:e98d1c2b16c6 193
chris 0:e98d1c2b16c6 194 return (highByte << 8) | lowByte;
chris 0:e98d1c2b16c6 195 }
chris 0:e98d1c2b16c6 196
chris 0:e98d1c2b16c6 197 static void SIEconfigureDevice(void)
chris 0:e98d1c2b16c6 198 {
chris 0:e98d1c2b16c6 199 /* SIE Configure device command */
chris 0:e98d1c2b16c6 200 SIECommand(SIE_CMD_CONFIGURE_DEVICE);
chris 0:e98d1c2b16c6 201 SIEWriteData(SIE_CONF_DEVICE);
chris 0:e98d1c2b16c6 202 }
chris 0:e98d1c2b16c6 203
chris 0:e98d1c2b16c6 204 static void SIEunconfigureDevice(void)
chris 0:e98d1c2b16c6 205 {
chris 0:e98d1c2b16c6 206 /* SIE Configure device command */
chris 0:e98d1c2b16c6 207 SIECommand(SIE_CMD_CONFIGURE_DEVICE);
chris 0:e98d1c2b16c6 208 SIEWriteData(0);
chris 0:e98d1c2b16c6 209 }
chris 0:e98d1c2b16c6 210
chris 0:e98d1c2b16c6 211 static void SIEconnect(void)
chris 0:e98d1c2b16c6 212 {
chris 0:e98d1c2b16c6 213 /* Connect USB device */
chris 0:e98d1c2b16c6 214 uint8_t status;
chris 0:e98d1c2b16c6 215
chris 0:e98d1c2b16c6 216 status = SIEgetDeviceStatus();
chris 0:e98d1c2b16c6 217 SIEsetDeviceStatus(status | SIE_DS_CON);
chris 0:e98d1c2b16c6 218 }
chris 0:e98d1c2b16c6 219
chris 0:e98d1c2b16c6 220
chris 0:e98d1c2b16c6 221 static void SIEdisconnect(void)
chris 0:e98d1c2b16c6 222 {
chris 0:e98d1c2b16c6 223 /* Disconnect USB device */
chris 0:e98d1c2b16c6 224 uint8_t status;
chris 0:e98d1c2b16c6 225
chris 0:e98d1c2b16c6 226 status = SIEgetDeviceStatus();
chris 0:e98d1c2b16c6 227 SIEsetDeviceStatus(status & ~SIE_DS_CON);
chris 0:e98d1c2b16c6 228 }
chris 0:e98d1c2b16c6 229
chris 0:e98d1c2b16c6 230 /*
chris 0:e98d1c2b16c6 231 * Endpoint commands
chris 0:e98d1c2b16c6 232 */
chris 0:e98d1c2b16c6 233
chris 0:e98d1c2b16c6 234 static uint8_t selectEndpointClearInterrupt(uint8_t endpoint)
chris 0:e98d1c2b16c6 235 {
chris 0:e98d1c2b16c6 236 /* Implemented using using EP_INT_CLR. */
chris 0:e98d1c2b16c6 237 LPC_USB->USBEpIntClr = EP(endpoint);
chris 0:e98d1c2b16c6 238 while (!(LPC_USB->USBDevIntSt & CDFULL));
chris 0:e98d1c2b16c6 239 return (uint8_t)LPC_USB->USBCmdData;
chris 0:e98d1c2b16c6 240 }
chris 0:e98d1c2b16c6 241
chris 0:e98d1c2b16c6 242 static void stallEndpoint(uint8_t endpoint)
chris 0:e98d1c2b16c6 243 {
chris 0:e98d1c2b16c6 244 /* Stall an endpoint */
chris 0:e98d1c2b16c6 245 if ( (endpoint==EP0IN) || (endpoint==EP0OUT) )
chris 0:e98d1c2b16c6 246 {
chris 0:e98d1c2b16c6 247 /* Conditionally stall both control endpoints */
chris 0:e98d1c2b16c6 248 SIEsetEndpointStatus(EP0OUT, SIE_SES_CND_ST);
chris 0:e98d1c2b16c6 249 }
chris 0:e98d1c2b16c6 250 else
chris 0:e98d1c2b16c6 251 {
chris 0:e98d1c2b16c6 252 SIEsetEndpointStatus(endpoint, SIE_SES_ST);
chris 0:e98d1c2b16c6 253
chris 0:e98d1c2b16c6 254 /* Update stall state */
chris 0:e98d1c2b16c6 255 endpointStallState |= EP(endpoint);
chris 0:e98d1c2b16c6 256 }
chris 0:e98d1c2b16c6 257 }
chris 0:e98d1c2b16c6 258
chris 0:e98d1c2b16c6 259 static void unstallEndpoint(uint8_t endpoint)
chris 0:e98d1c2b16c6 260 {
chris 0:e98d1c2b16c6 261 /* Unstall an endpoint. The endpoint will also be reinitialised */
chris 0:e98d1c2b16c6 262 SIEsetEndpointStatus(endpoint, 0);
chris 0:e98d1c2b16c6 263
chris 0:e98d1c2b16c6 264 /* Update stall state */
chris 0:e98d1c2b16c6 265 endpointStallState &= ~EP(endpoint);
chris 0:e98d1c2b16c6 266 }
chris 0:e98d1c2b16c6 267
chris 0:e98d1c2b16c6 268 static bool getEndpointStallState(uint8_t endpoint)
chris 0:e98d1c2b16c6 269 {
chris 0:e98d1c2b16c6 270 /* Returns true if endpoint stalled */
chris 0:e98d1c2b16c6 271 return endpointStallState & EP(endpoint);
chris 0:e98d1c2b16c6 272 }
chris 0:e98d1c2b16c6 273
chris 0:e98d1c2b16c6 274 static void realiseEndpoint(uint8_t endpoint, uint32_t maxPacket)
chris 0:e98d1c2b16c6 275 {
chris 0:e98d1c2b16c6 276 /* Realise an endpoint */
chris 0:e98d1c2b16c6 277 LPC_USB->USBDevIntClr = EP_RLZED;
chris 0:e98d1c2b16c6 278 LPC_USB->USBReEp |= EP(endpoint);
chris 0:e98d1c2b16c6 279 LPC_USB->USBEpInd = endpoint;
chris 0:e98d1c2b16c6 280 LPC_USB->USBMaxPSize = maxPacket;
chris 0:e98d1c2b16c6 281
chris 0:e98d1c2b16c6 282 while (!(LPC_USB->USBDevIntSt & EP_RLZED));
chris 0:e98d1c2b16c6 283 LPC_USB->USBDevIntClr = EP_RLZED;
chris 0:e98d1c2b16c6 284
chris 0:e98d1c2b16c6 285 /* Clear stall state */
chris 0:e98d1c2b16c6 286 endpointStallState &= ~EP(endpoint);
chris 0:e98d1c2b16c6 287 }
chris 0:e98d1c2b16c6 288
chris 0:e98d1c2b16c6 289 static void enableEndpointEvent(uint8_t endpoint)
chris 0:e98d1c2b16c6 290 {
chris 0:e98d1c2b16c6 291 /* Enable an endpoint interrupt */
chris 0:e98d1c2b16c6 292 LPC_USB->USBEpIntEn |= EP(endpoint);
chris 0:e98d1c2b16c6 293 }
chris 0:e98d1c2b16c6 294
chris 0:e98d1c2b16c6 295 static void disableEndpointEvent(uint8_t endpoint) __attribute__ ((unused));
chris 0:e98d1c2b16c6 296 static void disableEndpointEvent(uint8_t endpoint)
chris 0:e98d1c2b16c6 297 {
chris 0:e98d1c2b16c6 298 /* Disable an endpoint interrupt */
chris 0:e98d1c2b16c6 299 LPC_USB->USBEpIntEn &= ~EP(endpoint);
chris 0:e98d1c2b16c6 300 }
chris 0:e98d1c2b16c6 301
chris 0:e98d1c2b16c6 302 static volatile uint32_t __attribute__((used)) dummyRead;
chris 0:e98d1c2b16c6 303
chris 0:e98d1c2b16c6 304 static uint32_t endpointRead(uint8_t endpoint, uint8_t *buffer)
chris 0:e98d1c2b16c6 305 {
chris 0:e98d1c2b16c6 306 /* Read from an OUT endpoint */
chris 0:e98d1c2b16c6 307 uint32_t size;
chris 0:e98d1c2b16c6 308 uint32_t i;
chris 0:e98d1c2b16c6 309 uint32_t data;
chris 0:e98d1c2b16c6 310 uint8_t offset;
chris 0:e98d1c2b16c6 311
chris 0:e98d1c2b16c6 312 LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN;
chris 0:e98d1c2b16c6 313 while (!(LPC_USB->USBRxPLen & PKT_RDY));
chris 0:e98d1c2b16c6 314
chris 0:e98d1c2b16c6 315 size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK;
chris 0:e98d1c2b16c6 316
chris 0:e98d1c2b16c6 317 offset = 0;
chris 0:e98d1c2b16c6 318
chris 0:e98d1c2b16c6 319 if (size > 0)
chris 0:e98d1c2b16c6 320 {
chris 0:e98d1c2b16c6 321 for (i=0; i<size; i++)
chris 0:e98d1c2b16c6 322 {
chris 0:e98d1c2b16c6 323 if (offset==0)
chris 0:e98d1c2b16c6 324 {
chris 0:e98d1c2b16c6 325 /* Fetch up to four bytes of data as a word */
chris 0:e98d1c2b16c6 326 data = LPC_USB->USBRxData;
chris 0:e98d1c2b16c6 327 }
chris 0:e98d1c2b16c6 328
chris 0:e98d1c2b16c6 329 /* extract a byte */
chris 0:e98d1c2b16c6 330 *buffer++ = data>>offset;
chris 0:e98d1c2b16c6 331
chris 0:e98d1c2b16c6 332 /* move on to the next byte */
chris 0:e98d1c2b16c6 333 offset = (offset + 8) % 32;
chris 0:e98d1c2b16c6 334 }
chris 0:e98d1c2b16c6 335 }
chris 0:e98d1c2b16c6 336 else
chris 0:e98d1c2b16c6 337 {
chris 0:e98d1c2b16c6 338 dummyRead = LPC_USB->USBRxData;
chris 0:e98d1c2b16c6 339 }
chris 0:e98d1c2b16c6 340
chris 0:e98d1c2b16c6 341 SIEselectEndpoint(endpoint);
chris 0:e98d1c2b16c6 342 SIEclearBuffer();
chris 0:e98d1c2b16c6 343 return size;
chris 0:e98d1c2b16c6 344 }
chris 0:e98d1c2b16c6 345
chris 0:e98d1c2b16c6 346 static void endpointWrite(uint8_t endpoint, uint8_t *buffer, uint32_t size)
chris 0:e98d1c2b16c6 347 {
chris 0:e98d1c2b16c6 348 /* Write to an IN endpoint */
chris 0:e98d1c2b16c6 349 uint32_t temp, data;
chris 0:e98d1c2b16c6 350 uint8_t offset;
chris 0:e98d1c2b16c6 351
chris 0:e98d1c2b16c6 352 LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN;
chris 0:e98d1c2b16c6 353
chris 0:e98d1c2b16c6 354 LPC_USB->USBTxPLen = size;
chris 0:e98d1c2b16c6 355 offset = 0;
chris 0:e98d1c2b16c6 356 data = 0;
chris 0:e98d1c2b16c6 357
chris 0:e98d1c2b16c6 358 if (size>0)
chris 0:e98d1c2b16c6 359 {
chris 0:e98d1c2b16c6 360 do {
chris 0:e98d1c2b16c6 361 /* Fetch next data byte into a word-sized temporary variable */
chris 0:e98d1c2b16c6 362 temp = *buffer++;
chris 0:e98d1c2b16c6 363
chris 0:e98d1c2b16c6 364 /* Add to current data word */
chris 0:e98d1c2b16c6 365 temp = temp << offset;
chris 0:e98d1c2b16c6 366 data = data | temp;
chris 0:e98d1c2b16c6 367
chris 0:e98d1c2b16c6 368 /* move on to the next byte */
chris 0:e98d1c2b16c6 369 offset = (offset + 8) % 32;
chris 0:e98d1c2b16c6 370 size--;
chris 0:e98d1c2b16c6 371
chris 0:e98d1c2b16c6 372 if ((offset==0) || (size==0))
chris 0:e98d1c2b16c6 373 {
chris 0:e98d1c2b16c6 374 /* Write the word to the endpoint */
chris 0:e98d1c2b16c6 375 LPC_USB->USBTxData = data;
chris 0:e98d1c2b16c6 376 data = 0;
chris 0:e98d1c2b16c6 377 }
chris 0:e98d1c2b16c6 378 } while (size>0);
chris 0:e98d1c2b16c6 379 }
chris 0:e98d1c2b16c6 380 else
chris 0:e98d1c2b16c6 381 {
chris 0:e98d1c2b16c6 382 LPC_USB->USBTxData = 0;
chris 0:e98d1c2b16c6 383 }
chris 0:e98d1c2b16c6 384
chris 0:e98d1c2b16c6 385 /* Clear WR_EN to cover zero length packet case */
chris 0:e98d1c2b16c6 386 LPC_USB->USBCtrl=0;
chris 0:e98d1c2b16c6 387
chris 0:e98d1c2b16c6 388 SIEselectEndpoint(endpoint);
chris 0:e98d1c2b16c6 389 SIEvalidateBuffer();
chris 0:e98d1c2b16c6 390 }
chris 0:e98d1c2b16c6 391
chris 0:e98d1c2b16c6 392 /*
chris 0:e98d1c2b16c6 393 * USBBusInterface API
chris 0:e98d1c2b16c6 394 */
chris 0:e98d1c2b16c6 395
chris 0:e98d1c2b16c6 396 bool USBBusInterface_init(void)
chris 0:e98d1c2b16c6 397 {
chris 0:e98d1c2b16c6 398 /* Disable IRQ */
chris 0:e98d1c2b16c6 399 NVIC_DisableIRQ(USB_IRQn);
chris 0:e98d1c2b16c6 400
chris 0:e98d1c2b16c6 401 /* Enable power to USB device controller */
chris 0:e98d1c2b16c6 402 LPC_SC->PCONP |= PCUSB;
chris 0:e98d1c2b16c6 403
chris 0:e98d1c2b16c6 404 /* Enable USB clocks */
chris 0:e98d1c2b16c6 405 LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
chris 0:e98d1c2b16c6 406 while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
chris 0:e98d1c2b16c6 407
chris 0:e98d1c2b16c6 408 /* Configure pins P0.29 and P0.30 to be USB D+ and USB D- */
chris 0:e98d1c2b16c6 409 LPC_PINCON->PINSEL1 &= 0xc3ffffff;
chris 0:e98d1c2b16c6 410 LPC_PINCON->PINSEL1 |= 0x14000000;
chris 0:e98d1c2b16c6 411
chris 0:e98d1c2b16c6 412 /* Disconnect USB device */
chris 0:e98d1c2b16c6 413 SIEdisconnect();
chris 0:e98d1c2b16c6 414
chris 0:e98d1c2b16c6 415 /* Configure pin P2.9 to be Connect */
chris 0:e98d1c2b16c6 416 LPC_PINCON->PINSEL4 &= 0xfffcffff;
chris 0:e98d1c2b16c6 417 LPC_PINCON->PINSEL4 |= 0x00040000;
chris 0:e98d1c2b16c6 418
chris 0:e98d1c2b16c6 419 /* Connect must be low for at least 2.5uS */
chris 0:e98d1c2b16c6 420 wait(0.3);
chris 0:e98d1c2b16c6 421
chris 0:e98d1c2b16c6 422 /* Set the maximum packet size for the control endpoints */
chris 0:e98d1c2b16c6 423 realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0);
chris 0:e98d1c2b16c6 424 realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0);
chris 0:e98d1c2b16c6 425
chris 0:e98d1c2b16c6 426 /* Attach IRQ */
chris 0:e98d1c2b16c6 427 NVIC_EnableIRQ(USB_IRQn);
chris 0:e98d1c2b16c6 428
chris 0:e98d1c2b16c6 429 /* Enable interrupts for device events and EP0 */
chris 0:e98d1c2b16c6 430 LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT;
chris 0:e98d1c2b16c6 431 enableEndpointEvent(EP0IN);
chris 0:e98d1c2b16c6 432 enableEndpointEvent(EP0OUT);
chris 0:e98d1c2b16c6 433 return true;
chris 0:e98d1c2b16c6 434 }
chris 0:e98d1c2b16c6 435
chris 0:e98d1c2b16c6 436 void USBBusInterface_uninit(void)
chris 0:e98d1c2b16c6 437 {
chris 0:e98d1c2b16c6 438 /* Ensure device disconnected */
chris 0:e98d1c2b16c6 439 SIEdisconnect();
chris 0:e98d1c2b16c6 440
chris 0:e98d1c2b16c6 441 /* Disable USB interrupts */
chris 0:e98d1c2b16c6 442 NVIC_DisableIRQ(USB_IRQn);
chris 0:e98d1c2b16c6 443 }
chris 0:e98d1c2b16c6 444
chris 0:e98d1c2b16c6 445 void USBBusInterface_connect(void)
chris 0:e98d1c2b16c6 446 {
chris 0:e98d1c2b16c6 447 /* Connect USB device */
chris 0:e98d1c2b16c6 448 SIEconnect();
chris 0:e98d1c2b16c6 449 }
chris 0:e98d1c2b16c6 450
chris 0:e98d1c2b16c6 451 void USBBusInterface_disconnect(void)
chris 0:e98d1c2b16c6 452 {
chris 0:e98d1c2b16c6 453 /* Disconnect USB device */
chris 0:e98d1c2b16c6 454 SIEdisconnect();
chris 0:e98d1c2b16c6 455 }
chris 0:e98d1c2b16c6 456
chris 0:e98d1c2b16c6 457 void USBBusInterface_configureDevice(void)
chris 0:e98d1c2b16c6 458 {
chris 0:e98d1c2b16c6 459 SIEconfigureDevice();
chris 0:e98d1c2b16c6 460 }
chris 0:e98d1c2b16c6 461
chris 0:e98d1c2b16c6 462 void USBBusInterface_unconfigureDevice(void)
chris 0:e98d1c2b16c6 463 {
chris 0:e98d1c2b16c6 464 SIEunconfigureDevice();
chris 0:e98d1c2b16c6 465 }
chris 0:e98d1c2b16c6 466
chris 0:e98d1c2b16c6 467 void USBBusInterface_setAddress(uint8_t address)
chris 0:e98d1c2b16c6 468 {
chris 0:e98d1c2b16c6 469 SIEsetAddress(address);
chris 0:e98d1c2b16c6 470 }
chris 0:e98d1c2b16c6 471
chris 0:e98d1c2b16c6 472 void USBBusInterface_EP0setup(uint8_t *buffer)
chris 0:e98d1c2b16c6 473 {
chris 0:e98d1c2b16c6 474 endpointRead(EP0OUT, buffer);
chris 0:e98d1c2b16c6 475 }
chris 0:e98d1c2b16c6 476
chris 0:e98d1c2b16c6 477 void USBBusInterface_EP0read(void)
chris 0:e98d1c2b16c6 478 {
chris 0:e98d1c2b16c6 479 /* Not required */
chris 0:e98d1c2b16c6 480 }
chris 0:e98d1c2b16c6 481
chris 0:e98d1c2b16c6 482 uint32_t USBBusInterface_EP0getReadResult(uint8_t *buffer)
chris 0:e98d1c2b16c6 483 {
chris 0:e98d1c2b16c6 484 return endpointRead(EP0OUT, buffer);
chris 0:e98d1c2b16c6 485 }
chris 0:e98d1c2b16c6 486
chris 0:e98d1c2b16c6 487 void USBBusInterface_EP0write(uint8_t *buffer, uint32_t size)
chris 0:e98d1c2b16c6 488 {
chris 0:e98d1c2b16c6 489 endpointWrite(EP0IN, buffer, size);
chris 0:e98d1c2b16c6 490 }
chris 0:e98d1c2b16c6 491
chris 0:e98d1c2b16c6 492 void USBBusInterface_EP0getWriteResult(void)
chris 0:e98d1c2b16c6 493 {
chris 0:e98d1c2b16c6 494 /* Not required */
chris 0:e98d1c2b16c6 495 }
chris 0:e98d1c2b16c6 496
chris 0:e98d1c2b16c6 497 void USBBusInterface_EP0stall(void)
chris 0:e98d1c2b16c6 498 {
chris 0:e98d1c2b16c6 499 /* This will stall both control endpoints */
chris 0:e98d1c2b16c6 500 stallEndpoint(EP0OUT);
chris 0:e98d1c2b16c6 501 }
chris 0:e98d1c2b16c6 502
chris 0:e98d1c2b16c6 503 EP_STATUS USBBusInterface_endpointRead(uint8_t endpoint, uint8_t *data, uint32_t maximumSize)
chris 0:e98d1c2b16c6 504 {
chris 0:e98d1c2b16c6 505 if (getEndpointStallState(endpoint))
chris 0:e98d1c2b16c6 506 {
chris 0:e98d1c2b16c6 507 return EP_STALLED;
chris 0:e98d1c2b16c6 508 }
chris 0:e98d1c2b16c6 509
chris 0:e98d1c2b16c6 510 return EP_PENDING;
chris 0:e98d1c2b16c6 511 }
chris 0:e98d1c2b16c6 512
chris 0:e98d1c2b16c6 513 EP_STATUS USBBusInterface_endpointReadResult(uint8_t endpoint, uint32_t *bytesRead)
chris 0:e98d1c2b16c6 514 {
chris 0:e98d1c2b16c6 515 return EP_PENDING;
chris 0:e98d1c2b16c6 516 }
chris 0:e98d1c2b16c6 517
chris 0:e98d1c2b16c6 518 EP_STATUS USBBusInterface_endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size)
chris 0:e98d1c2b16c6 519 {
chris 0:e98d1c2b16c6 520 if (getEndpointStallState(endpoint))
chris 0:e98d1c2b16c6 521 {
chris 0:e98d1c2b16c6 522 return EP_STALLED;
chris 0:e98d1c2b16c6 523 }
chris 0:e98d1c2b16c6 524
chris 0:e98d1c2b16c6 525 epComplete &= EP(endpoint);
chris 0:e98d1c2b16c6 526
chris 0:e98d1c2b16c6 527 endpointWrite(endpoint, data, size);
chris 0:e98d1c2b16c6 528 return EP_PENDING;
chris 0:e98d1c2b16c6 529 }
chris 0:e98d1c2b16c6 530
chris 0:e98d1c2b16c6 531 EP_STATUS USBBusInterface_endpointWriteResult(uint8_t endpoint)
chris 0:e98d1c2b16c6 532 {
chris 0:e98d1c2b16c6 533 if (epComplete & EP(endpoint))
chris 0:e98d1c2b16c6 534 {
chris 0:e98d1c2b16c6 535 epComplete &= ~EP(endpoint);
chris 0:e98d1c2b16c6 536 return EP_COMPLETED;
chris 0:e98d1c2b16c6 537 }
chris 0:e98d1c2b16c6 538
chris 0:e98d1c2b16c6 539 return EP_PENDING;
chris 0:e98d1c2b16c6 540 }
chris 0:e98d1c2b16c6 541
chris 0:e98d1c2b16c6 542 bool USBBusInterface_realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flags)
chris 0:e98d1c2b16c6 543 {
chris 0:e98d1c2b16c6 544 realiseEndpoint(endpoint, maxPacket);
chris 0:e98d1c2b16c6 545 enableEndpointEvent(endpoint);
chris 0:e98d1c2b16c6 546 return true;
chris 0:e98d1c2b16c6 547 }
chris 0:e98d1c2b16c6 548
chris 0:e98d1c2b16c6 549 void USBBusInterface_stallEndpoint(uint8_t endpoint)
chris 0:e98d1c2b16c6 550 {
chris 0:e98d1c2b16c6 551 stallEndpoint(endpoint);
chris 0:e98d1c2b16c6 552 }
chris 0:e98d1c2b16c6 553
chris 0:e98d1c2b16c6 554 void USBBusInterface_unstallEndpoint(uint8_t endpoint)
chris 0:e98d1c2b16c6 555 {
chris 0:e98d1c2b16c6 556 unstallEndpoint(endpoint);
chris 0:e98d1c2b16c6 557 }
chris 0:e98d1c2b16c6 558
chris 0:e98d1c2b16c6 559 bool USBBusInterface_getEndpointStallState(uint8_t endpoint)
chris 0:e98d1c2b16c6 560 {
chris 0:e98d1c2b16c6 561 return getEndpointStallState(endpoint);
chris 0:e98d1c2b16c6 562 }
chris 0:e98d1c2b16c6 563
chris 0:e98d1c2b16c6 564 void USBBusInterface_remoteWakeup(void)
chris 0:e98d1c2b16c6 565 {
chris 0:e98d1c2b16c6 566 /* Remote wakeup */
chris 0:e98d1c2b16c6 567 uint8_t status;
chris 0:e98d1c2b16c6 568
chris 0:e98d1c2b16c6 569 /* Enable USB clocks */
chris 0:e98d1c2b16c6 570 LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN;
chris 0:e98d1c2b16c6 571 while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON));
chris 0:e98d1c2b16c6 572
chris 0:e98d1c2b16c6 573 status = SIEgetDeviceStatus();
chris 0:e98d1c2b16c6 574 SIEsetDeviceStatus(status & ~SIE_DS_SUS);
chris 0:e98d1c2b16c6 575 }
chris 0:e98d1c2b16c6 576
chris 0:e98d1c2b16c6 577 /*
chris 0:e98d1c2b16c6 578 * USB interrupt handler
chris 0:e98d1c2b16c6 579 */
chris 0:e98d1c2b16c6 580
chris 0:e98d1c2b16c6 581 extern "C"
chris 0:e98d1c2b16c6 582 {
chris 0:e98d1c2b16c6 583 void USB_IRQHandler(void)
chris 0:e98d1c2b16c6 584 {
chris 0:e98d1c2b16c6 585 uint8_t devStat;
chris 0:e98d1c2b16c6 586
chris 0:e98d1c2b16c6 587 if (LPC_USB->USBDevIntSt & FRAME)
chris 0:e98d1c2b16c6 588 {
chris 0:e98d1c2b16c6 589 /* Start of frame event */
chris 0:e98d1c2b16c6 590 USBDevice_SOF(SIEgetFrameNumber());
chris 0:e98d1c2b16c6 591 /* Clear interrupt status flag */
chris 0:e98d1c2b16c6 592 LPC_USB->USBDevIntClr = FRAME;
chris 0:e98d1c2b16c6 593 }
chris 0:e98d1c2b16c6 594
chris 0:e98d1c2b16c6 595 if (LPC_USB->USBDevIntSt & DEV_STAT)
chris 0:e98d1c2b16c6 596 {
chris 0:e98d1c2b16c6 597 /* Device Status interrupt */
chris 0:e98d1c2b16c6 598 /* Must clear the interrupt status flag before reading the device status from the SIE */
chris 0:e98d1c2b16c6 599 LPC_USB->USBDevIntClr = DEV_STAT;
chris 0:e98d1c2b16c6 600
chris 0:e98d1c2b16c6 601 /* Read device status from SIE */
chris 0:e98d1c2b16c6 602 devStat = SIEgetDeviceStatus();
chris 0:e98d1c2b16c6 603
chris 0:e98d1c2b16c6 604 if (devStat & SIE_DS_RST)
chris 0:e98d1c2b16c6 605 {
chris 0:e98d1c2b16c6 606 /* Bus reset */
chris 0:e98d1c2b16c6 607 USBDevice_busReset();
chris 0:e98d1c2b16c6 608 }
chris 0:e98d1c2b16c6 609 }
chris 0:e98d1c2b16c6 610
chris 0:e98d1c2b16c6 611 if (LPC_USB->USBDevIntSt & EP_SLOW)
chris 0:e98d1c2b16c6 612 {
chris 0:e98d1c2b16c6 613 /* (Slow) Endpoint Interrupt */
chris 0:e98d1c2b16c6 614
chris 0:e98d1c2b16c6 615 /* Process each endpoint interrupt */
chris 0:e98d1c2b16c6 616 if (LPC_USB->USBEpIntSt & EP(EP0OUT))
chris 0:e98d1c2b16c6 617 {
chris 0:e98d1c2b16c6 618 if (selectEndpointClearInterrupt(EP0OUT) & SIE_SE_STP)
chris 0:e98d1c2b16c6 619 {
chris 0:e98d1c2b16c6 620 /* this is a setup packet */
chris 0:e98d1c2b16c6 621 USBDevice_EP0setup();
chris 0:e98d1c2b16c6 622 }
chris 0:e98d1c2b16c6 623 else
chris 0:e98d1c2b16c6 624 {
chris 0:e98d1c2b16c6 625 USBDevice_EP0out();
chris 0:e98d1c2b16c6 626 }
chris 0:e98d1c2b16c6 627 }
chris 0:e98d1c2b16c6 628
chris 0:e98d1c2b16c6 629 if (LPC_USB->USBEpIntSt & EP(EP0IN))
chris 0:e98d1c2b16c6 630 {
chris 0:e98d1c2b16c6 631 selectEndpointClearInterrupt(EP0IN);
chris 0:e98d1c2b16c6 632 USBDevice_EP0in();
chris 0:e98d1c2b16c6 633 }
chris 0:e98d1c2b16c6 634
chris 0:e98d1c2b16c6 635 /* TODO: This should cover all endpoints, not just EP1,2,3:*/
chris 0:e98d1c2b16c6 636 if (LPC_USB->USBEpIntSt & EP(EP1IN))
chris 0:e98d1c2b16c6 637 {
chris 0:e98d1c2b16c6 638 selectEndpointClearInterrupt(EP1IN);
chris 0:e98d1c2b16c6 639 epComplete |= EP(EP1IN);
chris 0:e98d1c2b16c6 640 }
chris 0:e98d1c2b16c6 641
chris 0:e98d1c2b16c6 642 if (LPC_USB->USBEpIntSt & EP(EP1OUT))
chris 0:e98d1c2b16c6 643 {
chris 0:e98d1c2b16c6 644 selectEndpointClearInterrupt(EP1OUT);
chris 0:e98d1c2b16c6 645 epComplete |= EP(EP1OUT);
chris 0:e98d1c2b16c6 646 }
chris 0:e98d1c2b16c6 647
chris 0:e98d1c2b16c6 648 if (LPC_USB->USBEpIntSt & EP(EP2IN))
chris 0:e98d1c2b16c6 649 {
chris 0:e98d1c2b16c6 650 selectEndpointClearInterrupt(EP2IN);
chris 0:e98d1c2b16c6 651 epComplete |= EP(EP2IN);
chris 0:e98d1c2b16c6 652 }
chris 0:e98d1c2b16c6 653
chris 0:e98d1c2b16c6 654 if (LPC_USB->USBEpIntSt & EP(EP2OUT))
chris 0:e98d1c2b16c6 655 {
chris 0:e98d1c2b16c6 656 selectEndpointClearInterrupt(EP2OUT);
chris 0:e98d1c2b16c6 657 epComplete |= EP(EP2OUT);
chris 0:e98d1c2b16c6 658 }
chris 0:e98d1c2b16c6 659
chris 0:e98d1c2b16c6 660 if (LPC_USB->USBEpIntSt & EP(EP3IN))
chris 0:e98d1c2b16c6 661 {
chris 0:e98d1c2b16c6 662 selectEndpointClearInterrupt(EP3IN);
chris 0:e98d1c2b16c6 663 epComplete |= EP(EP3IN);
chris 0:e98d1c2b16c6 664 }
chris 0:e98d1c2b16c6 665
chris 0:e98d1c2b16c6 666 if (LPC_USB->USBEpIntSt & EP(EP3OUT))
chris 0:e98d1c2b16c6 667 {
chris 0:e98d1c2b16c6 668 selectEndpointClearInterrupt(EP3OUT);
chris 0:e98d1c2b16c6 669 epComplete |= EP(EP3OUT);
chris 0:e98d1c2b16c6 670 }
chris 0:e98d1c2b16c6 671
chris 0:e98d1c2b16c6 672 /* Clear interrupt status flag */
chris 0:e98d1c2b16c6 673 /* EP_SLOW and EP_FAST interrupt bits should be cleared after the corresponding endpoint interrupts are cleared. */
chris 0:e98d1c2b16c6 674 LPC_USB->USBDevIntClr = EP_SLOW;
chris 0:e98d1c2b16c6 675 }
chris 0:e98d1c2b16c6 676 }
chris 0:e98d1c2b16c6 677 }
chris 0:e98d1c2b16c6 678
chris 0:e98d1c2b16c6 679 #endif