Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: F401RE-USBHostMIDI_RecieveExample
Fork of F401RE-USBHost by
Diff: USBHost.cpp
- Revision:
- 1:c072d9e580b0
- Parent:
- 0:5160ee0c522d
- Child:
- 2:0cdac6bcc534
diff -r 5160ee0c522d -r c072d9e580b0 USBHost.cpp
--- a/USBHost.cpp Sat Jan 18 13:30:22 2014 +0000
+++ b/USBHost.cpp Tue Jan 21 08:59:28 2014 +0000
@@ -6,9 +6,16 @@
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);
-#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)
+#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))
@@ -38,6 +45,9 @@
address = (uint32_t)buf;
byte_count = size;
}
+ uint8_t getStatus() {
+ return (info>>2)&0x0f;
+ }
};
__attribute__((__aligned__(512))) BDT bdt[64];
@@ -55,6 +65,8 @@
USBHost::USBHost() {
inst = this;
+ memset(rx_data01, DATA1, sizeof(rx_data01));
+ memset(tx_data01, DATA1, sizeof(tx_data01));
}
void USBHost::init() {
@@ -86,6 +98,8 @@
// 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
@@ -96,22 +110,27 @@
wait_attach();
- // Enable RESET
- USB0->CTL |= USB_CTL_RESET_MASK;
- wait_ms(10);
- USB0->CTL &= ~USB_CTL_RESET_MASK;
+ 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);
+ // 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;
+ // token transfer initialize
+ tx_ptr = ODD;
+ rx_ptr = ODD;
+ USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK;
- enumeration();
-
+ if (enumeration()) {
+ break;
+ }
+ USB_DBG("retry=%d", retry);
+ USB_TEST_ASSERT(retry > 1);
+ }
}
void USBHost::wait_attach() {
@@ -120,34 +139,60 @@
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;
+ lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true;
+ if (lowSpeed) { // low speed
+ USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK;
}
- USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK;
+ USB_DBG("lowSpeed=%d", lowSpeed);
}
-void USBHost::enumeration() {
- uint8_t desc[18];
+bool USBHost::enumeration() {
+ uint8_t desc[64];
MaxPacketSize0 = 8;
+ dev_addr = 0;
+ USB0->ADDR = (lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(dev_addr);
+ wait_ms(100);
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);
+ if (result < 8) {
+ USB_DBG("result=%d %02x", result, LastStatus);
+ return false;
+ }
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);
+
result = ControlRead(&setup_get_descriptor, desc, sizeof(desc));
- USB_TEST_ASSERT(result == sizeof(desc));
- USB_DBG_HEX(desc, sizeof(desc));
+ if (result < 8) {
+ USB_DBG("result=%d", result);
+ return false;
+ }
+ USB_DBG_HEX(desc, result);
setup_get_descriptor.wValue = 2<<8; // config descriptor
result = ControlRead(&setup_get_descriptor, desc, 4);
- USB_TEST_ASSERT(result == 4);
+ if (result != 4) {
+ USB_DBG("result=%d", result);
+ return false;
+ }
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);
+ if (result != TotalLength) {
+ USB_DBG("result=%d TotalLength=%d %02x", result, TotalLength, LastStatus);
+ return false;
+ }
USB_DBG_HEX(buf, TotalLength);
for(int i = 0; i < TotalLength; ) {
@@ -173,97 +218,197 @@
}
delete[] buf;
- SETUP_PACKET setup_set_config = {0x00, SET_CONFIGURATION, 1, 0, 0}; // config = 1
- ControlWrite(&setup_set_config);
+ // 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);
+ if (lowSpeed && LastStatus == STALL) { // TODO:
+ wait_ms(100);
+ return true;
+ }
+ return false;
+ }
+ wait_ms(100);
+ return true;
}
int USBHost::ControlRead(SETUP_PACKET* setup, uint8_t* data, int size) {
token_setup(setup, size); // setup stage
+ USB_DBG("setup %02x", LastStatus);
+ if (LastStatus != ACK && lowSpeed == false) {
+ return -1;
+ }
+ rx_data01[0] = DATA1;
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);
+ USB_DBG("token_in result=%d %02x", result, LastStatus);
+ if (result < 0) {
+ if (LastStatus == NAK || LastStatus == Bus_Timeout) {
+ break;
+ }
+ return result;
+ }
read_len += result;
if (result < MaxPacketSize0) {
break;
}
}
- token_out(0); // status stage
+ tx_data01[0] = rx_data01[0];
+ int result = token_out(0); // 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) {
- token_setup(setup, size); // setup stage
- int result = 0;
+ if (token_setup(setup, size) != ACK) { // setup stage
+ return -1;
+ }
+ tx_data01[0] = DATA1;
+ int write_len = 0;
if (data != NULL) {
- result = token_out(0, data, size);
+ write_len = token_out(0, data, size);
+ if (write_len < 0) {
+ return -1;
+ }
}
- token_in(0); // status stage
- return result;
+ rx_data01[0] = tx_data01[0];
+ int result = token_in(0); // status stage
+ if (result < 0) {
+ return result;
+ }
+ return write_len;
}
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;
+ 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);
}
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);
+ token_ready();
+ USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPCTLDIS_MASK|
+ USB_ENDPT_EPRXEN_MASK|
+ USB_ENDPT_EPHSHK_MASK;
+ const int max_packet_size = 64;
+ int read_len = 0;
+ while(read_len < size) {
+ int size2 = std::min(size-read_len, max_packet_size);
+ int result = token_in(ep_bulk_in & 0x7f, data+read_len, size2);
+ if (result < 0) {
+ //USB_DBG("token_in result=%d %02x", result, LastStatus);
+ return result;
+ }
+ read_len += result;
+ if (result < max_packet_size) {
+ break;
+ }
+ }
+ return read_len;
}
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);
+ token_ready();
+ USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPCTLDIS_MASK|
+ USB_ENDPT_EPTXEN_MASK|
+ USB_ENDPT_EPHSHK_MASK;
+ const int max_packet_size = 64;
+ int write_len = 0;
+ while(write_len < size) {
+ int size2 = std::min(size-write_len, max_packet_size);
+ int result = token_out(ep_bulk_out, data+write_len, size2);
+ if (result < 0) {
+ //USB_DBG("token_in result=%d %02x", result, LastStatus);
+ return result;
+ }
+ write_len += result;
+ if (result < max_packet_size) {
+ break;
+ }
+ }
+ return write_len;
}
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;
+ 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;
+ 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);
- return (bdt[idx].info>>2)&0x0f;
+ 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_DATA01_MASK;
+ 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_DATA01_MASK;
+ 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);
- return bdt[idx].byte_count;
+ 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) {
@@ -276,10 +421,11 @@
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 = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
+ tx_ptr = next_ptr;
} else {
- rx_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
+ rx_ptr = next_ptr;
}
token_done = true;
}
