kekw
Dependencies: mbed C12832_lcd MMA7660
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 Wed Jul 20 2022 10:46:19 by 1.7.2