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