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 #ifndef _USBHOST_H_
19 #define _USBHOST_H_
20 
21 // So we can use delay() -- xxxajk
22 #if defined(ARDUINO) && ARDUINO >=100
23 #include "Arduino.h"
24 #else
25 #include <WProgram.h>
26 #endif
27 
28 #include "avrpins.h"
29 #include "max3421e.h"
30 #include "usb_ch9.h"
31 #include <stdio.h>
32 /* SPI initialization */
33 template< typename CLK, typename MOSI, typename MISO, typename SPI_SS > class SPi {
34 public:
35 
36  static void init() {
37  //uint8_t tmp;
38  CLK::SetDirWrite();
39  MOSI::SetDirWrite();
40  MISO::SetDirRead();
41  SPI_SS::SetDirWrite();
42  /* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */
43  SPCR = 0x50;
44  SPSR = 0x01; // 0x01
45 
46  //tmp = SPSR;
47  //tmp = SPDR;
48  }
49 };
50 
51 /* SPI pin definitions. see avrpins.h */
52 #if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
53 typedef SPi< Pb1, Pb2, Pb3, Pb0 > spi;
54 #endif
55 #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
56 typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi;
57 #endif
58 #if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__)
59 typedef SPi< Pb7, Pb5, Pb6, Pb4 > spi;
60 #endif
61 
62 typedef enum VBUS_t {
63  on = 0,
65 };
66 
67 template< typename SS, typename INTR > class MAX3421e /* : public spi */ {
68  static uint8_t vbusState;
69 
70 public:
71  MAX3421e();
72  void regWr(uint8_t reg, uint8_t data);
73  uint8_t* bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
74  void gpioWr(uint8_t data);
75  uint8_t regRd(uint8_t reg);
76  uint8_t* bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p);
77  uint8_t gpioRd();
78  uint16_t reset();
79  int8_t Init();
80  int8_t Init(int mseconds);
81 
82  void vbusPower(VBUS_t state) {
83  regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | state));
84  }
85 
86  uint8_t getVbusState(void) {
87  return vbusState;
88  };
89  void busprobe();
90  uint8_t GpxHandler();
91  uint8_t IntHandler();
92  uint8_t Task();
93 };
94 
95 template< typename SS, typename INTR >
97 
98 /* constructor */
99 template< typename SS, typename INTR >
101  /* pin and peripheral setup */
102  SS::SetDirWrite();
103  SS::Set();
104  spi::init();
105  INTR::SetDirRead();
106 #ifdef BOARD_MEGA_ADK
107  /* For Mega ADK, which has Max3421e on-board, set MAX_RESET to Output mode, and pull Reset to HIGH */
108  DDRJ |= _BV(PJ2);
109  PORTJ &= ~_BV(PJ2);
110  PORTJ |= _BV(PJ2);
111 #endif
112 
113  /* MAX3421E - full-duplex SPI, level interrupt */
114  regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL | GPX_VBDET));
115 };
116 
117 /* write single byte into MAX3421 register */
118 template< typename SS, typename INTR >
119 void MAX3421e< SS, INTR >::regWr(uint8_t reg, uint8_t data) {
120  SS::Clear();
121  SPDR = (reg | 0x02);
122  while(!(SPSR & (1 << SPIF)));
123  SPDR = data;
124  while(!(SPSR & (1 << SPIF)));
125  SS::Set();
126  return;
127 };
128 /* multiple-byte write */
129 
130 /* returns a pointer to memory position after last written */
131 template< typename SS, typename INTR >
132 uint8_t* MAX3421e< SS, INTR >::bytesWr(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
133  SS::Clear();
134  SPDR = (reg | 0x02); //set WR bit and send register number
135  while(nbytes--) {
136  while(!(SPSR & (1 << SPIF))); //check if previous byte was sent
137  SPDR = (*data_p); // send next data byte
138  data_p++; // advance data pointer
139  }
140  while(!(SPSR & (1 << SPIF)));
141  SS::Set();
142  return( data_p);
143 }
144 /* GPIO write */
145 /*GPIO byte is split between 2 registers, so two writes are needed to write one byte */
146 
147 /* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */
148 template< typename SS, typename INTR >
149 void MAX3421e< SS, INTR >::gpioWr(uint8_t data) {
150  regWr(rIOPINS1, data);
151  data >>= 4;
152  regWr(rIOPINS2, data);
153  return;
154 }
155 
156 /* single host register read */
157 template< typename SS, typename INTR >
158 uint8_t MAX3421e< SS, INTR >::regRd(uint8_t reg) {
159  SS::Clear();
160  SPDR = reg;
161  while(!(SPSR & (1 << SPIF)));
162  SPDR = 0; //send empty byte
163  while(!(SPSR & (1 << SPIF)));
164  SS::Set();
165  return( SPDR);
166 }
167 /* multiple-byte register read */
168 
169 /* returns a pointer to a memory position after last read */
170 template< typename SS, typename INTR >
171 uint8_t* MAX3421e< SS, INTR >::bytesRd(uint8_t reg, uint8_t nbytes, uint8_t* data_p) {
172  SS::Clear();
173  SPDR = reg;
174  while(!(SPSR & (1 << SPIF))); //wait
175  while(nbytes) {
176  SPDR = 0; //send empty byte
177  nbytes--;
178  while(!(SPSR & (1 << SPIF)));
179 #if 0
180  {
181  *data_p = SPDR;
182  printf("%2.2x ", *data_p);
183  }
184  data_p++;
185  }
186  printf("\r\n");
187 #else
188  *data_p++ = SPDR;
189  }
190 #endif
191  SS::Set();
192  return( data_p);
193 }
194 /* GPIO read. See gpioWr for explanation */
195 
196 /* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */
197 template< typename SS, typename INTR >
199  uint8_t gpin = 0;
200  gpin = regRd(rIOPINS2); //pins 4-7
201  gpin &= 0xf0; //clean lower nibble
202  gpin |= (regRd(rIOPINS1) >> 4); //shift low bits and OR with upper from previous operation.
203  return( gpin);
204 }
205 
206 /* reset MAX3421E. Returns number of cycles it took for PLL to stabilize after reset
207  or zero if PLL haven't stabilized in 65535 cycles */
208 template< typename SS, typename INTR >
210  uint16_t i = 0;
211  regWr(rUSBCTL, bmCHIPRES);
212  regWr(rUSBCTL, 0x00);
213  while(++i) {
214  if((regRd(rUSBIRQ) & bmOSCOKIRQ)) {
215  break;
216  }
217  }
218  return( i);
219 }
220 
221 /* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
222 template< typename SS, typename INTR >
224  if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
225  return( -1);
226  }
227 
228  // GPX pin on.
229  regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
230 
231  regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
232 
233  regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
234 
235  /* check if device is connected */
236  regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
237  while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
238 
239  busprobe(); //check if anything is connected
240 
241  regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
242  regWr(rCPUCTL, 0x01); //enable interrupt pin
243 
244  return( 0);
245 }
246 
247 /* initialize MAX3421E. Set Host mode, pullups, and stuff. Returns 0 if success, -1 if not */
248 template< typename SS, typename INTR >
249 int8_t MAX3421e< SS, INTR >::Init(int mseconds) {
250  if(reset() == 0) { //OSCOKIRQ hasn't asserted in time
251  return( -1);
252  }
253 
254  // Delay a minimum of 1 second to ensure any capacitors are drained.
255  // 1 second is required to make sure we do not smoke a Microdrive!
256  if(mseconds < 1000) mseconds = 1000;
257  delay(mseconds);
258 
259  regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST); // set pull-downs, Host
260 
261  regWr(rHIEN, bmCONDETIE | bmFRAMEIE); //connection detection
262 
263  /* check if device is connected */
264  regWr(rHCTL, bmSAMPLEBUS); // sample USB bus
265  while(!(regRd(rHCTL) & bmSAMPLEBUS)); //wait for sample operation to finish
266 
267  busprobe(); //check if anything is connected
268 
269  regWr(rHIRQ, bmCONDETIRQ); //clear connection detect interrupt
270  regWr(rCPUCTL, 0x01); //enable interrupt pin
271 
272  // GPX pin on. This is done here so that busprobe will fail if we have a switch connected.
273  regWr(rPINCTL, (bmFDUPSPI | bmINTLEVEL));
274 
275  return( 0);
276 }
277 
278 /* probe bus to determine device presence and speed and switch host to this speed */
279 template< typename SS, typename INTR >
281  uint8_t bus_sample;
282  bus_sample = regRd(rHRSL); //Get J,K status
283  bus_sample &= (bmJSTATUS | bmKSTATUS); //zero the rest of the byte
284  switch(bus_sample) { //start full-speed or low-speed host
285  case( bmJSTATUS):
286  if((regRd(rMODE) & bmLOWSPEED) == 0) {
287  regWr(rMODE, MODE_FS_HOST); //start full-speed host
288  vbusState = FSHOST;
289  } else {
290  regWr(rMODE, MODE_LS_HOST); //start low-speed host
291  vbusState = LSHOST;
292  }
293  break;
294  case( bmKSTATUS):
295  if((regRd(rMODE) & bmLOWSPEED) == 0) {
296  regWr(rMODE, MODE_LS_HOST); //start low-speed host
297  vbusState = LSHOST;
298  } else {
299  regWr(rMODE, MODE_FS_HOST); //start full-speed host
300  vbusState = FSHOST;
301  }
302  break;
303  case( bmSE1): //illegal state
304  vbusState = SE1;
305  break;
306  case( bmSE0): //disconnected state
307  regWr(rMODE, bmDPPULLDN | bmDMPULLDN | bmHOST | bmSEPIRQ);
308  vbusState = SE0;
309  break;
310  }//end switch( bus_sample )
311 }
312 
313 /* MAX3421 state change task and interrupt handler */
314 template< typename SS, typename INTR >
316  uint8_t rcode = 0;
317  uint8_t pinvalue;
318  //USB_HOST_SERIAL.print("Vbus state: ");
319  //USB_HOST_SERIAL.println( vbusState, HEX );
320  pinvalue = INTR::IsSet(); //Read();
321  //pinvalue = digitalRead( MAX_INT );
322  if(pinvalue == 0) {
323  rcode = IntHandler();
324  }
325  // pinvalue = digitalRead( MAX_GPX );
326  // if( pinvalue == LOW ) {
327  // GpxHandler();
328  // }
329  // usbSM(); //USB state machine
330  return( rcode);
331 }
332 
333 template< typename SS, typename INTR >
335  uint8_t HIRQ;
336  uint8_t HIRQ_sendback = 0x00;
337  HIRQ = regRd(rHIRQ); //determine interrupt source
338  //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler
339  // HIRQ_sendback |= bmFRAMEIRQ;
340  //}//end FRAMEIRQ handling
341  if(HIRQ & bmCONDETIRQ) {
342  busprobe();
343  HIRQ_sendback |= bmCONDETIRQ;
344  }
345  /* End HIRQ interrupts handling, clear serviced IRQs */
346  regWr(rHIRQ, HIRQ_sendback);
347  return( HIRQ_sendback);
348 }
349 //template< typename SS, typename INTR >
350 //uint8_t MAX3421e< SS, INTR >::GpxHandler()
351 //{
352 // uint8_t GPINIRQ = regRd( rGPINIRQ ); //read GPIN IRQ register
359 // return( GPINIRQ );
360 //}
361 
362 #endif //_USBHOST_H_