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.
usbdc.cpp
00001 /* usbdc.cpp */ 00002 /* USB device controller */ 00003 /* Copyright (c) Phil Wright 2008 */ 00004 00005 #include "mbed.h" 00006 #include "usbdc.h" 00007 #include "cmsis.h" 00008 00009 #ifdef TARGET_LPC2368 00010 #undef LPC_USB_BASE 00011 #define LPC_USB_BASE (0xFFE0C000) /* TODO */ 00012 #endif 00013 00014 /* Power Control for Peripherals register */ 00015 #define PCUSB ((unsigned long)1<<31) 00016 00017 /* USB Clock Control register */ 00018 #define DEV_CLK_EN ((unsigned long)1<<1) 00019 #define AHB_CLK_EN ((unsigned long)1<<4) 00020 00021 /* USB Clock Status register */ 00022 #define DEV_CLK_ON ((unsigned long)1<<1) 00023 #define AHB_CLK_ON ((unsigned long)1<<4) 00024 00025 /* USB Device Interupt registers */ 00026 #define FRAME ((unsigned long)1<<0) 00027 #define EP_FAST ((unsigned long)1<<1) 00028 #define EP_SLOW ((unsigned long)1<<2) 00029 #define DEV_STAT ((unsigned long)1<<3) 00030 #define CCEMPTY ((unsigned long)1<<4) 00031 #define CDFULL ((unsigned long)1<<5) 00032 #define RxENDPKT ((unsigned long)1<<6) 00033 #define TxENDPKT ((unsigned long)1<<7) 00034 #define EP_RLZED ((unsigned long)1<<8) 00035 #define ERR_INT ((unsigned long)1<<9) 00036 00037 /* Endpoint Interrupt Registers */ 00038 #define EP(endpoint) (1<<endpoint) 00039 00040 /* USB Control register */ 00041 #define RD_EN (1<<0) 00042 #define WR_EN (1<<1) 00043 #define LOG_ENDPOINT(endpoint) ((endpoint>>1)<<2) 00044 00045 /* USB Receive Packet Length register */ 00046 #define DV ((unsigned long)1<<10) 00047 #define PKT_RDY ((unsigned long)1<<11) 00048 #define PKT_LNGTH_MASK (0x3ff) 00049 00050 /* Serial Interface Engine (SIE) */ 00051 #define SIE_WRITE (0x01) 00052 #define SIE_READ (0x02) 00053 #define SIE_COMMAND (0x05) 00054 #define SIE_CMD_CODE(phase, data) ((phase<<8)|(data<<16)) 00055 00056 /* SIE Command codes */ 00057 #define SIE_CMD_SET_ADDRESS (0xD0) 00058 #define SIE_CMD_CONFIGURE_DEVICE (0xD8) 00059 #define SIE_CMD_SET_MODE (0xF3) 00060 #define SIE_CMD_READ_FRAME_NUMBER (0xF5) 00061 #define SIE_CMD_READ_TEST_REGISTER (0xFD) 00062 #define SIE_CMD_SET_DEVICE_STATUS (0xFE) 00063 #define SIE_CMD_GET_DEVICE_STATUS (0xFE) 00064 #define SIE_CMD_GET_ERROR_CODE (0xFF) 00065 #define SIE_CMD_READ_ERROR_STATUS (0xFB) 00066 00067 #define SIE_CMD_SELECT_ENDPOINT(endpoint) (0x00+endpoint) 00068 #define SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint) (0x40+endpoint) 00069 #define SIE_CMD_SET_ENDPOINT_STATUS(endpoint) (0x40+endpoint) 00070 00071 #define SIE_CMD_CLEAR_BUFFER (0xF2) 00072 #define SIE_CMD_VALIDATE_BUFFER (0xFA) 00073 00074 /* SIE Device Status register */ 00075 #define SIE_DS_CON (1<<0) 00076 #define SIE_DS_CON_CH (1<<1) 00077 #define SIE_DS_SUS (1<<2) 00078 #define SIE_DS_SUS_CH (1<<3) 00079 #define SIE_DS_RST (1<<4) 00080 00081 /* SIE Device Set Address register */ 00082 #define SIE_DSA_DEV_EN (1<<7) 00083 00084 /* SIE Configue Device register */ 00085 #define SIE_CONF_DEVICE (1<<0) 00086 00087 /* Select Endpoint register */ 00088 #define SIE_SE_FE (1<<0) 00089 #define SIE_SE_ST (1<<1) 00090 #define SIE_SE_STP (1<<2) 00091 #define SIE_SE_PO (1<<3) 00092 #define SIE_SE_EPN (1<<4) 00093 #define SIE_SE_B_1_FULL (1<<5) 00094 #define SIE_SE_B_2_FULL (1<<6) 00095 00096 /* Set Endpoint Status command */ 00097 #define SIE_SES_ST (1<<0) 00098 #define SIE_SES_DA (1<<5) 00099 #define SIE_SES_RF_MO (1<<6) 00100 #define SIE_SES_CND_ST (1<<7) 00101 00102 usbdc *usbdc::instance; 00103 00104 usbdc::usbdc() 00105 { 00106 #ifdef TARGET_LPC1768 00107 LPC_SC->USBCLKCFG=5; /* TODO */ 00108 #endif 00109 00110 /* Enable power to USB device controller */ 00111 LPC_SC->PCONP |= PCUSB; 00112 00113 /* Enable USB clocks */ 00114 LPC_USB->USBClkCtrl |= DEV_CLK_EN | AHB_CLK_EN; 00115 while (LPC_USB->USBClkSt != (DEV_CLK_ON | AHB_CLK_ON)); 00116 00117 /* Configure pins P0.29 and P0.30 to be USB D+ and USB D- */ 00118 LPC_PINCON->PINSEL1 &= 0xc3ffffff; 00119 LPC_PINCON->PINSEL1 |= 0x14000000; 00120 00121 #ifdef ENABLE_VBUS 00122 /* Configure pin P1.30 to be VBUS */ 00123 LPC_PINCON->PINSEL3 &= 0xcfffffff; 00124 LPC_PINCON->PINSEL3 |= 0x20000000; 00125 00126 /* Configure pin P1.30 to have pull-down */ 00127 LPC_PINCON->PINMODE3 |= 0x30000000; 00128 #endif 00129 00130 /* Configure pin P2.9 to be Connect */ 00131 LPC_PINCON->PINSEL4 &= 0xfffcffff; 00132 LPC_PINCON->PINSEL4 |= 0x00040000; 00133 00134 /* Connect must be low for at least 2.5uS */ 00135 wait_ms(1); 00136 00137 /* Attach IRQ */ 00138 instance = this; 00139 NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr); 00140 NVIC_EnableIRQ(USB_IRQn); 00141 00142 /* Enable device interrupts */ 00143 enableEvents(); 00144 } 00145 00146 void usbdc::connect(void) 00147 { 00148 /* Connect USB device */ 00149 unsigned char status; 00150 00151 status = getDeviceStatus(); 00152 setDeviceStatus(status | SIE_DS_CON); 00153 } 00154 00155 void usbdc::disconnect(void) 00156 { 00157 /* Disconnect USB device */ 00158 unsigned char status; 00159 00160 status = getDeviceStatus(); 00161 setDeviceStatus(status & ~SIE_DS_CON); 00162 } 00163 00164 void usbdc::SIECommand(unsigned long command) 00165 { 00166 /* The command phase of a SIE transaction */ 00167 LPC_USB->USBDevIntClr = CCEMPTY; 00168 LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_COMMAND, command); 00169 while (!(LPC_USB->USBDevIntSt & CCEMPTY)); 00170 } 00171 00172 void usbdc::SIEWriteData(unsigned char data) 00173 { 00174 /* The data write phase of a SIE transaction */ 00175 LPC_USB->USBDevIntClr = CCEMPTY; 00176 LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_WRITE, data); 00177 while (!(LPC_USB->USBDevIntSt & CCEMPTY)); 00178 } 00179 00180 unsigned char usbdc::SIEReadData(unsigned long command) 00181 { 00182 /* The data read phase of a SIE transaction */ 00183 LPC_USB->USBDevIntClr = CDFULL; 00184 LPC_USB->USBCmdCode = SIE_CMD_CODE(SIE_READ, command); 00185 while (!(LPC_USB->USBDevIntSt & CDFULL)); 00186 return (unsigned char)LPC_USB->USBCmdData; 00187 } 00188 00189 void usbdc::setDeviceStatus(unsigned char status) 00190 { 00191 /* Write SIE device status register */ 00192 SIECommand(SIE_CMD_SET_DEVICE_STATUS); 00193 SIEWriteData(status); 00194 } 00195 00196 unsigned char usbdc::getDeviceStatus(void) 00197 { 00198 /* Read SIE device status register */ 00199 SIECommand(SIE_CMD_GET_DEVICE_STATUS); 00200 return SIEReadData(SIE_CMD_GET_DEVICE_STATUS); 00201 } 00202 00203 void usbdc::setAddress(unsigned char address) 00204 { 00205 /* Write SIE device address register */ 00206 SIECommand(SIE_CMD_SET_ADDRESS); 00207 SIEWriteData((address & 0x7f) | SIE_DSA_DEV_EN); 00208 } 00209 00210 unsigned char usbdc::selectEndpoint(unsigned char endpoint) 00211 { 00212 /* SIE select endpoint command */ 00213 SIECommand(SIE_CMD_SELECT_ENDPOINT(endpoint)); 00214 return SIEReadData(SIE_CMD_SELECT_ENDPOINT(endpoint)); 00215 } 00216 00217 #if 1 00218 unsigned char usbdc::selectEndpointClearInterrupt(unsigned char endpoint) 00219 { 00220 /* SIE select endpoint and clear interrupt command */ 00221 /* Using the Select Endpoint / Clear Interrupt SIE command does not seem */ 00222 /* to clear the appropriate bit in EP_INT_STAT? - using EP_INT_CLR instead */ 00223 LPC_USB->USBEpIntClr = EP(endpoint); 00224 while (!(LPC_USB->USBDevIntSt & CDFULL)); 00225 return (unsigned char)LPC_USB->USBCmdData; 00226 } 00227 #else 00228 unsigned char usbdc::selectEndpointClearInterrupt(unsigned char endpoint) 00229 { 00230 /* SIE select endpoint and clear interrupt command */ 00231 SIECommand(SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint)); 00232 return SIEReadData(SIE_CMD_SELECT_ENDPOINT_CLEAR_INTERRUPT(endpoint)); 00233 } 00234 #endif 00235 00236 unsigned char usbdc::clearBuffer(void) 00237 { 00238 /* SIE clear buffer command */ 00239 SIECommand(SIE_CMD_CLEAR_BUFFER); 00240 return SIEReadData(SIE_CMD_CLEAR_BUFFER); 00241 } 00242 00243 void usbdc::validateBuffer(void) 00244 { 00245 /* SIE validate buffer command */ 00246 SIECommand(SIE_CMD_VALIDATE_BUFFER); 00247 } 00248 00249 void usbdc::setEndpointStatus(unsigned char endpoint, unsigned char status) 00250 { 00251 /* SIE set endpoint status command */ 00252 SIECommand(SIE_CMD_SET_ENDPOINT_STATUS(endpoint)); 00253 SIEWriteData(status); 00254 } 00255 00256 void usbdc::realiseEndpoint(unsigned char endpoint, unsigned long maxPacket) 00257 { 00258 /* Realise an endpoint */ 00259 LPC_USB->USBDevIntClr = EP_RLZED; 00260 LPC_USB->USBReEp |= EP(endpoint); 00261 LPC_USB->USBEpInd = endpoint; 00262 LPC_USB->USBMaxPSize = maxPacket; 00263 00264 while (!(LPC_USB->USBDevIntSt & EP_RLZED)); 00265 LPC_USB->USBDevIntClr = EP_RLZED; 00266 00267 /* Clear stall state */ 00268 endpointStallState &= ~EP(endpoint); 00269 } 00270 00271 void usbdc::enableEndpointEvent(unsigned char endpoint) 00272 { 00273 /* Enable an endpoint interrupt */ 00274 LPC_USB->USBEpIntEn |= EP(endpoint); 00275 } 00276 00277 void usbdc::disableEndpointEvent(unsigned char endpoint) 00278 { 00279 /* Disable an endpoint interrupt */ 00280 LPC_USB->USBEpIntEn &= ~EP(endpoint); 00281 } 00282 00283 void usbdc::stallEndpoint(unsigned char endpoint) 00284 { 00285 /* Stall an endpoint */ 00286 if ( (endpoint==EP0IN) || (endpoint==EP0OUT) ) 00287 { 00288 /* Conditionally stall both control endpoints */ 00289 setEndpointStatus(EP0OUT, SIE_SES_CND_ST); 00290 } 00291 else 00292 { 00293 setEndpointStatus(endpoint, SIE_SES_ST); 00294 00295 /* Update stall state */ 00296 endpointStallState |= EP(endpoint); 00297 } 00298 } 00299 00300 void usbdc::unstallEndpoint(unsigned char endpoint) 00301 { 00302 /* Unstall an endpoint. The endpoint will also be reinitialised */ 00303 setEndpointStatus(endpoint, 0); 00304 00305 /* Update stall state */ 00306 endpointStallState &= ~EP(endpoint); 00307 } 00308 00309 bool usbdc::getEndpointStallState(unsigned char endpoint) 00310 { 00311 /* Returns true if endpoint stalled */ 00312 return endpointStallState & EP(endpoint); 00313 } 00314 00315 void usbdc::configureDevice(void) 00316 { 00317 /* SIE Configure device command */ 00318 SIECommand(SIE_CMD_CONFIGURE_DEVICE); 00319 SIEWriteData(SIE_CONF_DEVICE); 00320 } 00321 00322 void usbdc::unconfigureDevice(void) 00323 { 00324 /* SIE Configure device command */ 00325 SIECommand(SIE_CMD_CONFIGURE_DEVICE); 00326 SIEWriteData(0); 00327 } 00328 00329 unsigned long usbdc::endpointRead(unsigned char endpoint, unsigned char *buffer) 00330 { 00331 /* Read from an OUT endpoint */ 00332 unsigned long size; 00333 unsigned long i; 00334 unsigned long data; 00335 unsigned char offset; 00336 00337 LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | RD_EN; 00338 while (!(LPC_USB->USBRxPLen & PKT_RDY)); 00339 00340 size = LPC_USB->USBRxPLen & PKT_LNGTH_MASK; 00341 00342 offset = 0; 00343 00344 for (i=0; i<size; i++) 00345 { 00346 if (offset==0) 00347 { 00348 /* Fetch up to four bytes of data as a word */ 00349 data = LPC_USB->USBRxData; 00350 } 00351 00352 /* extract a byte */ 00353 *buffer++ = data>>offset; 00354 00355 /* move on to the next byte */ 00356 offset = (offset + 8) % 32; 00357 } 00358 00359 /* Clear RD_EN to cover zero length packet case */ 00360 LPC_USB->USBCtrl=0; 00361 00362 selectEndpoint(endpoint); 00363 clearBuffer(); 00364 00365 return size; 00366 } 00367 00368 void usbdc::endpointWrite(unsigned char endpoint, unsigned char *buffer, unsigned long size) 00369 { 00370 /* Write to an IN endpoint */ 00371 unsigned long temp, data; 00372 unsigned char offset; 00373 00374 LPC_USB->USBCtrl = LOG_ENDPOINT(endpoint) | WR_EN; 00375 00376 LPC_USB->USBTxPLen = size; 00377 offset = 0; 00378 data = 0; 00379 00380 if (size>0) 00381 { 00382 do { 00383 /* Fetch next data byte into a word-sized temporary variable */ 00384 temp = *buffer++; 00385 00386 /* Add to current data word */ 00387 temp = temp << offset; 00388 data = data | temp; 00389 00390 /* move on to the next byte */ 00391 offset = (offset + 8) % 32; 00392 size--; 00393 00394 if ((offset==0) || (size==0)) 00395 { 00396 /* Write the word to the endpoint */ 00397 LPC_USB->USBTxData = data; 00398 data = 0; 00399 } 00400 } while (size>0); 00401 } 00402 00403 /* Clear WR_EN to cover zero length packet case */ 00404 LPC_USB->USBCtrl=0; 00405 00406 selectEndpoint(endpoint); 00407 validateBuffer(); 00408 } 00409 00410 void usbdc::enableEvents(void) 00411 { 00412 /* Enable interrupt sources */ 00413 LPC_USB->USBDevIntEn = EP_SLOW | DEV_STAT; 00414 } 00415 00416 void usbdc::disableEvents(void) 00417 { 00418 /* Disable interrupt sources */ 00419 LPC_USB->USBDevIntClr = EP_SLOW | DEV_STAT; 00420 } 00421 00422 void usbdc::usbisr(void) 00423 { 00424 unsigned char devStat; 00425 00426 if (LPC_USB->USBDevIntSt & FRAME) 00427 { 00428 /* Frame event */ 00429 deviceEventFrame(); 00430 /* Clear interrupt status flag */ 00431 LPC_USB->USBDevIntClr = FRAME; 00432 } 00433 00434 if (LPC_USB->USBDevIntSt & DEV_STAT) 00435 { 00436 /* Device Status interrupt */ 00437 /* Must clear the interrupt status flag before reading the device status from the SIE */ 00438 LPC_USB->USBDevIntClr = DEV_STAT; 00439 00440 /* Read device status from SIE */ 00441 devStat = getDeviceStatus(); 00442 00443 if (devStat & SIE_DS_RST) 00444 { 00445 /* Bus reset */ 00446 deviceEventReset(); 00447 } 00448 } 00449 00450 if (LPC_USB->USBDevIntSt & EP_SLOW) 00451 { 00452 /* (Slow) Endpoint Interrupt */ 00453 00454 /* Process each endpoint interrupt */ 00455 if (LPC_USB->USBEpIntSt & EP(EP0OUT)) 00456 { 00457 if (selectEndpointClearInterrupt(EP0OUT) & SIE_SE_STP) 00458 { 00459 /* this is a setup packet */ 00460 endpointEventEP0Setup(); 00461 } 00462 else 00463 { 00464 endpointEventEP0Out(); 00465 } 00466 } 00467 00468 if (LPC_USB->USBEpIntSt & EP(EP0IN)) 00469 { 00470 selectEndpointClearInterrupt(EP0IN); 00471 endpointEventEP0In(); 00472 } 00473 00474 if (LPC_USB->USBEpIntSt & EP(EP1OUT)) 00475 { 00476 selectEndpointClearInterrupt(EP1OUT); 00477 endpointEventEP1Out(); 00478 } 00479 00480 if (LPC_USB->USBEpIntSt & EP(EP1IN)) 00481 { 00482 selectEndpointClearInterrupt(EP1IN); 00483 endpointEventEP1In(); 00484 } 00485 00486 if (LPC_USB->USBEpIntSt & EP(EP2OUT)) 00487 { 00488 selectEndpointClearInterrupt(EP2OUT); 00489 endpointEventEP2Out(); 00490 } 00491 00492 if (LPC_USB->USBEpIntSt & EP(EP2IN)) 00493 { 00494 selectEndpointClearInterrupt(EP2IN); 00495 endpointEventEP2In(); 00496 } 00497 00498 /* Clear interrupt status flag */ 00499 /* EP_SLOW and EP_FAST interrupt bits should be cleared after the corresponding endpoint interrupts are cleared. */ 00500 LPC_USB->USBDevIntClr = EP_SLOW; 00501 } 00502 } 00503 00504 00505 void usbdc::_usbisr(void) 00506 { 00507 instance->usbisr(); 00508 } 00509 00510 void usbdc::deviceEventReset(void) 00511 { 00512 } 00513 00514 void usbdc::deviceEventFrame(void) 00515 { 00516 } 00517 00518 void usbdc::endpointEventEP0Setup(void) 00519 { 00520 } 00521 00522 void usbdc::endpointEventEP0In(void) 00523 { 00524 } 00525 00526 void usbdc::endpointEventEP0Out(void) 00527 { 00528 } 00529 00530 void usbdc::endpointEventEP1In(void) 00531 { 00532 } 00533 00534 void usbdc::endpointEventEP1Out(void) 00535 { 00536 } 00537 00538 void usbdc::endpointEventEP2In(void) 00539 { 00540 } 00541 00542 void usbdc::endpointEventEP2Out(void) 00543 { 00544 }
Generated on Tue Jul 12 2022 19:23:02 by
