I started porting my PIC USB host code to Arduino platform. There is now a repository on GitHub. Right now it contains a single class of functions talking to MAX3421E. This is not enough to support full USB host functionality, but enough to get started. To follow examples given in this article, create a sub-directory in your Arduino hardware libraries directory and copy MAX3421E*.* files from the repository into it.
MAX3421E talks to Arduino via SPI, so you will need Arduino SPI library. SPI uses pin13 – a pin also used to blink LEDs. Some Arduinos even have this LED hard-wired to pin13. My Arduino has it, and it co-exists peacefully with MAX3421E, however, there is no guarantee it will work on others. It would depend on current drawn by the LED. If you have problems communicating with MAX3421E and/or you can’t see SPI clock on this pin with your oscilloscope or protocol analyzer, try to disconnect the LED and see if it changes anything.
Picture on the right shows the final arrangement. The breakout board sitting on top of protoshield is a 3.3V part. Since I’m using 3.3V Arduino Pro from Sparkfun, no level converters are necessary. Look at the previous article for the closeout picture and schematic. The breakout receives power from Arduino.
Let’s start using our MAX3421E functions to get better understanding how this controller operates. First of all, we need to make sure that Arduino talks to MAX3421E. Below is a little test which writes numbers from 0 to 255 to MAX3421E GPINPOL register and reads them back. It can be run from terminal or directly from IDE. If there is no errors, it will print a dot after each 65535 transmissions.
/* MAX3421E USB Host controller SPI test */ /* This sketch tests SPI communication between Arduino and MAX3421E USB host controller */ #include <Spi.h> #include <Max3421e.h> void setup(); void loop(); byte i; byte j = 0; byte gpinpol_copy; MAX3421E Max; void setup() { Serial.begin( 9600 ); Max.powerOn(); delay(200); } void loop() { gpinpol_copy = Max.regRd( rGPINPOL ); Serial.println("SPI test. Each '.' indicates 64K transferred. Press any key to stop."); while( Serial.available() == 0 ) { for( i = 0; i < 255; i++ ) { Max.regWr( rGPINPOL, i ); if( Max.regRd( rGPINPOL ) != i ) { Serial.println("SPI transmit/receive mismatch"); } }//for( i = 0; i < 255; i++ j++; if( j == 0 ) { Serial.print("."); } }//while( Serial.available() == 0 Max.regWr( rGPINPOL, gpinpol_copy ); Serial.println("\r\nStopped."); while( 1 ); //stop here }
The next sketch outputs MAX3421E registers. It is helpful to see the state of USB bus or transfer result. Here I just dump them all to the screen. There is no input, so this sketch can be run from serial monitor. Regretfully, default Arduino print doesn’t have a format for printing hex numbers with leading zeroes; to generate proper output, I borrowed a function from Peter H Anderson’s website.
/* This sketch dumps MAX3421E registers */ #include <Spi.h> #include <Max3421e.h> MAX3421E Max; //MAX3421E instance /* Regiser names/numbers for MAX3421E register dump */ typedef struct { const char* name; char number; } REGISTER_OUTPUT; REGISTER_OUTPUT max_register[] = { { "\r\nRCVFIFO:\t", rRCVFIFO }, { "\r\nSNDFIFO:\t", rSNDFIFO }, { "\r\nSUDFIFO:\t", rSUDFIFO }, { "\r\nRCVBC:\t", rRCVBC }, { "\r\nSNDBC:\t", rSNDBC }, { "\r\nUSBIRQ:\t", rUSBIRQ }, { "\r\nUSBIEN:\t", rUSBIEN }, { "\r\nUSBCTL:\t", rUSBCTL }, { "\r\nCPUCTL:\t", rCPUCTL }, { "\r\nPINCTL:\t", rPINCTL }, { "\r\nREVISION:\t", rREVISION }, { "\r\nIOPINS1:\t", rIOPINS1 }, { "\r\nIOPINS2:\t", rIOPINS2 }, { "\r\nGPINIRQ:\t", rGPINIRQ }, { "\r\nGPINIEN:\t", rGPINIEN }, { "\r\nGPINPOL:\t", rGPINPOL }, { "\r\nHIRQ:\t", rHIRQ }, { "\r\nHIEN:\t", rHIEN }, { "\r\nMODE:\t", rMODE }, { "\r\nPERADDR:\t", rPERADDR }, { "\r\nHCTL:\t", rHCTL }, { "\r\nHXFR:\t", rHXFR }, { "\r\nHRSL:\t", rHRSL } }; void setup() { Serial.begin( 9600 ); Max.powerOn(); } void loop() { unsigned char i; unsigned char numregs = sizeof( max_register )/sizeof( REGISTER_OUTPUT); for( i = 0; i < numregs; i++ ) { Serial.print( max_register[ i ].name); print_hex( Max.regRd( max_register[ i ].number ), 8 ); } while(1); } /* prints hex numbers with leading zeroes */ // copyright, Peter H Anderson, Baltimore, MD, Nov, '07 // source: http://www.phanderson.com/arduino/arduino_display.html void print_hex(int v, int num_places) { int mask=0, n, num_nibbles, digit; for (n=1; n<=num_places; n++) { mask = (mask << 1) | 0x0001; } v = v & mask; // truncate v to specified number of places num_nibbles = num_places / 4; if ((num_places % 4) != 0) { ++num_nibbles; } do { digit = ((v >> (num_nibbles-1) * 4)) & 0x0f; Serial.print(digit, HEX); } while(--num_nibbles); }
The last sketch demonstrates connection detection. We need to add 5 volts to the Vbus for this sketch to work.
This sketch prints Vbus state. Connection detection interrupts are serviced by MAX3421E::Task() function. print_vbus_state() function prints Vbus state when it changes.
/* MAX3421E interrupt loop */ #include <Spi.h> #include <Max3421e.h> MAX3421E Max; byte rcode; byte vbus_state; void setup() { Serial.begin( 9600 ); Serial.println("Start"); Max.powerOn(); } void loop() { Max.Task(); print_vbus_state(); } void print_vbus_state( void ) { char* vbus_states[] = { "Disconnected", "Illegal", "Full speed", "Low speed" }; byte tmpbyte; static byte last_state = 4; tmpbyte = Max.getVbusState(); if( tmpbyte != last_state ) { last_state = tmpbyte; Serial.println( vbus_states[ tmpbyte ] ); } return; }
Run the sketch and plug a device into USB connector. The sketch will print device speed. Unplug it and plug another one. USB flash drives are usually full-speed devices, mice and keyboards are often low-speed.
This is all about low-level functions. Next step is to generating USB transfers. I’m hoping to finish porting this part from my PIC firmware in a week or two. I will post results here as soon as I’m done.
Oleg.
Related posts:
- Arduino USB Host Mini – initial revision
- Digital camera control using Arduino USB Host Shield. Part 1 – basics.
- PS3 and Wiimote Game Controllers on the Arduino Host Shield: Part 3
- PS3 and Wiimote Game Controllers on the Arduino Host Shield: Part 2
- PS3 and Wiimote Game Controllers on the Arduino Host Shield: Part 1
- How to drive USB keyboard from Arduino
- Arduino USB Host – Peripherals.
- USB Host Shield for Arduino – first prototype.
- Arduino USB Host – USB Descriptors.
- Arduino USB host – Pre-prototyping.


