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
USBHost/USBHALHost.cpp@5:10bfc10afcc8, 2014-01-27 (annotated)
- Committer:
- va009039
- Date:
- Mon Jan 27 11:00:28 2014 +0000
- Revision:
- 5:10bfc10afcc8
add isochronous transfer
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
va009039 | 5:10bfc10afcc8 | 1 | // Simple USBHost for FRDM-KL46Z |
va009039 | 5:10bfc10afcc8 | 2 | #include "USBHALHost.h" |
va009039 | 5:10bfc10afcc8 | 3 | #include <algorithm> |
va009039 | 5:10bfc10afcc8 | 4 | |
va009039 | 5:10bfc10afcc8 | 5 | template <bool>struct CtAssert; |
va009039 | 5:10bfc10afcc8 | 6 | template <>struct CtAssert<true> {}; |
va009039 | 5:10bfc10afcc8 | 7 | #define CTASSERT(A) CtAssert<A>(); |
va009039 | 5:10bfc10afcc8 | 8 | |
va009039 | 5:10bfc10afcc8 | 9 | |
va009039 | 5:10bfc10afcc8 | 10 | #ifdef _USB_DBG |
va009039 | 5:10bfc10afcc8 | 11 | #define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");} while(0); |
va009039 | 5:10bfc10afcc8 | 12 | #define USB_DBG_HEX(A,B) debug_hex(A,B) |
va009039 | 5:10bfc10afcc8 | 13 | void debug_hex(uint8_t* buf, int size); |
va009039 | 5:10bfc10afcc8 | 14 | #else |
va009039 | 5:10bfc10afcc8 | 15 | #define USB_DBG(...) while(0) |
va009039 | 5:10bfc10afcc8 | 16 | #define USB_DBG_HEX(A,B) while(0) |
va009039 | 5:10bfc10afcc8 | 17 | #endif |
va009039 | 5:10bfc10afcc8 | 18 | |
va009039 | 5:10bfc10afcc8 | 19 | #define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);}; |
va009039 | 5:10bfc10afcc8 | 20 | #define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A)) |
va009039 | 5:10bfc10afcc8 | 21 | |
va009039 | 5:10bfc10afcc8 | 22 | #define BD_OWN_MASK (1<<7) |
va009039 | 5:10bfc10afcc8 | 23 | #define BD_DATA01_MASK (1<<6) |
va009039 | 5:10bfc10afcc8 | 24 | #define BD_KEEP_MASK (1<<5) |
va009039 | 5:10bfc10afcc8 | 25 | #define BD_NINC_MASK (1<<4) |
va009039 | 5:10bfc10afcc8 | 26 | #define BD_DTS_MASK (1<<3) |
va009039 | 5:10bfc10afcc8 | 27 | #define BD_STALL_MASK (1<<2) |
va009039 | 5:10bfc10afcc8 | 28 | |
va009039 | 5:10bfc10afcc8 | 29 | #define TX 1 |
va009039 | 5:10bfc10afcc8 | 30 | #define RX 0 |
va009039 | 5:10bfc10afcc8 | 31 | |
va009039 | 5:10bfc10afcc8 | 32 | #define EP0_BDT_IDX(dir, odd) (((2 * dir) + (1 * odd))) |
va009039 | 5:10bfc10afcc8 | 33 | |
va009039 | 5:10bfc10afcc8 | 34 | #define SETUP_TOKEN 0x0D |
va009039 | 5:10bfc10afcc8 | 35 | #define IN_TOKEN 0x09 |
va009039 | 5:10bfc10afcc8 | 36 | #define OUT_TOKEN 0x01 |
va009039 | 5:10bfc10afcc8 | 37 | |
va009039 | 5:10bfc10afcc8 | 38 | // for each endpt: 8 bytes |
va009039 | 5:10bfc10afcc8 | 39 | struct BDT { |
va009039 | 5:10bfc10afcc8 | 40 | uint8_t info; // BD[0:7] |
va009039 | 5:10bfc10afcc8 | 41 | uint8_t dummy; // RSVD: BD[8:15] |
va009039 | 5:10bfc10afcc8 | 42 | uint16_t byte_count; // BD[16:32] |
va009039 | 5:10bfc10afcc8 | 43 | uint32_t address; // Addr |
va009039 | 5:10bfc10afcc8 | 44 | void setBuffer(uint8_t* buf, int size) { |
va009039 | 5:10bfc10afcc8 | 45 | address = (uint32_t)buf; |
va009039 | 5:10bfc10afcc8 | 46 | byte_count = size; |
va009039 | 5:10bfc10afcc8 | 47 | } |
va009039 | 5:10bfc10afcc8 | 48 | uint8_t getStatus() { |
va009039 | 5:10bfc10afcc8 | 49 | return (info>>2)&0x0f; |
va009039 | 5:10bfc10afcc8 | 50 | } |
va009039 | 5:10bfc10afcc8 | 51 | }; |
va009039 | 5:10bfc10afcc8 | 52 | |
va009039 | 5:10bfc10afcc8 | 53 | __attribute__((__aligned__(512))) BDT bdt[64]; |
va009039 | 5:10bfc10afcc8 | 54 | |
va009039 | 5:10bfc10afcc8 | 55 | USBHALHost* USBHALHost::instHost; |
va009039 | 5:10bfc10afcc8 | 56 | |
va009039 | 5:10bfc10afcc8 | 57 | USBHALHost::USBHALHost() { |
va009039 | 5:10bfc10afcc8 | 58 | instHost = this; |
va009039 | 5:10bfc10afcc8 | 59 | report.clear(); |
va009039 | 5:10bfc10afcc8 | 60 | } |
va009039 | 5:10bfc10afcc8 | 61 | |
va009039 | 5:10bfc10afcc8 | 62 | void USBHALHost::init() { |
va009039 | 5:10bfc10afcc8 | 63 | // Disable IRQ |
va009039 | 5:10bfc10afcc8 | 64 | NVIC_DisableIRQ(USB0_IRQn); |
va009039 | 5:10bfc10afcc8 | 65 | |
va009039 | 5:10bfc10afcc8 | 66 | // choose usb src as PLL |
va009039 | 5:10bfc10afcc8 | 67 | SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK); |
va009039 | 5:10bfc10afcc8 | 68 | |
va009039 | 5:10bfc10afcc8 | 69 | // enable OTG clock |
va009039 | 5:10bfc10afcc8 | 70 | SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK; |
va009039 | 5:10bfc10afcc8 | 71 | |
va009039 | 5:10bfc10afcc8 | 72 | // USB Module Configuration |
va009039 | 5:10bfc10afcc8 | 73 | // Reset USB Module |
va009039 | 5:10bfc10afcc8 | 74 | USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK; |
va009039 | 5:10bfc10afcc8 | 75 | while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK); |
va009039 | 5:10bfc10afcc8 | 76 | |
va009039 | 5:10bfc10afcc8 | 77 | // Clear interrupt flag |
va009039 | 5:10bfc10afcc8 | 78 | USB0->ISTAT = 0xff; |
va009039 | 5:10bfc10afcc8 | 79 | |
va009039 | 5:10bfc10afcc8 | 80 | // Set BDT Base Register |
va009039 | 5:10bfc10afcc8 | 81 | USB0->BDTPAGE1=(uint8_t)((uint32_t)bdt>>8); |
va009039 | 5:10bfc10afcc8 | 82 | USB0->BDTPAGE2=(uint8_t)((uint32_t)bdt>>16); |
va009039 | 5:10bfc10afcc8 | 83 | USB0->BDTPAGE3=(uint8_t)((uint32_t)bdt>>24); |
va009039 | 5:10bfc10afcc8 | 84 | |
va009039 | 5:10bfc10afcc8 | 85 | // Set SOF threshold |
va009039 | 5:10bfc10afcc8 | 86 | USB0->SOFTHLD = USB_SOFTHLD_CNT(1); |
va009039 | 5:10bfc10afcc8 | 87 | |
va009039 | 5:10bfc10afcc8 | 88 | // pulldown D+ and D- |
va009039 | 5:10bfc10afcc8 | 89 | USB0->USBCTRL = USB_USBCTRL_PDE_MASK; |
va009039 | 5:10bfc10afcc8 | 90 | |
va009039 | 5:10bfc10afcc8 | 91 | USB0->USBTRC0 |= 0x40; |
va009039 | 5:10bfc10afcc8 | 92 | |
va009039 | 5:10bfc10afcc8 | 93 | // Host mode |
va009039 | 5:10bfc10afcc8 | 94 | USB0->CTL |= USB_CTL_HOSTMODEEN_MASK; |
va009039 | 5:10bfc10afcc8 | 95 | // Desable SOF packet generation |
va009039 | 5:10bfc10afcc8 | 96 | USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK; |
va009039 | 5:10bfc10afcc8 | 97 | |
va009039 | 5:10bfc10afcc8 | 98 | NVIC_SetVector(USB0_IRQn, (uint32_t)_usbisr); |
va009039 | 5:10bfc10afcc8 | 99 | NVIC_EnableIRQ(USB0_IRQn); |
va009039 | 5:10bfc10afcc8 | 100 | |
va009039 | 5:10bfc10afcc8 | 101 | wait_attach(); |
va009039 | 5:10bfc10afcc8 | 102 | |
va009039 | 5:10bfc10afcc8 | 103 | for(int retry = 2; retry > 0; retry--) { |
va009039 | 5:10bfc10afcc8 | 104 | // Enable RESET |
va009039 | 5:10bfc10afcc8 | 105 | USB0->CTL |= USB_CTL_RESET_MASK; |
va009039 | 5:10bfc10afcc8 | 106 | wait_ms(500); |
va009039 | 5:10bfc10afcc8 | 107 | USB0->CTL &= ~USB_CTL_RESET_MASK; |
va009039 | 5:10bfc10afcc8 | 108 | |
va009039 | 5:10bfc10afcc8 | 109 | // Enable SOF |
va009039 | 5:10bfc10afcc8 | 110 | USB0->CTL |= USB_CTL_USBENSOFEN_MASK; |
va009039 | 5:10bfc10afcc8 | 111 | wait_ms(100); |
va009039 | 5:10bfc10afcc8 | 112 | |
va009039 | 5:10bfc10afcc8 | 113 | // token transfer initialize |
va009039 | 5:10bfc10afcc8 | 114 | token_transfer_init(); |
va009039 | 5:10bfc10afcc8 | 115 | |
va009039 | 5:10bfc10afcc8 | 116 | USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK| |
va009039 | 5:10bfc10afcc8 | 117 | USB_INTEN_ERROREN_MASK; |
va009039 | 5:10bfc10afcc8 | 118 | USB0->ERREN |= USB_ERREN_PIDERREN_MASK| |
va009039 | 5:10bfc10afcc8 | 119 | USB_ERREN_CRC5EOFEN_MASK| |
va009039 | 5:10bfc10afcc8 | 120 | USB_ERREN_CRC16EN_MASK| |
va009039 | 5:10bfc10afcc8 | 121 | USB_ERREN_DFN8EN_MASK| |
va009039 | 5:10bfc10afcc8 | 122 | USB_ERREN_BTOERREN_MASK| |
va009039 | 5:10bfc10afcc8 | 123 | USB_ERREN_DMAERREN_MASK| |
va009039 | 5:10bfc10afcc8 | 124 | USB_ERREN_BTSERREN_MASK; |
va009039 | 5:10bfc10afcc8 | 125 | |
va009039 | 5:10bfc10afcc8 | 126 | if (enumeration()) { |
va009039 | 5:10bfc10afcc8 | 127 | break; |
va009039 | 5:10bfc10afcc8 | 128 | } |
va009039 | 5:10bfc10afcc8 | 129 | USB_DBG("retry=%d", retry); |
va009039 | 5:10bfc10afcc8 | 130 | USB_TEST_ASSERT(retry > 1); |
va009039 | 5:10bfc10afcc8 | 131 | } |
va009039 | 5:10bfc10afcc8 | 132 | } |
va009039 | 5:10bfc10afcc8 | 133 | |
va009039 | 5:10bfc10afcc8 | 134 | void USBHALHost::wait_attach() { |
va009039 | 5:10bfc10afcc8 | 135 | attach_done = false; |
va009039 | 5:10bfc10afcc8 | 136 | USB0->INTEN = USB_INTEN_ATTACHEN_MASK; |
va009039 | 5:10bfc10afcc8 | 137 | while(!attach_done); |
va009039 | 5:10bfc10afcc8 | 138 | wait_ms(100); |
va009039 | 5:10bfc10afcc8 | 139 | USB_TEST_ASSERT_FALSE(USB0->CTL & USB_CTL_SE0_MASK); |
va009039 | 5:10bfc10afcc8 | 140 | lowSpeed = (USB0->CTL & USB_CTL_JSTATE_MASK) ? false : true; |
va009039 | 5:10bfc10afcc8 | 141 | if (lowSpeed) { // low speed |
va009039 | 5:10bfc10afcc8 | 142 | USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK; |
va009039 | 5:10bfc10afcc8 | 143 | } |
va009039 | 5:10bfc10afcc8 | 144 | USB_DBG("lowSpeed=%d", lowSpeed); |
va009039 | 5:10bfc10afcc8 | 145 | } |
va009039 | 5:10bfc10afcc8 | 146 | |
va009039 | 5:10bfc10afcc8 | 147 | void USBHALHost::setAddr(int _addr) { |
va009039 | 5:10bfc10afcc8 | 148 | USB0->ADDR = (lowSpeed ? USB_ADDR_LSEN_MASK : 0x00) | USB_ADDR_ADDR(_addr); |
va009039 | 5:10bfc10afcc8 | 149 | } |
va009039 | 5:10bfc10afcc8 | 150 | |
va009039 | 5:10bfc10afcc8 | 151 | void USBHALHost::setEndpoint(bool use_retry) { |
va009039 | 5:10bfc10afcc8 | 152 | USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00)| |
va009039 | 5:10bfc10afcc8 | 153 | USB_ENDPT_EPCTLDIS_MASK| |
va009039 | 5:10bfc10afcc8 | 154 | (use_retry ? 0x00 : USB_ENDPT_RETRYDIS_MASK)| |
va009039 | 5:10bfc10afcc8 | 155 | USB_ENDPT_EPRXEN_MASK| |
va009039 | 5:10bfc10afcc8 | 156 | USB_ENDPT_EPTXEN_MASK| |
va009039 | 5:10bfc10afcc8 | 157 | USB_ENDPT_EPHSHK_MASK; |
va009039 | 5:10bfc10afcc8 | 158 | } |
va009039 | 5:10bfc10afcc8 | 159 | |
va009039 | 5:10bfc10afcc8 | 160 | void USBHALHost::token_transfer_init() { |
va009039 | 5:10bfc10afcc8 | 161 | tx_ptr = ODD; |
va009039 | 5:10bfc10afcc8 | 162 | rx_ptr = ODD; |
va009039 | 5:10bfc10afcc8 | 163 | } |
va009039 | 5:10bfc10afcc8 | 164 | |
va009039 | 5:10bfc10afcc8 | 165 | int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) { |
va009039 | 5:10bfc10afcc8 | 166 | for(int retry = 0;; retry++) { |
va009039 | 5:10bfc10afcc8 | 167 | token_ready(); |
va009039 | 5:10bfc10afcc8 | 168 | USB0->ENDPOINT[0].ENDPT = (lowSpeed ? USB_ENDPT_HOSTWOHUB_MASK : 0x00) | |
va009039 | 5:10bfc10afcc8 | 169 | USB_ENDPT_RETRYDIS_MASK| |
va009039 | 5:10bfc10afcc8 | 170 | USB_ENDPT_EPRXEN_MASK| |
va009039 | 5:10bfc10afcc8 | 171 | USB_ENDPT_EPTXEN_MASK| |
va009039 | 5:10bfc10afcc8 | 172 | USB_ENDPT_EPHSHK_MASK; |
va009039 | 5:10bfc10afcc8 | 173 | CTASSERT(sizeof(SETUP_PACKET) == 8); |
va009039 | 5:10bfc10afcc8 | 174 | setup->wLength = wLength; |
va009039 | 5:10bfc10afcc8 | 175 | int idx = EP0_BDT_IDX(TX, tx_ptr); |
va009039 | 5:10bfc10afcc8 | 176 | bdt[idx].setBuffer((uint8_t*)setup, sizeof(SETUP_PACKET)); |
va009039 | 5:10bfc10afcc8 | 177 | bdt[idx].info = BD_OWN_MASK | |
va009039 | 5:10bfc10afcc8 | 178 | BD_DTS_MASK; // always data0 |
va009039 | 5:10bfc10afcc8 | 179 | token_done = false; |
va009039 | 5:10bfc10afcc8 | 180 | USB0->TOKEN = USB_TOKEN_TOKENPID(SETUP_TOKEN)| |
va009039 | 5:10bfc10afcc8 | 181 | USB_TOKEN_TOKENENDPT(ep->getAddress() & 0x7f); |
va009039 | 5:10bfc10afcc8 | 182 | while(!token_done); |
va009039 | 5:10bfc10afcc8 | 183 | LastStatus = bdt[idx].getStatus(); |
va009039 | 5:10bfc10afcc8 | 184 | if (LastStatus == ACK) { |
va009039 | 5:10bfc10afcc8 | 185 | if (retry > 0) { |
va009039 | 5:10bfc10afcc8 | 186 | USB_DBG("retry=%d %02x", retry, prev_LastStatus); |
va009039 | 5:10bfc10afcc8 | 187 | } |
va009039 | 5:10bfc10afcc8 | 188 | break; |
va009039 | 5:10bfc10afcc8 | 189 | } else if (LastStatus == STALL) { |
va009039 | 5:10bfc10afcc8 | 190 | report.stall++; |
va009039 | 5:10bfc10afcc8 | 191 | return STALL; |
va009039 | 5:10bfc10afcc8 | 192 | } |
va009039 | 5:10bfc10afcc8 | 193 | if (retry > 10) { |
va009039 | 5:10bfc10afcc8 | 194 | USB_DBG("retry=%d", retry); |
va009039 | 5:10bfc10afcc8 | 195 | break; |
va009039 | 5:10bfc10afcc8 | 196 | } |
va009039 | 5:10bfc10afcc8 | 197 | prev_LastStatus = LastStatus; |
va009039 | 5:10bfc10afcc8 | 198 | wait_ms(100 * retry); |
va009039 | 5:10bfc10afcc8 | 199 | } |
va009039 | 5:10bfc10afcc8 | 200 | ep->setData01(DATA1); // next toggle |
va009039 | 5:10bfc10afcc8 | 201 | return LastStatus; |
va009039 | 5:10bfc10afcc8 | 202 | } |
va009039 | 5:10bfc10afcc8 | 203 | |
va009039 | 5:10bfc10afcc8 | 204 | int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) { |
va009039 | 5:10bfc10afcc8 | 205 | for(int retry = 0;; retry++) { |
va009039 | 5:10bfc10afcc8 | 206 | token_ready(); |
va009039 | 5:10bfc10afcc8 | 207 | int idx = EP0_BDT_IDX(RX, rx_ptr); |
va009039 | 5:10bfc10afcc8 | 208 | bdt[idx].setBuffer(data, size); |
va009039 | 5:10bfc10afcc8 | 209 | bdt[idx].info = BD_OWN_MASK| |
va009039 | 5:10bfc10afcc8 | 210 | BD_DTS_MASK| |
va009039 | 5:10bfc10afcc8 | 211 | (ep->getData01() == DATA1 ? BD_DATA01_MASK : 0); |
va009039 | 5:10bfc10afcc8 | 212 | token_done = false; |
va009039 | 5:10bfc10afcc8 | 213 | USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)| |
va009039 | 5:10bfc10afcc8 | 214 | USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f); |
va009039 | 5:10bfc10afcc8 | 215 | while(!token_done); |
va009039 | 5:10bfc10afcc8 | 216 | LastStatus = bdt[idx].getStatus(); |
va009039 | 5:10bfc10afcc8 | 217 | int len = bdt[idx].byte_count; |
va009039 | 5:10bfc10afcc8 | 218 | if (LastStatus == DATA0 || LastStatus == DATA1) { |
va009039 | 5:10bfc10afcc8 | 219 | USB_TEST_ASSERT(ep->getData01() == LastStatus); |
va009039 | 5:10bfc10afcc8 | 220 | ep->setData01(LastStatus == DATA0 ? DATA1 : DATA0); |
va009039 | 5:10bfc10afcc8 | 221 | if (retry > 0) { |
va009039 | 5:10bfc10afcc8 | 222 | USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); |
va009039 | 5:10bfc10afcc8 | 223 | } |
va009039 | 5:10bfc10afcc8 | 224 | return len; |
va009039 | 5:10bfc10afcc8 | 225 | } else if (LastStatus == STALL) { |
va009039 | 5:10bfc10afcc8 | 226 | report.stall++; |
va009039 | 5:10bfc10afcc8 | 227 | return -1; |
va009039 | 5:10bfc10afcc8 | 228 | } else if (LastStatus == NAK) { |
va009039 | 5:10bfc10afcc8 | 229 | report.nak++; |
va009039 | 5:10bfc10afcc8 | 230 | if (retry >= retryLimit) { |
va009039 | 5:10bfc10afcc8 | 231 | if (retryLimit > 0) { |
va009039 | 5:10bfc10afcc8 | 232 | USB_DBG("retry=%d retryLimit=%d", retry, retryLimit); |
va009039 | 5:10bfc10afcc8 | 233 | } |
va009039 | 5:10bfc10afcc8 | 234 | return -1; |
va009039 | 5:10bfc10afcc8 | 235 | } |
va009039 | 5:10bfc10afcc8 | 236 | wait_ms(100 * retry); |
va009039 | 5:10bfc10afcc8 | 237 | } else { |
va009039 | 5:10bfc10afcc8 | 238 | return -1; |
va009039 | 5:10bfc10afcc8 | 239 | } |
va009039 | 5:10bfc10afcc8 | 240 | prev_LastStatus = LastStatus; |
va009039 | 5:10bfc10afcc8 | 241 | } |
va009039 | 5:10bfc10afcc8 | 242 | } |
va009039 | 5:10bfc10afcc8 | 243 | |
va009039 | 5:10bfc10afcc8 | 244 | int USBHALHost::token_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) { |
va009039 | 5:10bfc10afcc8 | 245 | for(int retry = 0;; retry++) { |
va009039 | 5:10bfc10afcc8 | 246 | token_ready(); |
va009039 | 5:10bfc10afcc8 | 247 | int idx = EP0_BDT_IDX(TX, tx_ptr); |
va009039 | 5:10bfc10afcc8 | 248 | bdt[idx].setBuffer((uint8_t*)data, size); |
va009039 | 5:10bfc10afcc8 | 249 | bdt[idx].info = BD_OWN_MASK| |
va009039 | 5:10bfc10afcc8 | 250 | BD_DTS_MASK| |
va009039 | 5:10bfc10afcc8 | 251 | (ep->getData01() == DATA1 ? BD_DATA01_MASK : 0); |
va009039 | 5:10bfc10afcc8 | 252 | token_done = false; |
va009039 | 5:10bfc10afcc8 | 253 | USB0->TOKEN = USB_TOKEN_TOKENPID(OUT_TOKEN)| |
va009039 | 5:10bfc10afcc8 | 254 | USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f); |
va009039 | 5:10bfc10afcc8 | 255 | while(!token_done); |
va009039 | 5:10bfc10afcc8 | 256 | LastStatus = bdt[idx].getStatus(); |
va009039 | 5:10bfc10afcc8 | 257 | int len = bdt[idx].byte_count; |
va009039 | 5:10bfc10afcc8 | 258 | //USB_DBG("len=%d %02x", len, LastStatus); |
va009039 | 5:10bfc10afcc8 | 259 | if (LastStatus == ACK) { |
va009039 | 5:10bfc10afcc8 | 260 | ep->toggleData01(); |
va009039 | 5:10bfc10afcc8 | 261 | if (retry > 0) { |
va009039 | 5:10bfc10afcc8 | 262 | USB_DBG("len=%d retry=%d %02x", len, retry, prev_LastStatus); |
va009039 | 5:10bfc10afcc8 | 263 | } |
va009039 | 5:10bfc10afcc8 | 264 | return len; |
va009039 | 5:10bfc10afcc8 | 265 | } else if (LastStatus == STALL) { |
va009039 | 5:10bfc10afcc8 | 266 | report.stall++; |
va009039 | 5:10bfc10afcc8 | 267 | return -1; |
va009039 | 5:10bfc10afcc8 | 268 | } else if (LastStatus == NAK) { |
va009039 | 5:10bfc10afcc8 | 269 | report.nak++; |
va009039 | 5:10bfc10afcc8 | 270 | if (retry > retryLimit) { |
va009039 | 5:10bfc10afcc8 | 271 | USB_DBG("retry=%d retryLimit=%d", retry, retryLimit); |
va009039 | 5:10bfc10afcc8 | 272 | return -1; |
va009039 | 5:10bfc10afcc8 | 273 | } |
va009039 | 5:10bfc10afcc8 | 274 | wait_ms(100 * retry); |
va009039 | 5:10bfc10afcc8 | 275 | } else { |
va009039 | 5:10bfc10afcc8 | 276 | return -1; |
va009039 | 5:10bfc10afcc8 | 277 | } |
va009039 | 5:10bfc10afcc8 | 278 | prev_LastStatus = LastStatus; |
va009039 | 5:10bfc10afcc8 | 279 | } |
va009039 | 5:10bfc10afcc8 | 280 | } |
va009039 | 5:10bfc10afcc8 | 281 | |
va009039 | 5:10bfc10afcc8 | 282 | int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) { |
va009039 | 5:10bfc10afcc8 | 283 | while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK); // TOKEN_BUSY ? |
va009039 | 5:10bfc10afcc8 | 284 | USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF |
va009039 | 5:10bfc10afcc8 | 285 | while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK)); |
va009039 | 5:10bfc10afcc8 | 286 | USB0->SOFTHLD = 0; // this is needed as without this you can get errors |
va009039 | 5:10bfc10afcc8 | 287 | USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF |
va009039 | 5:10bfc10afcc8 | 288 | |
va009039 | 5:10bfc10afcc8 | 289 | USB0->ENDPOINT[0].ENDPT = USB_ENDPT_EPCTLDIS_MASK| |
va009039 | 5:10bfc10afcc8 | 290 | USB_ENDPT_RETRYDIS_MASK| |
va009039 | 5:10bfc10afcc8 | 291 | USB_ENDPT_EPRXEN_MASK| |
va009039 | 5:10bfc10afcc8 | 292 | USB_ENDPT_EPTXEN_MASK; |
va009039 | 5:10bfc10afcc8 | 293 | int idx = EP0_BDT_IDX(RX, rx_ptr); |
va009039 | 5:10bfc10afcc8 | 294 | bdt[idx].setBuffer(data, size); |
va009039 | 5:10bfc10afcc8 | 295 | bdt[idx].info = BD_OWN_MASK| |
va009039 | 5:10bfc10afcc8 | 296 | BD_DTS_MASK; // always DATA0 |
va009039 | 5:10bfc10afcc8 | 297 | token_done = false; |
va009039 | 5:10bfc10afcc8 | 298 | USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)| |
va009039 | 5:10bfc10afcc8 | 299 | USB_TOKEN_TOKENENDPT(ep->getAddress()&0x7f); |
va009039 | 5:10bfc10afcc8 | 300 | while(!token_done); |
va009039 | 5:10bfc10afcc8 | 301 | LastStatus = bdt[idx].getStatus(); |
va009039 | 5:10bfc10afcc8 | 302 | int len = bdt[idx].byte_count; |
va009039 | 5:10bfc10afcc8 | 303 | if (LastStatus == DATA0) { |
va009039 | 5:10bfc10afcc8 | 304 | return len; |
va009039 | 5:10bfc10afcc8 | 305 | } |
va009039 | 5:10bfc10afcc8 | 306 | return -1; |
va009039 | 5:10bfc10afcc8 | 307 | } |
va009039 | 5:10bfc10afcc8 | 308 | |
va009039 | 5:10bfc10afcc8 | 309 | void USBHALHost::token_ready() { |
va009039 | 5:10bfc10afcc8 | 310 | while(USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) { // TOKEN_BUSY ? |
va009039 | 5:10bfc10afcc8 | 311 | wait_ms(1); |
va009039 | 5:10bfc10afcc8 | 312 | } |
va009039 | 5:10bfc10afcc8 | 313 | USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // Clear SOF |
va009039 | 5:10bfc10afcc8 | 314 | while (!(USB0->ISTAT & USB_ISTAT_SOFTOK_MASK)); |
va009039 | 5:10bfc10afcc8 | 315 | USB0->SOFTHLD = 0; // this is needed as without this you can get errors |
va009039 | 5:10bfc10afcc8 | 316 | USB0->ISTAT |= USB_ISTAT_SOFTOK_MASK; // clear SOF |
va009039 | 5:10bfc10afcc8 | 317 | } |
va009039 | 5:10bfc10afcc8 | 318 | |
va009039 | 5:10bfc10afcc8 | 319 | void USBHALHost::_usbisr(void) { |
va009039 | 5:10bfc10afcc8 | 320 | if (instHost) { |
va009039 | 5:10bfc10afcc8 | 321 | instHost->UsbIrqhandler(); |
va009039 | 5:10bfc10afcc8 | 322 | } |
va009039 | 5:10bfc10afcc8 | 323 | } |
va009039 | 5:10bfc10afcc8 | 324 | |
va009039 | 5:10bfc10afcc8 | 325 | void USBHALHost::UsbIrqhandler() { |
va009039 | 5:10bfc10afcc8 | 326 | uint8_t istat = USB0->ISTAT; |
va009039 | 5:10bfc10afcc8 | 327 | if (istat & USB_ISTAT_TOKDNE_MASK) { |
va009039 | 5:10bfc10afcc8 | 328 | uint8_t stat = USB0->STAT; |
va009039 | 5:10bfc10afcc8 | 329 | ODD_EVEN next_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN; |
va009039 | 5:10bfc10afcc8 | 330 | if (stat & USB_STAT_TX_MASK) { |
va009039 | 5:10bfc10afcc8 | 331 | tx_ptr = next_ptr; |
va009039 | 5:10bfc10afcc8 | 332 | } else { |
va009039 | 5:10bfc10afcc8 | 333 | rx_ptr = next_ptr; |
va009039 | 5:10bfc10afcc8 | 334 | } |
va009039 | 5:10bfc10afcc8 | 335 | token_done = true; |
va009039 | 5:10bfc10afcc8 | 336 | } |
va009039 | 5:10bfc10afcc8 | 337 | if (istat & USB_ISTAT_ATTACH_MASK) { |
va009039 | 5:10bfc10afcc8 | 338 | USB0->INTEN &= ~USB_INTEN_ATTACHEN_MASK; |
va009039 | 5:10bfc10afcc8 | 339 | attach_done = true; |
va009039 | 5:10bfc10afcc8 | 340 | } |
va009039 | 5:10bfc10afcc8 | 341 | if (istat & USB_ISTAT_ERROR_MASK) { |
va009039 | 5:10bfc10afcc8 | 342 | uint8_t errstat = USB0->ERRSTAT; |
va009039 | 5:10bfc10afcc8 | 343 | if (errstat & USB_ERRSTAT_PIDERR_MASK) { |
va009039 | 5:10bfc10afcc8 | 344 | report.errstat_piderr++; |
va009039 | 5:10bfc10afcc8 | 345 | } |
va009039 | 5:10bfc10afcc8 | 346 | if (errstat & USB_ERRSTAT_CRC5EOF_MASK) { |
va009039 | 5:10bfc10afcc8 | 347 | report.errstat_crc5eof++; |
va009039 | 5:10bfc10afcc8 | 348 | } |
va009039 | 5:10bfc10afcc8 | 349 | if (errstat & USB_ERRSTAT_CRC16_MASK) { |
va009039 | 5:10bfc10afcc8 | 350 | report.errstat_crc16++; |
va009039 | 5:10bfc10afcc8 | 351 | } |
va009039 | 5:10bfc10afcc8 | 352 | if (errstat & USB_ERRSTAT_DFN8_MASK) { |
va009039 | 5:10bfc10afcc8 | 353 | report.errstat_dfn8++; |
va009039 | 5:10bfc10afcc8 | 354 | } |
va009039 | 5:10bfc10afcc8 | 355 | if (errstat & USB_ERRSTAT_BTOERR_MASK) { |
va009039 | 5:10bfc10afcc8 | 356 | report.errstat_btoerr++; |
va009039 | 5:10bfc10afcc8 | 357 | } |
va009039 | 5:10bfc10afcc8 | 358 | if (errstat & USB_ERRSTAT_DMAERR_MASK) { |
va009039 | 5:10bfc10afcc8 | 359 | report.errstat_dmaerr++; |
va009039 | 5:10bfc10afcc8 | 360 | } |
va009039 | 5:10bfc10afcc8 | 361 | if (errstat & USB_ERRSTAT_BTSERR_MASK) { |
va009039 | 5:10bfc10afcc8 | 362 | report.errstat_btoerr++; |
va009039 | 5:10bfc10afcc8 | 363 | } |
va009039 | 5:10bfc10afcc8 | 364 | USB0->ERRSTAT = errstat; |
va009039 | 5:10bfc10afcc8 | 365 | } |
va009039 | 5:10bfc10afcc8 | 366 | USB0->ISTAT = istat; // clear |
va009039 | 5:10bfc10afcc8 | 367 | } |
va009039 | 5:10bfc10afcc8 | 368 | |
va009039 | 5:10bfc10afcc8 | 369 | void Report::clear() { |
va009039 | 5:10bfc10afcc8 | 370 | errstat_piderr = 0; |
va009039 | 5:10bfc10afcc8 | 371 | errstat_crc5eof = 0; |
va009039 | 5:10bfc10afcc8 | 372 | errstat_crc16 = 0; |
va009039 | 5:10bfc10afcc8 | 373 | errstat_dfn8 = 0; |
va009039 | 5:10bfc10afcc8 | 374 | errstat_btoerr = 0; |
va009039 | 5:10bfc10afcc8 | 375 | errstat_dmaerr = 0; |
va009039 | 5:10bfc10afcc8 | 376 | errstat_bsterr = 0; |
va009039 | 5:10bfc10afcc8 | 377 | // |
va009039 | 5:10bfc10afcc8 | 378 | nak = 0; |
va009039 | 5:10bfc10afcc8 | 379 | } |
va009039 | 5:10bfc10afcc8 | 380 | |
va009039 | 5:10bfc10afcc8 | 381 | void Report::print_errstat() { |
va009039 | 5:10bfc10afcc8 | 382 | printf("ERRSTAT PID: %d, CRC5EOF: %d, CRC16: %d, DFN8: %d, BTO: %d, DMA: %d, BST: %d\n", |
va009039 | 5:10bfc10afcc8 | 383 | errstat_piderr, errstat_crc5eof, |
va009039 | 5:10bfc10afcc8 | 384 | errstat_crc16, errstat_dfn8, |
va009039 | 5:10bfc10afcc8 | 385 | errstat_btoerr, errstat_dmaerr, errstat_bsterr); |
va009039 | 5:10bfc10afcc8 | 386 | } |
va009039 | 5:10bfc10afcc8 | 387 | |
va009039 | 5:10bfc10afcc8 | 388 | void debug_hex(uint8_t* buf, int size) { |
va009039 | 5:10bfc10afcc8 | 389 | for(int i = 0; i < size; i++) { |
va009039 | 5:10bfc10afcc8 | 390 | fprintf(stderr, "%02x ", buf[i]); |
va009039 | 5:10bfc10afcc8 | 391 | if (i%16 == 15) { |
va009039 | 5:10bfc10afcc8 | 392 | fprintf(stderr, "\r\n"); |
va009039 | 5:10bfc10afcc8 | 393 | } |
va009039 | 5:10bfc10afcc8 | 394 | } |
va009039 | 5:10bfc10afcc8 | 395 | fprintf(stderr, "\r\n"); |
va009039 | 5:10bfc10afcc8 | 396 | } |
va009039 | 5:10bfc10afcc8 | 397 |