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 5:10bfc10afcc8, committed 2014-01-27
- Comitter:
- va009039
- Date:
- Mon Jan 27 11:00:28 2014 +0000
- Parent:
- 4:21d651ad6987
- Child:
- 6:03ef38d6e1ba
- Commit message:
- add isochronous transfer
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBEndpoint.h Mon Jan 27 11:00:28 2014 +0000 @@ -0,0 +1,22 @@ +#pragma once +#include "USBHostTypes.h" + +class USBEndpoint { +public: + USBEndpoint() : data01_toggle(DATA0),address(0),MaxPacketSize(8) {} + void setState(uint8_t st){}; // dummy + void setSize(int size) { MaxPacketSize = size; } + void setAddress(uint8_t addr) { address = addr; } + void setData01(uint8_t data01) { data01_toggle = data01; } + uint8_t getAddress(){ return address; }; + int getSize() { return MaxPacketSize; } + uint8_t getData01() { return data01_toggle; } + void toggleData01() { + data01_toggle = (data01_toggle == DATA0) ? DATA1 : DATA0; + } + +private: + uint8_t data01_toggle; // DATA0,DATA1 + uint8_t address; + int MaxPacketSize; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHALHost.cpp Mon Jan 27 11:00:28 2014 +0000 @@ -0,0 +1,397 @@ +// 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; + report.clear(); +} + +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 + token_transfer_init(); + + USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK| + USB_INTEN_ERROREN_MASK; + USB0->ERREN |= USB_ERREN_PIDERREN_MASK| + USB_ERREN_CRC5EOFEN_MASK| + USB_ERREN_CRC16EN_MASK| + USB_ERREN_DFN8EN_MASK| + USB_ERREN_BTOERREN_MASK| + USB_ERREN_DMAERREN_MASK| + USB_ERREN_BTSERREN_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; +} + +void USBHALHost::token_transfer_init() { + tx_ptr = ODD; + rx_ptr = ODD; +} + +int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) { + for(int retry = 0;; retry++) { + 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(ep->getAddress() & 0x7f); + while(!token_done); + LastStatus = bdt[idx].getStatus(); + if (LastStatus == ACK) { + if (retry > 0) { + USB_DBG("retry=%d %02x", retry, prev_LastStatus); + } + break; + } else if (LastStatus == STALL) { + report.stall++; + return STALL; + } + if (retry > 10) { + USB_DBG("retry=%d", retry); + break; + } + prev_LastStatus = LastStatus; + wait_ms(100 * retry); + } + ep->setData01(DATA1); // next toggle + return LastStatus; +} + +int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) { + 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| + (ep->getData01() == DATA1 ? BD_DATA01_MASK : 0); + token_done = false; + USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)| + USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f); + while(!token_done); + LastStatus = bdt[idx].getStatus(); + int len = bdt[idx].byte_count; + if (LastStatus == DATA0 || LastStatus == DATA1) { + USB_TEST_ASSERT(ep->getData01() == LastStatus); + ep->setData01(LastStatus == DATA0 ? DATA1 : DATA0); + if (retry > 0) { + USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); + } + return len; + } else if (LastStatus == STALL) { + report.stall++; + return -1; + } else if (LastStatus == NAK) { + report.nak++; + if (retry >= retryLimit) { + if (retryLimit > 0) { + USB_DBG("retry=%d retryLimit=%d", retry, retryLimit); + } + return -1; + } + wait_ms(100 * retry); + } else { + return -1; + } + prev_LastStatus = LastStatus; + } +} + +int USBHALHost::token_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) { + for(int retry = 0;; retry++) { + token_ready(); + int idx = EP0_BDT_IDX(TX, tx_ptr); + bdt[idx].setBuffer((uint8_t*)data, size); + bdt[idx].info = BD_OWN_MASK| + BD_DTS_MASK| + (ep->getData01() == DATA1 ? BD_DATA01_MASK : 0); + token_done = false; + USB0->TOKEN = USB_TOKEN_TOKENPID(OUT_TOKEN)| + USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f); + while(!token_done); + LastStatus = bdt[idx].getStatus(); + int len = bdt[idx].byte_count; + //USB_DBG("len=%d %02x", len, LastStatus); + if (LastStatus == ACK) { + ep->toggleData01(); + if (retry > 0) { + USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); + } + return len; + } else if (LastStatus == STALL) { + report.stall++; + return -1; + } else if (LastStatus == NAK) { + report.nak++; + if (retry > retryLimit) { + USB_DBG("retry=%d retryLimit=%d", retry, retryLimit); + return -1; + } + wait_ms(100 * retry); + } else { + return -1; + } + prev_LastStatus = LastStatus; + } +} + +int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) { + while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK); // TOKEN_BUSY ? + 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 + + USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPCTLDIS_MASK| + USB_ENDPT_RETRYDIS_MASK| + USB_ENDPT_EPRXEN_MASK| + USB_ENDPT_EPTXEN_MASK; + int idx = EP0_BDT_IDX(RX, rx_ptr); + bdt[idx].setBuffer(data, size); + bdt[idx].info = BD_OWN_MASK| + BD_DTS_MASK; // always DATA0 + token_done = false; + USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)| + USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f); + while(!token_done); + LastStatus = bdt[idx].getStatus(); + int len = bdt[idx].byte_count; + if (LastStatus == DATA0) { + return len; + } + 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; + } + if (istat & USB_ISTAT_ERROR_MASK) { + uint8_t errstat = USB0->ERRSTAT; + if (errstat & USB_ERRSTAT_PIDERR_MASK) { + report.errstat_piderr++; + } + if (errstat & USB_ERRSTAT_CRC5EOF_MASK) { + report.errstat_crc5eof++; + } + if (errstat & USB_ERRSTAT_CRC16_MASK) { + report.errstat_crc16++; + } + if (errstat & USB_ERRSTAT_DFN8_MASK) { + report.errstat_dfn8++; + } + if (errstat & USB_ERRSTAT_BTOERR_MASK) { + report.errstat_btoerr++; + } + if (errstat & USB_ERRSTAT_DMAERR_MASK) { + report.errstat_dmaerr++; + } + if (errstat & USB_ERRSTAT_BTSERR_MASK) { + report.errstat_btoerr++; + } + USB0->ERRSTAT = errstat; + } + USB0->ISTAT = istat; // clear +} + +void Report::clear() { + errstat_piderr = 0; + errstat_crc5eof = 0; + errstat_crc16 = 0; + errstat_dfn8 = 0; + errstat_btoerr = 0; + errstat_dmaerr = 0; + errstat_bsterr = 0; + // + nak = 0; +} + +void Report::print_errstat() { + printf("ERRSTAT PID: %d, CRC5EOF: %d, CRC16: %d, DFN8: %d, BTO: %d, DMA: %d, BST: %d\n", + errstat_piderr, errstat_crc5eof, + errstat_crc16, errstat_dfn8, + errstat_btoerr, errstat_dmaerr, errstat_bsterr); +} + +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/USBHALHost.h Mon Jan 27 11:00:28 2014 +0000 @@ -0,0 +1,71 @@ +// Simple USBHost for FRDM-KL46Z +#pragma once +#include "mbed.h" +#include "USBHostTypes.h" +#include "USBEndpoint.h" + +struct SETUP_PACKET { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +}; + +#define GET_CONFIGURATION 8 + +// TOK_PID[5:2] +#define Bus_Timeout 0x00 +#define Data_Error 0x0f + +enum ODD_EVEN { + ODD = 0, + EVEN = 1, +}; + +class Report { +public: + void clear(); + void print_errstat(); + // error count + uint32_t errstat_piderr; // USBx_ERRSTAT[PIDERR] + uint32_t errstat_crc5eof;// USBx_ERRSTAT[CRC5EOF] + uint32_t errstat_crc16; // USBx_ERRSTAT[CRC16] + uint32_t errstat_dfn8; // USBx_ERRSTAT[DFN8] + uint32_t errstat_btoerr; // USBx_ERRSTAT[BTOERR] + uint32_t errstat_dmaerr; // USBx_ERRSTAT[DMAERR] + uint32_t errstat_bsterr; // USBx_ERRSTAT[BTSERR] + // + uint32_t nak; + uint32_t stall; +}; + +class USBHALHost { +public: + uint8_t LastStatus; + uint8_t prev_LastStatus; + Report report; + +protected: + USBHALHost(); + void init(); + virtual bool enumeration() = 0; + bool lowSpeed; + void setAddr(int addr); + void setEndpoint(bool use_retry = false); + void token_transfer_init(); + int token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength = 0); + int token_in(USBEndpoint* ep, uint8_t* data = NULL, int size = 0, int retryLimit = 10); + int token_out(USBEndpoint* ep, const uint8_t* data = NULL, int size = 0, int retryLimit = 10); + int token_iso_in(USBEndpoint* ep, uint8_t* data, int size); + void token_ready(); +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; +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHost.cpp Mon Jan 27 11:00:28 2014 +0000 @@ -0,0 +1,339 @@ +// Simple USBHost for FRDM-KL46Z +#include "USBHost.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_DBG2(...) 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) +#define USB_DBG_ERRSTAT() report.print_errstat(); +void debug_hex(uint8_t* buf, int size); +#else +#define USB_DBG(...) while(0) +#define USB_DBG2(...) while(0) +#define USB_DBG_HEX(A,B) while(0) +#define USB_DBG_ERRSTAT() 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 USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);}while(0); + +USBHost* USBHost::inst = NULL; + +USBHost* USBHost::getHostInst() +{ + if (inst == NULL) { + inst = new USBHost(); + inst->init(); + } + return inst; +} + +USBHost::USBHost() { +} + +/* virtual */ bool USBHost::enumeration() { + USBEndpoint* ep = &ep_ctl_in_out; + uint8_t desc[64]; + ep->setAddress(0); + ep->setSize(8); // max packet size + dev_addr = 0; + wait_ms(100); + SETUP_PACKET setup_get_descriptor = {0x80, GET_DESCRIPTOR, 1<<8, 0, 0}; + int result = ControlRead(&setup_get_descriptor, desc, ep->getSize()); + if (result < ep->getSize()) { + USB_DBG("result=%d %02x", result, LastStatus); + USB_DBG_ERRSTAT(); + return false; + } + USB_DBG_HEX(desc, result); + USB_DBG_ERRSTAT(); + DeviceDescriptor* dev_desc = reinterpret_cast<DeviceDescriptor*>(desc); + ep->setSize(dev_desc->bMaxPacketSize); + + 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); + USB_DBG_ERRSTAT(); + return false; + } + wait_ms(100); + dev_addr = 1; + + result = ControlRead(&setup_get_descriptor, desc, sizeof(desc)); + if (result < 8) { + USB_DBG("result=%d", result); + USB_DBG_ERRSTAT(); + return false; + } + USB_DBG_HEX(desc, result); + USB_DBG_ERRSTAT(); + + USB_INFO("USB VID: %04x, PID: %04x\n", dev_desc->idVendor, dev_desc->idProduct); + if (dev_desc->bDeviceClass == HUB_CLASS) { + USB_INFO("USB hub not supported.\n\n"); + exit(1); + } + + setup_get_descriptor.wValue = 2<<8; // config descriptor + result = ControlRead(&setup_get_descriptor, desc, 4); + if (result != 4) { + USB_DBG("result=%d", result); + USB_DBG_ERRSTAT(); + return false; + } + USB_DBG_HEX(desc, 4); + USB_DBG_ERRSTAT(); + + int TotalLength = desc[2]|desc[3]<<8; + uint8_t* buf = new uint8_t[TotalLength]; + result = ControlRead(&setup_get_descriptor, buf, TotalLength); + if (result != TotalLength) { + USB_DBG("result=%d TotalLength=%d %02x", result, TotalLength, LastStatus); + USB_DBG_ERRSTAT(); + return false; + } + USB_DBG_HEX(buf, TotalLength); + USB_DBG_ERRSTAT(); + + for(int i = 0; i < TotalLength; ) { + int Length = buf[i]; + uint8_t DescriptorType = buf[i+1]; + if (DescriptorType == 0x05) { // endpoint + EndpointDescriptor* desc = reinterpret_cast<EndpointDescriptor*>(buf+i); + USBEndpoint* ep = NULL; + if (desc->bmAttributes == 0x03) { // interrupt + if (desc->bEndpointAddress & 0x80) { + ep = &ep_int_in; + } + } else if (desc->bmAttributes == 0x02) { // bulk + ep = (desc->bEndpointAddress & 0x80) ? &ep_bulk_in : &ep_bulk_out; + } + if (ep) { + ep->setAddress(desc->bEndpointAddress); + ep->setSize(desc->wMaxPacketSize); + } + } + USB_DBG_HEX(buf+i, Length); + i += Length; + } + delete[] buf; + + // config = 1 + SETUP_PACKET setup_set_config = {0x00, SET_CONFIGURATION, 1, 0, 0}; + result = ControlWrite(&setup_set_config); + if (result < 0) { + USB_DBG("set config: %02x", LastStatus); + USB_DBG_ERRSTAT(); + if (lowSpeed && LastStatus == STALL) { // TODO: + wait_ms(100); + return true; + } + return false; + } + wait_ms(100); + return true; +} + +USB_TYPE USBHost::controlRead(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) { + SETUP_PACKET setup = {requestType, request, value, index}; + int result = ControlRead(&setup, buf, len); + USB_DBG2("result=%d %02x", result, LastStatus); + return (result >= 0) ? USB_TYPE_OK : USB_TYPE_ERROR; +} + +USB_TYPE USBHost::controlWrite(USBDeviceConnected* dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) { + SETUP_PACKET setup = {requestType, request, value, index}; + int result = ControlWrite(&setup, buf, len); + if (result >= 0) { + return USB_TYPE_OK; + } + USB_DBG("result=%d %02x", result, LastStatus); + USB_DBG_ERRSTAT(); + USB_DBG_HEX(buf, len); + return USB_TYPE_ERROR; +} + +USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) { + USB_TEST_ASSERT(blocking); + int result = BulkRead(buf, len); + if (result >= 0) { + return USB_TYPE_OK; + } + //USB_DBG2("result=%d %02x", result, host->LastStatus); + return USB_TYPE_ERROR; +} + +USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) { + USB_TEST_ASSERT(blocking); + int result = BulkWrite(buf, len); + if (result >= 0) { + return USB_TYPE_OK; + } + USB_DBG2("result=%d %02x", result, LastStatus); + return USB_TYPE_ERROR; +} + +USB_TYPE USBHost::interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) { + USB_TEST_ASSERT(blocking); + int result = InterruptRead(buf, len); + if (result >= 0) { + return USB_TYPE_OK; + } + return USB_TYPE_ERROR; +} + +int USBHost::ControlRead(SETUP_PACKET* setup, uint8_t* data, int size) { + USBEndpoint* ep = &ep_ctl_in_out; + setAddr(dev_addr); + token_setup(ep, setup, size); // setup stage + if (LastStatus != ACK) { + USB_DBG("setup %02x", LastStatus); + return -1; + } + int read_len = 0; + while(read_len < size) { + int size2 = std::min(size-read_len, ep->getSize()); + int result = token_in(ep, data+read_len, size2); + //USB_DBG("token_in result=%d %02x", result, LastStatus); + if (result < 0) { + USB_DBG("token_in %d/%d %02x", read_len, size, LastStatus); + return result; + } + read_len += result; + if (result < ep->getSize()) { + break; + } + } + int result = token_out(ep); // status stage + if (result < 0) { + USB_DBG("status token_out %02x", LastStatus); + if (LastStatus == STALL) { + return read_len; + } + return result; + } + return read_len; +} + +int USBHost::ControlWrite(SETUP_PACKET* setup, uint8_t* data, int size) { + USBEndpoint* ep = &ep_ctl_in_out; + setAddr(dev_addr); + token_setup(ep, setup, size); // setup stage + if (LastStatus != ACK) { + USB_DBG("setup %02x", LastStatus); + return -1; + } + int write_len = 0; + if (data != NULL) { + write_len = token_out(ep, data, size); + if (write_len < 0) { + return -1; + } + } + int result = token_in(ep); // status stage + if (result < 0) { + USB_DBG("result=%d %02x", result, LastStatus); + //return result; + } + return write_len; +} + +int USBHost::InterruptRead(uint8_t* data, int size) { + USBEndpoint* ep = &ep_int_in; + setAddr(dev_addr); + setEndpoint(); + const int retryLimit = 0; + int read_len = 0; + for(int n = 0; read_len < size; n++) { + int size2 = std::min(size-read_len, ep->getSize()); + int result = token_in(ep, data+read_len, size2, retryLimit); + if (result < 0) { + if (LastStatus == NAK) { + if (n == 0) { + return -1; + } + break; + } + USB_DBG("token_in result=%d %02x", result, LastStatus); + return result; + } + read_len += result; + if (result < ep->getSize()) { + break; + } + } + return read_len; +} + +int USBHost::BulkRead(uint8_t* data, int size, int timeout_ms) { + USBEndpoint* ep = &ep_bulk_in; + setAddr(dev_addr); + setEndpoint(); + int retryLimit = (timeout_ms == 0) ? 0 : 10; + int read_len = 0; + Timer t; + for(int n = 0; read_len < size; n++) { + int size2 = std::min(size-read_len, ep->getSize()); + int result = token_in(ep, data+read_len, size2, retryLimit); + if (result < 0) { + if (LastStatus == NAK) { + if (n == 0) { + return -1; + } + break; + } + USB_DBG("token_in result=%d %02x", result, LastStatus); + return result; + } + read_len += result; + if (result < ep->getSize()) { + break; + } + if (timeout_ms > 0 && t.read_ms() > timeout_ms) { + USB_DBG("timeout_ms: %d", timeout_ms); + break; + } + } + return read_len; +} + +int USBHost::BulkWrite(const uint8_t* data, int size) { + USBEndpoint* ep = &ep_bulk_out; + setAddr(dev_addr); + setEndpoint(); + int write_len = 0; + for(int n = 0; write_len < size; n++) { + int size2 = std::min(size-write_len, ep->getSize()); + int result = token_out(ep, data+write_len, size2); + if (result < 0) { + if (LastStatus == NAK) { + if (n == 0) { + return -1; + } + break; + } + USB_DBG("token_out result=%d %02x", result, LastStatus); + return result; + } + write_len += result; + if (result < ep->getSize()) { + break; + } + } + return write_len; +} + +int USBHost::IsochronousRead(USBEndpoint* ep, uint8_t* data, int size) { + setAddr(dev_addr); + return token_iso_in(ep, data, size); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHost.h Mon Jan 27 11:00:28 2014 +0000 @@ -0,0 +1,115 @@ +// Simple USBHost for FRDM-KL46Z +#pragma once +#include "mbed.h" +#include "USBHALHost.h" +#include "USBEndpoint.h" + +class USBDeviceConnected {}; //dummy +class IUSBEnumerator {}; // dummy + +class USBHost : public USBHALHost { +public: + /** + * Static method to create or retrieve the single USBHost instance + */ + static USBHost* getHostInst(); + + /** + * Control read: setup stage, data stage and status stage + * + * @param dev the control read will be done for this device + * @param requestType request type + * @param request request + * @param value value + * @param index index + * @param buf pointer on a buffer where will be store the data received + * @param len length of the transfer + * + * @returns status of the control read + */ + USB_TYPE controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len); + + /** + * Control write: setup stage, data stage and status stage + * + * @param dev the control write will be done for this device + * @param requestType request type + * @param request request + * @param value value + * @param index index + * @param buf pointer on a buffer which will be written + * @param len length of the transfer + * + * @returns status of the control write + */ + USB_TYPE controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len); + /** + * Bulk read + * + * @param dev the bulk transfer will be done for this device + * @param ep USBEndpoint which will be used to read a packet + * @param buf pointer on a buffer where will be store the data received + * @param len length of the transfer + * @param blocking if true, the read is blocking (wait for completion) + * + * @returns status of the bulk read + */ + USB_TYPE bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true); + + /** + * Bulk write + * + * @param dev the bulk transfer will be done for this device + * @param ep USBEndpoint which will be used to write a packet + * @param buf pointer on a buffer which will be written + * @param len length of the transfer + * @param blocking if true, the write is blocking (wait for completion) + * + * @returns status of the bulk write + */ + USB_TYPE bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true); + + /** + * Interrupt read + * + * @param dev the interrupt transfer will be done for this device + * @param ep USBEndpoint which will be used to write a packet + * @param buf pointer on a buffer which will be written + * @param len length of the transfer + * @param blocking if true, the read is blocking (wait for completion) + * + * @returns status of the interrupt read + */ + USB_TYPE interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true); + + /** + * Interrupt write + * + * @param dev the interrupt transfer will be done for this device + * @param ep USBEndpoint which will be used to write a packet + * @param buf pointer on a buffer which will be written + * @param len length of the transfer + * @param blocking if true, the write is blocking (wait for completion) + * + * @returns status of the interrupt write + */ + USB_TYPE interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true); + + 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 timeout_ms = -1); + int BulkWrite(const uint8_t* data, int size); + int InterruptRead(uint8_t* data, int size); + int IsochronousRead(USBEndpoint*ep, uint8_t* data, int size); + +private: + USBHost(); + static USBHost* inst; + virtual bool enumeration(); + int dev_addr; + USBEndpoint ep_ctl_in_out; + USBEndpoint ep_int_in; + USBEndpoint ep_bulk_in; + USBEndpoint ep_bulk_out; +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHostConf.h Mon Jan 27 11:00:28 2014 +0000 @@ -0,0 +1,86 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBHOST_CONF_H +#define USBHOST_CONF_H + +/* +* Maximum number of devices that can be connected +* to the usb host +*/ +#define MAX_DEVICE_CONNECTED 5 + +/* +* Maximum of Hub connected to the usb host +*/ +#define MAX_HUB_NB 2 + +/* +* Maximum number of ports on a USB hub +*/ +#define MAX_HUB_PORT 4 + +/* +* Enable USBHostMSD +*/ +#define USBHOST_MSD 1 + +/* +* Enable USBHostKeyboard +*/ +#define USBHOST_KEYBOARD 1 + +/* +* Enable USBHostMouse +*/ +#define USBHOST_MOUSE 1 + +/* +* Enable USBHostSerial or USBHostMultiSerial (if set > 1) +*/ +#define USBHOST_SERIAL 1 + +/* +* Enable USB3Gmodule +*/ +#define USBHOST_3GMODULE 1 + +/* +* Maximum number of interfaces of a usb device +*/ +#define MAX_INTF 4 + +/* +* Maximum number of endpoints on each interface +*/ +#define MAX_ENDPOINT_PER_INTERFACE 3 + +/* +* Maximum number of endpoint descriptors that can be allocated +*/ +#define MAX_ENDPOINT (MAX_DEVICE_CONNECTED * MAX_INTF * MAX_ENDPOINT_PER_INTERFACE) + +/* +* Maximum number of transfer descriptors that can be allocated +*/ +#define MAX_TD (MAX_ENDPOINT*2) + +/* +* usb_thread stack size +*/ +#define USB_THREAD_STACK (256*4 + MAX_HUB_NB*256*4) + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/USBHost/USBHostTypes.h Mon Jan 27 11:00:28 2014 +0000 @@ -0,0 +1,165 @@ +/* mbed USBHost Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USB_INC_H +#define USB_INC_H + +#include "mbed.h" +#include "toolchain.h" + +enum USB_TYPE { + USB_TYPE_OK = 0, + + // completion code + USB_TYPE_CRC_ERROR = 1, + USB_TYPE_BIT_STUFFING_ERROR = 2, + USB_TYPE_DATA_TOGGLE_MISMATCH_ERROR = 3, + USB_TYPE_STALL_ERROR = 4, + USB_TYPE_DEVICE_NOT_RESPONDING_ERROR = 5, + USB_TYPE_PID_CHECK_FAILURE_ERROR = 6, + USB_TYPE_UNEXPECTED_PID_ERROR = 7, + USB_TYPE_DATA_OVERRUN_ERROR = 8, + USB_TYPE_DATA_UNDERRUN_ERROR = 9, + USB_TYPE_RESERVED = 9, + USB_TYPE_RESERVED_ = 10, + USB_TYPE_BUFFER_OVERRUN_ERROR = 12, + USB_TYPE_BUFFER_UNDERRUN_ERROR = 13, + + // general usb state + USB_TYPE_DISCONNECTED = 14, + USB_TYPE_FREE = 15, + USB_TYPE_IDLE = 16, + USB_TYPE_PROCESSING = 17, + + USB_TYPE_ERROR = 18, +}; + + +enum ENDPOINT_DIRECTION { + OUT = 1, + IN +}; + +enum ENDPOINT_TYPE { + CONTROL_ENDPOINT = 0, + ISOCHRONOUS_ENDPOINT, + BULK_ENDPOINT, + INTERRUPT_ENDPOINT +}; + +#define AUDIO_CLASS 0x01 +#define CDC_CLASS 0x02 +#define HID_CLASS 0x03 +#define MSD_CLASS 0x08 +#define HUB_CLASS 0x09 +#define SERIAL_CLASS 0x0A + +#define DEVICE_DESCRIPTOR (1) +#define CONFIGURATION_DESCRIPTOR (2) +#define INTERFACE_DESCRIPTOR (4) +#define ENDPOINT_DESCRIPTOR (5) +#define HID_DESCRIPTOR (33) + +// ----------- Control RequestType Fields ----------- +#define USB_DEVICE_TO_HOST 0x80 +#define USB_HOST_TO_DEVICE 0x00 +#define USB_REQUEST_TYPE_CLASS 0x20 +#define USB_REQUEST_TYPE_STANDARD 0x00 +#define USB_RECIPIENT_DEVICE 0x00 +#define USB_RECIPIENT_INTERFACE 0x01 +#define USB_RECIPIENT_ENDPOINT 0x02 + +// -------------- USB Standard Requests -------------- +#define SET_ADDRESS 0x05 +#define GET_DESCRIPTOR 0x06 +#define SET_CONFIGURATION 0x09 +#define SET_INTERFACE 0x0b +#define CLEAR_FEATURE 0x01 + +// -------------- USB Descriptor Length -------------- +#define DEVICE_DESCRIPTOR_LENGTH 0x12 +#define CONFIGURATION_DESCRIPTOR_LENGTH 0x09 + +// PID +#define DATA0 0x03 +#define DATA1 0x0b +#define ACK 0x02 +#define STALL 0x0e +#define NAK 0x0a + +#pragma pack(push,1) +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} PACKED DeviceDescriptor; + +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +} PACKED ConfigurationDescriptor; + +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} InterfaceDescriptor; + +typedef struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} EndpointDescriptor; + +typedef struct { + uint8_t bDescLength; + uint8_t bDescriptorType; + uint8_t bNbrPorts; + uint16_t wHubCharacteristics; + uint8_t bPwrOn2PwrGood; + uint8_t bHubContrCurrent; + uint8_t DeviceRemovable; + uint8_t PortPweCtrlMak; +} HubDescriptor; +#pragma pack(pop) + +#endif