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