USBMSD SD card Hello World for Mbed platforms

Dependencies:   mbed USBMSD_SD USBDevice

Committer:
samux
Date:
Sun Dec 11 15:22:50 2011 +0000
Revision:
18:08b207d10056
Parent:
14:757226626acb
all is working: rename...

Who changed what in which revision?

UserRevisionLine numberNew contents of line
samux 14:757226626acb 1 // USBBusInterface_LPC11U.c
samux 14:757226626acb 2 // USB Bus Interface for NXP LPC11Uxx
samux 14:757226626acb 3 // Copyright (c) 2011 ARM Limited. All rights reserved.
samux 14:757226626acb 4
samux 14:757226626acb 5 // Reference:
samux 14:757226626acb 6 // NXP UM10462 LPC11U1x User manual Rev. 1 � 14 April 2011
samux 14:757226626acb 7
samux 14:757226626acb 8 #ifdef TARGET_LPC11U24
samux 14:757226626acb 9
samux 14:757226626acb 10 #include "USBBusInterface.h"
samux 14:757226626acb 11
samux 14:757226626acb 12 USBHAL * USBHAL::instance;
samux 14:757226626acb 13
samux 14:757226626acb 14
samux 14:757226626acb 15 // Valid physical endpoint numbers are 0 to (NUMBER_OF_PHYSICAL_ENDPOINTS-1)
samux 14:757226626acb 16 #define LAST_PHYSICAL_ENDPOINT (NUMBER_OF_PHYSICAL_ENDPOINTS-1)
samux 14:757226626acb 17
samux 14:757226626acb 18 // Convert physical endpoint number to register bit
samux 14:757226626acb 19 #define EP(endpoint) (1UL<<endpoint)
samux 14:757226626acb 20
samux 14:757226626acb 21 // Convert physical to logical
samux 14:757226626acb 22 #define PHY_TO_LOG(endpoint) ((endpoint)>>1)
samux 14:757226626acb 23
samux 14:757226626acb 24 // Get endpoint direction
samux 14:757226626acb 25 #define IN_EP(endpoint) ((endpoint) & 1U ? true : false)
samux 14:757226626acb 26 #define OUT_EP(endpoint) ((endpoint) & 1U ? false : true)
samux 14:757226626acb 27
samux 14:757226626acb 28 // USB RAM
samux 14:757226626acb 29 #define USB_RAM_START (0x20004000)
samux 14:757226626acb 30 #define USB_RAM_SIZE (0x00000800)
samux 14:757226626acb 31
samux 14:757226626acb 32 // SYSAHBCLKCTRL
samux 14:757226626acb 33 #define CLK_USB (1UL<<14)
samux 14:757226626acb 34 #define CLK_USBRAM (1UL<<27)
samux 14:757226626acb 35
samux 14:757226626acb 36 // USB Information register
samux 14:757226626acb 37 #define FRAME_NR(a) ((a) & 0x7ff) // Frame number
samux 14:757226626acb 38
samux 14:757226626acb 39 // USB Device Command/Status register
samux 14:757226626acb 40 #define DEV_ADDR_MASK (0x7f) // Device address
samux 14:757226626acb 41 #define DEV_ADDR(a) ((a) & DEV_ADDR_MASK)
samux 14:757226626acb 42 #define DEV_EN (1UL<<7) // Device enable
samux 14:757226626acb 43 #define SETUP (1UL<<8) // SETUP token received
samux 14:757226626acb 44 #define PLL_ON (1UL<<9) // PLL enabled in suspend
samux 14:757226626acb 45 #define DCON (1UL<<16) // Device status - connect
samux 14:757226626acb 46 #define DSUS (1UL<<17) // Device status - suspend
samux 14:757226626acb 47 #define DCON_C (1UL<<24) // Connect change
samux 14:757226626acb 48 #define DSUS_C (1UL<<25) // Suspend change
samux 14:757226626acb 49 #define DRES_C (1UL<<26) // Reset change
samux 14:757226626acb 50 #define VBUSDEBOUNCED (1UL<<28) // Vbus detected
samux 14:757226626acb 51
samux 14:757226626acb 52 // Endpoint Command/Status list
samux 14:757226626acb 53 #define CMDSTS_A (1UL<<31) // Active
samux 14:757226626acb 54 #define CMDSTS_D (1UL<<30) // Disable
samux 14:757226626acb 55 #define CMDSTS_S (1UL<<29) // Stall
samux 14:757226626acb 56 #define CMDSTS_TR (1UL<<28) // Toggle Reset
samux 14:757226626acb 57 #define CMDSTS_RF (1UL<<27) // Rate Feedback mode
samux 14:757226626acb 58 #define CMDSTS_TV (1UL<<27) // Toggle Value
samux 14:757226626acb 59 #define CMDSTS_T (1UL<<26) // Endpoint Type
samux 14:757226626acb 60 #define CMDSTS_NBYTES(n) (((n)&0x3ff)<<16) // Number of bytes
samux 14:757226626acb 61 #define CMDSTS_ADDRESS_OFFSET(a) (((a)>>6)&0xffff) // Buffer start address
samux 14:757226626acb 62
samux 14:757226626acb 63 #define BYTES_REMAINING(s) (((s)>>16)&0x3ff) // Bytes remaining after transfer
samux 14:757226626acb 64
samux 14:757226626acb 65 // USB Non-endpoint interrupt sources
samux 14:757226626acb 66 #define FRAME_INT (1UL<<30)
samux 14:757226626acb 67 #define DEV_INT (1UL<<31)
samux 14:757226626acb 68
samux 14:757226626acb 69 static volatile int epComplete = 0;
samux 14:757226626acb 70
samux 14:757226626acb 71 // One entry for a double-buffered logical endpoint in the endpoint
samux 14:757226626acb 72 // command/status list. Endpoint 0 is single buffered, out[1] is used
samux 14:757226626acb 73 // for the SETUP packet and in[1] is not used
samux 14:757226626acb 74 typedef __packed struct {
samux 14:757226626acb 75 uint32_t out[2];
samux 14:757226626acb 76 uint32_t in[2];
samux 14:757226626acb 77 } EP_COMMAND_STATUS;
samux 14:757226626acb 78
samux 14:757226626acb 79 typedef __packed struct {
samux 14:757226626acb 80 uint8_t out[MAX_PACKET_SIZE_EP0];
samux 14:757226626acb 81 uint8_t in[MAX_PACKET_SIZE_EP0];
samux 14:757226626acb 82 uint8_t setup[SETUP_PACKET_SIZE];
samux 14:757226626acb 83 } CONTROL_TRANSFER;
samux 14:757226626acb 84
samux 14:757226626acb 85 typedef __packed struct {
samux 14:757226626acb 86 uint32_t maxPacket;
samux 14:757226626acb 87 uint32_t buffer[2];
samux 14:757226626acb 88 uint32_t options;
samux 14:757226626acb 89 } EP_STATE;
samux 14:757226626acb 90
samux 14:757226626acb 91 static volatile EP_STATE endpointState[NUMBER_OF_PHYSICAL_ENDPOINTS];
samux 14:757226626acb 92
samux 14:757226626acb 93 // Pointer to the endpoint command/status list
samux 14:757226626acb 94 static EP_COMMAND_STATUS *ep = NULL;
samux 14:757226626acb 95
samux 14:757226626acb 96 // Pointer to endpoint 0 data (IN/OUT and SETUP)
samux 14:757226626acb 97 static CONTROL_TRANSFER *ct = NULL;
samux 14:757226626acb 98
samux 14:757226626acb 99 // Shadow DEVCMDSTAT register to avoid accidentally clearing flags or
samux 14:757226626acb 100 // initiating a remote wakeup event.
samux 14:757226626acb 101 static volatile uint32_t devCmdStat;
samux 14:757226626acb 102
samux 14:757226626acb 103 // Pointers used to allocate USB RAM
samux 14:757226626acb 104 static uint32_t usbRamPtr = USB_RAM_START;
samux 14:757226626acb 105 static uint32_t epRamPtr = 0; // Buffers for endpoints > 0 start here
samux 14:757226626acb 106
samux 14:757226626acb 107 #define ROUND_UP_TO_MULTIPLE(x, m) ((((x)+((m)-1))/(m))*(m))
samux 14:757226626acb 108
samux 14:757226626acb 109 void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size);
samux 14:757226626acb 110 void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size) {
samux 14:757226626acb 111 if (size > 0) {
samux 14:757226626acb 112 do {
samux 14:757226626acb 113 *dst++ = *src++;
samux 14:757226626acb 114 } while (--size > 0);
samux 14:757226626acb 115 }
samux 14:757226626acb 116 }
samux 14:757226626acb 117
samux 14:757226626acb 118
samux 14:757226626acb 119 USBHAL::USBHAL(void) {
samux 14:757226626acb 120 NVIC_DisableIRQ(USB_IRQn);
samux 14:757226626acb 121
samux 14:757226626acb 122 // nUSB_CONNECT output
samux 14:757226626acb 123 LPC_IOCON->PIO0_6 = 0x00000001;
samux 14:757226626acb 124
samux 14:757226626acb 125 // Enable clocks (USB registers, USB RAM)
samux 14:757226626acb 126 LPC_SYSCON->SYSAHBCLKCTRL |= CLK_USB | CLK_USBRAM;
samux 14:757226626acb 127
samux 14:757226626acb 128 // Ensure device disconnected (DCON not set)
samux 14:757226626acb 129 LPC_USB->DEVCMDSTAT = 0;
samux 14:757226626acb 130
samux 14:757226626acb 131 // to ensure that the USB host sees the device as
samux 14:757226626acb 132 // disconnected if the target CPU is reset.
samux 14:757226626acb 133 wait(0.3);
samux 14:757226626acb 134
samux 14:757226626acb 135 // Reserve space in USB RAM for endpoint command/status list
samux 14:757226626acb 136 // Must be 256 byte aligned
samux 14:757226626acb 137 usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 256);
samux 14:757226626acb 138 ep = (EP_COMMAND_STATUS *)usbRamPtr;
samux 14:757226626acb 139 usbRamPtr += (sizeof(EP_COMMAND_STATUS) * NUMBER_OF_LOGICAL_ENDPOINTS);
samux 14:757226626acb 140 LPC_USB->EPLISTSTART = (uint32_t)(ep) & 0xffffff00;
samux 14:757226626acb 141
samux 14:757226626acb 142 // Reserve space in USB RAM for Endpoint 0
samux 14:757226626acb 143 // Must be 64 byte aligned
samux 14:757226626acb 144 usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 64);
samux 14:757226626acb 145 ct = (CONTROL_TRANSFER *)usbRamPtr;
samux 14:757226626acb 146 usbRamPtr += sizeof(CONTROL_TRANSFER);
samux 14:757226626acb 147 LPC_USB->DATABUFSTART =(uint32_t)(ct) & 0xffc00000;
samux 14:757226626acb 148
samux 14:757226626acb 149 // Setup command/status list for EP0
samux 14:757226626acb 150 ep[0].out[0] = 0;
samux 14:757226626acb 151 ep[0].in[0] = 0;
samux 14:757226626acb 152 ep[0].out[1] = CMDSTS_ADDRESS_OFFSET((uint32_t)ct->setup);
samux 14:757226626acb 153
samux 14:757226626acb 154 // Route all interrupts to IRQ, some can be routed to
samux 14:757226626acb 155 // USB_FIQ if you wish.
samux 14:757226626acb 156 LPC_USB->INTROUTING = 0;
samux 14:757226626acb 157
samux 14:757226626acb 158 // Set device address 0, enable USB device, no remote wakeup
samux 14:757226626acb 159 devCmdStat = DEV_ADDR(0) | DEV_EN | DSUS;
samux 14:757226626acb 160 LPC_USB->DEVCMDSTAT = devCmdStat;
samux 14:757226626acb 161
samux 14:757226626acb 162 // Enable interrupts for device events and EP0
samux 14:757226626acb 163 LPC_USB->INTEN = DEV_INT | EP(EP0IN) | EP(EP0OUT) | FRAME_INT;
samux 14:757226626acb 164 instance = this;
samux 14:757226626acb 165
samux 14:757226626acb 166 //attach IRQ handler and enable interrupts
samux 14:757226626acb 167 NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
samux 14:757226626acb 168 NVIC_EnableIRQ(USB_IRQn);
samux 14:757226626acb 169 }
samux 14:757226626acb 170
samux 14:757226626acb 171 USBHAL::~USBHAL(void) {
samux 14:757226626acb 172 // Ensure device disconnected (DCON not set)
samux 14:757226626acb 173 LPC_USB->DEVCMDSTAT = 0;
samux 14:757226626acb 174
samux 14:757226626acb 175 // Disable USB interrupts
samux 14:757226626acb 176 NVIC_DisableIRQ(USB_IRQn);
samux 14:757226626acb 177 }
samux 14:757226626acb 178
samux 14:757226626acb 179 void USBHAL::connect(void) {
samux 14:757226626acb 180 devCmdStat |= DCON;
samux 14:757226626acb 181 LPC_USB->DEVCMDSTAT = devCmdStat;
samux 14:757226626acb 182 }
samux 14:757226626acb 183
samux 14:757226626acb 184 void USBHAL::disconnect(void) {
samux 14:757226626acb 185 devCmdStat &= ~DCON;
samux 14:757226626acb 186 LPC_USB->DEVCMDSTAT = devCmdStat;
samux 14:757226626acb 187 }
samux 14:757226626acb 188
samux 14:757226626acb 189 void USBHAL::configureDevice(void) {
samux 14:757226626acb 190 }
samux 14:757226626acb 191
samux 14:757226626acb 192 void USBHAL::unconfigureDevice(void) {
samux 14:757226626acb 193 }
samux 14:757226626acb 194
samux 14:757226626acb 195 void USBHAL::EP0setup(uint8_t *buffer) {
samux 14:757226626acb 196 // Copy setup packet data
samux 14:757226626acb 197 USBMemCopy(buffer, ct->setup, SETUP_PACKET_SIZE);
samux 14:757226626acb 198 }
samux 14:757226626acb 199
samux 14:757226626acb 200 void USBHAL::EP0read(void) {
samux 14:757226626acb 201 // Start an endpoint 0 read
samux 14:757226626acb 202
samux 14:757226626acb 203 // The USB ISR will call USBDevice_EP0out() when a packet has been read,
samux 14:757226626acb 204 // the USBDevice layer then calls USBBusInterface_EP0getReadResult() to
samux 14:757226626acb 205 // read the data.
samux 14:757226626acb 206
samux 14:757226626acb 207 ep[0].out[0] = CMDSTS_A |CMDSTS_NBYTES(MAX_PACKET_SIZE_EP0) \
samux 14:757226626acb 208 | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out);
samux 14:757226626acb 209 }
samux 14:757226626acb 210
samux 14:757226626acb 211 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
samux 14:757226626acb 212 // Complete an endpoint 0 read
samux 14:757226626acb 213 uint32_t bytesRead;
samux 14:757226626acb 214
samux 14:757226626acb 215 // Find how many bytes were read
samux 14:757226626acb 216 bytesRead = MAX_PACKET_SIZE_EP0 - BYTES_REMAINING(ep[0].out[0]);
samux 14:757226626acb 217
samux 14:757226626acb 218 // Copy data
samux 14:757226626acb 219 USBMemCopy(buffer, ct->out, bytesRead);
samux 14:757226626acb 220 return bytesRead;
samux 14:757226626acb 221 }
samux 14:757226626acb 222
samux 14:757226626acb 223 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
samux 14:757226626acb 224 // Start and endpoint 0 write
samux 14:757226626acb 225
samux 14:757226626acb 226 // The USB ISR will call USBDevice_EP0in() when the data has
samux 14:757226626acb 227 // been written, the USBDevice layer then calls
samux 14:757226626acb 228 // USBBusInterface_EP0getWriteResult() to complete the transaction.
samux 14:757226626acb 229
samux 14:757226626acb 230 // Copy data
samux 14:757226626acb 231 USBMemCopy(ct->in, buffer, size);
samux 14:757226626acb 232
samux 14:757226626acb 233 // Start transfer
samux 14:757226626acb 234 ep[0].in[0] = CMDSTS_A | CMDSTS_NBYTES(size) \
samux 14:757226626acb 235 | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->in);
samux 14:757226626acb 236 }
samux 14:757226626acb 237
samux 14:757226626acb 238
samux 14:757226626acb 239 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
samux 14:757226626acb 240 uint8_t bf = 0;
samux 14:757226626acb 241 uint32_t flags = 0;
samux 14:757226626acb 242
samux 14:757226626acb 243 //check which buffer must be filled
samux 14:757226626acb 244 if (LPC_USB->EPBUFCFG & EP(endpoint)) {
samux 14:757226626acb 245 // Double buffered
samux 14:757226626acb 246 if (LPC_USB->EPINUSE & EP(endpoint)) {
samux 14:757226626acb 247 bf = 1;
samux 14:757226626acb 248 } else {
samux 14:757226626acb 249 bf = 0;
samux 14:757226626acb 250 }
samux 14:757226626acb 251 }
samux 14:757226626acb 252
samux 14:757226626acb 253 // if isochronous endpoint, T = 1
samux 14:757226626acb 254 if(endpointState[endpoint].options & ISOCHRONOUS)
samux 14:757226626acb 255 {
samux 14:757226626acb 256 flags |= CMDSTS_T;
samux 14:757226626acb 257 }
samux 14:757226626acb 258
samux 14:757226626acb 259 //Active the endpoint for reading
samux 14:757226626acb 260 ep[PHY_TO_LOG(endpoint)].out[bf] = CMDSTS_A | CMDSTS_NBYTES(maximumSize) \
samux 14:757226626acb 261 | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out) | flags;
samux 14:757226626acb 262 return EP_PENDING;
samux 14:757226626acb 263 }
samux 14:757226626acb 264
samux 14:757226626acb 265 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead) {
samux 14:757226626acb 266
samux 14:757226626acb 267 uint8_t bf = 0;
samux 14:757226626acb 268
samux 14:757226626acb 269 if (!(epComplete & EP(endpoint)))
samux 14:757226626acb 270 return EP_PENDING;
samux 14:757226626acb 271 else {
samux 14:757226626acb 272 epComplete &= ~EP(endpoint);
samux 14:757226626acb 273
samux 14:757226626acb 274 //check which buffer has been filled
samux 14:757226626acb 275 if (LPC_USB->EPBUFCFG & EP(endpoint)) {
samux 14:757226626acb 276 // Double buffered (here we read the previous buffer which was used)
samux 14:757226626acb 277 if (LPC_USB->EPINUSE & EP(endpoint)) {
samux 14:757226626acb 278 bf = 0;
samux 14:757226626acb 279 } else {
samux 14:757226626acb 280 bf = 1;
samux 14:757226626acb 281 }
samux 14:757226626acb 282 }
samux 14:757226626acb 283
samux 14:757226626acb 284 // Find how many bytes were read
samux 14:757226626acb 285 *bytesRead = (uint32_t) (endpointState[endpoint].maxPacket - BYTES_REMAINING(ep[PHY_TO_LOG(endpoint)].out[bf]));
samux 14:757226626acb 286
samux 14:757226626acb 287 // Copy data
samux 14:757226626acb 288 USBMemCopy(data, ct->out, *bytesRead);
samux 14:757226626acb 289 return EP_COMPLETED;
samux 14:757226626acb 290 }
samux 14:757226626acb 291 }
samux 14:757226626acb 292
samux 14:757226626acb 293 void USBHAL::EP0getWriteResult(void) {
samux 14:757226626acb 294 // Complete an endpoint 0 write
samux 14:757226626acb 295
samux 14:757226626acb 296 // Nothing required for this target
samux 14:757226626acb 297 return;
samux 14:757226626acb 298 }
samux 14:757226626acb 299
samux 14:757226626acb 300 void USBHAL::EP0stall(void) {
samux 14:757226626acb 301 ep[0].in[0] = CMDSTS_S;
samux 14:757226626acb 302 ep[0].out[0] = CMDSTS_S;
samux 14:757226626acb 303 }
samux 14:757226626acb 304
samux 14:757226626acb 305 void USBHAL::setAddress(uint8_t address) {
samux 14:757226626acb 306 devCmdStat &= ~DEV_ADDR_MASK;
samux 14:757226626acb 307 devCmdStat |= DEV_ADDR(address);
samux 14:757226626acb 308 LPC_USB->DEVCMDSTAT = devCmdStat;
samux 14:757226626acb 309 }
samux 14:757226626acb 310
samux 14:757226626acb 311 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) {
samux 14:757226626acb 312 uint32_t flags = 0;
samux 14:757226626acb 313 uint32_t bf;
samux 14:757226626acb 314
samux 14:757226626acb 315 // Validate parameters
samux 14:757226626acb 316 if (data == NULL) {
samux 14:757226626acb 317 return EP_INVALID;
samux 14:757226626acb 318 }
samux 14:757226626acb 319
samux 14:757226626acb 320 if (endpoint > LAST_PHYSICAL_ENDPOINT) {
samux 14:757226626acb 321 return EP_INVALID;
samux 14:757226626acb 322 }
samux 14:757226626acb 323
samux 14:757226626acb 324 if ((endpoint==EP0IN) || (endpoint==EP0OUT)) {
samux 14:757226626acb 325 return EP_INVALID;
samux 14:757226626acb 326 }
samux 14:757226626acb 327
samux 14:757226626acb 328 if (size > endpointState[endpoint].maxPacket) {
samux 14:757226626acb 329 return EP_INVALID;
samux 14:757226626acb 330 }
samux 14:757226626acb 331
samux 14:757226626acb 332 if (LPC_USB->EPBUFCFG & EP(endpoint)) {
samux 14:757226626acb 333 // Double buffered
samux 14:757226626acb 334 if (LPC_USB->EPINUSE & EP(endpoint)) {
samux 14:757226626acb 335 bf = 1;
samux 14:757226626acb 336 } else {
samux 14:757226626acb 337 bf = 0;
samux 14:757226626acb 338 }
samux 14:757226626acb 339 } else {
samux 14:757226626acb 340 // Single buffered
samux 14:757226626acb 341 bf = 0;
samux 14:757226626acb 342 }
samux 14:757226626acb 343
samux 14:757226626acb 344 // Check if already active
samux 14:757226626acb 345 if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) {
samux 14:757226626acb 346 return EP_INVALID;
samux 14:757226626acb 347 }
samux 14:757226626acb 348
samux 14:757226626acb 349 // Check if stalled
samux 14:757226626acb 350 if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) {
samux 14:757226626acb 351 return EP_STALLED;
samux 14:757226626acb 352 }
samux 14:757226626acb 353
samux 14:757226626acb 354 // Copy data to USB RAM
samux 14:757226626acb 355 USBMemCopy((uint8_t *)endpointState[endpoint].buffer[bf], data, size);
samux 14:757226626acb 356
samux 14:757226626acb 357 // Add options
samux 14:757226626acb 358 if (endpointState[endpoint].options & RATE_FEEDBACK_MODE) {
samux 14:757226626acb 359 flags |= CMDSTS_RF;
samux 14:757226626acb 360 }
samux 14:757226626acb 361
samux 14:757226626acb 362 if (endpointState[endpoint].options & ISOCHRONOUS) {
samux 14:757226626acb 363 flags |= CMDSTS_T;
samux 14:757226626acb 364 }
samux 14:757226626acb 365
samux 14:757226626acb 366 // Add transfer
samux 14:757226626acb 367 ep[PHY_TO_LOG(endpoint)].in[bf] = CMDSTS_ADDRESS_OFFSET( \
samux 14:757226626acb 368 endpointState[endpoint].buffer[bf]) \
samux 14:757226626acb 369 | CMDSTS_NBYTES(size) | CMDSTS_A | flags;
samux 14:757226626acb 370
samux 14:757226626acb 371 return EP_PENDING;
samux 14:757226626acb 372 }
samux 14:757226626acb 373
samux 14:757226626acb 374 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) {
samux 14:757226626acb 375 uint32_t bf;
samux 14:757226626acb 376 // Validate parameters
samux 14:757226626acb 377
samux 14:757226626acb 378 if (endpoint > LAST_PHYSICAL_ENDPOINT) {
samux 14:757226626acb 379 return EP_INVALID;
samux 14:757226626acb 380 }
samux 14:757226626acb 381
samux 14:757226626acb 382 if (OUT_EP(endpoint)) {
samux 14:757226626acb 383 return EP_INVALID;
samux 14:757226626acb 384 }
samux 14:757226626acb 385
samux 14:757226626acb 386 if (LPC_USB->EPBUFCFG & EP(endpoint)) {
samux 14:757226626acb 387 // Double buffered // TODO: FIX THIS
samux 14:757226626acb 388 if (LPC_USB->EPINUSE & EP(endpoint)) {
samux 14:757226626acb 389 bf = 1;
samux 14:757226626acb 390 } else {
samux 14:757226626acb 391 bf = 0;
samux 14:757226626acb 392 }
samux 14:757226626acb 393 } else {
samux 14:757226626acb 394 // Single buffered
samux 14:757226626acb 395 bf = 0;
samux 14:757226626acb 396 }
samux 14:757226626acb 397
samux 14:757226626acb 398 // Check if endpoint still active
samux 14:757226626acb 399 if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) {
samux 14:757226626acb 400 return EP_PENDING;
samux 14:757226626acb 401 }
samux 14:757226626acb 402
samux 14:757226626acb 403 // Check if stalled
samux 14:757226626acb 404 if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) {
samux 14:757226626acb 405 return EP_STALLED;
samux 14:757226626acb 406 }
samux 14:757226626acb 407
samux 14:757226626acb 408 return EP_COMPLETED;
samux 14:757226626acb 409 }
samux 14:757226626acb 410
samux 14:757226626acb 411 void USBHAL::stallEndpoint(uint8_t endpoint) {
samux 14:757226626acb 412
samux 14:757226626acb 413 // TODO: should this clear active bit?
samux 14:757226626acb 414
samux 14:757226626acb 415 if (IN_EP(endpoint)) {
samux 14:757226626acb 416 ep[PHY_TO_LOG(endpoint)].in[0] |= CMDSTS_S;
samux 14:757226626acb 417 ep[PHY_TO_LOG(endpoint)].in[1] |= CMDSTS_S;
samux 14:757226626acb 418 } else {
samux 14:757226626acb 419 ep[PHY_TO_LOG(endpoint)].out[0] |= CMDSTS_S;
samux 14:757226626acb 420 ep[PHY_TO_LOG(endpoint)].out[1] |= CMDSTS_S;
samux 14:757226626acb 421 }
samux 14:757226626acb 422 }
samux 14:757226626acb 423
samux 14:757226626acb 424 void USBHAL::unstallEndpoint(uint8_t endpoint) {
samux 14:757226626acb 425 if (LPC_USB->EPBUFCFG & EP(endpoint)) {
samux 14:757226626acb 426 // Double buffered
samux 14:757226626acb 427 if (IN_EP(endpoint)) {
samux 14:757226626acb 428 ep[PHY_TO_LOG(endpoint)].in[0] = 0; // S = 0
samux 14:757226626acb 429 ep[PHY_TO_LOG(endpoint)].in[1] = 0; // S = 0
samux 14:757226626acb 430
samux 14:757226626acb 431 if (LPC_USB->EPINUSE & EP(endpoint)) {
samux 14:757226626acb 432 ep[PHY_TO_LOG(endpoint)].in[1] = CMDSTS_TR; // S =0, TR=1, TV = 0
samux 14:757226626acb 433 } else {
samux 14:757226626acb 434 ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S =0, TR=1, TV = 0
samux 14:757226626acb 435 }
samux 14:757226626acb 436 } else {
samux 14:757226626acb 437 ep[PHY_TO_LOG(endpoint)].out[0] = 0; // S = 0
samux 14:757226626acb 438 ep[PHY_TO_LOG(endpoint)].out[1] = 0; // S = 0
samux 14:757226626acb 439
samux 14:757226626acb 440 if (LPC_USB->EPINUSE & EP(endpoint)) {
samux 14:757226626acb 441 ep[PHY_TO_LOG(endpoint)].out[1] = CMDSTS_TR; // S =0, TR=1, TV = 0
samux 14:757226626acb 442 } else {
samux 14:757226626acb 443 ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S =0, TR=1, TV = 0
samux 14:757226626acb 444 }
samux 14:757226626acb 445 }
samux 14:757226626acb 446 } else {
samux 14:757226626acb 447 // Single buffered
samux 14:757226626acb 448 if (IN_EP(endpoint)) {
samux 14:757226626acb 449 ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S=0, TR=1, TV = 0
samux 14:757226626acb 450 } else {
samux 14:757226626acb 451 ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S=0, TR=1, TV = 0
samux 14:757226626acb 452 }
samux 14:757226626acb 453 }
samux 14:757226626acb 454 }
samux 14:757226626acb 455
samux 14:757226626acb 456 bool USBHAL::getEndpointStallState(unsigned char endpoint) {
samux 14:757226626acb 457 if (IN_EP(endpoint)) {
samux 14:757226626acb 458 if (LPC_USB->EPINUSE & EP(endpoint)) {
samux 14:757226626acb 459 if (ep[PHY_TO_LOG(endpoint)].in[1] & CMDSTS_S) {
samux 14:757226626acb 460 return true;
samux 14:757226626acb 461 }
samux 14:757226626acb 462 } else {
samux 14:757226626acb 463 if (ep[PHY_TO_LOG(endpoint)].in[0] & CMDSTS_S) {
samux 14:757226626acb 464 return true;
samux 14:757226626acb 465 }
samux 14:757226626acb 466 }
samux 14:757226626acb 467 } else {
samux 14:757226626acb 468 if (LPC_USB->EPINUSE & EP(endpoint)) {
samux 14:757226626acb 469 if (ep[PHY_TO_LOG(endpoint)].out[1] & CMDSTS_S) {
samux 14:757226626acb 470 return true;
samux 14:757226626acb 471 }
samux 14:757226626acb 472 } else {
samux 14:757226626acb 473 if (ep[PHY_TO_LOG(endpoint)].out[0] & CMDSTS_S) {
samux 14:757226626acb 474 return true;
samux 14:757226626acb 475 }
samux 14:757226626acb 476 }
samux 14:757226626acb 477 }
samux 14:757226626acb 478
samux 14:757226626acb 479 return false;
samux 14:757226626acb 480 }
samux 14:757226626acb 481
samux 14:757226626acb 482 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options) {
samux 14:757226626acb 483 uint32_t tmpEpRamPtr;
samux 14:757226626acb 484
samux 14:757226626acb 485 if (endpoint > LAST_PHYSICAL_ENDPOINT) {
samux 14:757226626acb 486 return false;
samux 14:757226626acb 487 }
samux 14:757226626acb 488
samux 14:757226626acb 489 // Not applicable to the control endpoints
samux 14:757226626acb 490 if ((endpoint==EP0IN) || (endpoint==EP0OUT)) {
samux 14:757226626acb 491 return false;
samux 14:757226626acb 492 }
samux 14:757226626acb 493
samux 14:757226626acb 494 // Allocate buffers in USB RAM
samux 14:757226626acb 495 tmpEpRamPtr = epRamPtr;
samux 14:757226626acb 496
samux 14:757226626acb 497 // Must be 64 byte aligned
samux 14:757226626acb 498 tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64);
samux 14:757226626acb 499
samux 14:757226626acb 500 if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) {
samux 14:757226626acb 501 // Out of memory
samux 14:757226626acb 502 return false;
samux 14:757226626acb 503 }
samux 14:757226626acb 504
samux 14:757226626acb 505 // Allocate first buffer
samux 14:757226626acb 506 endpointState[endpoint].buffer[0] = tmpEpRamPtr;
samux 14:757226626acb 507 tmpEpRamPtr += maxPacket;
samux 14:757226626acb 508
samux 14:757226626acb 509 if (!(options & SINGLE_BUFFERED)) {
samux 14:757226626acb 510 // Must be 64 byte aligned
samux 14:757226626acb 511 tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64);
samux 14:757226626acb 512
samux 14:757226626acb 513 if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) {
samux 14:757226626acb 514 // Out of memory
samux 14:757226626acb 515 return false;
samux 14:757226626acb 516 }
samux 14:757226626acb 517
samux 14:757226626acb 518 // Allocate second buffer
samux 14:757226626acb 519 endpointState[endpoint].buffer[1] = tmpEpRamPtr;
samux 14:757226626acb 520 tmpEpRamPtr += maxPacket;
samux 14:757226626acb 521 }
samux 14:757226626acb 522
samux 14:757226626acb 523 // Commit to this USB RAM allocation
samux 14:757226626acb 524 epRamPtr = tmpEpRamPtr;
samux 14:757226626acb 525
samux 14:757226626acb 526 // Remaining endpoint state values
samux 14:757226626acb 527 endpointState[endpoint].maxPacket = maxPacket;
samux 14:757226626acb 528 endpointState[endpoint].options = options;
samux 14:757226626acb 529
samux 14:757226626acb 530 // Enable double buffering if required
samux 14:757226626acb 531 if (options & SINGLE_BUFFERED) {
samux 14:757226626acb 532 LPC_USB->EPBUFCFG &= ~EP(endpoint);
samux 14:757226626acb 533 } else {
samux 14:757226626acb 534 // Double buffered
samux 14:757226626acb 535 LPC_USB->EPBUFCFG |= EP(endpoint);
samux 14:757226626acb 536 }
samux 14:757226626acb 537
samux 14:757226626acb 538 // Enable interrupt
samux 14:757226626acb 539 LPC_USB->INTEN |= EP(endpoint);
samux 14:757226626acb 540
samux 14:757226626acb 541 // Enable endpoint
samux 14:757226626acb 542 unstallEndpoint(endpoint);
samux 14:757226626acb 543 return true;
samux 14:757226626acb 544 }
samux 14:757226626acb 545
samux 14:757226626acb 546 void USBHAL::remoteWakeup(void) {
samux 14:757226626acb 547 // Clearing DSUS bit initiates a remote wakeup if the
samux 14:757226626acb 548 // device is currently enabled and suspended - otherwise
samux 14:757226626acb 549 // it has no effect.
samux 14:757226626acb 550 LPC_USB->DEVCMDSTAT = devCmdStat & ~DSUS;
samux 14:757226626acb 551 }
samux 14:757226626acb 552
samux 14:757226626acb 553
samux 14:757226626acb 554 static void disableEndpoints(void) {
samux 14:757226626acb 555 uint32_t logEp;
samux 14:757226626acb 556
samux 14:757226626acb 557 // Ref. Table 158 "When a bus reset is received, software
samux 14:757226626acb 558 // must set the disable bit of all endpoints to 1".
samux 14:757226626acb 559
samux 14:757226626acb 560 for (logEp = 1; logEp < NUMBER_OF_LOGICAL_ENDPOINTS; logEp++) {
samux 14:757226626acb 561 ep[logEp].out[0] = CMDSTS_D;
samux 14:757226626acb 562 ep[logEp].out[1] = CMDSTS_D;
samux 14:757226626acb 563 ep[logEp].in[0] = CMDSTS_D;
samux 14:757226626acb 564 ep[logEp].in[1] = CMDSTS_D;
samux 14:757226626acb 565 }
samux 14:757226626acb 566
samux 14:757226626acb 567 // Start of USB RAM for endpoints > 0
samux 14:757226626acb 568 epRamPtr = usbRamPtr;
samux 14:757226626acb 569 }
samux 14:757226626acb 570
samux 14:757226626acb 571
samux 14:757226626acb 572
samux 14:757226626acb 573 void USBHAL::_usbisr(void) {
samux 14:757226626acb 574 instance->usbisr();
samux 14:757226626acb 575 }
samux 14:757226626acb 576
samux 14:757226626acb 577
samux 14:757226626acb 578 void USBHAL::usbisr(void) {
samux 14:757226626acb 579 // Start of frame
samux 14:757226626acb 580 if (LPC_USB->INTSTAT & FRAME_INT) {
samux 14:757226626acb 581 // Clear SOF interrupt
samux 14:757226626acb 582 LPC_USB->INTSTAT = FRAME_INT;
samux 14:757226626acb 583
samux 14:757226626acb 584 // SOF event, read frame number
samux 14:757226626acb 585 SOF(FRAME_NR(LPC_USB->INFO));
samux 14:757226626acb 586 }
samux 14:757226626acb 587
samux 14:757226626acb 588 // Device state
samux 14:757226626acb 589 if (LPC_USB->INTSTAT & DEV_INT) {
samux 14:757226626acb 590 LPC_USB->INTSTAT = DEV_INT;
samux 14:757226626acb 591
samux 14:757226626acb 592 if (LPC_USB->DEVCMDSTAT & DCON_C) {
samux 14:757226626acb 593 // Connect status changed
samux 14:757226626acb 594 LPC_USB->DEVCMDSTAT = devCmdStat | DCON_C;
samux 14:757226626acb 595
samux 14:757226626acb 596 connectStateChanged((LPC_USB->DEVCMDSTAT & DCON) != 0);
samux 14:757226626acb 597 }
samux 14:757226626acb 598
samux 14:757226626acb 599 if (LPC_USB->DEVCMDSTAT & DSUS_C) {
samux 14:757226626acb 600 // Suspend status changed
samux 14:757226626acb 601 LPC_USB->DEVCMDSTAT = devCmdStat | DSUS_C;
samux 14:757226626acb 602
samux 14:757226626acb 603 suspendStateChanged((LPC_USB->DEVCMDSTAT & DSUS) != 0);
samux 14:757226626acb 604 }
samux 14:757226626acb 605
samux 14:757226626acb 606 if (LPC_USB->DEVCMDSTAT & DRES_C) {
samux 14:757226626acb 607 // Bus reset
samux 14:757226626acb 608 LPC_USB->DEVCMDSTAT = devCmdStat | DRES_C;
samux 14:757226626acb 609
samux 14:757226626acb 610 // Disable endpoints > 0
samux 14:757226626acb 611 disableEndpoints();
samux 14:757226626acb 612
samux 14:757226626acb 613 // Bus reset event
samux 14:757226626acb 614 busReset();
samux 14:757226626acb 615 }
samux 14:757226626acb 616 }
samux 14:757226626acb 617
samux 14:757226626acb 618 // Endpoint 0
samux 14:757226626acb 619 if (LPC_USB->INTSTAT & EP(EP0OUT)) {
samux 14:757226626acb 620 // Clear EP0OUT/SETUP interrupt
samux 14:757226626acb 621 LPC_USB->INTSTAT = EP(EP0OUT);
samux 14:757226626acb 622
samux 14:757226626acb 623 // Check if SETUP
samux 14:757226626acb 624 if (LPC_USB->DEVCMDSTAT & SETUP) {
samux 14:757226626acb 625 // Clear Active and Stall bits for EP0
samux 14:757226626acb 626 // Documentation does not make it clear if we must use the
samux 14:757226626acb 627 // EPSKIP register to achieve this, Fig. 16 and NXP reference
samux 14:757226626acb 628 // code suggests we can just clear the Active bits - check with
samux 14:757226626acb 629 // NXP to be sure.
samux 14:757226626acb 630 ep[0].in[0] = 0;
samux 14:757226626acb 631 ep[0].out[0] = 0;
samux 14:757226626acb 632
samux 14:757226626acb 633 // Clear EP0IN interrupt
samux 14:757226626acb 634 LPC_USB->INTSTAT = EP(EP0IN);
samux 14:757226626acb 635
samux 14:757226626acb 636 // Clear SETUP (and INTONNAK_CI/O) in device status register
samux 14:757226626acb 637 LPC_USB->DEVCMDSTAT = devCmdStat | SETUP;
samux 14:757226626acb 638
samux 14:757226626acb 639 // EP0 SETUP event (SETUP data received)
samux 14:757226626acb 640 EP0setupCallback();
samux 14:757226626acb 641 } else {
samux 14:757226626acb 642 // EP0OUT ACK event (OUT data received)
samux 14:757226626acb 643 EP0out();
samux 14:757226626acb 644 }
samux 14:757226626acb 645 }
samux 14:757226626acb 646
samux 14:757226626acb 647 if (LPC_USB->INTSTAT & EP(EP0IN)) {
samux 14:757226626acb 648 // Clear EP0IN interrupt
samux 14:757226626acb 649 LPC_USB->INTSTAT = EP(EP0IN);
samux 14:757226626acb 650
samux 14:757226626acb 651 // EP0IN ACK event (IN data sent)
samux 14:757226626acb 652 EP0in();
samux 14:757226626acb 653 }
samux 14:757226626acb 654
samux 14:757226626acb 655 if (LPC_USB->INTSTAT & EP(EP1IN)) {
samux 14:757226626acb 656 // Clear EP1IN interrupt
samux 14:757226626acb 657 LPC_USB->INTSTAT = EP(EP1IN);
samux 14:757226626acb 658 epComplete |= EP(EP1IN);
samux 14:757226626acb 659 if (EP1_IN_callback())
samux 14:757226626acb 660 epComplete &= ~EP(EP1IN);
samux 14:757226626acb 661 }
samux 14:757226626acb 662
samux 14:757226626acb 663 if (LPC_USB->INTSTAT & EP(EP1OUT)) {
samux 14:757226626acb 664 // Clear EP1OUT interrupt
samux 14:757226626acb 665 LPC_USB->INTSTAT = EP(EP1OUT);
samux 14:757226626acb 666 epComplete |= EP(EP1OUT);
samux 14:757226626acb 667 if (EP1_OUT_callback())
samux 14:757226626acb 668 epComplete &= ~EP(EP1OUT);
samux 14:757226626acb 669 }
samux 14:757226626acb 670
samux 14:757226626acb 671 if (LPC_USB->INTSTAT & EP(EP2IN)) {
samux 14:757226626acb 672 // Clear EPBULK_IN interrupt
samux 14:757226626acb 673 LPC_USB->INTSTAT = EP(EP2IN);
samux 14:757226626acb 674 epComplete |= EP(EP2IN);
samux 14:757226626acb 675 if (EP2_IN_callback())
samux 14:757226626acb 676 epComplete &= ~EP(EP2IN);
samux 14:757226626acb 677 }
samux 14:757226626acb 678
samux 14:757226626acb 679 if (LPC_USB->INTSTAT & EP(EP2OUT)) {
samux 14:757226626acb 680 // Clear EPBULK_OUT interrupt
samux 14:757226626acb 681 LPC_USB->INTSTAT = EP(EP2OUT);
samux 14:757226626acb 682 epComplete |= EP(EP2OUT);
samux 14:757226626acb 683 //Call callback function. If true, clear epComplete
samux 14:757226626acb 684 if (EP2_OUT_callback())
samux 14:757226626acb 685 epComplete &= ~EP(EP2OUT);
samux 14:757226626acb 686 }
samux 14:757226626acb 687
samux 14:757226626acb 688 if (LPC_USB->INTSTAT & EP(EP3IN)) {
samux 14:757226626acb 689 // Clear EP3_IN interrupt
samux 14:757226626acb 690 LPC_USB->INTSTAT = EP(EP3IN);
samux 14:757226626acb 691 epComplete |= EP(EP3IN);
samux 14:757226626acb 692 if (EP3_IN_callback())
samux 14:757226626acb 693 epComplete &= ~EP(EP3IN);
samux 14:757226626acb 694 }
samux 14:757226626acb 695
samux 14:757226626acb 696 if (LPC_USB->INTSTAT & EP(EP3OUT)) {
samux 14:757226626acb 697 // Clear EP3_OUT interrupt
samux 14:757226626acb 698 LPC_USB->INTSTAT = EP(EP3OUT);
samux 14:757226626acb 699 epComplete |= EP(EP3OUT);
samux 14:757226626acb 700 //Call callback function. If true, clear epComplete
samux 14:757226626acb 701 if (EP3_OUT_callback())
samux 14:757226626acb 702 epComplete &= ~EP(EP3OUT);
samux 14:757226626acb 703 }
samux 14:757226626acb 704 }
samux 14:757226626acb 705
samux 14:757226626acb 706 #endif