Simple USBHost library for Nucleo F446RE/F411RE/F401RE FRDM-KL46Z/KL25Z/F64F LPC4088/LPC1768

Dependencies:   FATFileSystem

Dependents:   F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld

Fork of KL46Z-USBHost by Norimasa Okamoto

簡易USBホストライブラリです。
official-USBHostの下位互換で対応プログラムを僅かな修正で動かすことが出来ます。

Platforms

  • Nucleo F446RE
  • Nucleo F411RE
  • Nucleo F401RE
  • FRDM-K64F
  • FRDM-KL46Z
  • FRDM-KL25Z
  • LPC4088
  • LPC1768

Nucleo F446RE/F411RE/F401REのUSB接続方法

ST morphoUSB
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

Committer:
va009039
Date:
Sat Jan 18 13:30:22 2014 +0000
Revision:
0:5160ee0c522d
Child:
1:c072d9e580b0
first commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
va009039 0:5160ee0c522d 1 // Simple USBHost for FRDM-KL46Z
va009039 0:5160ee0c522d 2 #include "USBHost.h"
va009039 0:5160ee0c522d 3 #include <algorithm>
va009039 0:5160ee0c522d 4
va009039 0:5160ee0c522d 5 template <bool>struct CtAssert;
va009039 0:5160ee0c522d 6 template <>struct CtAssert<true> {};
va009039 0:5160ee0c522d 7 #define CTASSERT(A) CtAssert<A>();
va009039 0:5160ee0c522d 8
va009039 0:5160ee0c522d 9 void debug_hex(uint8_t* buf, int size);
va009039 0:5160ee0c522d 10 #define USB_DBG(...) do{fprintf(stderr,"[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);fprintf(stderr,__VA_ARGS__);} while(0);
va009039 0:5160ee0c522d 11 #define USB_DBG_HEX(A,B) debug_hex(A,B)
va009039 0:5160ee0c522d 12 #define USB_TEST_ASSERT(A) while(!(A)){fprintf(stderr,"\n\n%s@%d %s ASSERT!\n\n",__PRETTY_FUNCTION__,__LINE__,#A);exit(1);};
va009039 0:5160ee0c522d 13 #define USB_TEST_ASSERT_FALSE(A) USB_TEST_ASSERT(!(A))
va009039 0:5160ee0c522d 14
va009039 0:5160ee0c522d 15 #define BD_OWN_MASK (1<<7)
va009039 0:5160ee0c522d 16 #define BD_DATA01_MASK (1<<6)
va009039 0:5160ee0c522d 17 #define BD_KEEP_MASK (1<<5)
va009039 0:5160ee0c522d 18 #define BD_NINC_MASK (1<<4)
va009039 0:5160ee0c522d 19 #define BD_DTS_MASK (1<<3)
va009039 0:5160ee0c522d 20 #define BD_STALL_MASK (1<<2)
va009039 0:5160ee0c522d 21
va009039 0:5160ee0c522d 22 #define TX 1
va009039 0:5160ee0c522d 23 #define RX 0
va009039 0:5160ee0c522d 24
va009039 0:5160ee0c522d 25 #define EP0_BDT_IDX(dir, odd) (((2 * dir) + (1 * odd)))
va009039 0:5160ee0c522d 26
va009039 0:5160ee0c522d 27 #define SETUP_TOKEN 0x0D
va009039 0:5160ee0c522d 28 #define IN_TOKEN 0x09
va009039 0:5160ee0c522d 29 #define OUT_TOKEN 0x01
va009039 0:5160ee0c522d 30
va009039 0:5160ee0c522d 31 // for each endpt: 8 bytes
va009039 0:5160ee0c522d 32 struct BDT {
va009039 0:5160ee0c522d 33 uint8_t info; // BD[0:7]
va009039 0:5160ee0c522d 34 uint8_t dummy; // RSVD: BD[8:15]
va009039 0:5160ee0c522d 35 uint16_t byte_count; // BD[16:32]
va009039 0:5160ee0c522d 36 uint32_t address; // Addr
va009039 0:5160ee0c522d 37 void setBuffer(uint8_t* buf, int size) {
va009039 0:5160ee0c522d 38 address = (uint32_t)buf;
va009039 0:5160ee0c522d 39 byte_count = size;
va009039 0:5160ee0c522d 40 }
va009039 0:5160ee0c522d 41 };
va009039 0:5160ee0c522d 42
va009039 0:5160ee0c522d 43 __attribute__((__aligned__(512))) BDT bdt[64];
va009039 0:5160ee0c522d 44
va009039 0:5160ee0c522d 45 USBHost* USBHost::inst = NULL;
va009039 0:5160ee0c522d 46
va009039 0:5160ee0c522d 47 USBHost* USBHost::getHostInst()
va009039 0:5160ee0c522d 48 {
va009039 0:5160ee0c522d 49 if (inst == NULL) {
va009039 0:5160ee0c522d 50 inst = new USBHost();
va009039 0:5160ee0c522d 51 inst->init();
va009039 0:5160ee0c522d 52 }
va009039 0:5160ee0c522d 53 return inst;
va009039 0:5160ee0c522d 54 }
va009039 0:5160ee0c522d 55
va009039 0:5160ee0c522d 56 USBHost::USBHost() {
va009039 0:5160ee0c522d 57 inst = this;
va009039 0:5160ee0c522d 58 }
va009039 0:5160ee0c522d 59
va009039 0:5160ee0c522d 60 void USBHost::init() {
va009039 0:5160ee0c522d 61 // Disable IRQ
va009039 0:5160ee0c522d 62 NVIC_DisableIRQ(USB0_IRQn);
va009039 0:5160ee0c522d 63
va009039 0:5160ee0c522d 64 // choose usb src as PLL
va009039 0:5160ee0c522d 65 SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL_MASK);
va009039 0:5160ee0c522d 66
va009039 0:5160ee0c522d 67 // enable OTG clock
va009039 0:5160ee0c522d 68 SIM->SCGC4 |= SIM_SCGC4_USBOTG_MASK;
va009039 0:5160ee0c522d 69
va009039 0:5160ee0c522d 70 // USB Module Configuration
va009039 0:5160ee0c522d 71 // Reset USB Module
va009039 0:5160ee0c522d 72 USB0->USBTRC0 |= USB_USBTRC0_USBRESET_MASK;
va009039 0:5160ee0c522d 73 while(USB0->USBTRC0 & USB_USBTRC0_USBRESET_MASK);
va009039 0:5160ee0c522d 74
va009039 0:5160ee0c522d 75 // Clear interrupt flag
va009039 0:5160ee0c522d 76 USB0->ISTAT = 0xff;
va009039 0:5160ee0c522d 77
va009039 0:5160ee0c522d 78 // Set BDT Base Register
va009039 0:5160ee0c522d 79 USB0->BDTPAGE1=(uint8_t)((uint32_t)bdt>>8);
va009039 0:5160ee0c522d 80 USB0->BDTPAGE2=(uint8_t)((uint32_t)bdt>>16);
va009039 0:5160ee0c522d 81 USB0->BDTPAGE3=(uint8_t)((uint32_t)bdt>>24);
va009039 0:5160ee0c522d 82
va009039 0:5160ee0c522d 83 // Set SOF threshold
va009039 0:5160ee0c522d 84 USB0->SOFTHLD = USB_SOFTHLD_CNT(1);
va009039 0:5160ee0c522d 85
va009039 0:5160ee0c522d 86 // pulldown D+ and D-
va009039 0:5160ee0c522d 87 USB0->USBCTRL = USB_USBCTRL_PDE_MASK;
va009039 0:5160ee0c522d 88
va009039 0:5160ee0c522d 89 // Host mode
va009039 0:5160ee0c522d 90 USB0->CTL |= USB_CTL_HOSTMODEEN_MASK;
va009039 0:5160ee0c522d 91 // Desable SOF packet generation
va009039 0:5160ee0c522d 92 USB0->CTL &= ~USB_CTL_USBENSOFEN_MASK;
va009039 0:5160ee0c522d 93
va009039 0:5160ee0c522d 94 NVIC_SetVector(USB0_IRQn, (uint32_t)_usbisr);
va009039 0:5160ee0c522d 95 NVIC_EnableIRQ(USB0_IRQn);
va009039 0:5160ee0c522d 96
va009039 0:5160ee0c522d 97 wait_attach();
va009039 0:5160ee0c522d 98
va009039 0:5160ee0c522d 99 // Enable RESET
va009039 0:5160ee0c522d 100 USB0->CTL |= USB_CTL_RESET_MASK;
va009039 0:5160ee0c522d 101 wait_ms(10);
va009039 0:5160ee0c522d 102 USB0->CTL &= ~USB_CTL_RESET_MASK;
va009039 0:5160ee0c522d 103
va009039 0:5160ee0c522d 104 // Enable SOF
va009039 0:5160ee0c522d 105 USB0->CTL |= USB_CTL_USBENSOFEN_MASK;
va009039 0:5160ee0c522d 106 wait_ms(100);
va009039 0:5160ee0c522d 107
va009039 0:5160ee0c522d 108 // token transfer initialize
va009039 0:5160ee0c522d 109 tx_ptr = ODD;
va009039 0:5160ee0c522d 110 rx_ptr = ODD;
va009039 0:5160ee0c522d 111 USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK;
va009039 0:5160ee0c522d 112
va009039 0:5160ee0c522d 113 enumeration();
va009039 0:5160ee0c522d 114
va009039 0:5160ee0c522d 115 }
va009039 0:5160ee0c522d 116
va009039 0:5160ee0c522d 117 void USBHost::wait_attach() {
va009039 0:5160ee0c522d 118 attach_done = false;
va009039 0:5160ee0c522d 119 USB0->INTEN = USB_INTEN_ATTACHEN_MASK;
va009039 0:5160ee0c522d 120 while(!attach_done);
va009039 0:5160ee0c522d 121 wait_ms(100);
va009039 0:5160ee0c522d 122 USB_TEST_ASSERT_FALSE(USB0->CTL & USB_CTL_SE0_MASK);
va009039 0:5160ee0c522d 123 if (!(USB0->CTL & USB_CTL_JSTATE_MASK)) { // low speed
va009039 0:5160ee0c522d 124 USB0->ADDR |= USB_ADDR_LSEN_MASK;
va009039 0:5160ee0c522d 125 }
va009039 0:5160ee0c522d 126 USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_HOSTWOHUB_MASK;
va009039 0:5160ee0c522d 127 }
va009039 0:5160ee0c522d 128
va009039 0:5160ee0c522d 129 void USBHost::enumeration() {
va009039 0:5160ee0c522d 130 uint8_t desc[18];
va009039 0:5160ee0c522d 131 MaxPacketSize0 = 8;
va009039 0:5160ee0c522d 132 SETUP_PACKET setup_get_descriptor = {0x80, GET_DESCRIPTOR, 1<<8, 0, 0};
va009039 0:5160ee0c522d 133 int result = ControlRead(&setup_get_descriptor, desc, 8);
va009039 0:5160ee0c522d 134 USB_TEST_ASSERT(result == 8);
va009039 0:5160ee0c522d 135 USB_DBG_HEX(desc, result);
va009039 0:5160ee0c522d 136 MaxPacketSize0 = desc[7];
va009039 0:5160ee0c522d 137
va009039 0:5160ee0c522d 138 result = ControlRead(&setup_get_descriptor, desc, sizeof(desc));
va009039 0:5160ee0c522d 139 USB_TEST_ASSERT(result == sizeof(desc));
va009039 0:5160ee0c522d 140 USB_DBG_HEX(desc, sizeof(desc));
va009039 0:5160ee0c522d 141
va009039 0:5160ee0c522d 142 setup_get_descriptor.wValue = 2<<8; // config descriptor
va009039 0:5160ee0c522d 143 result = ControlRead(&setup_get_descriptor, desc, 4);
va009039 0:5160ee0c522d 144 USB_TEST_ASSERT(result == 4);
va009039 0:5160ee0c522d 145 USB_DBG_HEX(desc, 4);
va009039 0:5160ee0c522d 146
va009039 0:5160ee0c522d 147 int TotalLength = desc[2]|desc[3]<<8;
va009039 0:5160ee0c522d 148 uint8_t* buf = new uint8_t[TotalLength];
va009039 0:5160ee0c522d 149 result = ControlRead(&setup_get_descriptor, buf, TotalLength);
va009039 0:5160ee0c522d 150 USB_TEST_ASSERT(result == TotalLength);
va009039 0:5160ee0c522d 151 USB_DBG_HEX(buf, TotalLength);
va009039 0:5160ee0c522d 152
va009039 0:5160ee0c522d 153 for(int i = 0; i < TotalLength; ) {
va009039 0:5160ee0c522d 154 int Length = buf[i];
va009039 0:5160ee0c522d 155 uint8_t DescriptorType = buf[i+1];
va009039 0:5160ee0c522d 156 if (DescriptorType == 0x05) { // endpoint
va009039 0:5160ee0c522d 157 uint8_t EndpointAddress = buf[i+2];
va009039 0:5160ee0c522d 158 uint8_t Attributes = buf[i+3];
va009039 0:5160ee0c522d 159 if (Attributes == 0x03) { // interrupt
va009039 0:5160ee0c522d 160 if (EndpointAddress & 0x80) {
va009039 0:5160ee0c522d 161 ep_int_in = EndpointAddress;
va009039 0:5160ee0c522d 162 }
va009039 0:5160ee0c522d 163 } else if (Attributes == 0x02) { // bulk
va009039 0:5160ee0c522d 164 if (EndpointAddress & 0x80) {
va009039 0:5160ee0c522d 165 ep_bulk_in = EndpointAddress;
va009039 0:5160ee0c522d 166 } else {
va009039 0:5160ee0c522d 167 ep_bulk_out = EndpointAddress;
va009039 0:5160ee0c522d 168 }
va009039 0:5160ee0c522d 169 }
va009039 0:5160ee0c522d 170 }
va009039 0:5160ee0c522d 171 USB_DBG_HEX(buf+i, Length);
va009039 0:5160ee0c522d 172 i += Length;
va009039 0:5160ee0c522d 173 }
va009039 0:5160ee0c522d 174 delete[] buf;
va009039 0:5160ee0c522d 175
va009039 0:5160ee0c522d 176 SETUP_PACKET setup_set_config = {0x00, SET_CONFIGURATION, 1, 0, 0}; // config = 1
va009039 0:5160ee0c522d 177 ControlWrite(&setup_set_config);
va009039 0:5160ee0c522d 178 }
va009039 0:5160ee0c522d 179
va009039 0:5160ee0c522d 180 int USBHost::ControlRead(SETUP_PACKET* setup, uint8_t* data, int size) {
va009039 0:5160ee0c522d 181 token_setup(setup, size); // setup stage
va009039 0:5160ee0c522d 182 int read_len = 0;
va009039 0:5160ee0c522d 183 while(read_len < size) {
va009039 0:5160ee0c522d 184 int size2 = std::min(size-read_len, MaxPacketSize0);
va009039 0:5160ee0c522d 185 int result = token_in(0, data+read_len, size2);
va009039 0:5160ee0c522d 186 read_len += result;
va009039 0:5160ee0c522d 187 if (result < MaxPacketSize0) {
va009039 0:5160ee0c522d 188 break;
va009039 0:5160ee0c522d 189 }
va009039 0:5160ee0c522d 190 }
va009039 0:5160ee0c522d 191 token_out(0); // status stage
va009039 0:5160ee0c522d 192 return read_len;
va009039 0:5160ee0c522d 193 }
va009039 0:5160ee0c522d 194
va009039 0:5160ee0c522d 195 int USBHost::ControlWrite(SETUP_PACKET* setup, uint8_t* data, int size) {
va009039 0:5160ee0c522d 196 token_setup(setup, size); // setup stage
va009039 0:5160ee0c522d 197 int result = 0;
va009039 0:5160ee0c522d 198 if (data != NULL) {
va009039 0:5160ee0c522d 199 result = token_out(0, data, size);
va009039 0:5160ee0c522d 200 }
va009039 0:5160ee0c522d 201 token_in(0); // status stage
va009039 0:5160ee0c522d 202 return result;
va009039 0:5160ee0c522d 203 }
va009039 0:5160ee0c522d 204
va009039 0:5160ee0c522d 205 int USBHost::InterruptRead(uint8_t* data, int size) {
va009039 0:5160ee0c522d 206 USB0->ISTAT = 0xff;
va009039 0:5160ee0c522d 207 USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_EPCTLDIS_MASK|
va009039 0:5160ee0c522d 208 USB_ENDPT_EPRXEN_MASK|
va009039 0:5160ee0c522d 209 USB_ENDPT_EPTXEN_MASK|
va009039 0:5160ee0c522d 210 USB_ENDPT_EPHSHK_MASK;
va009039 0:5160ee0c522d 211 return token_in(ep_int_in & 0x7f, data, size);
va009039 0:5160ee0c522d 212 }
va009039 0:5160ee0c522d 213
va009039 0:5160ee0c522d 214 int USBHost::BulkRead(uint8_t* data, int size) {
va009039 0:5160ee0c522d 215 USB0->ISTAT = 0xff;
va009039 0:5160ee0c522d 216 USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_EPCTLDIS_MASK|
va009039 0:5160ee0c522d 217 USB_ENDPT_EPRXEN_MASK|
va009039 0:5160ee0c522d 218 USB_ENDPT_EPTXEN_MASK|
va009039 0:5160ee0c522d 219 USB_ENDPT_EPHSHK_MASK;
va009039 0:5160ee0c522d 220 return token_in(ep_bulk_in & 0x7f, data, size);
va009039 0:5160ee0c522d 221 }
va009039 0:5160ee0c522d 222
va009039 0:5160ee0c522d 223 int USBHost::BulkWrite(const uint8_t* data, int size) {
va009039 0:5160ee0c522d 224 USB0->ISTAT = 0xff;
va009039 0:5160ee0c522d 225 USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_EPCTLDIS_MASK|
va009039 0:5160ee0c522d 226 USB_ENDPT_EPRXEN_MASK|
va009039 0:5160ee0c522d 227 USB_ENDPT_EPTXEN_MASK|
va009039 0:5160ee0c522d 228 USB_ENDPT_EPHSHK_MASK;
va009039 0:5160ee0c522d 229 return token_out(ep_bulk_out & 0x7f, data, size);
va009039 0:5160ee0c522d 230 }
va009039 0:5160ee0c522d 231
va009039 0:5160ee0c522d 232 int USBHost::token_setup(SETUP_PACKET* setup, uint16_t wLength) {
va009039 0:5160ee0c522d 233 USB0->ISTAT = 0xff;
va009039 0:5160ee0c522d 234 USB0->ERRSTAT = 0xff;
va009039 0:5160ee0c522d 235 USB0->ENDPOINT[0].ENDPT |= USB_ENDPT_EPRXEN_MASK|
va009039 0:5160ee0c522d 236 USB_ENDPT_EPTXEN_MASK|
va009039 0:5160ee0c522d 237 USB_ENDPT_EPHSHK_MASK;
va009039 0:5160ee0c522d 238 int idx = EP0_BDT_IDX(TX, tx_ptr);
va009039 0:5160ee0c522d 239 bdt[idx].info = BD_OWN_MASK;
va009039 0:5160ee0c522d 240 setup->wLength = wLength;
va009039 0:5160ee0c522d 241 bdt[idx].setBuffer((uint8_t*)setup, sizeof(SETUP_PACKET));
va009039 0:5160ee0c522d 242 CTASSERT(sizeof(SETUP_PACKET) == 8);
va009039 0:5160ee0c522d 243 token_done = false;
va009039 0:5160ee0c522d 244 USB0->TOKEN = USB_TOKEN_TOKENPID(SETUP_TOKEN)|USB_TOKEN_TOKENENDPT(0);
va009039 0:5160ee0c522d 245 while(!token_done);
va009039 0:5160ee0c522d 246 return (bdt[idx].info>>2)&0x0f;
va009039 0:5160ee0c522d 247 }
va009039 0:5160ee0c522d 248
va009039 0:5160ee0c522d 249 int USBHost::token_in(uint8_t ep, uint8_t* data, int size) {
va009039 0:5160ee0c522d 250 int idx = EP0_BDT_IDX(RX, rx_ptr);
va009039 0:5160ee0c522d 251 bdt[idx].info = BD_OWN_MASK|BD_DATA01_MASK;
va009039 0:5160ee0c522d 252 bdt[idx].setBuffer(data, size);
va009039 0:5160ee0c522d 253 token_done = false;
va009039 0:5160ee0c522d 254 USB0->TOKEN = USB_TOKEN_TOKENPID(IN_TOKEN)|USB_TOKEN_TOKENENDPT(ep);
va009039 0:5160ee0c522d 255 while(!token_done);
va009039 0:5160ee0c522d 256 return bdt[idx].byte_count;
va009039 0:5160ee0c522d 257 }
va009039 0:5160ee0c522d 258
va009039 0:5160ee0c522d 259 int USBHost::token_out(uint8_t ep, const uint8_t* data, int size) {
va009039 0:5160ee0c522d 260 int idx = EP0_BDT_IDX(TX, tx_ptr);
va009039 0:5160ee0c522d 261 bdt[idx].info = BD_OWN_MASK|BD_DATA01_MASK;
va009039 0:5160ee0c522d 262 bdt[idx].setBuffer((uint8_t*)data, size);
va009039 0:5160ee0c522d 263 token_done = false;
va009039 0:5160ee0c522d 264 USB0->TOKEN = USB_TOKEN_TOKENPID(OUT_TOKEN)|USB_TOKEN_TOKENENDPT(ep);
va009039 0:5160ee0c522d 265 while(!token_done);
va009039 0:5160ee0c522d 266 return bdt[idx].byte_count;
va009039 0:5160ee0c522d 267 }
va009039 0:5160ee0c522d 268
va009039 0:5160ee0c522d 269 void USBHost::_usbisr(void) {
va009039 0:5160ee0c522d 270 if (inst) {
va009039 0:5160ee0c522d 271 inst->UsbIrqhandler();
va009039 0:5160ee0c522d 272 }
va009039 0:5160ee0c522d 273 }
va009039 0:5160ee0c522d 274
va009039 0:5160ee0c522d 275 void USBHost::UsbIrqhandler() {
va009039 0:5160ee0c522d 276 uint8_t istat = USB0->ISTAT;
va009039 0:5160ee0c522d 277 if (istat & USB_ISTAT_TOKDNE_MASK) {
va009039 0:5160ee0c522d 278 uint8_t stat = USB0->STAT;
va009039 0:5160ee0c522d 279 if (stat & USB_STAT_TX_MASK) {
va009039 0:5160ee0c522d 280 tx_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
va009039 0:5160ee0c522d 281 } else {
va009039 0:5160ee0c522d 282 rx_ptr = (stat & USB_STAT_ODD_MASK) ? ODD : EVEN;
va009039 0:5160ee0c522d 283 }
va009039 0:5160ee0c522d 284 token_done = true;
va009039 0:5160ee0c522d 285 }
va009039 0:5160ee0c522d 286 if (istat & USB_ISTAT_ATTACH_MASK) {
va009039 0:5160ee0c522d 287 USB0->INTEN &= ~USB_INTEN_ATTACHEN_MASK;
va009039 0:5160ee0c522d 288 attach_done = true;
va009039 0:5160ee0c522d 289 }
va009039 0:5160ee0c522d 290 USB0->ISTAT = istat; // clear
va009039 0:5160ee0c522d 291 }
va009039 0:5160ee0c522d 292
va009039 0:5160ee0c522d 293 void debug_hex(uint8_t* buf, int size) {
va009039 0:5160ee0c522d 294 for(int i = 0; i < size; i++) {
va009039 0:5160ee0c522d 295 fprintf(stderr, "%02x ", buf[i]);
va009039 0:5160ee0c522d 296 if (i%16 == 15) {
va009039 0:5160ee0c522d 297 fprintf(stderr, "\r\n");
va009039 0:5160ee0c522d 298 }
va009039 0:5160ee0c522d 299 }
va009039 0:5160ee0c522d 300 fprintf(stderr, "\r\n");
va009039 0:5160ee0c522d 301 }
va009039 0:5160ee0c522d 302