Simple USBHost library for Nucleo F446RE/F411RE/F401RE FRDM-KL46Z/KL25Z/F64F LPC4088/LPC1768
Dependents: F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld
Fork of KL46Z-USBHost by
USBHALHost_KL46Z.cpp
00001 // Simple USBHost for FRDM-KL46Z 00002 #if defined(TARGET_KL46Z)||defined(TARGET_KL25Z)||defined(TARGET_K64F) 00003 #include "USBHALHost.h" 00004 #include <algorithm> 00005 00006 #ifdef _USB_DBG 00007 #define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); 00008 #define USB_DBG_HEX(A,B) debug_hex(A,B) 00009 void debug_hex(uint8_t* buf, int size); 00010 #else 00011 #define USB_DBG(...) while(0) 00012 #define USB_DBG_HEX(A,B) while(0) 00013 #endif 00014 00015 #undef USB_TEST_ASSERT 00016 extern void usb_test_assert_internal(const char *expr, const char *file, int line); 00017 #define USB_TEST_ASSERT(EXPR) while(!(EXPR)){usb_test_assert_internal(#EXPR,__FILE__,__LINE__);} 00018 00019 #define USB_TRACE1(A) while(0) 00020 00021 #define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0); 00022 00023 #define BD_OWN_MASK (1<<7) 00024 #define BD_DATA01_MASK (1<<6) 00025 #define BD_KEEP_MASK (1<<5) 00026 #define BD_NINC_MASK (1<<4) 00027 #define BD_DTS_MASK (1<<3) 00028 #define BD_STALL_MASK (1<<2) 00029 00030 #define TX 1 00031 #define RX 0 00032 00033 #define EP0_BDT_IDX(dir, odd) (((2 * dir) + (1 * odd))) 00034 00035 #define SETUP_TOKEN 0x0D 00036 #define IN_TOKEN 0x09 00037 #define OUT_TOKEN 0x01 00038 00039 // for each endpt: 8 bytes 00040 struct BDT { 00041 uint8_t info; // BD[0:7] 00042 uint8_t dummy; // RSVD: BD[8:15] 00043 uint16_t byte_count; // BD[16:32] 00044 uint32_t address; // Addr 00045 void setBuffer(uint8_t* buf, int size) { 00046 address = (uint32_t)buf; 00047 byte_count = size; 00048 } 00049 uint8_t getStatus() { 00050 return (info>>2)&0x0f; 00051 } 00052 }; 00053 00054 __attribute__((__aligned__(512))) BDT bdt[64]; 00055 00056 USBHALHost* USBHALHost::instHost; 00057 00058 USBHALHost::USBHALHost() { 00059 instHost = this; 00060 report.clear(); 00061 } 00062 00063 void USBHALHost::init() { 00064 // Disable IRQ 00065 NVIC_DisableIRQ(USB0_IRQn); 00066 00067 #if defined(TARGET_K64F) 00068 MPU->CESR=0; 00069 #endif 00070 00071 // choose usb src as PLL 00072 SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK); 00073 00074 // enable OTG clock 00075 SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK; 00076 00077 // USB Module Configuration 00078 // Reset USB Module 00079 USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK; 00080 while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK); 00081 00082 // Clear interrupt flag 00083 USB0->ISTAT = 0xff; 00084 00085 // Set BDT Base Register 00086 USB0->BDTPAGE1=(uint8_t)((uint32_t)bdt>>8); 00087 USB0->BDTPAGE2=(uint8_t)((uint32_t)bdt>>16); 00088 USB0->BDTPAGE3=(uint8_t)((uint32_t)bdt>>24); 00089 00090 // Set SOF threshold 00091 USB0->SOFTHLD = USB_SOFTHLD_CNT(1); 00092 00093 // pulldown D+ and D- 00094 USB0->USBCTRL = USB_USBCTRL_PDE_MASK; 00095 00096 USB0->USBTRC0 |= 0x40; 00097 00098 // Host mode 00099 USB0->CTL |= USB_CTL_HOSTMODEEN_MASK; 00100 // Desable SOF packet generation 00101 USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK; 00102 00103 NVIC_SetVector(USB0_IRQn, (uint32_t)_usbisr); 00104 NVIC_EnableIRQ(USB0_IRQn); 00105 00106 bool lowSpeed = wait_attach(); 00107 00108 for(int retry = 2; retry > 0; retry--) { 00109 // Enable RESET 00110 USB0->CTL |= USB_CTL_RESET_MASK; 00111 wait_ms(500); 00112 USB0->CTL &= ~USB_CTL_RESET_MASK; 00113 00114 // Enable SOF 00115 USB0->CTL |= USB_CTL_USBENSOFEN_MASK; 00116 wait_ms(100); 00117 00118 // token transfer initialize 00119 token_transfer_init(); 00120 00121 USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK| 00122 USB_INTEN_ERROREN_MASK; 00123 USB0->ERREN |= USB_ERREN_PIDERREN_MASK| 00124 USB_ERREN_CRC5EOFEN_MASK| 00125 USB_ERREN_CRC16EN_MASK| 00126 USB_ERREN_DFN8EN_MASK| 00127 USB_ERREN_BTOERREN_MASK| 00128 USB_ERREN_DMAERREN_MASK| 00129 USB_ERREN_BTSERREN_MASK; 00130 00131 if (addDevice(NULL, 0, lowSpeed)) { 00132 break; 00133 } 00134 USB_DBG("retry=%d", retry); 00135 USB_TEST_ASSERT(retry > 1); 00136 } 00137 } 00138 00139 bool USBHALHost::wait_attach() { 00140 attach_done = false; 00141 USB0->INTEN = USB_INTEN_ATTACHEN_MASK; 00142 Timer t; 00143 t.reset(); 00144 t.start(); 00145 while(!attach_done) { 00146 if (t.read_ms() > 5*1000) { 00147 t.reset(); 00148 USB_INFO("Please attach USB device."); 00149 } 00150 } 00151 wait_ms(100); 00152 USB_TEST_ASSERT(!(USB0->CTL & USB_CTL_SE0_MASK)); 00153 root_lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true; 00154 return root_lowSpeed; 00155 } 00156 00157 void USBHALHost::setAddr(int _addr, bool _lowSpeed) { 00158 USB0->ADDR = (_lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(_addr); 00159 } 00160 00161 void USBHALHost::setEndpoint() { 00162 USB0->ENDPOINT[0].ENDPT = (root_lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00)| 00163 USB_ENDPT_RETRYDIS_MASK| 00164 USB_ENDPT_EPCTLDIS_MASK| 00165 USB_ENDPT_EPRXEN_MASK| 00166 USB_ENDPT_EPTXEN_MASK| 00167 USB_ENDPT_EPHSHK_MASK; 00168 } 00169 00170 void USBHALHost::token_transfer_init() { 00171 tx_ptr = ODD; 00172 rx_ptr = ODD; 00173 } 00174 00175 int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) { 00176 USBDeviceConnected* dev = ep->getDevice(); 00177 setAddr(dev->getAddress(), dev->getSpeed()); 00178 00179 for(int retry = 0;; retry++) { 00180 token_ready(); 00181 USB0->ENDPOINT[0].ENDPT = (root_lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) | 00182 USB_ENDPT_RETRYDIS_MASK| 00183 USB_ENDPT_EPRXEN_MASK| 00184 USB_ENDPT_EPTXEN_MASK| 00185 USB_ENDPT_EPHSHK_MASK; 00186 CTASSERT(sizeof(SETUP_PACKET) == 8); 00187 setup->wLength = wLength; 00188 int idx = EP0_BDT_IDX(TX, tx_ptr); 00189 bdt[idx].setBuffer((uint8_t*)setup, sizeof(SETUP_PACKET)); 00190 bdt[idx].info = BD_OWN_MASK | 00191 BD_DTS_MASK; // always data0 00192 token_done = false; 00193 USB0->TOKEN = USB_TOKEN_TOKENPID(SETUP_TOKEN)| 00194 USB_TOKEN_TOKENENDPT(ep->getAddress() & 0x7f); 00195 while(!token_done); 00196 LastStatus = bdt[idx].getStatus(); 00197 if (LastStatus == ACK) { 00198 if (retry > 0) { 00199 USB_DBG("retry=%d %02x", retry, prev_LastStatus); 00200 } 00201 break; 00202 } else if (LastStatus == STALL) { 00203 report.stall++; 00204 return STALL; 00205 } 00206 if (retry > 10) { 00207 USB_DBG("retry=%d", retry); 00208 break; 00209 } 00210 prev_LastStatus = LastStatus; 00211 wait_ms(100 * retry); 00212 } 00213 ep->setData01(DATA1); // next toggle 00214 return LastStatus; 00215 } 00216 00217 int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) { 00218 USBDeviceConnected* dev = ep->getDevice(); 00219 setAddr(dev->getAddress(), dev->getSpeed()); 00220 setEndpoint(); 00221 00222 for(int retry = 0;; retry++) { 00223 token_ready(); 00224 int idx = EP0_BDT_IDX(RX, rx_ptr); 00225 bdt[idx].setBuffer(data, size); 00226 bdt[idx].info = BD_OWN_MASK| 00227 BD_DTS_MASK| 00228 (ep->getData01() == DATA1 ? BD_DATA01_MASK : 0); 00229 token_done = false; 00230 USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)| 00231 USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f); 00232 while(!token_done); 00233 LastStatus = bdt[idx].getStatus(); 00234 int len = bdt[idx].byte_count; 00235 if (LastStatus == DATA0 || LastStatus == DATA1) { 00236 USB_TEST_ASSERT(ep->getData01() == LastStatus); 00237 ep->setData01(LastStatus == DATA0 ? DATA1 : DATA0); 00238 if (retry > 0) { 00239 //USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); 00240 } 00241 return len; 00242 } else if (LastStatus == STALL) { 00243 report.stall++; 00244 return -1; 00245 } else if (LastStatus == NAK) { 00246 report.nak++; 00247 if (retry >= retryLimit) { 00248 if (retryLimit > 0) { 00249 USB_DBG("retry=%d retryLimit=%d", retry, retryLimit); 00250 } 00251 return -1; 00252 } 00253 wait_ms(100 * retry); 00254 } else if (LastStatus == Bus_Timeout) { 00255 if (retry >= retryLimit) { 00256 if (retryLimit > 0) { 00257 USB_DBG("Bus_Timeout retry=%d retryLimit=%d", retry, retryLimit); 00258 } 00259 return -1; 00260 } 00261 wait_ms(500 + 100 * retry); 00262 } else { 00263 return -1; 00264 } 00265 prev_LastStatus = LastStatus; 00266 } 00267 } 00268 00269 int USBHALHost::token_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) { 00270 USBDeviceConnected* dev = ep->getDevice(); 00271 USB_TEST_ASSERT(dev); 00272 setAddr(dev->getAddress(), dev->getSpeed()); 00273 setEndpoint(); 00274 00275 for(int retry = 0;; retry++) { 00276 token_ready(); 00277 int idx = EP0_BDT_IDX(TX, tx_ptr); 00278 bdt[idx].setBuffer((uint8_t*)data, size); 00279 bdt[idx].info = BD_OWN_MASK| 00280 BD_DTS_MASK| 00281 (ep->getData01() == DATA1 ? BD_DATA01_MASK : 0); 00282 token_done = false; 00283 USB0->TOKEN = USB_TOKEN_TOKENPID(OUT_TOKEN)| 00284 USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f); 00285 while(!token_done); 00286 LastStatus = bdt[idx].getStatus(); 00287 int len = bdt[idx].byte_count; 00288 //USB_DBG("len=%d %02x", len, LastStatus); 00289 if (LastStatus == ACK) { 00290 ep->toggleData01(); 00291 if (retry > 0) { 00292 USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); 00293 } 00294 return len; 00295 } else if (LastStatus == STALL) { 00296 report.stall++; 00297 return -1; 00298 } else if (LastStatus == NAK) { 00299 report.nak++; 00300 if (retry > retryLimit) { 00301 USB_DBG("retry=%d retryLimit=%d", retry, retryLimit); 00302 return -1; 00303 } 00304 wait_ms(100 * retry); 00305 } else { 00306 return -1; 00307 } 00308 prev_LastStatus = LastStatus; 00309 } 00310 } 00311 00312 void USBHALHost::multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size) { 00313 USB_TRACE1(size); 00314 USB_TEST_ASSERT(ep->getState() != USB_TYPE_PROCESSING); 00315 ep->setBuffer(data, size); 00316 ep->setState(USB_TYPE_PROCESSING); 00317 } 00318 00319 USB_TYPE USBHALHost::multi_token_inNB_result(USBEndpoint* ep) { 00320 USB_TEST_ASSERT(ep->getState() == USB_TYPE_PROCESSING); 00321 uint8_t* buf = ep->getBufStart(); 00322 int size = ep->getBufSize(); 00323 int result = multi_token_in(ep, buf, size, false); 00324 USB_TRACE1(result); 00325 if (result < 0) { 00326 return USB_TYPE_PROCESSING; 00327 } 00328 ep->setLengthTransferred(result); 00329 ep->setState(USB_TYPE_IDLE); 00330 return USB_TYPE_OK; 00331 } 00332 00333 void USBHALHost::setToggle(USBEndpoint* ep, uint8_t toggle) { 00334 USB_TEST_ASSERT(toggle == 1); 00335 ep->setData01(toggle == 0 ? DATA0 : DATA1); 00336 } 00337 00338 int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) { 00339 USBDeviceConnected* dev = ep->getDevice(); 00340 USB_TEST_ASSERT(dev); 00341 setAddr(dev->getAddress()); 00342 00343 while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK); // TOKEN_BUSY ? 00344 USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF 00345 while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK)); 00346 USB0->SOFTHLD = 0; // this is needed as without this you can get errors 00347 USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF 00348 00349 USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPCTLDIS_MASK| 00350 USB_ENDPT_RETRYDIS_MASK| 00351 USB_ENDPT_EPRXEN_MASK| 00352 USB_ENDPT_EPTXEN_MASK; 00353 int idx = EP0_BDT_IDX(RX, rx_ptr); 00354 bdt[idx].setBuffer(data, size); 00355 bdt[idx].info = BD_OWN_MASK| 00356 BD_DTS_MASK; // always DATA0 00357 token_done = false; 00358 USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)| 00359 USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f); 00360 while(!token_done); 00361 LastStatus = bdt[idx].getStatus(); 00362 int len = bdt[idx].byte_count; 00363 if (LastStatus == DATA0) { 00364 return len; 00365 } 00366 return -1; 00367 } 00368 00369 void USBHALHost::token_ready() { 00370 while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) { // TOKEN_BUSY ? 00371 wait_ms(1); 00372 } 00373 USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF 00374 while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK)); 00375 USB0->SOFTHLD = 0; // this is needed as without this you can get errors 00376 USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF 00377 } 00378 00379 int USBHALHost::multi_token_in(USBEndpoint* ep, uint8_t* data, size_t total, bool block) { 00380 if (total == 0) { 00381 return token_in(ep); 00382 } 00383 int retryLimit = block ? 10 : 0; 00384 int read_len = 0; 00385 for(int n = 0; read_len < total; n++) { 00386 int size = std::min((int)total-read_len, ep->getSize()); 00387 int result = token_in(ep, data+read_len, size, retryLimit); 00388 if (result < 0) { 00389 if (block) { 00390 return -1; 00391 } 00392 if (LastStatus == NAK) { 00393 if (n == 0) { 00394 return -1; 00395 } 00396 break; 00397 } 00398 return result; 00399 } 00400 read_len += result; 00401 if (result < ep->getSize()) { 00402 break; 00403 } 00404 } 00405 return read_len; 00406 } 00407 00408 int USBHALHost::multi_token_out(USBEndpoint* ep, const uint8_t* data, size_t total) { 00409 if (total == 0) { 00410 return token_out(ep); 00411 } 00412 int write_len = 0; 00413 for(int n = 0; write_len < total; n++) { 00414 int size = std::min((int)total-write_len, ep->getSize()); 00415 int result = token_out(ep, data+write_len, size); 00416 if (result < 0) { 00417 if (LastStatus == NAK) { 00418 if (n == 0) { 00419 return -1; 00420 } 00421 break; 00422 } 00423 USB_DBG("token_out result=%d %02x", result, LastStatus); 00424 return result; 00425 } 00426 write_len += result; 00427 if (result < ep->getSize()) { 00428 break; 00429 } 00430 } 00431 return write_len; 00432 } 00433 00434 void USBHALHost::_usbisr(void) { 00435 if (instHost) { 00436 instHost->UsbIrqhandler(); 00437 } 00438 } 00439 00440 void USBHALHost::UsbIrqhandler() { 00441 if (USB0->ISTAT & USB_ISTAT_TOKDNE_MASK) { 00442 uint8_t stat = USB0->STAT; 00443 ODD_EVEN next_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN; 00444 if (stat & USB_STAT_TX_MASK) { 00445 tx_ptr = next_ptr; 00446 } else { 00447 rx_ptr = next_ptr; 00448 } 00449 USB0->ISTAT = USB_ISTAT_TOKDNE_MASK; 00450 token_done = true; 00451 } 00452 if (USB0->ISTAT & USB_ISTAT_ATTACH_MASK) { 00453 USB0->INTEN &= ~USB_INTEN_ATTACHEN_MASK; 00454 USB0->ISTAT = USB_ISTAT_ATTACH_MASK; 00455 attach_done = true; 00456 } 00457 if (USB0->ISTAT & USB_ISTAT_ERROR_MASK) { 00458 uint8_t errstat = USB0->ERRSTAT; 00459 if (errstat & USB_ERRSTAT_PIDERR_MASK) { 00460 report.errstat_piderr++; 00461 } 00462 if (errstat & USB_ERRSTAT_CRC5EOF_MASK) { 00463 report.errstat_crc5eof++; 00464 } 00465 if (errstat & USB_ERRSTAT_CRC16_MASK) { 00466 report.errstat_crc16++; 00467 } 00468 if (errstat & USB_ERRSTAT_DFN8_MASK) { 00469 report.errstat_dfn8++; 00470 } 00471 if (errstat & USB_ERRSTAT_BTOERR_MASK) { 00472 report.errstat_btoerr++; 00473 } 00474 if (errstat & USB_ERRSTAT_DMAERR_MASK) { 00475 report.errstat_dmaerr++; 00476 } 00477 if (errstat & USB_ERRSTAT_BTSERR_MASK) { 00478 report.errstat_btoerr++; 00479 } 00480 USB0->ERRSTAT = errstat; 00481 USB0->ISTAT = USB_ISTAT_ERROR_MASK; 00482 } 00483 } 00484 00485 void Report::clear() { 00486 errstat_piderr = 0; 00487 errstat_crc5eof = 0; 00488 errstat_crc16 = 0; 00489 errstat_dfn8 = 0; 00490 errstat_btoerr = 0; 00491 errstat_dmaerr = 0; 00492 errstat_bsterr = 0; 00493 // 00494 nak = 0; 00495 } 00496 00497 void Report::print_errstat() { 00498 printf("ERRSTAT PID: %d, CRC5EOF: %d, CRC16: %d, DFN8: %d, BTO: %d, DMA: %d, BST: %d\n", 00499 errstat_piderr, errstat_crc5eof, 00500 errstat_crc16, errstat_dfn8, 00501 errstat_btoerr, errstat_dmaerr, errstat_bsterr); 00502 } 00503 00504 void debug_hex(uint8_t* buf, int size) { 00505 int n = 0; 00506 for(int i = 0; i < size; i++) { 00507 fprintf(stderr, "%02x ", buf[i]); 00508 if (++n >= 16) { 00509 fprintf(stderr, "\n"); 00510 n = 0; 00511 } 00512 } 00513 if (n > 0) { 00514 fprintf(stderr, "\n"); 00515 } 00516 } 00517 00518 #endif 00519 00520
Generated on Wed Jul 13 2022 05:41:27 by 1.7.2