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:
Sat Jan 18 13:30:22 2014 +0000
Child:
1:c072d9e580b0
Commit message:
first commit

Changed in this revision

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
USBHostGPS.h Show annotated file Show diff for this revision Revisions of this file
USBHostMouse.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHost.cpp	Sat Jan 18 13:30:22 2014 +0000
@@ -0,0 +1,302 @@
+// Simple USBHost for FRDM-KL46Z
+#include "USBHost.h"
+#include <algorithm>
+
+template <bool>struct CtAssert;
+template <>struct CtAssert<true> {};
+#define CTASSERT(A) CtAssert<A>();
+
+void debug_hex(uint8_t* buf, int size);
+#define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0);
+#define USB_DBG_HEX(A,B) debug_hex(A,B)
+#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;
+    }
+};
+
+__attribute__((__aligned__(512))) BDT bdt[64];
+
+USBHost* USBHost::inst = NULL;
+
+USBHost* USBHost::getHostInst()
+{
+    if (inst == NULL) {
+        inst = new USBHost();
+        inst->init();
+    }
+    return inst;
+}
+
+USBHost::USBHost() {
+    inst = this;
+}
+
+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;
+
+    // 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();
+
+    // Enable RESET
+    USB0->CTL |= USB_CTL_RESET_MASK;
+    wait_ms(10);
+    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;
+
+    enumeration();
+
+}
+
+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);
+    if (!(USB0->CTL & USB_CTL_JSTATE_MASK)) { // low speed
+        USB0->ADDR |= USB_ADDR_LSEN_MASK;
+    }
+    USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK;
+}
+
+void USBHost::enumeration() {
+    uint8_t desc[18];
+    MaxPacketSize0 = 8;
+    SETUP_PACKET setup_get_descriptor = {0x80, GET_DESCRIPTOR, 1<<8, 0, 0};
+    int result = ControlRead(&setup_get_descriptor, desc, 8);
+    USB_TEST_ASSERT(result == 8);
+    USB_DBG_HEX(desc, result);
+    MaxPacketSize0 = desc[7];
+
+    result = ControlRead(&setup_get_descriptor, desc, sizeof(desc));
+    USB_TEST_ASSERT(result == sizeof(desc));
+    USB_DBG_HEX(desc, sizeof(desc));
+
+    setup_get_descriptor.wValue = 2<<8; // config descriptor
+    result = ControlRead(&setup_get_descriptor, desc, 4);
+    USB_TEST_ASSERT(result == 4);
+    USB_DBG_HEX(desc, 4);
+
+    int TotalLength = desc[2]|desc[3]<<8;
+    uint8_t* buf = new uint8_t[TotalLength];
+    result = ControlRead(&setup_get_descriptor, buf, TotalLength);
+    USB_TEST_ASSERT(result == TotalLength);
+    USB_DBG_HEX(buf, TotalLength);
+
+    for(int i = 0; i < TotalLength; ) {
+        int Length = buf[i];
+        uint8_t DescriptorType = buf[i+1];
+        if (DescriptorType == 0x05) { // endpoint
+            uint8_t EndpointAddress = buf[i+2];
+            uint8_t Attributes = buf[i+3];
+            if (Attributes == 0x03) { // interrupt
+                if (EndpointAddress & 0x80) {
+                    ep_int_in = EndpointAddress;
+                }
+            } else if (Attributes == 0x02) { // bulk
+                if (EndpointAddress & 0x80) {
+                    ep_bulk_in = EndpointAddress;
+                } else {
+                    ep_bulk_out = EndpointAddress;
+                }
+            }
+        }
+        USB_DBG_HEX(buf+i, Length);
+        i += Length;
+    }
+    delete[] buf;
+
+    SETUP_PACKET setup_set_config = {0x00, SET_CONFIGURATION, 1, 0, 0}; // config = 1
+    ControlWrite(&setup_set_config);
+}
+
+int USBHost::ControlRead(SETUP_PACKET* setup, uint8_t* data, int size) {
+    token_setup(setup, size); // setup stage
+    int read_len = 0;
+    while(read_len < size) {
+        int size2 = std::min(size-read_len, MaxPacketSize0);
+        int result = token_in(0, data+read_len, size2);
+        read_len += result;
+        if (result < MaxPacketSize0) {
+            break;
+        }
+    }    
+    token_out(0); // status stage
+    return read_len;
+}
+
+int USBHost::ControlWrite(SETUP_PACKET* setup, uint8_t* data, int size) {
+    token_setup(setup, size); // setup stage
+    int result = 0;
+    if (data != NULL) {
+        result = token_out(0, data, size);
+    }
+    token_in(0); // status stage
+    return result;
+}
+
+int USBHost::InterruptRead(uint8_t* data, int size) {
+    USB0->ISTAT = 0xff;
+    USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_EPCTLDIS_MASK|
+                               USB_ENDPT_EPRXEN_MASK|
+                               USB_ENDPT_EPTXEN_MASK|
+                               USB_ENDPT_EPHSHK_MASK;
+    return token_in(ep_int_in & 0x7f, data, size);
+}
+
+int USBHost::BulkRead(uint8_t* data, int size) {
+    USB0->ISTAT = 0xff;
+    USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_EPCTLDIS_MASK|
+                               USB_ENDPT_EPRXEN_MASK|
+                               USB_ENDPT_EPTXEN_MASK|
+                               USB_ENDPT_EPHSHK_MASK;
+    return token_in(ep_bulk_in & 0x7f, data, size);
+}
+
+int USBHost::BulkWrite(const uint8_t* data, int size) {
+    USB0->ISTAT = 0xff;
+    USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_EPCTLDIS_MASK|
+                               USB_ENDPT_EPRXEN_MASK|
+                               USB_ENDPT_EPTXEN_MASK|
+                               USB_ENDPT_EPHSHK_MASK;
+    return token_out(ep_bulk_out & 0x7f, data, size);
+}
+
+int USBHost::token_setup(SETUP_PACKET* setup, uint16_t wLength) {
+    USB0->ISTAT = 0xff;
+    USB0->ERRSTAT = 0xff;
+    USB0->ENDPOINT[0].ENDPT |= 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;
+    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);
+    return (bdt[idx].info>>2)&0x0f;
+}
+
+int USBHost::token_in(uint8_t ep, uint8_t* data, int size) {
+    int idx = EP0_BDT_IDX(RX, rx_ptr);
+    bdt[idx].info = BD_OWN_MASK|BD_DATA01_MASK;
+    bdt[idx].setBuffer(data, size);
+    token_done = false;
+    USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)|USB_TOKEN_TOKENENDPT(ep);
+    while(!token_done);
+    return bdt[idx].byte_count;
+}
+
+int USBHost::token_out(uint8_t ep, const uint8_t* data, int size) {
+    int idx = EP0_BDT_IDX(TX, tx_ptr);
+    bdt[idx].info = BD_OWN_MASK|BD_DATA01_MASK;
+    bdt[idx].setBuffer((uint8_t*)data, size);
+    token_done = false;
+    USB0->TOKEN = USB_TOKEN_TOKENPID(OUT_TOKEN)|USB_TOKEN_TOKENENDPT(ep);
+    while(!token_done);
+    return bdt[idx].byte_count;
+}
+
+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;
+        if (stat & USB_STAT_TX_MASK) {
+            tx_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
+        } else {
+            rx_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
+        }
+        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/USBHost.h	Sat Jan 18 13:30:22 2014 +0000
@@ -0,0 +1,54 @@
+// 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;
+};
+
+#define SET_ADDRESS 5
+#define GET_DESCRIPTOR 6
+#define GET_CONFIGURATION 8
+#define SET_CONFIGURATION 9
+
+enum ODD_EVEN {
+    ODD = 0,
+    EVEN = 1,
+};
+
+class USBHost {
+public:
+    static USBHost* getHostInst();
+    int InterruptRead(uint8_t* data, int size);
+    int ControlRead(SETUP_PACKET* setup, uint8_t* data, int size);
+    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);
+
+protected:
+    USBHost();
+    void init();
+    void wait_attach();
+    void enumeration();
+    uint8_t ep_int_in;
+    uint8_t ep_bulk_in;
+    uint8_t ep_bulk_out;
+    int MaxPacketSize0;
+
+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 UsbIrqhandler();
+    __IO bool attach_done;
+    __IO bool token_done;
+    ODD_EVEN tx_ptr;
+    ODD_EVEN rx_ptr;
+    static USBHost* inst;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostGPS.h	Sat Jan 18 13:30:22 2014 +0000
@@ -0,0 +1,21 @@
+// Simple USBHost GPS Dongle for FRDM-KL46Z
+#include "USBHost.h"
+
+#define PL2303_SET_LINE_CODING 0x20
+
+class USBHostGPS {
+public:
+    USBHostGPS(int baud = 38400) {
+        host = USBHost::getHostInst();
+        // stop bit = 1, parity = none, 8bit
+        uint8_t data[] = {baud&0xff, baud>>8, baud>>16, baud>>24, 0x00, 0x00, 0x08};
+        SETUP_PACKET setup = {0x21, PL2303_SET_LINE_CODING, 0, 0, 0};
+        host->ControlWrite(&setup, data, sizeof(data));
+    }
+    int readNMEA(char* data, int size) {
+        return host->BulkRead((uint8_t*)data, size);
+    }
+
+private:
+    USBHost * host;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBHostMouse.h	Sat Jan 18 13:30:22 2014 +0000
@@ -0,0 +1,16 @@
+// Simple USBHost Mouse for FRDM-KL46Z
+#include "USBHost.h"
+
+class USBHostMouse {
+public:
+    USBHostMouse() {
+        host = USBHost::getHostInst();
+    }
+    int readReport(uint8_t* data) {
+        return host->InterruptRead(data, 4);
+    }
+
+private:
+    USBHost * host;
+};
+