GambitDev / F401RE-USBHost

Dependencies:   FATFileSystem

Fork of F401RE-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)||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