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