[go: nahoru, domu]

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