Subversion Repositories Projects

Rev

Go to most recent revision | 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
//}