Simple USBHost library for Nucleo F446RE/F411RE/F401RE FRDM-KL46Z/KL25Z/F64F LPC4088/LPC1768

Dependencies:   FATFileSystem

Dependents:   F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld

Fork of KL46Z-USBHost by Norimasa Okamoto

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHALHost_KL46Z.cpp Source File

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