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 F401RE-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 Tue Jul 12 2022 21:43:28 by
1.7.2
