Axeda Ready Demo for Freescale FRDM-KL46Z as accident alert system

Dependencies:   FRDM_MMA8451Q KL46Z-USBHost MAG3110 SocketModem TSI mbed FATFileSystem

Fork of AxedaGo-Freescal_FRDM-KL46Z revert by Axeda Corp

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHALHost.cpp Source File

USBHALHost.cpp

00001 // Simple USBHost for FRDM-KL46Z
00002 #include "USBHALHost.h"
00003 
00004 template <bool>struct CtAssert;
00005 template <>struct CtAssert<true> {};
00006 #define CTASSERT(A) CtAssert<A>();
00007 
00008 
00009 #ifdef _USB_DBG
00010 #define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0);
00011 #define USB_DBG_HEX(A,B) debug_hex(A,B)
00012 void debug_hex(uint8_t* buf, int size);
00013 #else
00014 #define USB_DBG(...) while(0)
00015 #define USB_DBG_HEX(A,B) while(0)
00016 #endif
00017 
00018 #ifdef _USB_TEST
00019 #define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
00020 #define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A))
00021 #else
00022 #define USB_TEST_ASSERT(A) while(0)
00023 #define USB_TEST_ASSERT_FALSE(A) while(0)
00024 #endif
00025 
00026 #define BD_OWN_MASK        (1<<7)
00027 #define BD_DATA01_MASK     (1<<6)
00028 #define BD_KEEP_MASK       (1<<5)
00029 #define BD_NINC_MASK       (1<<4)
00030 #define BD_DTS_MASK        (1<<3)
00031 #define BD_STALL_MASK      (1<<2)
00032 
00033 #define TX    1
00034 #define RX    0
00035 
00036 #define EP0_BDT_IDX(dir, odd) (((2 * dir) + (1 * odd)))
00037 
00038 #define SETUP_TOKEN    0x0D
00039 #define IN_TOKEN       0x09
00040 #define OUT_TOKEN      0x01
00041 
00042 // for each endpt: 8 bytes
00043 struct BDT {
00044     uint8_t   info;       // BD[0:7]
00045     uint8_t   dummy;      // RSVD: BD[8:15]
00046     uint16_t  byte_count; // BD[16:32]
00047     uint32_t  address;    // Addr
00048     void setBuffer(uint8_t* buf, int size) {
00049         address = (uint32_t)buf;
00050         byte_count = size;
00051     }
00052     uint8_t getStatus() {
00053         return (info>>2)&0x0f;
00054     }    
00055 };
00056 
00057 __attribute__((__aligned__(512))) BDT bdt[64];
00058 
00059 USBHALHost* USBHALHost::instHost;
00060 
00061 USBHALHost::USBHALHost() {
00062     instHost = this;
00063     report.clear();
00064 }
00065 
00066 void USBHALHost::init() {
00067     // Disable IRQ
00068     NVIC_DisableIRQ(USB0_IRQn);
00069 
00070     // choose usb src as PLL
00071     SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK);
00072 
00073     // enable OTG clock
00074     SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK;
00075 
00076     // USB Module Configuration
00077     // Reset USB Module
00078     USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
00079     while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
00080 
00081     // Clear interrupt flag
00082     USB0->ISTAT = 0xff;
00083 
00084     // Set BDT Base Register
00085     USB0->BDTPAGE1=(uint8_t)((uint32_t)bdt>>8);
00086     USB0->BDTPAGE2=(uint8_t)((uint32_t)bdt>>16);
00087     USB0->BDTPAGE3=(uint8_t)((uint32_t)bdt>>24);
00088 
00089     // Set SOF threshold
00090     USB0->SOFTHLD = USB_SOFTHLD_CNT(1);
00091 
00092     // pulldown D+ and D-
00093     USB0->USBCTRL = USB_USBCTRL_PDE_MASK;
00094 
00095     USB0->USBTRC0 |= 0x40;
00096 
00097     // Host mode
00098     USB0->CTL |= USB_CTL_HOSTMODEEN_MASK;
00099     // Desable SOF packet generation
00100     USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK;
00101 
00102     NVIC_SetVector(USB0_IRQn, (uint32_t)_usbisr);
00103     NVIC_EnableIRQ(USB0_IRQn);
00104 
00105     bool lowSpeed = wait_attach();
00106 
00107     for(int retry = 2; retry > 0; retry--) {
00108         // Enable RESET
00109         USB0->CTL |= USB_CTL_RESET_MASK;
00110         wait_ms(500);
00111         USB0->CTL &= ~USB_CTL_RESET_MASK;
00112     
00113         // Enable SOF
00114         USB0->CTL |= USB_CTL_USBENSOFEN_MASK;
00115         wait_ms(100);
00116 
00117         // token transfer initialize
00118         token_transfer_init();
00119 
00120         USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK|
00121                        USB_INTEN_ERROREN_MASK;
00122         USB0->ERREN |= USB_ERREN_PIDERREN_MASK|
00123                        USB_ERREN_CRC5EOFEN_MASK|
00124                        USB_ERREN_CRC16EN_MASK|
00125                        USB_ERREN_DFN8EN_MASK|
00126                        USB_ERREN_BTOERREN_MASK|
00127                        USB_ERREN_DMAERREN_MASK|
00128                        USB_ERREN_BTSERREN_MASK;
00129 
00130         if (addDevice(0, 0, lowSpeed)) {
00131             break;
00132         }
00133         USB_DBG("retry=%d", retry);
00134         USB_TEST_ASSERT(retry > 1);
00135     }
00136 }
00137 
00138 bool USBHALHost::wait_attach() {
00139     attach_done = false;
00140     USB0->INTEN = USB_INTEN_ATTACHEN_MASK;
00141     while(!attach_done);
00142     wait_ms(100);
00143     USB_TEST_ASSERT_FALSE(USB0->CTL & USB_CTL_SE0_MASK);
00144     root_lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true;
00145     return root_lowSpeed;
00146 }
00147 
00148 void USBHALHost::setAddr(int _addr, bool _lowSpeed) {
00149     USB0->ADDR = (_lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(_addr);
00150 }
00151 
00152 void USBHALHost::setEndpoint() {
00153     USB0->ENDPOINT[0].ENDPT = (root_lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00)|
00154                               USB_ENDPT_RETRYDIS_MASK|
00155                               USB_ENDPT_EPCTLDIS_MASK|
00156                               USB_ENDPT_EPRXEN_MASK|
00157                               USB_ENDPT_EPTXEN_MASK|
00158                               USB_ENDPT_EPHSHK_MASK;
00159 }
00160 
00161 void USBHALHost::token_transfer_init() {
00162     tx_ptr = ODD;
00163     rx_ptr = ODD;
00164 }
00165 
00166 int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) {
00167     USBDeviceConnected* dev = ep->getDevice();
00168     for(int retry = 0;; retry++) {
00169         token_ready();
00170         USB0->ENDPOINT[0].ENDPT = (root_lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) |
00171                                   USB_ENDPT_RETRYDIS_MASK|
00172                                   USB_ENDPT_EPRXEN_MASK|
00173                                   USB_ENDPT_EPTXEN_MASK|
00174                                   USB_ENDPT_EPHSHK_MASK;
00175         CTASSERT(sizeof(SETUP_PACKET) == 8);
00176         setup->wLength = wLength;
00177         int idx = EP0_BDT_IDX(TX, tx_ptr);
00178         bdt[idx].setBuffer((uint8_t*)setup, sizeof(SETUP_PACKET));
00179         bdt[idx].info = BD_OWN_MASK |
00180                         BD_DTS_MASK; // always data0
00181         token_done = false;
00182         USB0->TOKEN = USB_TOKEN_TOKENPID(SETUP_TOKEN)|
00183                       USB_TOKEN_TOKENENDPT(ep->getAddress() & 0x7f);
00184         while(!token_done);
00185         LastStatus = bdt[idx].getStatus();
00186         if (LastStatus == ACK) {
00187             if (retry > 0) {
00188                 USB_DBG("retry=%d %02x", retry, prev_LastStatus);
00189             }
00190             break;
00191         } else if (LastStatus == STALL) {
00192             report.stall++;
00193             return STALL;
00194         }
00195         if (retry > 10) {
00196             USB_DBG("retry=%d", retry);
00197             break;
00198         }
00199         prev_LastStatus = LastStatus;
00200         wait_ms(100 * retry);
00201     }
00202     ep->setData01(DATA1); // next toggle
00203     return LastStatus;
00204 }
00205 
00206 int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) {
00207     for(int retry = 0;; retry++) {
00208         token_ready();
00209         int idx = EP0_BDT_IDX(RX, rx_ptr);
00210         bdt[idx].setBuffer(data, size);
00211         bdt[idx].info = BD_OWN_MASK|
00212                         BD_DTS_MASK|
00213                         (ep->getData01() == DATA1 ? BD_DATA01_MASK : 0);
00214         token_done = false;
00215         USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)|
00216                       USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f);
00217         while(!token_done);
00218         LastStatus = bdt[idx].getStatus();
00219         int len = bdt[idx].byte_count;
00220         if (LastStatus == DATA0 || LastStatus == DATA1) {
00221             USB_TEST_ASSERT(ep->getData01() == LastStatus);
00222             ep->setData01(LastStatus == DATA0 ? DATA1 : DATA0);
00223             if (retry > 0) {
00224                 //USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus);
00225             }
00226             return len;
00227         } else if (LastStatus == STALL) {
00228             report.stall++;
00229             return -1;
00230         } else if (LastStatus == NAK) {
00231             report.nak++;
00232             if (retry >= retryLimit) {
00233                 if (retryLimit > 0) {
00234                     USB_DBG("retry=%d retryLimit=%d", retry, retryLimit);
00235                 }
00236                 return -1;
00237             }
00238             wait_ms(100 * retry);
00239         } else if (LastStatus == Bus_Timeout) {
00240             if (retry >= retryLimit) {
00241                 if (retryLimit > 0) {
00242                     USB_DBG("Bus_Timeout retry=%d retryLimit=%d", retry, retryLimit);
00243                 }                
00244                 return -1;
00245             }
00246             wait_ms(500 + 100 * retry);
00247         } else {
00248             return -1;
00249         }
00250         prev_LastStatus = LastStatus;
00251     }
00252 }
00253 
00254 int USBHALHost::token_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) {
00255     for(int retry = 0;; retry++) {
00256         token_ready();
00257         int idx = EP0_BDT_IDX(TX, tx_ptr);
00258         bdt[idx].setBuffer((uint8_t*)data, size);
00259         bdt[idx].info = BD_OWN_MASK|
00260                         BD_DTS_MASK|
00261                        (ep->getData01() == DATA1 ? BD_DATA01_MASK : 0);
00262         token_done = false;
00263         USB0->TOKEN = USB_TOKEN_TOKENPID(OUT_TOKEN)|
00264                       USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f);
00265         while(!token_done);
00266         LastStatus = bdt[idx].getStatus();
00267         int len = bdt[idx].byte_count;
00268         //USB_DBG("len=%d %02x", len, LastStatus);
00269         if (LastStatus == ACK) {
00270             ep->toggleData01();
00271             if (retry > 0) {
00272                 USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus);
00273             }
00274             return len;
00275         } else if (LastStatus == STALL) {
00276             report.stall++;
00277             return -1;
00278         } else if (LastStatus == NAK) {
00279             report.nak++;
00280             if (retry > retryLimit) {
00281                 USB_DBG("retry=%d retryLimit=%d", retry, retryLimit);
00282                 return -1;
00283             }
00284             wait_ms(100 * retry);
00285         } else {
00286             return -1;
00287         }
00288         prev_LastStatus = LastStatus;
00289     }
00290 }
00291 
00292 int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) {
00293     while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK); // TOKEN_BUSY ?
00294     USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF
00295     while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK));
00296     USB0->SOFTHLD = 0; // this is needed as without this you can get errors
00297     USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF
00298 
00299     USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPCTLDIS_MASK|
00300                               USB_ENDPT_RETRYDIS_MASK|
00301                               USB_ENDPT_EPRXEN_MASK|
00302                               USB_ENDPT_EPTXEN_MASK;
00303     int idx = EP0_BDT_IDX(RX, rx_ptr);
00304     bdt[idx].setBuffer(data, size);
00305     bdt[idx].info = BD_OWN_MASK|
00306                     BD_DTS_MASK; // always DATA0
00307     token_done = false;
00308     USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)|
00309                   USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f);
00310     while(!token_done);
00311     LastStatus = bdt[idx].getStatus();
00312     int len = bdt[idx].byte_count;
00313     if (LastStatus == DATA0) {
00314         return len;
00315     }
00316     return -1;
00317 }
00318 
00319 void USBHALHost::token_ready() {
00320     while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) { // TOKEN_BUSY ?
00321         wait_ms(1);
00322     }
00323     USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF
00324     while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK));
00325     USB0->SOFTHLD = 0; // this is needed as without this you can get errors
00326     USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF
00327 }
00328 
00329 void USBHALHost::_usbisr(void) {
00330     if (instHost) {
00331         instHost->UsbIrqhandler();
00332     }
00333 }
00334 
00335 void USBHALHost::UsbIrqhandler() {
00336     if (USB0->ISTAT & USB_ISTAT_TOKDNE_MASK) {
00337         uint8_t stat = USB0->STAT;
00338         ODD_EVEN next_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
00339         if (stat & USB_STAT_TX_MASK) {
00340             tx_ptr = next_ptr;
00341         } else {
00342             rx_ptr = next_ptr;
00343         }
00344         USB0->ISTAT = USB_ISTAT_TOKDNE_MASK;
00345         token_done = true;
00346     }
00347     if (USB0->ISTAT & USB_ISTAT_ATTACH_MASK) {
00348         USB0->INTEN &= ~USB_INTEN_ATTACHEN_MASK;
00349         USB0->ISTAT = USB_ISTAT_ATTACH_MASK;
00350         attach_done = true;
00351     }
00352     if (USB0->ISTAT & USB_ISTAT_ERROR_MASK) {
00353         uint8_t errstat = USB0->ERRSTAT;
00354         if (errstat & USB_ERRSTAT_PIDERR_MASK) {
00355             report.errstat_piderr++;
00356         }
00357         if (errstat & USB_ERRSTAT_CRC5EOF_MASK) {
00358             report.errstat_crc5eof++;
00359         }
00360         if (errstat & USB_ERRSTAT_CRC16_MASK) {
00361             report.errstat_crc16++;
00362         }
00363         if (errstat & USB_ERRSTAT_DFN8_MASK) {
00364             report.errstat_dfn8++;
00365         }
00366         if (errstat & USB_ERRSTAT_BTOERR_MASK) {
00367             report.errstat_btoerr++;
00368         }
00369         if (errstat & USB_ERRSTAT_DMAERR_MASK) {
00370             report.errstat_dmaerr++;
00371         }
00372         if (errstat & USB_ERRSTAT_BTSERR_MASK) {
00373             report.errstat_btoerr++;
00374         }
00375         USB0->ERRSTAT = errstat;
00376         USB0->ISTAT = USB_ISTAT_ERROR_MASK;
00377     }
00378 }
00379 
00380 void Report::clear() {
00381     errstat_piderr = 0;
00382     errstat_crc5eof = 0;
00383     errstat_crc16 = 0;
00384     errstat_dfn8 = 0;
00385     errstat_btoerr = 0;
00386     errstat_dmaerr = 0;
00387     errstat_bsterr = 0;
00388     //
00389     nak = 0;
00390 }
00391 
00392 void Report::print_errstat() {
00393     printf("ERRSTAT PID: %d, CRC5EOF: %d, CRC16: %d, DFN8: %d, BTO: %d, DMA: %d, BST: %d\n",
00394         errstat_piderr, errstat_crc5eof,
00395         errstat_crc16, errstat_dfn8,
00396         errstat_btoerr, errstat_dmaerr, errstat_bsterr);
00397 }
00398 
00399 void debug_hex(uint8_t* buf, int size) {
00400     int n = 0;
00401     for(int i = 0; i < size; i++) {
00402         fprintf(stderr, "%02x ", buf[i]);
00403         if (++n >= 16) {
00404             fprintf(stderr, "\n");
00405             n = 0;
00406         }
00407     }
00408     if (n > 0) {
00409         fprintf(stderr, "\n");
00410     }
00411 }
00412