USB Host Shield 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
usbhost.h
Go to the documentation of this file.
1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
2 
3 This software may be distributed and modified under the terms of the GNU
4 General Public License version 2 (GPL2) as published by the Free Software
5 Foundation and appearing in the file GPL2.TXT included in the packaging of
6 this file. Please note that GPL2 Section 2[b] requires that all works based
7 on this software must also be made publicly available under the terms of
8 the GPL2 ("Copyleft").
9 
10 Contact information
11 -------------------
12 
13 Circuits At Home, LTD
14 Web : http://www.circuitsathome.com
15 e-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 */
31 template< typename SPI_CLK, typename SPI_MOSI, typename SPI_MISO, typename SPI_SS > class SPi {
32 public:
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 defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
43  static void init() {
44  SPI_SS::SetDirWrite();
45  SPI_SS::Set();
46  SPI.begin();
47  SPI.setClockDivider(4); // Set speed to 84MHz/4=21MHz - the MAX3421E can handle up to 26MHz
48  }
49 #else
50  static void init() {
51  //uint8_t tmp;
52  SPI_CLK::SetDirWrite();
53  SPI_MOSI::SetDirWrite();
54  SPI_MISO::SetDirRead();
55  SPI_SS::SetDirWrite();
56  /* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */
57  SPCR = 0x50;
58  SPSR = 0x01; // 0x01
59 
60  //tmp = SPSR;
61  //tmp = SPDR;
62  }
63 #endif
64 };
65 
66 /* SPI pin definitions. see avrpins.h */
67 #if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
68 typedef SPi< Pb1, Pb2, Pb3, Pb0 > spi;
69 #elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
70 typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi;
71 #elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
72 typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi;
73 #elif defined(CORE_TEENSY) && (defined(__MK20DX128__) || defined(__MK20DX256__))
74 typedef SPi< P13, P11, P12, P10 > spi;
75 #elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
76 typedef SPi< P76, P75, P74, P10 > spi;
77 #else
78 #error "No SPI entry in usbhost.h"
79 #endif
80 
81 typedef enum {
82  vbus_on = 0,
84 } VBUS_t;
85 
86 template< typename SPI_SS, typename INTR > class MAX3421e /* : public spi */ {
87  static uint8_t vbusState;
88 
89 public:
90  MAX3421e();
91  void regWr(uint8_t reg, uint8_t data);
92  uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
93  void gpioWr(uint8_t data);
94  uint8_t regRd(uint8_t reg);
95  uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
96  uint8_t gpioRd();
97  uint16_t reset();
98  int8_t Init();
99  int8_t Init(int mseconds);
100 
101  void vbusPower(VBUS_t state) {
102  regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | state));
103  }
104 
105  uint8_t getVbusState(void) {
106  return vbusState;
107  };
108  void busprobe();
109  uint8_t GpxHandler();
110  uint8_t IntHandler();
111  uint8_t Task();
112 };
113 
114 template< typename SPI_SS, typename INTR >
116 
117 /* constructor */
118 template< typename SPI_SS, typename INTR >
120  // Leaving ADK hardware setup in here, for now. This really belongs with the other parts.
121 #ifdef BOARD_MEGA_ADK
122  // For Mega ADK, which has a Max3421e on-board, set MAX_RESET to output mode, and then set it to HIGH
123  P55::SetDirWrite();
124  P55::Set();
125 #endif
126 };
127 
128 /* write single byte into MAX3421 register */
129 template< typename SPI_SS, typename INTR >
130 void MAX3421e< SPI_SS, INTR >::regWr(uint8_t reg, uint8_t data) {
132  SPI_SS::Clear();
133 #if USING_SPI4TEENSY3
134  uint8_t c[2];
135  c[0] = reg | 0x02;
136  c[1] = data;
137  spi4teensy3::send(c, 2);
138 #elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
139  SPI.transfer(reg | 0x02);
140  SPI.transfer(data);
141 #else
142  SPDR = (reg | 0x02);
143  while(!(SPSR & (1 << SPIF)));
144  SPDR = data;
145  while(!(SPSR & (1 << SPIF)));
146 #endif
147  SPI_SS::Set();
149  return;
150 };
151 /* multiple-byte write */
152 
153 /* returns a pointer to memory position after last written */
154 template< typename SPI_SS, typename INTR >
155 uint8_t* MAX3421e< SPI_SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
157  SPI_SS::Clear();
158 #if USING_SPI4TEENSY3
159  spi4teensy3::send(reg | 0x02);
160  spi4teensy3::send(data_p, nbytes);
161  data_p += nbytes;
162 #elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
163  SPI.transfer(reg | 0x02);
164  while(nbytes) {
165  SPI.transfer(*data_p);
166  nbytes--;
167  data_p++; // advance data pointer
168  }
169 #else
170  SPDR = (reg | 0x02); //set WR bit and send register number
171  while(nbytes) {
172  while(!(SPSR & (1 << SPIF))); //check if previous byte was sent
173  SPDR = (*data_p); // send next data byte
174  nbytes--;
175  data_p++; // advance data pointer
176  }
177  while(!(SPSR & (1 << SPIF)));
178 #endif
179  SPI_SS::Set();
181  return ( data_p);
182 }
183 /* GPIO write */
184 /*GPIO byte is split between 2 registers, so two writes are needed to write one byte */
185 
186 /* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */
187 template< typename SPI_SS, typename INTR >
189  regWr(rIOPINS1, data);
190  data >>= 4;
191  regWr(rIOPINS2, data);
192  return;
193 }
194 
195 /* single host register read */
196 template< typename SPI_SS, typename INTR >
197 uint8_t MAX3421e< SPI_SS, INTR >::regRd(uint8_t reg) {
199  SPI_SS::Clear();
200 #if USING_SPI4TEENSY3
201  spi4teensy3::send(reg);
202  uint8_t rv = spi4teensy3::receive();
203  SPI_SS::Set();
204 #elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
205  SPI.transfer(reg);
206  uint8_t rv = SPI.transfer(0);
207  SPI_SS::Set();
208 #else
209  SPDR = reg;
210  while(!(SPSR & (1 << SPIF)));
211  SPDR = 0; //send empty byte
212  while(!(SPSR & (1 << SPIF)));
213  SPI_SS::Set();
214  uint8_t rv = SPDR;
215 #endif
217  return (rv);
218 }
219 /* multiple-byte register read */
220 
221 /* returns a pointer to a memory position after last read */
222 template< typename SPI_SS, typename INTR >
223 uint8_t* MAX3421e< SPI_SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
225  SPI_SS::Clear();
226 #if USING_SPI4TEENSY3
227  spi4teensy3::send(reg);
228  spi4teensy3::receive(data_p, nbytes);
229  data_p += nbytes;
230 #elif defined(ARDUINO_SAM_DUE) && defined(__SAM3X8E__)
231  SPI.transfer(reg);
232  while(nbytes) {
233  *data_p++ = SPI.transfer(0);
234  nbytes--;
235  }
236 #else
237  SPDR = reg;
238  while(!(SPSR & (1 << SPIF))); //wait
239  while(nbytes) {
240  SPDR = 0; //send empty byte
241  nbytes--;
242  while(!(SPSR & (1 << SPIF)));
243 #if 0
244  {
245  *data_p = SPDR;
246  printf("%2.2x ", *data_p);
247  }
248  data_p++;
249  }
250  printf("\r\n");
251 #else
252  *data_p++ = SPDR;
253  }
254 #endif
255 #endif
256  SPI_SS::Set();
258  return ( data_p);
259 }
260 /* GPIO read. See gpioWr for explanation */
261 
262 /* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */
263 template< typename SPI_SS, typename INTR >
265  uint8_t gpin = 0;
266  gpin = regRd(rIOPINS2); //pins 4-7
267  gpin &= 0xf0; //clean lower nibble
268  gpin |= (regRd(rIOPINS1) >> 4); //shift low bits and OR with upper from previous operation.
269  return ( gpin);
270 }
271 
272 /* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset
273  or zero if PLL haven't stabilized in 65535 cycles */
274 template< typename SPI_SS, typename INTR >
276  uint16_t i = 0;
277  regWr(rUSBCTL, bmCHIPRES);
278  regWr(rUSBCTL, 0x00);
279  while(++i) {
280  if((regRd(rUSBIRQ) & bmOSCOKIRQ)) {
281  break;
282  }
283  }
284  return ( i);
285 }
286 
287 /* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
288 template< typename SPI_SS, typename INTR >
291  // Moved here.
292  // you really should not init hardware in the constructor when it involves locks.
293  // Also avoids the vbus flicker issue confusing some devices.
294  /* pin and peripheral setup */
295  SPI_SS::SetDirWrite();
296  SPI_SS::Set();
297  spi::init();
298  INTR::SetDirRead();
300  /* MAX3421E - full-duplex SPI, level interrupt */
301  // GPX pin on. Moved here, otherwise we flicker the vbus.
302  regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
303 
304  if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
305  return ( -1);
306  }
307 
308  regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
309 
310  regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
311 
312  /* check if device is connected */
313  regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
314  while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
315 
316  busprobe(); //check if anything is connected
317 
318  regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
319  regWr(rCPUCTL, 0x01); //enable interrupt pin
320 
321  return ( 0);
322 }
323 
324 /* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
325 template< typename SPI_SS, typename INTR >
326 int8_t MAX3421e< SPI_SS, INTR >::Init(int mseconds) {
328  // Moved here.
329  // you really should not init hardware in the constructor when it involves locks.
330  // Also avoids the vbus flicker issue confusing some devices.
331  /* pin and peripheral setup */
332  SPI_SS::SetDirWrite();
333  SPI_SS::Set();
334  spi::init();
335  INTR::SetDirRead();
337  /* MAX3421E - full-duplex SPI, level interrupt, vbus off */
338  regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET));
339 
340  if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
341  return ( -1);
342  }
343 
344  // Delay a minimum of 1 second to ensure any capacitors are drained.
345  // 1 second is required to make sure we do not smoke a Microdrive!
346  if(mseconds < 1000) mseconds = 1000;
347  delay(mseconds);
348 
349  regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
350 
351  regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
352 
353  /* check if device is connected */
354  regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
355  while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
356 
357  busprobe(); //check if anything is connected
358 
359  regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
360  regWr(rCPUCTL, 0x01); //enable interrupt pin
361 
362  // GPX pin on. This is done here so that busprobe will fail if we have a switch connected.
363  regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
364 
365  return ( 0);
366 }
367 
368 /* probe bus to determine device presence and speed and switch host to this speed */
369 template< typename SPI_SS, typename INTR >
371  uint8_t bus_sample;
372  bus_sample = regRd(rHRSL); //Get J,K status
373  bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the byte
374  switch(bus_sample) { //start full-speed or low-speed host
375  case( bmJSTATUS):
376  if((regRd(rMODE) & bmLOWSPEED) == 0) {
377  regWr(rMODE, MODE_FS_HOST); //start full-speed host
378  vbusState = FSHOST;
379  } else {
380  regWr(rMODE, MODE_LS_HOST); //start low-speed host
381  vbusState = LSHOST;
382  }
383  break;
384  case( bmKSTATUS):
385  if((regRd(rMODE) & bmLOWSPEED) == 0) {
386  regWr(rMODE, MODE_LS_HOST); //start low-speed host
387  vbusState = LSHOST;
388  } else {
389  regWr(rMODE, MODE_FS_HOST); //start full-speed host
390  vbusState = FSHOST;
391  }
392  break;
393  case( bmSE1): //illegal state
394  vbusState = SE1;
395  break;
396  case( bmSE0): //disconnected state
397  regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ);
398  vbusState = SE0;
399  break;
400  }//end switch( bus_sample )
401 }
402 
403 /* MAX3421 state change task and interrupt handler */
404 template< typename SPI_SS, typename INTR >
406  uint8_t rcode = 0;
407  uint8_t pinvalue;
408  //USB_HOST_SERIAL.print("Vbus state: ");
409  //USB_HOST_SERIAL.println( vbusState, HEX );
410  pinvalue = INTR::IsSet(); //Read();
411  //pinvalue = digitalRead( MAX_INT );
412  if(pinvalue == 0) {
413  rcode = IntHandler();
414  }
415  // pinvalue = digitalRead( MAX_GPX );
416  // if( pinvalue == LOW ) {
417  // GpxHandler();
418  // }
419  // usbSM(); //USB state machine
420  return ( rcode);
421 }
422 
423 template< typename SPI_SS, typename INTR >
425  uint8_t HIRQ;
426  uint8_t HIRQ_sendback = 0x00;
427  HIRQ = regRd(rHIRQ); //determine interrupt source
428  //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler
429  // HIRQ_sendback |= bmFRAMEIRQ;
430  //}//end FRAMEIRQ handling
431  if(HIRQ & bmCONDETIRQ) {
432  busprobe();
433  HIRQ_sendback |= bmCONDETIRQ;
434  }
435  /* End HIRQ interrupts handling, clear serviced IRQs */
436  regWr(rHIRQ, HIRQ_sendback);
437  return ( HIRQ_sendback);
438 }
439 //template< typename SPI_SS, typename INTR >
440 //uint8_t MAX3421e< SPI_SS, INTR >::GpxHandler()
441 //{
442 // uint8_t GPINIRQ = regRd( rGPINIRQ ); //read GPIN IRQ register
449 // return( GPINIRQ );
450 //}
451 
452 #endif //_USBHOST_H_
#define GPX_VBDET
Definition: max3421e.h:80
#define rIOPINS1
Definition: max3421e.h:86
void busprobe()
Definition: usbhost.h:370
#define rHIEN
Definition: max3421e.h:153
#define FSHOST
Definition: max3421e.h:35
#define rHCTL
Definition: max3421e.h:179
#define bmCONDETIRQ
Definition: max3421e.h:149
#define bmCONDETIE
Definition: max3421e.h:161
#define bmSE1
Definition: max3421e.h:209
#define bmCHIPRES
Definition: max3421e.h:62
uint8_t getVbusState(void)
Definition: usbhost.h:105
#define rCPUCTL
Definition: max3421e.h:65
#define bmJSTATUS
Definition: max3421e.h:207
uint16_t reset()
Definition: usbhost.h:275
#define MODE_LS_HOST
Definition: max3421e.h:230
#define bmINTLEVEL
Definition: max3421e.h:74
void gpioWr(uint8_t data)
Definition: usbhost.h:188
uint8_t Task()
Definition: usbhost.h:405
#define rUSBCTL
Definition: max3421e.h:60
#define bmSE0
Definition: max3421e.h:208
#define bmHOST
Definition: max3421e.h:168
#define bmSEPIRQ
Definition: max3421e.h:172
uint8_t gpioRd()
Definition: usbhost.h:264
int8_t Init()
Definition: usbhost.h:289
uint8_t GpxHandler()
#define LSHOST
Definition: max3421e.h:36
#define rMODE
Definition: max3421e.h:165
#define MODE_FS_HOST
Definition: max3421e.h:229
void vbusPower(VBUS_t state)
Definition: usbhost.h:101
#define bmKSTATUS
Definition: max3421e.h:206
#define rHRSL
Definition: max3421e.h:201
uint8_t * bytesRd(uint8_t reg, uint8_t nbytes, uint8_t *data_p)
Definition: usbhost.h:223
#define XMEM_ACQUIRE_SPI()
Definition: settings.h:123
#define bmLOWSPEED
Definition: max3421e.h:169
uint8_t * bytesWr(uint8_t reg, uint8_t nbytes, uint8_t *data_p)
Definition: usbhost.h:155
Definition: usbhost.h:31
#define rHIRQ
Definition: max3421e.h:142
#define rUSBIRQ
Definition: max3421e.h:48
#define XMEM_RELEASE_SPI()
Definition: settings.h:124
#define bmFDUPSPI
Definition: max3421e.h:73
#define rPINCTL
Definition: max3421e.h:71
VBUS_t
Definition: usbhost.h:81
void regWr(uint8_t reg, uint8_t data)
Definition: usbhost.h:130
#define bmFRAMEIE
Definition: max3421e.h:162
uint8_t IntHandler()
Definition: usbhost.h:424
#define bmOSCOKIRQ
Definition: max3421e.h:52
uint8_t regRd(uint8_t reg)
Definition: usbhost.h:197
MAX3421e()
Definition: usbhost.h:119
#define SE0
Definition: max3421e.h:33
#define rIOPINS2
Definition: max3421e.h:98
#define bmDMPULLDN
Definition: max3421e.h:174
#define SE1
Definition: max3421e.h:34
#define bmSAMPLEBUS
Definition: max3421e.h:183
static void init()
Definition: usbhost.h:50
#define bmDPPULLDN
Definition: max3421e.h:175