Simple USBHost library for Nucleo F446RE/F411RE/F401RE FRDM-KL46Z/KL25Z/F64F LPC4088/LPC1768
Dependents: F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld
Fork of KL46Z-USBHost by
簡易USBホストライブラリです。
official-USBHostの下位互換で対応プログラムを僅かな修正で動かすことが出来ます。
Platforms
- Nucleo F446RE
- Nucleo F411RE
- Nucleo F401RE
- FRDM-K64F
- FRDM-KL46Z
- FRDM-KL25Z
- LPC4088
- LPC1768
Nucleo F446RE/F411RE/F401REのUSB接続方法
ST morpho | USB |
---|---|
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
Revision 0:5160ee0c522d, committed 2014-01-18
- Comitter:
- va009039
- Date:
- Sat Jan 18 13:30:22 2014 +0000
- Child:
- 1:c072d9e580b0
- Commit message:
- first commit
Changed in this revision
--- /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; +}; +