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

簡易USBホストライブラリです。
official-USBHostの下位互換で対応プログラムを僅かな修正で動かすことが出来ます。

Platforms

  • Nucleo F446RE
  • Nucleo F411RE
  • Nucleo F401RE
  • FRDM-K64F
  • FRDM-KL46Z
  • FRDM-KL25Z
  • LPC4088
  • LPC1768

Nucleo F446RE/F411RE/F401REのUSB接続方法

ST morphoUSB
U5V (CN10-8)VBUS (1 RED)
PA11 (CN10-14)DM  (2 WHITE)
PA12 (CN10-12)DP  (3 GREEN)
GND (CN10-20)GND (4 BLACK)

Examples

Import programF446RE-USBHostMouse_HelloWorld

USBHostMouse Hello World for ST-Nucleo-F446RE

Import programF401RE-USBHostMSD_HelloWorld

Simple USBHost MSD(USB flash drive) for Nucleo F401RE/FRDM-KL46Z test program

Import programF401RE-USBHostC270_example

Simple USBHost WebCam test program

Import programK64F_USBHostC270_example

Simple USBHost C270 example

Import programF401RE-BTstack_example

BTstack for Nucleo F401RE/FRDM-KL46Z example program

Import programUSBHostRSSI_example

Bluetooth device discovery example program.

Import programKL46Z-USBHostGPS_HelloWorld

Simple USBHost GPS Dongle Receiver for FRDM-KL46Z test program

Files at this revision

API Documentation at this revision

Comitter:
va009039
Date:
Thu Jan 23 08:32:54 2014 +0000
Parent:
1:c072d9e580b0
Child:
3:a3872f7593e2
Commit message:
add retry in token transfer

Changed in this revision

