Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of USBDevice by
USBHAL_LPC11U.cpp
00001 /* Copyright (c) 2010-2011 mbed.org, MIT License 00002 * 00003 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 00004 * and associated documentation files (the "Software"), to deal in the Software without 00005 * restriction, including without limitation the rights to use, copy, modify, merge, publish, 00006 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 00007 * Software is furnished to do so, subject to the following conditions: 00008 * 00009 * The above copyright notice and this permission notice shall be included in all copies or 00010 * substantial portions of the Software. 00011 * 00012 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 00013 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00014 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 00015 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00016 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00017 */ 00018 00019 #if defined(TARGET_LPC11UXX) || defined(TARGET_LPC11U6X) || defined(TARGET_LPC1347) || defined(TARGET_LPC1549) 00020 00021 #if defined(TARGET_LPC1347) || defined(TARGET_LPC1549) 00022 #define USB_IRQ USB_IRQ_IRQn 00023 #else 00024 #define USB_IRQ USB_IRQn 00025 #endif 00026 00027 #include "USBHAL.h" 00028 00029 USBHAL * USBHAL::instance; 00030 #if defined(TARGET_LPC1549) 00031 static uint8_t usbmem[2048] __attribute__((aligned(2048))); 00032 #endif 00033 00034 // Valid physical endpoint numbers are 0 to (NUMBER_OF_PHYSICAL_ENDPOINTS-1) 00035 #define LAST_PHYSICAL_ENDPOINT (NUMBER_OF_PHYSICAL_ENDPOINTS-1) 00036 00037 // Convert physical endpoint number to register bit 00038 #define EP(endpoint) (1UL<<endpoint) 00039 00040 // Convert physical to logical 00041 #define PHY_TO_LOG(endpoint) ((endpoint)>>1) 00042 00043 // Get endpoint direction 00044 #define IN_EP(endpoint) ((endpoint) & 1U ? true : false) 00045 #define OUT_EP(endpoint) ((endpoint) & 1U ? false : true) 00046 00047 // USB RAM 00048 #if defined(TARGET_LPC1549) 00049 #define USB_RAM_START ((uint32_t)usbmem) 00050 #define USB_RAM_SIZE sizeof(usbmem) 00051 #else 00052 #define USB_RAM_START (0x20004000) 00053 #define USB_RAM_SIZE (0x00000800) 00054 #endif 00055 00056 // SYSAHBCLKCTRL 00057 #if defined(TARGET_LPC1549) 00058 #define CLK_USB (1UL<<23) 00059 #else 00060 #define CLK_USB (1UL<<14) 00061 #define CLK_USBRAM (1UL<<27) 00062 #endif 00063 00064 // USB Information register 00065 #define FRAME_NR(a) ((a) & 0x7ff) // Frame number 00066 00067 // USB Device Command/Status register 00068 #define DEV_ADDR_MASK (0x7f) // Device address 00069 #define DEV_ADDR(a) ((a) & DEV_ADDR_MASK) 00070 #define DEV_EN (1UL<<7) // Device enable 00071 #define SETUP (1UL<<8) // SETUP token received 00072 #define PLL_ON (1UL<<9) // PLL enabled in suspend 00073 #define DCON (1UL<<16) // Device status - connect 00074 #define DSUS (1UL<<17) // Device status - suspend 00075 #define DCON_C (1UL<<24) // Connect change 00076 #define DSUS_C (1UL<<25) // Suspend change 00077 #define DRES_C (1UL<<26) // Reset change 00078 #define VBUSDEBOUNCED (1UL<<28) // Vbus detected 00079 00080 // Endpoint Command/Status list 00081 #define CMDSTS_A (1UL<<31) // Active 00082 #define CMDSTS_D (1UL<<30) // Disable 00083 #define CMDSTS_S (1UL<<29) // Stall 00084 #define CMDSTS_TR (1UL<<28) // Toggle Reset 00085 #define CMDSTS_RF (1UL<<27) // Rate Feedback mode 00086 #define CMDSTS_TV (1UL<<27) // Toggle Value 00087 #define CMDSTS_T (1UL<<26) // Endpoint Type 00088 #define CMDSTS_NBYTES(n) (((n)&0x3ff)<<16) // Number of bytes 00089 #define CMDSTS_ADDRESS_OFFSET(a) (((a)>>6)&0xffff) // Buffer start address 00090 00091 #define BYTES_REMAINING(s) (((s)>>16)&0x3ff) // Bytes remaining after transfer 00092 00093 // USB Non-endpoint interrupt sources 00094 #define FRAME_INT (1UL<<30) 00095 #define DEV_INT (1UL<<31) 00096 00097 static volatile int epComplete = 0; 00098 00099 // One entry for a double-buffered logical endpoint in the endpoint 00100 // command/status list. Endpoint 0 is single buffered, out[1] is used 00101 // for the SETUP packet and in[1] is not used 00102 typedef struct { 00103 uint32_t out[2]; 00104 uint32_t in[2]; 00105 } PACKED EP_COMMAND_STATUS; 00106 00107 typedef struct { 00108 uint8_t out[MAX_PACKET_SIZE_EP0]; 00109 uint8_t in[MAX_PACKET_SIZE_EP0]; 00110 uint8_t setup[SETUP_PACKET_SIZE]; 00111 } PACKED CONTROL_TRANSFER; 00112 00113 typedef struct { 00114 uint32_t maxPacket; 00115 uint32_t buffer[2]; 00116 uint32_t options; 00117 } PACKED EP_STATE; 00118 00119 static volatile EP_STATE endpointState[NUMBER_OF_PHYSICAL_ENDPOINTS]; 00120 00121 // Pointer to the endpoint command/status list 00122 static EP_COMMAND_STATUS *ep = NULL; 00123 00124 // Pointer to endpoint 0 data (IN/OUT and SETUP) 00125 static CONTROL_TRANSFER *ct = NULL; 00126 00127 // Shadow DEVCMDSTAT register to avoid accidentally clearing flags or 00128 // initiating a remote wakeup event. 00129 static volatile uint32_t devCmdStat; 00130 00131 // Pointers used to allocate USB RAM 00132 static uint32_t usbRamPtr = USB_RAM_START; 00133 static uint32_t epRamPtr = 0; // Buffers for endpoints > 0 start here 00134 00135 #define ROUND_UP_TO_MULTIPLE(x, m) ((((x)+((m)-1))/(m))*(m)) 00136 00137 void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size); 00138 void USBMemCopy(uint8_t *dst, uint8_t *src, uint32_t size) { 00139 if (size > 0) { 00140 do { 00141 *dst++ = *src++; 00142 } while (--size > 0); 00143 } 00144 } 00145 00146 00147 USBHAL::USBHAL(void) { 00148 NVIC_DisableIRQ(USB_IRQ); 00149 00150 // fill in callback array 00151 epCallback[0] = &USBHAL::EP1_OUT_callback; 00152 epCallback[1] = &USBHAL::EP1_IN_callback; 00153 epCallback[2] = &USBHAL::EP2_OUT_callback; 00154 epCallback[3] = &USBHAL::EP2_IN_callback; 00155 epCallback[4] = &USBHAL::EP3_OUT_callback; 00156 epCallback[5] = &USBHAL::EP3_IN_callback; 00157 epCallback[6] = &USBHAL::EP4_OUT_callback; 00158 epCallback[7] = &USBHAL::EP4_IN_callback; 00159 00160 #if defined(TARGET_LPC1549) 00161 /* Set USB PLL input to system oscillator */ 00162 LPC_SYSCON->USBPLLCLKSEL = 0x01; 00163 00164 /* Setup USB PLL (FCLKIN = 12MHz) * 4 = 48MHz 00165 MSEL = 3 (this is pre-decremented), PSEL = 1 (for P = 2) 00166 FCLKOUT = FCLKIN * (MSEL + 1) = 12MHz * 4 = 48MHz 00167 FCCO = FCLKOUT * 2 * P = 48MHz * 2 * 2 = 192MHz (within FCCO range) */ 00168 LPC_SYSCON->USBPLLCTRL = (0x3 | (1UL << 6)); 00169 00170 /* Powerup USB PLL */ 00171 LPC_SYSCON->PDRUNCFG &= ~(CLK_USB); 00172 00173 /* Wait for PLL to lock */ 00174 while(!(LPC_SYSCON->USBPLLSTAT & 0x01)); 00175 00176 /* enable USB main clock */ 00177 LPC_SYSCON->USBCLKSEL = 0x02; 00178 LPC_SYSCON->USBCLKDIV = 1; 00179 00180 /* Enable AHB clock to the USB block. */ 00181 LPC_SYSCON->SYSAHBCLKCTRL1 |= CLK_USB; 00182 00183 /* power UP USB Phy */ 00184 LPC_SYSCON->PDRUNCFG &= ~(1UL << 9); 00185 00186 /* Reset USB block */ 00187 LPC_SYSCON->PRESETCTRL1 |= (CLK_USB); 00188 LPC_SYSCON->PRESETCTRL1 &= ~(CLK_USB); 00189 00190 #else 00191 #if defined(TARGET_LPC11U35_401) || defined(TARGET_LPC11U35_501) 00192 // USB_VBUS input with pull-down 00193 LPC_IOCON->PIO0_3 = 0x00000009; 00194 #endif 00195 00196 // nUSB_CONNECT output 00197 LPC_IOCON->PIO0_6 = 0x00000001; 00198 00199 // Enable clocks (USB registers, USB RAM) 00200 LPC_SYSCON->SYSAHBCLKCTRL |= CLK_USB | CLK_USBRAM; 00201 00202 // Ensure device disconnected (DCON not set) 00203 LPC_USB->DEVCMDSTAT = 0; 00204 #endif 00205 // to ensure that the USB host sees the device as 00206 // disconnected if the target CPU is reset. 00207 wait(0.3); 00208 00209 // Reserve space in USB RAM for endpoint command/status list 00210 // Must be 256 byte aligned 00211 usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 256); 00212 ep = (EP_COMMAND_STATUS *)usbRamPtr; 00213 usbRamPtr += (sizeof(EP_COMMAND_STATUS) * NUMBER_OF_LOGICAL_ENDPOINTS); 00214 LPC_USB->EPLISTSTART = (uint32_t)(ep) & 0xffffff00; 00215 00216 // Reserve space in USB RAM for Endpoint 0 00217 // Must be 64 byte aligned 00218 usbRamPtr = ROUND_UP_TO_MULTIPLE(usbRamPtr, 64); 00219 ct = (CONTROL_TRANSFER *)usbRamPtr; 00220 usbRamPtr += sizeof(CONTROL_TRANSFER); 00221 LPC_USB->DATABUFSTART =(uint32_t)(ct) & 0xffc00000; 00222 00223 // Setup command/status list for EP0 00224 ep[0].out[0] = 0; 00225 ep[0].in[0] = 0; 00226 ep[0].out[1] = CMDSTS_ADDRESS_OFFSET((uint32_t)ct->setup); 00227 00228 // Route all interrupts to IRQ, some can be routed to 00229 // USB_FIQ if you wish. 00230 LPC_USB->INTROUTING = 0; 00231 00232 // Set device address 0, enable USB device, no remote wakeup 00233 devCmdStat = DEV_ADDR(0) | DEV_EN | DSUS; 00234 LPC_USB->DEVCMDSTAT = devCmdStat; 00235 00236 // Enable interrupts for device events and EP0 00237 LPC_USB->INTEN = DEV_INT | EP(EP0IN) | EP(EP0OUT) | FRAME_INT; 00238 instance = this; 00239 00240 //attach IRQ handler and enable interrupts 00241 NVIC_SetVector(USB_IRQ, (uint32_t)&_usbisr); 00242 } 00243 00244 USBHAL::~USBHAL(void) { 00245 // Ensure device disconnected (DCON not set) 00246 LPC_USB->DEVCMDSTAT = 0; 00247 // Disable USB interrupts 00248 NVIC_DisableIRQ(USB_IRQ); 00249 } 00250 00251 void USBHAL::connect(void) { 00252 NVIC_EnableIRQ(USB_IRQ); 00253 devCmdStat |= DCON; 00254 LPC_USB->DEVCMDSTAT = devCmdStat; 00255 } 00256 00257 void USBHAL::disconnect(void) { 00258 NVIC_DisableIRQ(USB_IRQ); 00259 devCmdStat &= ~DCON; 00260 LPC_USB->DEVCMDSTAT = devCmdStat; 00261 } 00262 00263 void USBHAL::configureDevice(void) { 00264 // Not required 00265 } 00266 00267 void USBHAL::unconfigureDevice(void) { 00268 // Not required 00269 } 00270 00271 void USBHAL::EP0setup(uint8_t *buffer) { 00272 // Copy setup packet data 00273 USBMemCopy(buffer, ct->setup, SETUP_PACKET_SIZE); 00274 } 00275 00276 void USBHAL::EP0read(void) { 00277 // Start an endpoint 0 read 00278 00279 // The USB ISR will call USBDevice_EP0out() when a packet has been read, 00280 // the USBDevice layer then calls USBBusInterface_EP0getReadResult() to 00281 // read the data. 00282 00283 ep[0].out[0] = CMDSTS_A |CMDSTS_NBYTES(MAX_PACKET_SIZE_EP0) \ 00284 | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out); 00285 } 00286 00287 uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) { 00288 // Complete an endpoint 0 read 00289 uint32_t bytesRead; 00290 00291 // Find how many bytes were read 00292 bytesRead = MAX_PACKET_SIZE_EP0 - BYTES_REMAINING(ep[0].out[0]); 00293 00294 // Copy data 00295 USBMemCopy(buffer, ct->out, bytesRead); 00296 return bytesRead; 00297 } 00298 00299 00300 void USBHAL::EP0readStage(void) { 00301 // Not required 00302 } 00303 00304 void USBHAL::EP0write(uint8_t *buffer, uint32_t size) { 00305 // Start and endpoint 0 write 00306 00307 // The USB ISR will call USBDevice_EP0in() when the data has 00308 // been written, the USBDevice layer then calls 00309 // USBBusInterface_EP0getWriteResult() to complete the transaction. 00310 00311 // Copy data 00312 USBMemCopy(ct->in, buffer, size); 00313 00314 // Start transfer 00315 ep[0].in[0] = CMDSTS_A | CMDSTS_NBYTES(size) \ 00316 | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->in); 00317 } 00318 00319 00320 EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) { 00321 uint8_t bf = 0; 00322 uint32_t flags = 0; 00323 00324 //check which buffer must be filled 00325 if (LPC_USB->EPBUFCFG & EP(endpoint)) { 00326 // Double buffered 00327 if (LPC_USB->EPINUSE & EP(endpoint)) { 00328 bf = 1; 00329 } else { 00330 bf = 0; 00331 } 00332 } 00333 00334 // if isochronous endpoint, T = 1 00335 if(endpointState[endpoint].options & ISOCHRONOUS) 00336 { 00337 flags |= CMDSTS_T; 00338 } 00339 00340 //Active the endpoint for reading 00341 ep[PHY_TO_LOG(endpoint)].out[bf] = CMDSTS_A | CMDSTS_NBYTES(maximumSize) \ 00342 | CMDSTS_ADDRESS_OFFSET((uint32_t)ct->out) | flags; 00343 return EP_PENDING; 00344 } 00345 00346 EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t *data, uint32_t *bytesRead) { 00347 00348 uint8_t bf = 0; 00349 00350 if (!(epComplete & EP(endpoint))) 00351 return EP_PENDING; 00352 else { 00353 epComplete &= ~EP(endpoint); 00354 00355 //check which buffer has been filled 00356 if (LPC_USB->EPBUFCFG & EP(endpoint)) { 00357 // Double buffered (here we read the previous buffer which was used) 00358 if (LPC_USB->EPINUSE & EP(endpoint)) { 00359 bf = 0; 00360 } else { 00361 bf = 1; 00362 } 00363 } 00364 00365 // Find how many bytes were read 00366 *bytesRead = (uint32_t) (endpointState[endpoint].maxPacket - BYTES_REMAINING(ep[PHY_TO_LOG(endpoint)].out[bf])); 00367 00368 // Copy data 00369 USBMemCopy(data, ct->out, *bytesRead); 00370 return EP_COMPLETED; 00371 } 00372 } 00373 00374 void USBHAL::EP0getWriteResult(void) { 00375 // Not required 00376 } 00377 00378 void USBHAL::EP0stall(void) { 00379 ep[0].in[0] = CMDSTS_S; 00380 ep[0].out[0] = CMDSTS_S; 00381 } 00382 00383 void USBHAL::setAddress(uint8_t address) { 00384 devCmdStat &= ~DEV_ADDR_MASK; 00385 devCmdStat |= DEV_ADDR(address); 00386 LPC_USB->DEVCMDSTAT = devCmdStat; 00387 } 00388 00389 EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size) { 00390 uint32_t flags = 0; 00391 uint32_t bf; 00392 00393 // Validate parameters 00394 if (data == NULL) { 00395 return EP_INVALID; 00396 } 00397 00398 if (endpoint > LAST_PHYSICAL_ENDPOINT) { 00399 return EP_INVALID; 00400 } 00401 00402 if ((endpoint==EP0IN) || (endpoint==EP0OUT)) { 00403 return EP_INVALID; 00404 } 00405 00406 if (size > endpointState[endpoint].maxPacket) { 00407 return EP_INVALID; 00408 } 00409 00410 if (LPC_USB->EPBUFCFG & EP(endpoint)) { 00411 // Double buffered 00412 if (LPC_USB->EPINUSE & EP(endpoint)) { 00413 bf = 1; 00414 } else { 00415 bf = 0; 00416 } 00417 } else { 00418 // Single buffered 00419 bf = 0; 00420 } 00421 00422 // Check if already active 00423 if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) { 00424 return EP_INVALID; 00425 } 00426 00427 // Check if stalled 00428 if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) { 00429 return EP_STALLED; 00430 } 00431 00432 // Copy data to USB RAM 00433 USBMemCopy((uint8_t *)endpointState[endpoint].buffer[bf], data, size); 00434 00435 // Add options 00436 if (endpointState[endpoint].options & RATE_FEEDBACK_MODE) { 00437 flags |= CMDSTS_RF; 00438 } 00439 00440 if (endpointState[endpoint].options & ISOCHRONOUS) { 00441 flags |= CMDSTS_T; 00442 } 00443 00444 // Add transfer 00445 ep[PHY_TO_LOG(endpoint)].in[bf] = CMDSTS_ADDRESS_OFFSET( \ 00446 endpointState[endpoint].buffer[bf]) \ 00447 | CMDSTS_NBYTES(size) | CMDSTS_A | flags; 00448 00449 return EP_PENDING; 00450 } 00451 00452 EP_STATUS USBHAL::endpointWriteResult(uint8_t endpoint) { 00453 uint32_t bf; 00454 00455 // Validate parameters 00456 if (endpoint > LAST_PHYSICAL_ENDPOINT) { 00457 return EP_INVALID; 00458 } 00459 00460 if (OUT_EP(endpoint)) { 00461 return EP_INVALID; 00462 } 00463 00464 if (LPC_USB->EPBUFCFG & EP(endpoint)) { 00465 // Double buffered // TODO: FIX THIS 00466 if (LPC_USB->EPINUSE & EP(endpoint)) { 00467 bf = 1; 00468 } else { 00469 bf = 0; 00470 } 00471 } else { 00472 // Single buffered 00473 bf = 0; 00474 } 00475 00476 // Check if endpoint still active 00477 if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_A) { 00478 return EP_PENDING; 00479 } 00480 00481 // Check if stalled 00482 if (ep[PHY_TO_LOG(endpoint)].in[bf] & CMDSTS_S) { 00483 return EP_STALLED; 00484 } 00485 00486 return EP_COMPLETED; 00487 } 00488 00489 void USBHAL::stallEndpoint(uint8_t endpoint) { 00490 00491 // FIX: should this clear active bit? 00492 if (IN_EP(endpoint)) { 00493 ep[PHY_TO_LOG(endpoint)].in[0] |= CMDSTS_S; 00494 ep[PHY_TO_LOG(endpoint)].in[1] |= CMDSTS_S; 00495 } else { 00496 ep[PHY_TO_LOG(endpoint)].out[0] |= CMDSTS_S; 00497 ep[PHY_TO_LOG(endpoint)].out[1] |= CMDSTS_S; 00498 } 00499 } 00500 00501 void USBHAL::unstallEndpoint(uint8_t endpoint) { 00502 if (LPC_USB->EPBUFCFG & EP(endpoint)) { 00503 // Double buffered 00504 if (IN_EP(endpoint)) { 00505 ep[PHY_TO_LOG(endpoint)].in[0] = 0; // S = 0 00506 ep[PHY_TO_LOG(endpoint)].in[1] = 0; // S = 0 00507 00508 if (LPC_USB->EPINUSE & EP(endpoint)) { 00509 ep[PHY_TO_LOG(endpoint)].in[1] = CMDSTS_TR; // S = 0, TR = 1, TV = 0 00510 } else { 00511 ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S = 0, TR = 1, TV = 0 00512 } 00513 } else { 00514 ep[PHY_TO_LOG(endpoint)].out[0] = 0; // S = 0 00515 ep[PHY_TO_LOG(endpoint)].out[1] = 0; // S = 0 00516 00517 if (LPC_USB->EPINUSE & EP(endpoint)) { 00518 ep[PHY_TO_LOG(endpoint)].out[1] = CMDSTS_TR; // S = 0, TR = 1, TV = 0 00519 } else { 00520 ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S = 0, TR = 1, TV = 0 00521 } 00522 } 00523 } else { 00524 // Single buffered 00525 if (IN_EP(endpoint)) { 00526 ep[PHY_TO_LOG(endpoint)].in[0] = CMDSTS_TR; // S = 0, TR = 1, TV = 0 00527 } else { 00528 ep[PHY_TO_LOG(endpoint)].out[0] = CMDSTS_TR; // S = 0, TR = 1, TV = 0 00529 } 00530 } 00531 } 00532 00533 bool USBHAL::getEndpointStallState(unsigned char endpoint) { 00534 if (IN_EP(endpoint)) { 00535 if (LPC_USB->EPINUSE & EP(endpoint)) { 00536 if (ep[PHY_TO_LOG(endpoint)].in[1] & CMDSTS_S) { 00537 return true; 00538 } 00539 } else { 00540 if (ep[PHY_TO_LOG(endpoint)].in[0] & CMDSTS_S) { 00541 return true; 00542 } 00543 } 00544 } else { 00545 if (LPC_USB->EPINUSE & EP(endpoint)) { 00546 if (ep[PHY_TO_LOG(endpoint)].out[1] & CMDSTS_S) { 00547 return true; 00548 } 00549 } else { 00550 if (ep[PHY_TO_LOG(endpoint)].out[0] & CMDSTS_S) { 00551 return true; 00552 } 00553 } 00554 } 00555 00556 return false; 00557 } 00558 00559 bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t options) { 00560 uint32_t tmpEpRamPtr; 00561 00562 if (endpoint > LAST_PHYSICAL_ENDPOINT) { 00563 return false; 00564 } 00565 00566 // Not applicable to the control endpoints 00567 if ((endpoint==EP0IN) || (endpoint==EP0OUT)) { 00568 return false; 00569 } 00570 00571 // Allocate buffers in USB RAM 00572 tmpEpRamPtr = epRamPtr; 00573 00574 // Must be 64 byte aligned 00575 tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64); 00576 00577 if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) { 00578 // Out of memory 00579 return false; 00580 } 00581 00582 // Allocate first buffer 00583 endpointState[endpoint].buffer[0] = tmpEpRamPtr; 00584 tmpEpRamPtr += maxPacket; 00585 00586 if (!(options & SINGLE_BUFFERED)) { 00587 // Must be 64 byte aligned 00588 tmpEpRamPtr = ROUND_UP_TO_MULTIPLE(tmpEpRamPtr, 64); 00589 00590 if ((tmpEpRamPtr + maxPacket) > (USB_RAM_START + USB_RAM_SIZE)) { 00591 // Out of memory 00592 return false; 00593 } 00594 00595 // Allocate second buffer 00596 endpointState[endpoint].buffer[1] = tmpEpRamPtr; 00597 tmpEpRamPtr += maxPacket; 00598 } 00599 00600 // Commit to this USB RAM allocation 00601 epRamPtr = tmpEpRamPtr; 00602 00603 // Remaining endpoint state values 00604 endpointState[endpoint].maxPacket = maxPacket; 00605 endpointState[endpoint].options = options; 00606 00607 // Enable double buffering if required 00608 if (options & SINGLE_BUFFERED) { 00609 LPC_USB->EPBUFCFG &= ~EP(endpoint); 00610 } else { 00611 // Double buffered 00612 LPC_USB->EPBUFCFG |= EP(endpoint); 00613 } 00614 00615 // Enable interrupt 00616 LPC_USB->INTEN |= EP(endpoint); 00617 00618 // Enable endpoint 00619 unstallEndpoint(endpoint); 00620 return true; 00621 } 00622 00623 void USBHAL::remoteWakeup(void) { 00624 // Clearing DSUS bit initiates a remote wakeup if the 00625 // device is currently enabled and suspended - otherwise 00626 // it has no effect. 00627 LPC_USB->DEVCMDSTAT = devCmdStat & ~DSUS; 00628 } 00629 00630 00631 static void disableEndpoints(void) { 00632 uint32_t logEp; 00633 00634 // Ref. Table 158 "When a bus reset is received, software 00635 // must set the disable bit of all endpoints to 1". 00636 00637 for (logEp = 1; logEp < NUMBER_OF_LOGICAL_ENDPOINTS; logEp++) { 00638 ep[logEp].out[0] = CMDSTS_D; 00639 ep[logEp].out[1] = CMDSTS_D; 00640 ep[logEp].in[0] = CMDSTS_D; 00641 ep[logEp].in[1] = CMDSTS_D; 00642 } 00643 00644 // Start of USB RAM for endpoints > 0 00645 epRamPtr = usbRamPtr; 00646 } 00647 00648 00649 00650 void USBHAL::_usbisr(void) { 00651 instance->usbisr(); 00652 } 00653 00654 void USBHAL::usbisr(void) { 00655 // Start of frame 00656 if (LPC_USB->INTSTAT & FRAME_INT) { 00657 // Clear SOF interrupt 00658 LPC_USB->INTSTAT = FRAME_INT; 00659 00660 // SOF event, read frame number 00661 SOF(FRAME_NR(LPC_USB->INFO)); 00662 } 00663 00664 // Device state 00665 if (LPC_USB->INTSTAT & DEV_INT) { 00666 LPC_USB->INTSTAT = DEV_INT; 00667 00668 if (LPC_USB->DEVCMDSTAT & DSUS_C) { 00669 // Suspend status changed 00670 LPC_USB->DEVCMDSTAT = devCmdStat | DSUS_C; 00671 if (LPC_USB->DEVCMDSTAT & DSUS) { 00672 suspendStateChanged(1); 00673 } else { 00674 suspendStateChanged(0); 00675 } 00676 } 00677 00678 if (LPC_USB->DEVCMDSTAT & DRES_C) { 00679 // Bus reset 00680 LPC_USB->DEVCMDSTAT = devCmdStat | DRES_C; 00681 00682 // Disable endpoints > 0 00683 disableEndpoints(); 00684 00685 // Bus reset event 00686 busReset(); 00687 } 00688 } 00689 00690 // Endpoint 0 00691 if (LPC_USB->INTSTAT & EP(EP0OUT)) { 00692 // Clear EP0OUT/SETUP interrupt 00693 LPC_USB->INTSTAT = EP(EP0OUT); 00694 00695 // Check if SETUP 00696 if (LPC_USB->DEVCMDSTAT & SETUP) { 00697 // Clear Active and Stall bits for EP0 00698 // Documentation does not make it clear if we must use the 00699 // EPSKIP register to achieve this, Fig. 16 and NXP reference 00700 // code suggests we can just clear the Active bits - check with 00701 // NXP to be sure. 00702 ep[0].in[0] = 0; 00703 ep[0].out[0] = 0; 00704 00705 // Clear EP0IN interrupt 00706 LPC_USB->INTSTAT = EP(EP0IN); 00707 00708 // Clear SETUP (and INTONNAK_CI/O) in device status register 00709 LPC_USB->DEVCMDSTAT = devCmdStat | SETUP; 00710 00711 // EP0 SETUP event (SETUP data received) 00712 EP0setupCallback(); 00713 } else { 00714 // EP0OUT ACK event (OUT data received) 00715 EP0out(); 00716 } 00717 } 00718 00719 if (LPC_USB->INTSTAT & EP(EP0IN)) { 00720 // Clear EP0IN interrupt 00721 LPC_USB->INTSTAT = EP(EP0IN); 00722 00723 // EP0IN ACK event (IN data sent) 00724 EP0in(); 00725 } 00726 00727 for (uint8_t num = 2; num < 5*2; num++) { 00728 if (LPC_USB->INTSTAT & EP(num)) { 00729 LPC_USB->INTSTAT = EP(num); 00730 epComplete |= EP(num); 00731 if ((instance->*(epCallback[num - 2]))()) { 00732 epComplete &= ~EP(num); 00733 } 00734 } 00735 } 00736 } 00737 00738 #endif
Generated on Tue Jul 12 2022 14:14:02 by
