USB Host Shield 2.0
Loading...
Searching...
No Matches
usbhost.h
Go to the documentation of this file.
1/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
2
3This program is free software; you can redistribute it and/or modify
4it under the terms of the GNU General Public License as published by
5the Free Software Foundation; either version 2 of the License, or
6(at your option) any later version.
7
8This program is distributed in the hope that it will be useful,
9but WITHOUT ANY WARRANTY; without even the implied warranty of
10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11GNU General Public License for more details.
12
13You should have received a copy of the GNU General Public License
14along with this program; if not, write to the Free Software
15Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
17Contact information
18-------------------
19
20Circuits At Home, LTD
21Web : http://www.circuitsathome.com
22e-mail : support@circuitsathome.com
23 */
24/* MAX3421E-based USB Host Library header file */
25
26
27#if !defined(_usb_h_) || defined(_USBHOST_H_)
28#error "Never include usbhost.h directly; include Usb.h instead"
29#else
30#define _USBHOST_H_
31
32#if USING_SPI4TEENSY3
33#include <spi4teensy3.h>
34#include <sys/types.h>
35#endif
36
37/* SPI initialization */
38template< typename SPI_CLK, typename SPI_MOSI, typename SPI_MISO, typename SPI_SS > class SPi {
39public:
40#if USING_SPI4TEENSY3
41 static void init() {
42 // spi4teensy3 inits everything for us, except /SS
43 // CLK, MOSI and MISO are hard coded for now.
44 // spi4teensy3::init(0,0,0); // full speed, cpol 0, cpha 0
45 spi4teensy3::init(); // full speed, cpol 0, cpha 0
48 }
49#elif defined(SPI_HAS_TRANSACTION)
50 static void init() {
51 USB_SPI.begin(); // The SPI library with transaction will take care of setting up the pins - settings is set in beginTransaction()
54 }
55#elif defined(STM32F4)
56#warning "You need to initialize the SPI interface manually when using the STM32F4 platform"
57 static void init() {
58 // Should be initialized by the user manually for now
59 }
60#elif !defined(SPDR)
61 static void init() {
64 USB_SPI.begin();
65#if defined(__MIPSEL__)
66 USB_SPI.setClockDivider(1);
67#elif defined(__ARDUINO_X86__)
68 #ifdef SPI_CLOCK_1M // Hack used to check if setClockSpeed is available
69 USB_SPI.setClockSpeed(12000000); // The MAX3421E can handle up to 26MHz, but in practice this was the maximum that I could reliably use
70 #else
71 USB_SPI.setClockDivider(SPI_CLOCK_DIV2); // This will set the SPI frequency to 8MHz - it could be higher, but it is not supported in the old API
72 #endif
73#elif !defined(RBL_NRF51822) && !defined(NRF52_SERIES)
74 USB_SPI.setClockDivider(4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz
75#endif
76 }
77#else
78 static void init() {
79 //uint8_t tmp;
84 /* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */
85 SPCR = 0x50;
86 SPSR = 0x01; // 0x01
87
88 //tmp = SPSR;
89 //tmp = SPDR;
90 }
91#endif
92};
93
94/* SPI pin definitions. see avrpins.h */
95#if defined(PIN_SPI_SCK) && defined(PIN_SPI_MOSI) && defined(PIN_SPI_MISO) && defined(PIN_SPI_SS)
96// Use pin defines: https://github.com/arduino/Arduino/pull/4814
97// Based on: https://www.mikeash.com/pyblog/friday-qa-2015-03-20-preprocessor-abuse-and-optional-parentheses.html
98#define NOTHING_EXTRACT
99#define EXTRACT(...) EXTRACT __VA_ARGS__
100#define PASTE(x, ...) x ## __VA_ARGS__
101#define EVALUATING_PASTE(x, ...) PASTE(x, __VA_ARGS__)
102#define UNPAREN(x) EVALUATING_PASTE(NOTHING_, EXTRACT x)
103#define APPEND_PIN(pin) P ## pin // Appends the pin to 'P', e.g. 1 becomes P1
104#define MAKE_PIN(x) EVALUATING_PASTE(APPEND_, PIN(UNPAREN(x)))
106#undef MAKE_PIN
107#elif defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
109#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
111#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
113#elif (defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__MKL26Z64__))) || defined(__ARDUINO_ARC__) || defined(__ARDUINO_X86__) || defined(__MIPSEL__) || defined(STM32F4) || defined(ARDUINO_UNOR4_MINIMA) || defined(ARDUINO_UNOR4_WIFI)
115#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
117#elif defined(RBL_NRF51822)
119#elif defined(ESP8266)
121#elif defined(ARDUINO_M5STACK_CORES3)
123#elif defined(ARDUINO_XIAO_ESP32S3)
125#elif defined(ESP32)
127#elif defined(ARDUINO_NRF52840_FEATHER) || defined(ARDUINO_NRF52840_FEATHER_SENSE)
129#elif defined(ARDUINO_Seeed_XIAO_nRF52840_Sense)
131#else
132#error "No SPI entry in usbhost.h"
133#endif
134
135typedef enum {
139
140template< typename SPI_SS, typename INTR > class MAX3421e /* : public spi */ {
141 static uint8_t vbusState;
142
143public:
144 MAX3421e();
145 void regWr(uint8_t reg, uint8_t data);
147 void gpioWr(uint8_t data);
150 uint8_t gpioRd();
152 uint16_t reset();
153 int8_t Init();
154 int8_t Init(int mseconds);
155
159
161 return vbusState;
162 };
163 void busprobe();
166 uint8_t Task();
167};
168
169template< typename SPI_SS, typename INTR >
171
172/* constructor */
173template< typename SPI_SS, typename INTR >
175 // Leaving ADK hardware setup in here, for now. This really belongs with the other parts.
176#ifdef BOARD_MEGA_ADK
177 // For Mega ADK, which has a Max3421e on-board, set MAX_RESET to output mode, and then set it to HIGH
179 P55::Set();
180#endif
181};
182
183/* write single byte into MAX3421 register */
184template< typename SPI_SS, typename INTR >
187#if defined(SPI_HAS_TRANSACTION)
188 USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0
189#endif
191
192#if USING_SPI4TEENSY3
193 uint8_t c[2];
194 c[0] = reg | 0x02;
195 c[1] = data;
196 spi4teensy3::send(c, 2);
197#elif defined(SPI_HAS_TRANSACTION) && !defined(ESP8266) && !defined(ESP32)
198 uint8_t c[2];
199 c[0] = reg | 0x02;
200 c[1] = data;
201 USB_SPI.transfer(c, 2);
202#elif defined(STM32F4)
203 uint8_t c[2];
204 c[0] = reg | 0x02;
205 c[1] = data;
207#elif !defined(SPDR) // ESP8266, ESP32
208 USB_SPI.transfer(reg | 0x02);
209 USB_SPI.transfer(data);
210#else
211 SPDR = (reg | 0x02);
212 while(!(SPSR & (1 << SPIF)));
213 SPDR = data;
214 while(!(SPSR & (1 << SPIF)));
215#endif
216
217 SPI_SS::Set();
218#if defined(SPI_HAS_TRANSACTION)
219 USB_SPI.endTransaction();
220#endif
222 return;
223};
224/* multiple-byte write */
225
226/* returns a pointer to memory position after last written */
227template< typename SPI_SS, typename INTR >
230#if defined(SPI_HAS_TRANSACTION)
231 USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0
232#endif
234
235#if USING_SPI4TEENSY3
236 spi4teensy3::send(reg | 0x02);
237 spi4teensy3::send(data_p, nbytes);
238 data_p += nbytes;
239#elif defined(STM32F4)
240 uint8_t data = reg | 0x02;
243 data_p += nbytes;
244#elif defined(__LGT8FX8P__)
245 USB_SPI.transfer(reg | 0x02);
246 USB_SPI.transfer(data_p, nbytes);
247 data_p += nbytes;
248#elif !defined(__AVR__) || !defined(SPDR)
249#if defined(ESP8266) || defined(ESP32)
250 yield();
251#endif
252 USB_SPI.transfer(reg | 0x02);
253 while(nbytes) {
254 USB_SPI.transfer(*data_p);
255 nbytes--;
256 data_p++; // advance data pointer
257 }
258#else
259 SPDR = (reg | 0x02); //set WR bit and send register number
260 while(nbytes) {
261 while(!(SPSR & (1 << SPIF))); //check if previous byte was sent
262 SPDR = (*data_p); // send next data byte
263 nbytes--;
264 data_p++; // advance data pointer
265 }
266 while(!(SPSR & (1 << SPIF)));
267#endif
268
269 SPI_SS::Set();
270#if defined(SPI_HAS_TRANSACTION)
271 USB_SPI.endTransaction();
272#endif
274 return ( data_p);
275}
276/* GPIO write */
277/*GPIO byte is split between 2 registers, so two writes are needed to write one byte */
278
279/* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */
280template< typename SPI_SS, typename INTR >
282 regWr(rIOPINS1, data);
283 data >>= 4;
284 regWr(rIOPINS2, data);
285 return;
286}
287
288/* single host register read */
289template< typename SPI_SS, typename INTR >
292#if defined(SPI_HAS_TRANSACTION)
293 USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0
294#endif
296
297#if USING_SPI4TEENSY3
298 spi4teensy3::send(reg);
300 SPI_SS::Set();
301#elif defined(STM32F4)
303 uint8_t rv = 0;
305 SPI_SS::Set();
306#elif !defined(SPDR) || defined(SPI_HAS_TRANSACTION)
307 USB_SPI.transfer(reg);
308 uint8_t rv = USB_SPI.transfer(0); // Send empty byte
309 SPI_SS::Set();
310#else
311 SPDR = reg;
312 while(!(SPSR & (1 << SPIF)));
313 SPDR = 0; // Send empty byte
314 while(!(SPSR & (1 << SPIF)));
315 SPI_SS::Set();
316 uint8_t rv = SPDR;
317#endif
318
319#if defined(SPI_HAS_TRANSACTION)
320 USB_SPI.endTransaction();
321#endif
323 return (rv);
324}
325/* multiple-byte register read */
326
327/* returns a pointer to a memory position after last read */
328template< typename SPI_SS, typename INTR >
331#if defined(SPI_HAS_TRANSACTION)
332 USB_SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0
333#endif
335
336#if USING_SPI4TEENSY3
337 spi4teensy3::send(reg);
339 data_p += nbytes;
340#elif defined(SPI_HAS_TRANSACTION) && !defined(ESP8266) && !defined(ESP32)
341 USB_SPI.transfer(reg);
342 memset(data_p, 0, nbytes); // Make sure we send out empty bytes
343 USB_SPI.transfer(data_p, nbytes);
344 data_p += nbytes;
345#elif defined(__ARDUINO_X86__)
346 USB_SPI.transfer(reg);
347 USB_SPI.transferBuffer(NULL, data_p, nbytes);
348 data_p += nbytes;
349#elif defined(STM32F4)
351 memset(data_p, 0, nbytes); // Make sure we send out empty bytes
353 data_p += nbytes;
354#elif !defined(SPDR) // ESP8266, ESP32
355 yield();
356 USB_SPI.transfer(reg);
357 while(nbytes) {
358 *data_p++ = USB_SPI.transfer(0);
359 nbytes--;
360 }
361#else
362 SPDR = reg;
363 while(!(SPSR & (1 << SPIF))); //wait
364 while(nbytes) {
365 SPDR = 0; // Send empty byte
366 nbytes--;
367 while(!(SPSR & (1 << SPIF)));
368#if 0
369 {
370 *data_p = SPDR;
371 printf("%2.2x ", *data_p);
372 }
373 data_p++;
374 }
375 printf("\r\n");
376#else
377 *data_p++ = SPDR;
378 }
379#endif
380#endif
381
382 SPI_SS::Set();
383#if defined(SPI_HAS_TRANSACTION)
384 USB_SPI.endTransaction();
385#endif
387 return ( data_p);
388}
389/* GPIO read. See gpioWr for explanation */
390
394/* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */
395template< typename SPI_SS, typename INTR >
397 uint8_t gpin = 0;
398 gpin = regRd(rIOPINS2); //pins 4-7
399 gpin &= 0xf0; //clean lower nibble
400 gpin |= (regRd(rIOPINS1) >> 4); //shift low bits and OR with upper from previous operation.
401 return ( gpin);
402}
403
407/* GPOUT pins are in low nibbles of IOPINS1, IOPINS2 */
408template< typename SPI_SS, typename INTR >
410 uint8_t gpout = 0;
411 gpout = regRd(rIOPINS1); //pins 0-3
412 gpout &= 0x0f; //clean upper nibble
413 gpout |= (regRd(rIOPINS2) << 4); //shift high bits and OR with lower from previous operation.
414 return ( gpout);
415}
416
417/* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset
418 or zero if PLL haven't stabilized in 65535 cycles */
419template< typename SPI_SS, typename INTR >
421 uint16_t i = 0;
422 regWr(rUSBCTL, bmCHIPRES);
423 regWr(rUSBCTL, 0x00);
424 while(++i) {
425 if((regRd(rUSBIRQ) & bmOSCOKIRQ)) {
426 break;
427 }
428 }
429 return ( i);
430}
431
432/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
433template< typename SPI_SS, typename INTR >
436 // Moved here.
437 // you really should not init hardware in the constructor when it involves locks.
438 // Also avoids the vbus flicker issue confusing some devices.
439 /* pin and peripheral setup */
441 SPI_SS::Set();
442 spi::init();
445 /* MAX3421E - full-duplex SPI, level interrupt */
446 // GPX pin on. Moved here, otherwise we flicker the vbus.
447 regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
448
449 if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
450 return ( -1);
451 }
452
453 regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
454
455 regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
456
457 /* check if device is connected */
458 regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
459 while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
460
461 busprobe(); //check if anything is connected
462
463 regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
464 regWr(rCPUCTL, 0x01); //enable interrupt pin
465
466 return ( 0);
467}
468
469/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
470template< typename SPI_SS, typename INTR >
473 // Moved here.
474 // you really should not init hardware in the constructor when it involves locks.
475 // Also avoids the vbus flicker issue confusing some devices.
476 /* pin and peripheral setup */
478 SPI_SS::Set();
479 spi::init();
482 /* MAX3421E - full-duplex SPI, level interrupt, vbus off */
484
485 if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
486 return ( -1);
487 }
488
489 // Delay a minimum of 1 second to ensure any capacitors are drained.
490 // 1 second is required to make sure we do not smoke a Microdrive!
491 if(mseconds < 1000) mseconds = 1000;
493
494 regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
495
496 regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
497
498 /* check if device is connected */
499 regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
500 while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
501
502 busprobe(); //check if anything is connected
503
504 regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
505 regWr(rCPUCTL, 0x01); //enable interrupt pin
506
507 // GPX pin on. This is done here so that busprobe will fail if we have a switch connected.
508 regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
509
510 return ( 0);
511}
512
513/* probe bus to determine device presence and speed and switch host to this speed */
514template< typename SPI_SS, typename INTR >
517 bus_sample = regRd(rHRSL); //Get J,K status
518 bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the byte
519 switch(bus_sample) { //start full-speed or low-speed host
520 case( bmJSTATUS):
521 if((regRd(rMODE) & bmLOWSPEED) == 0) {
522 regWr(rMODE, MODE_FS_HOST); //start full-speed host
523 vbusState = FSHOST;
524 } else {
525 regWr(rMODE, MODE_LS_HOST); //start low-speed host
526 vbusState = LSHOST;
527 }
528 break;
529 case( bmKSTATUS):
530 if((regRd(rMODE) & bmLOWSPEED) == 0) {
531 regWr(rMODE, MODE_LS_HOST); //start low-speed host
532 vbusState = LSHOST;
533 } else {
534 regWr(rMODE, MODE_FS_HOST); //start full-speed host
535 vbusState = FSHOST;
536 }
537 break;
538 case( bmSE1): //illegal state
539 vbusState = SE1;
540 break;
541 case( bmSE0): //disconnected state
543 vbusState = SE0;
544 break;
545 }//end switch( bus_sample )
546}
547
548/* MAX3421 state change task and interrupt handler */
549template< typename SPI_SS, typename INTR >
551 uint8_t rcode = 0;
553 //USB_HOST_SERIAL.print("Vbus state: ");
554 //USB_HOST_SERIAL.println( vbusState, HEX );
555 pinvalue = INTR::IsSet(); //Read();
556 //pinvalue = digitalRead( MAX_INT );
557 if(pinvalue == 0) {
558 rcode = IntHandler();
559 }
560 // pinvalue = digitalRead( MAX_GPX );
561 // if( pinvalue == LOW ) {
562 // GpxHandler();
563 // }
564 // usbSM(); //USB state machine
565 return ( rcode);
566}
567
568template< typename SPI_SS, typename INTR >
571 uint8_t HIRQ_sendback = 0x00;
572 HIRQ = regRd(rHIRQ); //determine interrupt source
573 //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler
574 // HIRQ_sendback |= bmFRAMEIRQ;
575 //}//end FRAMEIRQ handling
576 if(HIRQ & bmCONDETIRQ) {
577 busprobe();
579 }
580 /* End HIRQ interrupts handling, clear serviced IRQs */
581 regWr(rHIRQ, HIRQ_sendback);
582 return ( HIRQ_sendback);
583}
584//template< typename SPI_SS, typename INTR >
585//uint8_t MAX3421e< SPI_SS, INTR >::GpxHandler()
586//{
587// uint8_t GPINIRQ = regRd( rGPINIRQ ); //read GPIN IRQ register
594// return( GPINIRQ );
595//}
596
597#endif // _USBHOST_H_
ConfigDescParser(UsbConfigXtracter *xtractor)
MAX3421e()
Definition usbhost.h:174
uint8_t Task()
Definition usbhost.h:550
uint8_t GpxHandler()
uint16_t reset()
Definition usbhost.h:420
int8_t Init()
Definition usbhost.h:434
uint8_t regRd(uint8_t reg)
Definition usbhost.h:290
void vbusPower(VBUS_t state)
Definition usbhost.h:156
void busprobe()
Definition usbhost.h:515
void regWr(uint8_t reg, uint8_t data)
Definition usbhost.h:185
uint8_t * bytesWr(uint8_t reg, uint8_t nbytes, uint8_t *data_p)
Definition usbhost.h:228
uint8_t getVbusState(void)
Definition usbhost.h:160
uint8_t gpioRd()
Reads the current GPI input values.
Definition usbhost.h:396
uint8_t gpioRdOutput()
Reads the current GPI output values.
Definition usbhost.h:409
uint8_t * bytesRd(uint8_t reg, uint8_t nbytes, uint8_t *data_p)
Definition usbhost.h:329
uint8_t IntHandler()
Definition usbhost.h:569
void gpioWr(uint8_t data)
Definition usbhost.h:281
Definition usbhost.h:38
static void init()
Definition usbhost.h:61
#define bmFDUPSPI
Definition max3421e.h:75
#define rIOPINS2
Definition max3421e.h:100
#define rUSBIRQ
Definition max3421e.h:50
#define bmFRAMEIE
Definition max3421e.h:164
#define rIOPINS1
Definition max3421e.h:88
#define rUSBCTL
Definition max3421e.h:62
#define rHRSL
Definition max3421e.h:203
#define rMODE
Definition max3421e.h:167
#define bmCONDETIE
Definition max3421e.h:163
#define SE0
Definition max3421e.h:35
#define MODE_FS_HOST
Definition max3421e.h:231
#define rCPUCTL
Definition max3421e.h:67
#define bmSEPIRQ
Definition max3421e.h:174
#define bmHOST
Definition max3421e.h:170
#define SE1
Definition max3421e.h:36
#define bmSE0
Definition max3421e.h:210
#define rPINCTL
Definition max3421e.h:73
#define rHCTL
Definition max3421e.h:181
#define bmDMPULLDN
Definition max3421e.h:176
#define bmJSTATUS
Definition max3421e.h:209
#define FSHOST
Definition max3421e.h:37
#define bmLOWSPEED
Definition max3421e.h:171
#define rHIRQ
Definition max3421e.h:144
#define rHIEN
Definition max3421e.h:155
#define LSHOST
Definition max3421e.h:38
#define bmCHIPRES
Definition max3421e.h:64
#define MODE_LS_HOST
Definition max3421e.h:232
#define bmDPPULLDN
Definition max3421e.h:177
#define bmINTLEVEL
Definition max3421e.h:76
#define bmCONDETIRQ
Definition max3421e.h:151
#define bmSE1
Definition max3421e.h:211
#define bmOSCOKIRQ
Definition max3421e.h:54
#define bmSAMPLEBUS
Definition max3421e.h:185
#define bmKSTATUS
Definition max3421e.h:208
#define GPX_VBDET
Definition max3421e.h:82
#define USB_SPI
Definition settings.h:33
#define XMEM_ACQUIRE_SPI()
Definition settings.h:134
#define XMEM_RELEASE_SPI()
Definition settings.h:135
VBUS_t
Definition usbhost.h:135
@ vbus_on
Definition usbhost.h:136
@ vbus_off
Definition usbhost.h:137