USBHALHost.cpp Show annotated file Show diff for this revision Revisions of this file
USBHALHost.h Show annotated file Show diff for this revision Revisions of this file
USBHost.cpp Show annotated file Show diff for this revision Revisions of this file
USBHost.h Show annotated file Show diff for this revision Revisions of this file
USBHostMSD.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHALHost.cpp	Thu Jan 23 08:32:54 2014 +0000
@@ -0,0 +1,285 @@
+// Simple USBHost for FRDM-KL46Z
+#include "USBHALHost.h"
+#include <algorithm>
+
+template <bool>struct CtAssert;
+template <>struct CtAssert<true> {};
+#define CTASSERT(A) CtAssert<A>();
+
+
+#ifdef _USB_DBG
+#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0);
+#define USB_DBG_HEX(A,B) debug_hex(A,B)
+void debug_hex(uint8_t* buf, int size);
+#else
+#define USB_DBG(...) while(0)
+#define USB_DBG_HEX(A,B) while(0)
+#endif
+
+#define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
+#define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A))
+
+#define BD_OWN_MASK        (1<<7)
+#define BD_DATA01_MASK     (1<<6)
+#define BD_KEEP_MASK       (1<<5)
+#define BD_NINC_MASK       (1<<4)
+#define BD_DTS_MASK        (1<<3)
+#define BD_STALL_MASK      (1<<2)
+
+#define TX    1
+#define RX    0
+
+#define EP0_BDT_IDX(dir, odd) (((2 * dir) + (1 * odd)))
+
+#define SETUP_TOKEN    0x0D
+#define IN_TOKEN       0x09
+#define OUT_TOKEN      0x01
+
+// for each endpt: 8 bytes
+struct BDT {
+    uint8_t   info;       // BD[0:7]
+    uint8_t   dummy;      // RSVD: BD[8:15]
+    uint16_t  byte_count; // BD[16:32]
+    uint32_t  address;    // Addr
+    void setBuffer(uint8_t* buf, int size) {
+        address = (uint32_t)buf;
+        byte_count = size;
+    }
+    uint8_t getStatus() {
+        return (info>>2)&0x0f;
+    }    
+};
+
+__attribute__((__aligned__(512))) BDT bdt[64];
+
+USBHALHost* USBHALHost::instHost;
+
+USBHALHost::USBHALHost() {
+    instHost = this;
+    memset(rx_data01, DATA1, sizeof(rx_data01));
+    memset(tx_data01, DATA1, sizeof(tx_data01));
+}
+
+void USBHALHost::init() {
+    // Disable IRQ
+    NVIC_DisableIRQ(USB0_IRQn);
+
+    // choose usb src as PLL
+    SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK);
+
+    // enable OTG clock
+    SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK;
+
+    // USB Module Configuration
+    // Reset USB Module
+    USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
+    while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
+
+    // Clear interrupt flag
+    USB0->ISTAT = 0xff;
+
+    // Set BDT Base Register
+    USB0->BDTPAGE1=(uint8_t)((uint32_t)bdt>>8);
+    USB0->BDTPAGE2=(uint8_t)((uint32_t)bdt>>16);
+    USB0->BDTPAGE3=(uint8_t)((uint32_t)bdt>>24);
+
+    // Set SOF threshold
+    USB0->SOFTHLD = USB_SOFTHLD_CNT(1);
+
+    // pulldown D+ and D-
+    USB0->USBCTRL = USB_USBCTRL_PDE_MASK;
+
+    USB0->USBTRC0 |= 0x40;
+
+    // Host mode
+    USB0->CTL |= USB_CTL_HOSTMODEEN_MASK;
+    // Desable SOF packet generation
+    USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK;
+
+    NVIC_SetVector(USB0_IRQn, (uint32_t)_usbisr);
+    NVIC_EnableIRQ(USB0_IRQn);
+
+    wait_attach();
+
+    for(int retry = 2; retry > 0; retry--) {
+        // Enable RESET
+        USB0->CTL |= USB_CTL_RESET_MASK;
+        wait_ms(500);
+        USB0->CTL &= ~USB_CTL_RESET_MASK;
+    
+        // Enable SOF
+        USB0->CTL |= USB_CTL_USBENSOFEN_MASK;
+        wait_ms(100);
+
+        // token transfer initialize
+        tx_ptr = ODD;
+        rx_ptr = ODD;
+        USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK;
+
+        if (enumeration()) {
+            break;
+        }
+        USB_DBG("retry=%d", retry);
+        USB_TEST_ASSERT(retry > 1);
+    }
+}
+
+void USBHALHost::wait_attach() {
+    attach_done = false;
+    USB0->INTEN = USB_INTEN_ATTACHEN_MASK;
+    while(!attach_done);
+    wait_ms(100);
+    USB_TEST_ASSERT_FALSE(USB0->CTL & USB_CTL_SE0_MASK);
+    lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true;
+    if (lowSpeed) { // low speed
+        USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK;
+    }
+    USB_DBG("lowSpeed=%d", lowSpeed);
+}
+
+void USBHALHost::setAddr(int _addr) {
+    USB0->ADDR = (lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(_addr);
+}
+
+void USBHALHost::setEndpoint(bool use_retry) {
+    USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00)|
+                              USB_ENDPT_EPCTLDIS_MASK|
+                              (use_retry ? 0x00 : USB_ENDPT_RETRYDIS_MASK)|
+                              USB_ENDPT_EPRXEN_MASK|
+                              USB_ENDPT_EPTXEN_MASK|
+                              USB_ENDPT_EPHSHK_MASK;
+}
+
+int USBHALHost::token_setup(SETUP_PACKET* setup, uint16_t wLength) {
+    int retry = 0;
+    do {
+        token_ready();
+        USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) |
+                                  USB_ENDPT_RETRYDIS_MASK|
+                                  USB_ENDPT_EPRXEN_MASK|
+                                  USB_ENDPT_EPTXEN_MASK|
+                                  USB_ENDPT_EPHSHK_MASK;
+        CTASSERT(sizeof(SETUP_PACKET) == 8);
+        setup->wLength = wLength;
+        int idx = EP0_BDT_IDX(TX, tx_ptr);
+        bdt[idx].setBuffer((uint8_t*)setup, sizeof(SETUP_PACKET));
+        bdt[idx].info = BD_OWN_MASK |
+                        BD_DTS_MASK; // always data0
+        token_done = false;
+        USB0->TOKEN = USB_TOKEN_TOKENPID(SETUP_TOKEN)|USB_TOKEN_TOKENENDPT(0);
+        while(!token_done);
+        LastStatus = bdt[idx].getStatus();
+        if (LastStatus == ACK) {
+            if (retry > 0) {
+                USB_DBG("retry=%d %02x", retry, prev_LastStatus);
+            }
+            return ACK;
+        }
+        wait_ms(1);
+        prev_LastStatus = LastStatus;
+        //USB_DBG("retry=%d %02x", retry, prev_LastStatus);
+    }while(retry++ < 10);
+    return LastStatus;
+}
+
+int USBHALHost::token_in(uint8_t ep, uint8_t* data, int size, int retryLimit) {
+    USB_TEST_ASSERT(ep < sizeof(rx_data01));
+    for(int retry = 0;; retry++) {
+        token_ready();
+        int idx = EP0_BDT_IDX(RX, rx_ptr);
+        bdt[idx].setBuffer(data, size);
+        bdt[idx].info = BD_OWN_MASK|
+                        BD_DTS_MASK|
+                        ((rx_data01[ep] == DATA1) ? BD_DATA01_MASK : 0);
+        token_done = false;
+        USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)|USB_TOKEN_TOKENENDPT(ep);
+        while(!token_done);
+        LastStatus = bdt[idx].getStatus();
+        int len = bdt[idx].byte_count;
+        if (LastStatus == DATA0 || LastStatus == DATA1) {
+            rx_data01[ep] = LastStatus == DATA0 ? DATA1 : DATA0;
+            if (retry > 0) {
+                USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus);
+            }
+            return len;
+        }
+        if (++retry >= retryLimit) {
+            return -1;
+        }
+        wait_ms(100);
+        prev_LastStatus = LastStatus;
+    }
+}
+
+int USBHALHost::token_out(uint8_t ep, const uint8_t* data, int size) {
+    USB_TEST_ASSERT(ep < sizeof(tx_data01));
+    int retry = 0;
+    do {
+        token_ready();
+        int idx = EP0_BDT_IDX(TX, tx_ptr);
+        bdt[idx].info = BD_OWN_MASK|
+                        BD_DTS_MASK|
+                       ((tx_data01[ep] == DATA1) ? BD_DATA01_MASK : 0);
+        bdt[idx].setBuffer((uint8_t*)data, size);
+        token_done = false;
+        USB0->TOKEN = USB_TOKEN_TOKENPID(OUT_TOKEN)|USB_TOKEN_TOKENENDPT(ep);
+        while(!token_done);
+        LastStatus = bdt[idx].getStatus();
+        if (LastStatus == ACK) {
+            tx_data01[ep] = (tx_data01[ep] == DATA0) ? DATA1 : DATA0;
+            if (retry > 0) {
+                USB_DBG("retry=%d %02x", retry, prev_LastStatus);
+            }
+            return bdt[idx].byte_count;
+        }
+        wait_ms(10);
+        prev_LastStatus = LastStatus;
+    } while(retry++ < 10);
+    return -1;
+}
+
+void USBHALHost::token_ready() {
+    while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) { // TOKEN_BUSY ?
+        wait_ms(1);
+    }
+    USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF
+    while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK));
+    USB0->SOFTHLD = 0; // this is needed as without this you can get errors
+    USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF
+}
+
+void USBHALHost::_usbisr(void) {
+    if (instHost) {
+        instHost->UsbIrqhandler();
+    }
+}
+
+void USBHALHost::UsbIrqhandler() {
+    uint8_t istat = USB0->ISTAT;
+    if (istat & USB_ISTAT_TOKDNE_MASK) {
+        uint8_t stat = USB0->STAT;
+        ODD_EVEN next_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
+        if (stat & USB_STAT_TX_MASK) {
+            tx_ptr = next_ptr;
+        } else {
+            rx_ptr = next_ptr;
+        }
+        token_done = true;
+    }
+    if (istat & USB_ISTAT_ATTACH_MASK) {
+        USB0->INTEN &= ~USB_INTEN_ATTACHEN_MASK;
+        attach_done = true;
+    }
+    USB0->ISTAT = istat; // clear
+}
+
+void debug_hex(uint8_t* buf, int size) {
+    for(int i = 0; i < size; i++) {
+        fprintf(stderr, "%02x ", buf[i]);
+        if (i%16 == 15) {
+            fprintf(stderr, "\r\n");
+        }
+    }
+    fprintf(stderr, "\r\n");
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHALHost.h	Thu Jan 23 08:32:54 2014 +0000
@@ -0,0 +1,66 @@
+// Simple USBHost for FRDM-KL46Z
+#pragma once
+#include "mbed.h"
+
+struct SETUP_PACKET {
+    uint8_t bmRequestType;
+    uint8_t bRequest;
+    uint16_t wValue;
+    uint16_t wIndex;
+    uint16_t wLength;
+};
+
+#define SET_ADDRESS 5
+#define GET_DESCRIPTOR 6
+#define GET_CONFIGURATION 8
+#define SET_CONFIGURATION 9
+
+// TOK_PID[5:2]
+#define DATA0 0x03
+#define DATA1 0x0b
+#define ACK   0x02
+#define STALL 0x0e
+#define NAK   0x0a
+#define Bus_Timeout 0x00
+#define Data_Error 0x0f
+
+enum ODD_EVEN {
+    ODD = 0,
+    EVEN = 1,
+};
+
+class USBHALHost {
+public:
+    uint8_t LastStatus;
+    uint8_t prev_LastStatus;
+
+protected:
+    USBHALHost();
+    void init();
+    virtual bool enumeration() = 0;
+    bool lowSpeed;
+
+    uint8_t ep_int_in;
+    uint8_t ep_bulk_in;
+    uint8_t ep_bulk_out;
+    int MaxPacketSize0;
+    void setAddr(int addr);
+    void setEndpoint(bool use_retry = false);
+    int token_setup(SETUP_PACKET* setup, uint16_t wLength = 0);
+    int token_in(uint8_t ep, uint8_t* data = NULL, int size = 0, int retryLimit = 10);
+    int token_out(uint8_t ep, const uint8_t* data = NULL, int size = 0);
+    void token_ready();
+    uint8_t tx_data01[16];
+    uint8_t rx_data01[16];
+
+private:
+    static void _usbisr(void);
+    void UsbIrqhandler();
+
+    __IO bool attach_done;
+    __IO bool token_done;
+    void wait_attach();
+    ODD_EVEN tx_ptr;
+    ODD_EVEN rx_ptr;
+    static USBHALHost * instHost;
+};
--- a/USBHost.cpp	Tue Jan 21 08:59:28 2014 +0000
+++ b/USBHost.cpp	Thu Jan 23 08:32:54 2014 +0000
@@ -19,39 +19,6 @@
 #define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
 #define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A))
 
-#define BD_OWN_MASK        (1<<7)
-#define BD_DATA01_MASK     (1<<6)
-#define BD_KEEP_MASK       (1<<5)
-#define BD_NINC_MASK       (1<<4)
-#define BD_DTS_MASK        (1<<3)
-#define BD_STALL_MASK      (1<<2)
-
-#define TX    1
-#define RX    0
-
-#define EP0_BDT_IDX(dir, odd) (((2 * dir) + (1 * odd)))
-
-#define SETUP_TOKEN    0x0D
-#define IN_TOKEN       0x09
-#define OUT_TOKEN      0x01
-
-// for each endpt: 8 bytes
-struct BDT {
-    uint8_t   info;       // BD[0:7]
-    uint8_t   dummy;      // RSVD: BD[8:15]
-    uint16_t  byte_count; // BD[16:32]
-    uint32_t  address;    // Addr
-    void setBuffer(uint8_t* buf, int size) {
-        address = (uint32_t)buf;
-        byte_count = size;
-    }
-    uint8_t getStatus() {
-        return (info>>2)&0x0f;
-    }    
-};
-
-__attribute__((__aligned__(512))) BDT bdt[64];
-
 USBHost* USBHost::inst = NULL;
 
 USBHost* USBHost::getHostInst()
@@ -64,89 +31,9 @@
 }
 
 USBHost::USBHost() {
-    inst = this;
-    memset(rx_data01, DATA1, sizeof(rx_data01));
-    memset(tx_data01, DATA1, sizeof(tx_data01));
 }
 