hi,
i am uploading the codes in my usb host shield and im getting errors like “Error: OSCOKIRQ failed to assert” and “Error: Vbus overload”. these errors come from the max.poweron(). and there is a problem with reading and writing max3421e regiters using spi protocol. also, i dont know if i have to connect gpin0-7 to anything or not!!
please help
thanks
yashar
You can’t get vbus.overload error unless you get a short somewhere. Did you make this shield yourself or bought it here?
i have bought it from sparkfun. but here are the step i took!!!
i have all the source code necessary and the board and i swapped the pin numbers for GPX and RESET but it seems like nothing is getting written in the max3421e registers cause when i read them i dont get the same values . i even run your above codes that prints registers and all the registers are 00 and im getting “Error: OSCOKIRQ failed to assert” and “Error: Vbus overload” as well. however GPIN0-7 and GPout0-7 are not attached to anything in my board. i was wondering if they are significant or i should attach them some circuitry that im not aware of!!!
thanks
Have you tried contacting Sparkfun yet?
not yet, but cant you suggest anything? am i missing anything?
Did you make the changes required for the differences in the Sparkfun shield ?
the pin numbers are not simply swapped.
For the Sparkfun shield the reset must be on #define MAX_RESET 8
MAX_GPX is not used, but is best as #define MAX_GPX 7
Also remember the Sparkfun USB Host Shield is powered from Vin.
Do you have an external power supply to Vin ?
Hi
last time i got all Errors from above this thread. the prob`s solved when i connect to a power-supply, then OSCOKIRQ will now work without undervoltage(VIN)–SPI also run`s like hell :-)Every Device will connect as defined(fast/slow) and no errors at all.
think PC 5v from Arduino-Host is a little bit too small to support the usb-shield when testing githuk-files;-)
All of the testfiles from githuk now working perfectly…i`am very happy!!
dont forget to spend Volts on the Board! :)
Good work @oleg!
Thanks for posting this! My guess is you are talking about Sparkfun shield since mine is powered from 5V and not from Vin. As a result, it will work off of USB power with no problems.
It looks broken to me.