aboutsummaryrefslogtreecommitdiff
path: root/lib/usbhost/USB_Host_Shield_2.0/usbhost.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/usbhost/USB_Host_Shield_2.0/usbhost.h')
-rw-r--r--lib/usbhost/USB_Host_Shield_2.0/usbhost.h529
1 files changed, 529 insertions, 0 deletions
diff --git a/lib/usbhost/USB_Host_Shield_2.0/usbhost.h b/lib/usbhost/USB_Host_Shield_2.0/usbhost.h
new file mode 100644
index 000000000..eba480e60
--- /dev/null
+++ b/lib/usbhost/USB_Host_Shield_2.0/usbhost.h
@@ -0,0 +1,529 @@
1/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
2
3This software may be distributed and modified under the terms of the GNU
4General Public License version 2 (GPL2) as published by the Free Software
5Foundation and appearing in the file GPL2.TXT included in the packaging of
6this file. Please note that GPL2 Section 2[b] requires that all works based
7on this software must also be made publicly available under the terms of
8the GPL2 ("Copyleft").
9
10Contact information
11-------------------
12
13Circuits At Home, LTD
14Web : http://www.circuitsathome.com
15e-mail : support@circuitsathome.com
16 */
17/* MAX3421E-based USB Host Library header file */
18
19
20#if !defined(_usb_h_) || defined(_USBHOST_H_)
21#error "Never include usbhost.h directly; include Usb.h instead"
22#else
23#define _USBHOST_H_
24
25#if USING_SPI4TEENSY3
26#include <spi4teensy3.h>
27#include <sys/types.h>
28#endif
29
30/* SPI initialization */
31template< typename SPI_CLK, typename SPI_MOSI, typename SPI_MISO, typename SPI_SS > class SPi {
32public:
33#if USING_SPI4TEENSY3
34 static void init() {
35 // spi4teensy3 inits everything for us, except /SS
36 // CLK, MOSI and MISO are hard coded for now.
37 // spi4teensy3::init(0,0,0); // full speed, cpol 0, cpha 0
38 spi4teensy3::init(); // full speed, cpol 0, cpha 0
39 SPI_SS::SetDirWrite();
40 SPI_SS::Set();
41 }
42#elif SPI_HAS_TRANSACTION
43 static void init() {
44 SPI.begin(); // The SPI library with transaction will take care of setting up the pins - settings is set in beginTransaction()
45 }
46#elif !defined(SPDR)
47 static void init() {
48 SPI_SS::SetDirWrite();
49 SPI_SS::Set();
50 SPI.begin();
51#if defined(__MIPSEL__)
52 SPI.setClockDivider(1);
53#elif defined(__ARDUINO_X86__)
54 #ifdef SPI_CLOCK_1M // Hack used to check if setClockSpeed is available
55 SPI.setClockSpeed(12000000); // The MAX3421E can handle up to 26MHz, but in practice this was the maximum that I could reliably use
56 #else
57 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
58 #endif
59#else
60 SPI.setClockDivider(4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz
61#endif
62 }
63#elif defined(RBL_NRF51822)
64 static void init() {
65 SPI_SS::SetDirWrite();
66 SPI_SS::Set();
67 SPI.begin();
68 // SPI.setFrequency(SPI_FREQUENCY_8M);
69 }
70#else
71 static void init() {
72 //uint8_t tmp;
73 SPI_CLK::SetDirWrite();
74 SPI_MOSI::SetDirWrite();
75 SPI_MISO::SetDirRead();
76 SPI_SS::SetDirWrite();
77 /* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */
78 SPCR = 0x50;
79 SPSR = 0x01; // 0x01
80 /**/
81 //tmp = SPSR;
82 //tmp = SPDR;
83 }
84#endif
85};
86
87/* SPI pin definitions. see avrpins.h */
88#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
89typedef SPi< Pb1, Pb2, Pb3, Pb0 > spi;
90#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
91typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi;
92#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
93typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi;
94#elif (defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__))) || defined(__ARDUINO_X86__) || defined(__MIPSEL__)
95typedef SPi< P13, P11, P12, P10 > spi;
96#elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
97typedef SPi< P76, P75, P74, P10 > spi;
98#elif defined(RBL_NRF51822)
99typedef SPi< P16, P18, P17, P10 > spi;
100#else
101#error "No SPI entry in usbhost.h"
102#endif
103
104typedef enum {
105 vbus_on = 0,
106 vbus_off = GPX_VBDET
107} VBUS_t;
108
109template< typename SPI_SS, typename INTR > class MAX3421e /* : public spi */ {
110 static uint8_t vbusState;
111
112public:
113 MAX3421e();
114 void regWr(uint8_t reg, uint8_t data);
115 uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
116 void gpioWr(uint8_t data);
117 uint8_t regRd(uint8_t reg);
118 uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
119 uint8_t gpioRd();
120 uint16_t reset();
121 int8_t Init();
122 int8_t Init(int mseconds);
123
124 void vbusPower(VBUS_t state) {
125 regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | state));
126 }
127
128 uint8_t getVbusState(void) {
129 return vbusState;
130 };
131 void busprobe();
132 uint8_t GpxHandler();
133 uint8_t IntHandler();
134 uint8_t Task();
135};
136
137template< typename SPI_SS, typename INTR >
138 uint8_t MAX3421e< SPI_SS, INTR >::vbusState = 0;
139
140/* constructor */
141template< typename SPI_SS, typename INTR >
142MAX3421e< SPI_SS, INTR >::MAX3421e() {
143 // Leaving ADK hardware setup in here, for now. This really belongs with the other parts.
144#ifdef BOARD_MEGA_ADK
145 // For Mega ADK, which has a Max3421e on-board, set MAX_RESET to output mode, and then set it to HIGH
146 P55::SetDirWrite();
147 P55::Set();
148#endif
149};
150
151/* write single byte into MAX3421 register */
152template< typename SPI_SS, typename INTR >
153void MAX3421e< SPI_SS, INTR >::regWr(uint8_t reg, uint8_t data) {
154 XMEM_ACQUIRE_SPI();
155#if SPI_HAS_TRANSACTION
156 SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0
157#endif
158 SPI_SS::Clear();
159
160#if USING_SPI4TEENSY3
161 uint8_t c[2];
162 c[0] = reg | 0x02;
163 c[1] = data;
164 spi4teensy3::send(c, 2);
165#elif SPI_HAS_TRANSACTION
166 uint8_t c[2];
167 c[0] = reg | 0x02;
168 c[1] = data;
169 SPI.transfer(c, 2);
170#elif !defined(SPDR)
171 SPI.transfer(reg | 0x02);
172 SPI.transfer(data);
173#else
174 SPDR = (reg | 0x02);
175 while(!(SPSR & (1 << SPIF)));
176 SPDR = data;
177 while(!(SPSR & (1 << SPIF)));
178#endif
179
180 SPI_SS::Set();
181#if SPI_HAS_TRANSACTION
182 SPI.endTransaction();
183#endif
184 XMEM_RELEASE_SPI();
185 return;
186};
187/* multiple-byte write */
188
189/* returns a pointer to memory position after last written */
190template< typename SPI_SS, typename INTR >
191uint8_t* MAX3421e< SPI_SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
192 XMEM_ACQUIRE_SPI();
193#if SPI_HAS_TRANSACTION
194 SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0
195#endif
196 SPI_SS::Clear();
197
198#if USING_SPI4TEENSY3
199 spi4teensy3::send(reg | 0x02);
200 spi4teensy3::send(data_p, nbytes);
201 data_p += nbytes;
202#elif SPI_HAS_TRANSACTION
203 SPI.transfer(reg | 0x02);
204 SPI.transfer(data_p, nbytes);
205 data_p += nbytes;
206#elif defined(__ARDUINO_X86__)
207 SPI.transfer(reg | 0x02);
208 SPI.transferBuffer(data_p, NULL, nbytes);
209 data_p += nbytes;
210#elif !defined(SPDR)
211 SPI.transfer(reg | 0x02);
212 while(nbytes) {
213 SPI.transfer(*data_p);
214 nbytes--;
215 data_p++; // advance data pointer
216 }
217#else
218 SPDR = (reg | 0x02); //set WR bit and send register number
219 while(nbytes) {
220 while(!(SPSR & (1 << SPIF))); //check if previous byte was sent
221 SPDR = (*data_p); // send next data byte
222 nbytes--;
223 data_p++; // advance data pointer
224 }
225 while(!(SPSR & (1 << SPIF)));
226#endif
227
228 SPI_SS::Set();
229#if SPI_HAS_TRANSACTION
230 SPI.endTransaction();
231#endif
232 XMEM_RELEASE_SPI();
233 return ( data_p);
234}
235/* GPIO write */
236/*GPIO byte is split between 2 registers, so two writes are needed to write one byte */
237
238/* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */
239template< typename SPI_SS, typename INTR >
240void MAX3421e< SPI_SS, INTR >::gpioWr(uint8_t data) {
241 regWr(rIOPINS1, data);
242 data >>= 4;
243 regWr(rIOPINS2, data);
244 return;
245}
246
247/* single host register read */
248template< typename SPI_SS, typename INTR >
249uint8_t MAX3421e< SPI_SS, INTR >::regRd(uint8_t reg) {
250 XMEM_ACQUIRE_SPI();
251#if SPI_HAS_TRANSACTION
252 SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0
253#endif
254 SPI_SS::Clear();
255
256#if USING_SPI4TEENSY3
257 spi4teensy3::send(reg);
258 uint8_t rv = spi4teensy3::receive();
259 SPI_SS::Set();
260#elif !defined(SPDR) || SPI_HAS_TRANSACTION
261 SPI.transfer(reg);
262 uint8_t rv = SPI.transfer(0); // Send empty byte
263 SPI_SS::Set();
264#else
265 SPDR = reg;
266 while(!(SPSR & (1 << SPIF)));
267 SPDR = 0; // Send empty byte
268 while(!(SPSR & (1 << SPIF)));
269 SPI_SS::Set();
270 uint8_t rv = SPDR;
271#endif
272
273#if SPI_HAS_TRANSACTION
274 SPI.endTransaction();
275#endif
276 XMEM_RELEASE_SPI();
277 return (rv);
278}
279/* multiple-byte register read */
280
281/* returns a pointer to a memory position after last read */
282template< typename SPI_SS, typename INTR >
283uint8_t* MAX3421e< SPI_SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
284 XMEM_ACQUIRE_SPI();
285#if SPI_HAS_TRANSACTION
286 SPI.beginTransaction(SPISettings(26000000, MSBFIRST, SPI_MODE0)); // The MAX3421E can handle up to 26MHz, use MSB First and SPI mode 0
287#endif
288 SPI_SS::Clear();
289
290#if USING_SPI4TEENSY3
291 spi4teensy3::send(reg);
292 spi4teensy3::receive(data_p, nbytes);
293 data_p += nbytes;
294#elif SPI_HAS_TRANSACTION
295 SPI.transfer(reg);
296 memset(data_p, 0, nbytes); // Make sure we send out empty bytes
297 SPI.transfer(data_p, nbytes);
298 data_p += nbytes;
299#elif defined(__ARDUINO_X86__)
300 SPI.transfer(reg);
301 SPI.transferBuffer(NULL, data_p, nbytes);
302 data_p += nbytes;
303#elif !defined(SPDR)
304 SPI.transfer(reg);
305 while(nbytes) {
306 *data_p++ = SPI.transfer(0);
307 nbytes--;
308 }
309#else
310 SPDR = reg;
311 while(!(SPSR & (1 << SPIF))); //wait
312 while(nbytes) {
313 SPDR = 0; // Send empty byte
314 nbytes--;
315 while(!(SPSR & (1 << SPIF)));
316#if 0
317 {
318 *data_p = SPDR;
319 printf("%2.2x ", *data_p);
320 }
321 data_p++;
322 }
323 printf("\r\n");
324#else
325 *data_p++ = SPDR;
326 }
327#endif
328#endif
329
330 SPI_SS::Set();
331#if SPI_HAS_TRANSACTION
332 SPI.endTransaction();
333#endif
334 XMEM_RELEASE_SPI();
335 return ( data_p);
336}
337/* GPIO read. See gpioWr for explanation */
338
339/* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */
340template< typename SPI_SS, typename INTR >
341uint8_t MAX3421e< SPI_SS, INTR >::gpioRd() {
342 uint8_t gpin = 0;
343 gpin = regRd(rIOPINS2); //pins 4-7
344 gpin &= 0xf0; //clean lower nibble
345 gpin |= (regRd(rIOPINS1) >> 4); //shift low bits and OR with upper from previous operation.
346 return ( gpin);
347}
348
349/* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset
350 or zero if PLL haven't stabilized in 65535 cycles */
351template< typename SPI_SS, typename INTR >
352uint16_t MAX3421e< SPI_SS, INTR >::reset() {
353 uint16_t i = 0;
354 regWr(rUSBCTL, bmCHIPRES);
355 regWr(rUSBCTL, 0x00);
356 while(++i) {
357 if((regRd(rUSBIRQ) & bmOSCOKIRQ)) {
358 break;
359 }
360 }
361 return ( i);
362}
363
364/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
365template< typename SPI_SS, typename INTR >
366int8_t MAX3421e< SPI_SS, INTR >::Init() {
367 XMEM_ACQUIRE_SPI();
368 // Moved here.
369 // you really should not init hardware in the constructor when it involves locks.
370 // Also avoids the vbus flicker issue confusing some devices.
371 /* pin and peripheral setup */
372 SPI_SS::SetDirWrite();
373 SPI_SS::Set();
374 spi::init();
375 INTR::SetDirRead();
376 XMEM_RELEASE_SPI();
377 /* MAX3421E - full-duplex SPI, level interrupt */
378 // GPX pin on. Moved here, otherwise we flicker the vbus.
379 regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
380
381 if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
382 return ( -1);
383 }
384
385 regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
386
387 regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
388
389 /* check if device is connected */
390 regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
391 while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
392
393 busprobe(); //check if anything is connected
394
395 regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
396 regWr(rCPUCTL, 0x01); //enable interrupt pin
397
398 return ( 0);
399}
400
401/* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
402template< typename SPI_SS, typename INTR >
403int8_t MAX3421e< SPI_SS, INTR >::Init(int mseconds) {
404 XMEM_ACQUIRE_SPI();
405 // Moved here.
406 // you really should not init hardware in the constructor when it involves locks.
407 // Also avoids the vbus flicker issue confusing some devices.
408 /* pin and peripheral setup */
409 SPI_SS::SetDirWrite();
410 SPI_SS::Set();
411 spi::init();
412 INTR::SetDirRead();
413 XMEM_RELEASE_SPI();
414 /* MAX3421E - full-duplex SPI, level interrupt, vbus off */
415 regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET));
416
417 if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
418 return ( -1);
419 }
420
421 // Delay a minimum of 1 second to ensure any capacitors are drained.
422 // 1 second is required to make sure we do not smoke a Microdrive!
423 if(mseconds < 1000) mseconds = 1000;
424 delay(mseconds);
425
426 regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
427
428 regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
429
430 /* check if device is connected */
431 regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
432 while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
433
434 busprobe(); //check if anything is connected
435
436 regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
437 regWr(rCPUCTL, 0x01); //enable interrupt pin
438
439 // GPX pin on. This is done here so that busprobe will fail if we have a switch connected.
440 regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
441
442 return ( 0);
443}
444
445/* probe bus to determine device presence and speed and switch host to this speed */
446template< typename SPI_SS, typename INTR >
447void MAX3421e< SPI_SS, INTR >::busprobe() {
448 uint8_t bus_sample;
449 bus_sample = regRd(rHRSL); //Get J,K status
450 bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the byte
451 switch(bus_sample) { //start full-speed or low-speed host
452 case( bmJSTATUS):
453 if((regRd(rMODE) & bmLOWSPEED) == 0) {
454 regWr(rMODE, MODE_FS_HOST); //start full-speed host
455 vbusState = FSHOST;
456 } else {
457 regWr(rMODE, MODE_LS_HOST); //start low-speed host
458 vbusState = LSHOST;
459 }
460 break;
461 case( bmKSTATUS):
462 if((regRd(rMODE) & bmLOWSPEED) == 0) {
463 regWr(rMODE, MODE_LS_HOST); //start low-speed host
464 vbusState = LSHOST;
465 } else {
466 regWr(rMODE, MODE_FS_HOST); //start full-speed host
467 vbusState = FSHOST;
468 }
469 break;
470 case( bmSE1): //illegal state
471 vbusState = SE1;
472 break;
473 case( bmSE0): //disconnected state
474 regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ);
475 vbusState = SE0;
476 break;
477 }//end switch( bus_sample )
478}
479
480/* MAX3421 state change task and interrupt handler */
481template< typename SPI_SS, typename INTR >
482uint8_t MAX3421e< SPI_SS, INTR >::Task(void) {
483 uint8_t rcode = 0;
484 uint8_t pinvalue;
485 //USB_HOST_SERIAL.print("Vbus state: ");
486 //USB_HOST_SERIAL.println( vbusState, HEX );
487 pinvalue = INTR::IsSet(); //Read();
488 //pinvalue = digitalRead( MAX_INT );
489 if(pinvalue == 0) {
490 rcode = IntHandler();
491 }
492 // pinvalue = digitalRead( MAX_GPX );
493 // if( pinvalue == LOW ) {
494 // GpxHandler();
495 // }
496 // usbSM(); //USB state machine
497 return ( rcode);
498}
499
500template< typename SPI_SS, typename INTR >
501uint8_t MAX3421e< SPI_SS, INTR >::IntHandler() {
502 uint8_t HIRQ;
503 uint8_t HIRQ_sendback = 0x00;
504 HIRQ = regRd(rHIRQ); //determine interrupt source
505 //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler
506 // HIRQ_sendback |= bmFRAMEIRQ;
507 //}//end FRAMEIRQ handling
508 if(HIRQ & bmCONDETIRQ) {
509 busprobe();
510 HIRQ_sendback |= bmCONDETIRQ;
511 }
512 /* End HIRQ interrupts handling, clear serviced IRQs */
513 regWr(rHIRQ, HIRQ_sendback);
514 return ( HIRQ_sendback);
515}
516//template< typename SPI_SS, typename INTR >
517//uint8_t MAX3421e< SPI_SS, INTR >::GpxHandler()
518//{
519// uint8_t GPINIRQ = regRd( rGPINIRQ ); //read GPIN IRQ register
520//// if( GPINIRQ & bmGPINIRQ7 ) { //vbus overload
521//// vbusPwr( OFF ); //attempt powercycle
522//// delay( 1000 );
523//// vbusPwr( ON );
524//// regWr( rGPINIRQ, bmGPINIRQ7 );
525//// }
526// return( GPINIRQ );
527//}
528
529#endif // _USBHOST_H_