Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1702 | - | 1 | /* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */ |
2 | /* MAX3421E USB host controller support */ |
||
3 | |||
4 | #include "Max3421e.h" |
||
5 | // #include "Max3421e_constants.h" |
||
6 | |||
7 | static byte vbusState; |
||
8 | |||
9 | /* Functions */ |
||
10 | |||
11 | /* Constructor */ |
||
12 | MAX3421E::MAX3421E() |
||
13 | { |
||
14 | spi_init(); |
||
15 | pinMode( MAX_INT, INPUT); |
||
16 | pinMode( MAX_GPX, INPUT ); |
||
17 | pinMode( MAX_SS, OUTPUT ); |
||
18 | digitalWrite(MAX_SS,HIGH); |
||
19 | pinMode( MAX_RESET, OUTPUT ); |
||
20 | digitalWrite( MAX_RESET, HIGH ); //release MAX3421E from reset |
||
21 | } |
||
22 | |||
23 | byte MAX3421E::getVbusState( void ) |
||
24 | { |
||
25 | return( vbusState ); |
||
26 | } |
||
27 | /* initialization */ |
||
28 | //void MAX3421E::init() |
||
29 | //{ |
||
30 | // /* setup pins */ |
||
31 | // pinMode( MAX_INT, INPUT); |
||
32 | // pinMode( MAX_GPX, INPUT ); |
||
33 | // pinMode( MAX_SS, OUTPUT ); |
||
34 | // //pinMode( BPNT_0, OUTPUT ); |
||
35 | // //pinMode( BPNT_1, OUTPUT ); |
||
36 | // //digitalWrite( BPNT_0, LOW ); |
||
37 | // //digitalWrite( BPNT_1, LOW ); |
||
38 | // Deselect_MAX3421E; |
||
39 | // pinMode( MAX_RESET, OUTPUT ); |
||
40 | // digitalWrite( MAX_RESET, HIGH ); //release MAX3421E from reset |
||
41 | //} |
||
42 | //byte MAX3421E::getVbusState( void ) |
||
43 | //{ |
||
44 | // return( vbusState ); |
||
45 | //} |
||
46 | //void MAX3421E::toggle( byte pin ) |
||
47 | //{ |
||
48 | // digitalWrite( pin, HIGH ); |
||
49 | // digitalWrite( pin, LOW ); |
||
50 | //} |
||
51 | /* Single host register write */ |
||
52 | void MAX3421E::regWr( byte reg, byte val) |
||
53 | { |
||
54 | digitalWrite(MAX_SS,LOW); |
||
55 | SPDR = ( reg | 0x02 ); |
||
56 | while(!( SPSR & ( 1 << SPIF ))); |
||
57 | SPDR = val; |
||
58 | while(!( SPSR & ( 1 << SPIF ))); |
||
59 | digitalWrite(MAX_SS,HIGH); |
||
60 | return; |
||
61 | } |
||
62 | /* multiple-byte write */ |
||
63 | /* returns a pointer to a memory position after last written */ |
||
64 | char * MAX3421E::bytesWr( byte reg, byte nbytes, char * data ) |
||
65 | { |
||
66 | digitalWrite(MAX_SS,LOW); |
||
67 | SPDR = ( reg | 0x02 ); |
||
68 | while( nbytes-- ) { |
||
69 | while(!( SPSR & ( 1 << SPIF ))); //check if previous byte was sent |
||
70 | SPDR = ( *data ); // send next data byte |
||
71 | data++; // advance data pointer |
||
72 | } |
||
73 | while(!( SPSR & ( 1 << SPIF ))); |
||
74 | digitalWrite(MAX_SS,HIGH); |
||
75 | return( data ); |
||
76 | } |
||
77 | /* GPIO write. GPIO byte is split between 2 registers, so two writes are needed to write one byte */ |
||
78 | /* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */ |
||
79 | /* upper 4 bits of IOPINS1, IOPINS2 are read-only, so no masking is necessary */ |
||
80 | void MAX3421E::gpioWr( byte val ) |
||
81 | { |
||
82 | regWr( rIOPINS1, val ); |
||
83 | val = val >>4; |
||
84 | regWr( rIOPINS2, val ); |
||
85 | |||
86 | return; |
||
87 | } |
||
88 | /* Single host register read */ |
||
89 | byte MAX3421E::regRd( byte reg ) |
||
90 | { |
||
91 | byte tmp; |
||
92 | digitalWrite(MAX_SS,LOW); |
||
93 | SPDR = reg; |
||
94 | while(!( SPSR & ( 1 << SPIF ))); |
||
95 | SPDR = 0; //send empty byte |
||
96 | while(!( SPSR & ( 1 << SPIF ))); |
||
97 | digitalWrite(MAX_SS,HIGH); |
||
98 | return( SPDR ); |
||
99 | } |
||
100 | /* multiple-bytes register read */ |
||
101 | /* returns a pointer to a memory position after last read */ |
||
102 | char * MAX3421E::bytesRd ( byte reg, byte nbytes, char * data ) |
||
103 | { |
||
104 | digitalWrite(MAX_SS,LOW); |
||
105 | SPDR = reg; |
||
106 | while(!( SPSR & ( 1 << SPIF ))); //wait |
||
107 | while( nbytes ) { |
||
108 | SPDR = 0; //send empty byte |
||
109 | nbytes--; |
||
110 | while(!( SPSR & ( 1 << SPIF ))); |
||
111 | *data = SPDR; |
||
112 | data++; |
||
113 | } |
||
114 | digitalWrite(MAX_SS,HIGH); |
||
115 | return( data ); |
||
116 | } |
||
117 | /* GPIO read. See gpioWr for explanation */ |
||
118 | /* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */ |
||
119 | byte MAX3421E::gpioRd( void ) |
||
120 | { |
||
121 | byte tmpbyte = 0; |
||
122 | tmpbyte = regRd( rIOPINS2 ); //pins 4-7 |
||
123 | tmpbyte &= 0xf0; //clean lower nibble |
||
124 | tmpbyte |= ( regRd( rIOPINS1 ) >>4 ) ; //shift low bits and OR with upper from previous operation. Upper nibble zeroes during shift, at least with this compiler |
||
125 | return( tmpbyte ); |
||
126 | } |
||
127 | /* reset MAX3421E using chip reset bit. SPI configuration is not affected */ |
||
128 | boolean MAX3421E::reset() |
||
129 | { |
||
130 | byte tmp = 0; |
||
131 | regWr( rUSBCTL, bmCHIPRES ); //Chip reset. This stops the oscillator |
||
132 | regWr( rUSBCTL, 0x00 ); //Remove the reset |
||
133 | while(!(regRd( rUSBIRQ ) & bmOSCOKIRQ )) { //wait until the PLL is stable |
||
134 | tmp++; //timeout after 256 attempts |
||
135 | if( tmp == 0 ) { |
||
136 | return( false ); |
||
137 | } |
||
138 | } |
||
139 | return( true ); |
||
140 | } |
||
141 | /* turn USB power on/off */ |
||
142 | /* does nothing, returns TRUE. Left for compatibility with old sketches */ |
||
143 | /* will be deleted eventually */ |
||
144 | ///* ON pin of VBUS switch (MAX4793 or similar) is connected to GPOUT7 */ |
||
145 | ///* OVERLOAD pin of Vbus switch is connected to GPIN7 */ |
||
146 | ///* OVERLOAD state low. NO OVERLOAD or VBUS OFF state high. */ |
||
147 | boolean MAX3421E::vbusPwr ( boolean action ) |
||
148 | { |
||
149 | // byte tmp; |
||
150 | // tmp = regRd( rIOPINS2 ); //copy of IOPINS2 |
||
151 | // if( action ) { //turn on by setting GPOUT7 |
||
152 | // tmp |= bmGPOUT7; |
||
153 | // } |
||
154 | // else { //turn off by clearing GPOUT7 |
||
155 | // tmp &= ~bmGPOUT7; |
||
156 | // } |
||
157 | // regWr( rIOPINS2, tmp ); //send GPOUT7 |
||
158 | // if( action ) { |
||
159 | // delay( 60 ); |
||
160 | // } |
||
161 | // if (( regRd( rIOPINS2 ) & bmGPIN7 ) == 0 ) { // check if overload is present. MAX4793 /FLAG ( pin 4 ) goes low if overload |
||
162 | // return( false ); |
||
163 | // } |
||
164 | return( true ); // power on/off successful |
||
165 | } |
||
166 | /* probe bus to determine device presense and speed and switch host to this speed */ |
||
167 | void MAX3421E::busprobe( void ) |
||
168 | { |
||
169 | byte bus_sample; |
||
170 | bus_sample = regRd( rHRSL ); //Get J,K status |
||
171 | bus_sample &= ( bmJSTATUS|bmKSTATUS ); //zero the rest of the byte |
||
172 | switch( bus_sample ) { //start full-speed or low-speed host |
||
173 | case( bmJSTATUS ): |
||
174 | if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) { |
||
175 | regWr( rMODE, MODE_FS_HOST ); //start full-speed host |
||
176 | vbusState = FSHOST; |
||
177 | } |
||
178 | else { |
||
179 | regWr( rMODE, MODE_LS_HOST); //start low-speed host |
||
180 | vbusState = LSHOST; |
||
181 | } |
||
182 | break; |
||
183 | case( bmKSTATUS ): |
||
184 | if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) { |
||
185 | regWr( rMODE, MODE_LS_HOST ); //start low-speed host |
||
186 | vbusState = LSHOST; |
||
187 | } |
||
188 | else { |
||
189 | regWr( rMODE, MODE_FS_HOST ); //start full-speed host |
||
190 | vbusState = FSHOST; |
||
191 | } |
||
192 | break; |
||
193 | case( bmSE1 ): //illegal state |
||
194 | vbusState = SE1; |
||
195 | break; |
||
196 | case( bmSE0 ): //disconnected state |
||
197 | vbusState = SE0; |
||
198 | break; |
||
199 | }//end switch( bus_sample ) |
||
200 | } |
||
201 | /* MAX3421E initialization after power-on */ |
||
202 | void MAX3421E::powerOn() |
||
203 | { |
||
204 | /* Configure full-duplex SPI, interrupt pulse */ |
||
205 | regWr( rPINCTL,( bmFDUPSPI + bmINTLEVEL + bmGPXB )); //Full-duplex SPI, level interrupt, GPX |
||
206 | if( reset() == false ) { //stop/start the oscillator |
||
207 | Serial.println("Error: OSCOKIRQ failed to assert"); |
||
208 | } |
||
209 | |||
210 | /* configure host operation */ |
||
211 | regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ ); // set pull-downs, Host, Separate GPIN IRQ on GPX |
||
212 | regWr( rHIEN, bmCONDETIE|bmFRAMEIE ); //connection detection |
||
213 | /* check if device is connected */ |
||
214 | regWr( rHCTL,bmSAMPLEBUS ); // sample USB bus |
||
215 | while(!(regRd( rHCTL ) & bmSAMPLEBUS )); //wait for sample operation to finish |
||
216 | busprobe(); //check if anything is connected |
||
217 | regWr( rHIRQ, bmCONDETIRQ ); //clear connection detect interrupt |
||
218 | regWr( rCPUCTL, 0x01 ); //enable interrupt pin |
||
219 | } |
||
220 | /* MAX3421 state change task and interrupt handler */ |
||
221 | byte MAX3421E::Task( void ) |
||
222 | { |
||
223 | byte rcode = 0; |
||
224 | byte pinvalue; |
||
225 | //Serial.print("Vbus state: "); |
||
226 | //Serial.println( vbusState, HEX ); |
||
227 | pinvalue = digitalRead( MAX_INT ); |
||
228 | if( pinvalue == LOW ) { |
||
229 | rcode = IntHandler(); |
||
230 | } |
||
231 | pinvalue = digitalRead( MAX_GPX ); |
||
232 | if( pinvalue == LOW ) { |
||
233 | GpxHandler(); |
||
234 | } |
||
235 | // usbSM(); //USB state machine |
||
236 | return( rcode ); |
||
237 | } |
||
238 | byte MAX3421E::IntHandler() |
||
239 | { |
||
240 | byte HIRQ; |
||
241 | byte HIRQ_sendback = 0x00; |
||
242 | HIRQ = regRd( rHIRQ ); //determine interrupt source |
||
243 | //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler |
||
244 | // HIRQ_sendback |= bmFRAMEIRQ; |
||
245 | //}//end FRAMEIRQ handling |
||
246 | if( HIRQ & bmCONDETIRQ ) { |
||
247 | busprobe(); |
||
248 | HIRQ_sendback |= bmCONDETIRQ; |
||
249 | } |
||
250 | /* End HIRQ interrupts handling, clear serviced IRQs */ |
||
251 | regWr( rHIRQ, HIRQ_sendback ); |
||
252 | return( HIRQ_sendback ); |
||
253 | } |
||
254 | byte MAX3421E::GpxHandler() |
||
255 | { |
||
256 | byte GPINIRQ = regRd( rGPINIRQ ); //read GPIN IRQ register |
||
257 | // if( GPINIRQ & bmGPINIRQ7 ) { //vbus overload |
||
258 | // vbusPwr( OFF ); //attempt powercycle |
||
259 | // delay( 1000 ); |
||
260 | // vbusPwr( ON ); |
||
261 | // regWr( rGPINIRQ, bmGPINIRQ7 ); |
||
262 | // } |
||
263 | return( GPINIRQ ); |
||
264 | } |
||
265 | |||
266 | //void MAX3421E::usbSM( void ) //USB state machine |
||
267 | //{ |
||
268 | // |
||
269 | // |
||
270 | //} |