-void USBHost::init() {
-    // Disable IRQ
-    NVIC_DisableIRQ(USB0_IRQn);
-
-    // choose usb src as PLL
-    SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK);
-
-    // enable OTG clock
-    SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK;
-
-    // USB Module Configuration
-    // Reset USB Module
-    USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
-    while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
-
-    // Clear interrupt flag
-    USB0->ISTAT = 0xff;
-
-    // Set BDT Base Register
-    USB0->BDTPAGE1=(uint8_t)((uint32_t)bdt>>8);
-    USB0->BDTPAGE2=(uint8_t)((uint32_t)bdt>>16);
-    USB0->BDTPAGE3=(uint8_t)((uint32_t)bdt>>24);
-
-    // Set SOF threshold
-    USB0->SOFTHLD = USB_SOFTHLD_CNT(1);
-
-    // pulldown D+ and D-
-    USB0->USBCTRL = USB_USBCTRL_PDE_MASK;
-
-    USB0->USBTRC0 |= 0x40;
-
-    // Host mode
-    USB0->CTL |= USB_CTL_HOSTMODEEN_MASK;
-    // Desable SOF packet generation
-    USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK;
-
-    NVIC_SetVector(USB0_IRQn, (uint32_t)_usbisr);
-    NVIC_EnableIRQ(USB0_IRQn);
-
-    wait_attach();
-
-    for(int retry = 2; retry > 0; retry--) {
-        // Enable RESET
-        USB0->CTL |= USB_CTL_RESET_MASK;
-        wait_ms(500);
-        USB0->CTL &= ~USB_CTL_RESET_MASK;
-    
-        // Enable SOF
-        USB0->CTL |= USB_CTL_USBENSOFEN_MASK;
-        wait_ms(100);
-
-        // token transfer initialize
-        tx_ptr = ODD;
-        rx_ptr = ODD;
-        USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK;
-
-        if (enumeration()) {
-            break;
-        }
-        USB_DBG("retry=%d", retry);
-        USB_TEST_ASSERT(retry > 1);
-    }
-}
-
-void USBHost::wait_attach() {
-    attach_done = false;
-    USB0->INTEN = USB_INTEN_ATTACHEN_MASK;
-    while(!attach_done);
-    wait_ms(100);
-    USB_TEST_ASSERT_FALSE(USB0->CTL & USB_CTL_SE0_MASK);
-    lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true;
-    if (lowSpeed) { // low speed
-        USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK;
-    }
-    USB_DBG("lowSpeed=%d", lowSpeed);
-}
-
-bool USBHost::enumeration() {
+/* virtual */ bool USBHost::enumeration() {
     uint8_t desc[64];
     MaxPacketSize0 = 8;
     dev_addr = 0;
@@ -161,15 +48,14 @@
     USB_DBG_HEX(desc, result);
     MaxPacketSize0 = desc[7];
 
-    dev_addr = 1;
     SETUP_PACKET setup_set_address = {0x00, SET_ADDRESS, 1, 0, 0};
     result = ControlWrite(&setup_set_address);
     if (result < 0) {
         USB_DBG("result=%d %02x", result, LastStatus);
         return false;
     }
-    USB0->ADDR = (lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(dev_addr);
     wait_ms(100);
+    dev_addr = 1;
 
     result = ControlRead(&setup_get_descriptor, desc, sizeof(desc));
     if (result < 8) {
@@ -234,9 +120,10 @@
 }
 
 int USBHost::ControlRead(SETUP_PACKET* setup, uint8_t* data, int size) {
+    setAddr(dev_addr);
     token_setup(setup, size); // setup stage
-    USB_DBG("setup %02x", LastStatus);
-    if (LastStatus != ACK && lowSpeed == false) {
+    if (LastStatus != ACK) {
+        USB_DBG("setup %02x", LastStatus);
         return -1;
     }
     rx_data01[0] = DATA1;
@@ -244,11 +131,9 @@
     while(read_len < size) {
         int size2 = std::min(size-read_len, MaxPacketSize0);
         int result = token_in(0, data+read_len, size2);
-        USB_DBG("token_in result=%d %02x", result, LastStatus);
+        //USB_DBG("token_in result=%d %02x", result, LastStatus);
         if (result < 0) {
-            if (LastStatus == NAK || LastStatus == Bus_Timeout) {
-                break;
-            }
+            USB_DBG("token_in %d/%d %02x", read_len, size, LastStatus);
             return result;
         }
         read_len += result;
@@ -269,9 +154,13 @@
 }
 
 int USBHost::ControlWrite(SETUP_PACKET* setup, uint8_t* data, int size) {
-    if (token_setup(setup, size) != ACK) { // setup stage
+    setAddr(dev_addr);
+    token_setup(setup, size); // setup stage
+    if (LastStatus != ACK) {
+        USB_DBG("setup %02x", LastStatus);
         return -1;
     }
+
     tx_data01[0] = DATA1;
     int write_len = 0;
     if (data != NULL) {
@@ -289,19 +178,15 @@
 }
 
 int USBHost::InterruptRead(uint8_t* data, int size) {
-    USB0->ISTAT = 0xff;
-    USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) |
-                              USB_ENDPT_EPCTLDIS_MASK|
-                              USB_ENDPT_EPRXEN_MASK|
-                              USB_ENDPT_EPHSHK_MASK;
-    return token_in(ep_int_in & 0x7f, data, size);
+    setAddr(dev_addr);
+    setEndpoint();
+    const int retryLimit = 0;
+    return token_in(ep_int_in & 0x7f, data, size, retryLimit);
 }
 
 int USBHost::BulkRead(uint8_t* data, int size) {
-    token_ready();
-    USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPCTLDIS_MASK|
-                              USB_ENDPT_EPRXEN_MASK|
-                              USB_ENDPT_EPHSHK_MASK;
+    setAddr(dev_addr);
+    setEndpoint();
     const int max_packet_size = 64;
     int read_len = 0;
     while(read_len < size) {
@@ -320,10 +205,8 @@
 }
 
 int USBHost::BulkWrite(const uint8_t* data, int size) {
-    token_ready();
-    USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPCTLDIS_MASK|
-                              USB_ENDPT_EPTXEN_MASK|
-                              USB_ENDPT_EPHSHK_MASK;
+    setAddr(dev_addr);
+    setEndpoint();
     const int max_packet_size = 64;
     int write_len = 0;
     while(write_len < size) {
@@ -341,108 +224,3 @@
     return write_len;
 }
 
-int USBHost::token_setup(SETUP_PACKET* setup, uint16_t wLength) {
-    token_ready();
-    USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) |
-                              USB_ENDPT_EPRXEN_MASK|
-                              USB_ENDPT_EPTXEN_MASK|
-                              USB_ENDPT_EPHSHK_MASK;
-    int idx = EP0_BDT_IDX(TX, tx_ptr);
-    bdt[idx].info = BD_OWN_MASK |
-                    BD_DTS_MASK; // always data0
-    setup->wLength = wLength;
-    bdt[idx].setBuffer((uint8_t*)setup, sizeof(SETUP_PACKET));
-    CTASSERT(sizeof(SETUP_PACKET) == 8);
-    token_done = false;
-    USB0->TOKEN = USB_TOKEN_TOKENPID(SETUP_TOKEN)|USB_TOKEN_TOKENENDPT(0);
-    while(!token_done);
-    LastStatus = bdt[idx].getStatus();
-    return LastStatus;
-}
-
-int USBHost::token_in(uint8_t ep, uint8_t* data, int size) {
-    USB_TEST_ASSERT(ep < sizeof(rx_data01));
-    token_ready();
-    int idx = EP0_BDT_IDX(RX, rx_ptr);
-    bdt[idx].info = BD_OWN_MASK|
-                    BD_DTS_MASK|
-                    ((rx_data01[ep] == DATA1) ? BD_DATA01_MASK : 0);
-    bdt[idx].setBuffer(data, size);
-    token_done = false;
-    USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)|USB_TOKEN_TOKENENDPT(ep);
-    while(!token_done);
-    LastStatus = bdt[idx].getStatus();
-    if (LastStatus == DATA0) {
-        rx_data01[ep] = DATA1;
-    } else if (LastStatus == DATA1) {
-        rx_data01[ep] = DATA0;
-    } else {
-        return -1;
-    }
-    return bdt[idx].byte_count;
-}
-
-int USBHost::token_out(uint8_t ep, const uint8_t* data, int size) {
-    USB_TEST_ASSERT(ep < sizeof(tx_data01));
-    token_ready();
-    int idx = EP0_BDT_IDX(TX, tx_ptr);
-    bdt[idx].info = BD_OWN_MASK|
-                    BD_DTS_MASK|
-                   ((tx_data01[ep] == DATA1) ? BD_DATA01_MASK : 0);
-    bdt[idx].setBuffer((uint8_t*)data, size);
-    token_done = false;
-    USB0->TOKEN = USB_TOKEN_TOKENPID(OUT_TOKEN)|USB_TOKEN_TOKENENDPT(ep);
-    while(!token_done);
-    LastStatus = bdt[idx].getStatus();
-    if (LastStatus == ACK) {
-        tx_data01[ep] = (tx_data01[ep] == DATA0) ? DATA1 : DATA0;
-        return bdt[idx].byte_count;
-    }
-    return -1;
-}
-
-void USBHost::token_ready() {
-    while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) { // TOKEN_BUSY ?
-        wait_ms(1);
-    }
-    USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF
-    while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK));
-    USB0->SOFTHLD = 0; // this is needed as without this you can get errors
-    USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF
-}
-
-void USBHost::_usbisr(void) {
-    if (inst) {
-        inst->UsbIrqhandler();
-    }
-}
-
-void USBHost::UsbIrqhandler() {
-    uint8_t istat = USB0->ISTAT;
-    if (istat & USB_ISTAT_TOKDNE_MASK) {
-        uint8_t stat = USB0->STAT;
-        ODD_EVEN next_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
-        if (stat & USB_STAT_TX_MASK) {
-            tx_ptr = next_ptr;
-        } else {
-            rx_ptr = next_ptr;
-        }
-        token_done = true;
-    }
-    if (istat & USB_ISTAT_ATTACH_MASK) {
-        USB0->INTEN &= ~USB_INTEN_ATTACHEN_MASK;
-        attach_done = true;
-    }
-    USB0->ISTAT = istat; // clear
-}
-
-void debug_hex(uint8_t* buf, int size) {
-    for(int i = 0; i < size; i++) {
-        fprintf(stderr, "%02x ", buf[i]);
-        if (i%16 == 15) {
-            fprintf(stderr, "\r\n");
-        }
-    }
-    fprintf(stderr, "\r\n");
-}
-
--- a/USBHost.h	Tue Jan 21 08:59:28 2014 +0000
+++ b/USBHost.h	Thu Jan 23 08:32:54 2014 +0000
@@ -1,35 +1,9 @@
 // Simple USBHost for FRDM-KL46Z
-#include "mbed.h"
 #pragma once
-
-struct SETUP_PACKET {
-    uint8_t bmRequestType;
-    uint8_t bRequest;
-    uint16_t wValue;
-    uint16_t wIndex;
-    uint16_t wLength;
-};
+#include "mbed.h"
+#include "USBHALHost.h"
 
-#define SET_ADDRESS 5
-#define GET_DESCRIPTOR 6
-#define GET_CONFIGURATION 8
-#define SET_CONFIGURATION 9
-
-// TOK_PID[5:2]
-#define DATA0 0x03
-#define DATA1 0x0b
-#define ACK   0x02
-#define STALL 0x0e
-#define NAK   0x0a
-#define Bus_Timeout 0x00
-#define Data_Error 0x0f
-
-enum ODD_EVEN {
-    ODD = 0,
-    EVEN = 1,
-};
-
-class USBHost {
+class USBHost : public USBHALHost {
 public:
     static USBHost* getHostInst();
     int InterruptRead(uint8_t* data, int size);
@@ -37,33 +11,11 @@
     int ControlWrite(SETUP_PACKET* setup, uint8_t* data = NULL, int size = 0);
     int BulkRead(uint8_t* data, int size);
     int BulkWrite(const uint8_t* data, int size);
-    uint8_t LastStatus;
-
-protected:
-    USBHost();
-    void init();
-    void wait_attach();
-    bool enumeration();
-    uint8_t ep_int_in;
-    uint8_t ep_bulk_in;
-    uint8_t ep_bulk_out;
-    int MaxPacketSize0;
-    bool lowSpeed;
-    int dev_addr;
 
 private:
-    static void _usbisr(void);
-    int token_setup(SETUP_PACKET* setup, uint16_t wLength = 0);
-    int token_in(uint8_t ep, uint8_t* data = NULL, int size = 0);
-    int token_out(uint8_t ep, const uint8_t* data = NULL, int size = 0);
-    void token_ready();
-    void UsbIrqhandler();
-    __IO bool attach_done;
-    __IO bool token_done;
-    ODD_EVEN tx_ptr;
-    ODD_EVEN rx_ptr;
-    uint8_t tx_data01[16];
-    uint8_t rx_data01[16];
+    USBHost();
     static USBHost* inst;
+    virtual bool enumeration();
+    int dev_addr;
 };
 
--- a/USBHostMSD.h	Tue Jan 21 08:59:28 2014 +0000
+++ b/USBHostMSD.h	Thu Jan 23 08:32:54 2014 +0000
@@ -164,17 +164,11 @@
     }
     
     USB_TYPE bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true) {
-        for(int retry = 2; retry > 0; retry--) {
-            int result = host->BulkRead(buf, len);
-            if (result >= 0) {
-                return USB_TYPE_OK;
-            }
-            USB_DBG2("result=%d %02x", result, host->LastStatus);
-            if (host->LastStatus != Bus_Timeout) {
-                break;
-            }
-            wait_ms(10);
+        int result = host->BulkRead(buf, len);
+        if (result >= 0) {
+            return USB_TYPE_OK;
         }
+        //USB_DBG2("result=%d %02x", result, host->LastStatus);
         return USB_TYPE_ERROR;
     }