2

TL;DR

With regards to the USB host library:

  • Which is the correct file to modify the Arduino pin used for the USB Host slave select (SS) line?

I would like to add USB host functionality, to a particular Arduino setup, whilst, also, being able to use an Ethernet/SD (or just SD) shield.

As both the Ethernet shield and USB Host shield use pin 10 to select the W5500 and MAX3421E respectively1, obviously I can not use a standard USB Host shield. However, I could employ one of the small form factor boards, such as the USB Host Shield 2.0 Arduino UNO MEGA ADK Compatible Google Android ADK which I found on eBay:

USB Host shield

As this board is not in the usual shield "shape", one would not be constrained by which pin to connected to which MAX3421E input/output, in particular the chip select (SS) input. So, one could use a pin (or pins) that is not reserved by the Ethernet shield.

However, it does not appear to be possible to simply specify the "select pin" (i.e. the Arduino pin connected to the SS line) when using the USB Host shield library (or any of the pins used by the library), in setup().

Therefore, I wondered if it was possible to modify the library, so that the pin used to select the USB/MAX3421E could be changed, either by:

  • "Hardcoding" a different "select" pin number into a header file;
  • Adding an argument to the Init() method, or;
  • Adding a method to the USB class, such as Usb.DefineSelect().

The latter two options, I could work through, given the time. However, as a quick and dirty hack, where would I hardcode in a change from pin 10 to a pin of my choosing? Does anyone know? Has anyone had to do this?


Nitty-gritty

I have had a look through the library to see where pin 10 is defined as the chip select, and avrpins.h looked like a possible candidate for modification, although it would be rather "rude" (for want of a better word) and probably mess up the other boards.

usbhost.h seems a much better proposition. Looking at usbhost.h, the lines 88-91:

#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
typedef SPi< Pb1, Pb2, Pb3, Pb0 > spi;
#elif  defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi;

Looking at the statement

typedef SPi< Pb5, Pb3, Pb4, Pb2 > spi;

the last argument appears to be the pin used for select. For the Uno (ATmega328P), in avrpins.h (line 535) Pb2 is P10 (pin 10), so I could substitute Pb2 for some other pin definition, i.e. Pd5 for P5 (pin 5) (line 529 in avrpins.h).

However, what I don't understand is that for the statement

typedef SPi< Pb1, Pb2, Pb3, Pb0 > spi;

which deals with the Mega (ATmega2560), in avrpins.h (line 512) Pb0is P53 (pin 53). As Pb4 is actually P10 (pin 10) (line 466), why is Pb0 en lieu of Pb4 used? That doesn't tie up with the fact that Pin 10 is used for both the Uno and Mega boards. It seems to suggest the pin 10 is used on the Uno and pin 53 is used on the Mega. Unless I have misinterpreted the typedef.


Footnote

1 For the USB host shield, from Arduino USB Host Shield

Arduino communicates with the MAX3421E using the SPI bus (through the ICSP header). This is on digital pins 10, 11, 12, and 13 on the Uno and pins 10, 50, 51, and 52 on the Mega. On both boards, pin 10 is used to select the MAX3421E. Pins 7, 8 and 9 are used for GPX, INT and RES pins.

The key piece of information here is that pin 10 is used by both the Uno and Mega boards.

For the Ethernet shield, from Arduino Ethernet Shield V2

Arduino communicates with both the W5500 and SD card using the SPI bus (through the ICSP header). This is on digital pins 10, 11, 12, and 13 on the Uno and pins 50, 51, and 52 on the Mega. On both boards, pin 10 is used to select the W5500 and pin 4 for the SD card. These pins cannot be used for general I/O. On the Mega, the hardware SS pin, 53, is not used to select either the W5500 or the SD card, but it must be kept as an output or the SPI interface won't work.

Note that because the W5500 and SD card share the SPI bus, only one at a time can be active. If you are using both peripherals in your program, this should be taken care of by the corresponding libraries. If you're not using one of the peripherals in your program, however, you'll need to explicitly deselect it. To do this with the SD card, set pin 4 as an output and write a high to it. For the W5500, set digital pin 10 as a high output.

Here, yet again, the key piece of information here is that pin 10 is used by both the Uno and Mega boards to select the Ethernet.

8
  • 1
    It look like you are correct, and that you should edit the usbhost.h file. Not sure what you mean in the second question. The library uses the Arduinos SS pin. It does have to use this pin, but this prevents the pin from being an input and accidentally putting the atmega into SPI slave mode. The library also prefers to have all the pins on Port B.
    – Gerben
    Commented Jan 14, 2017 at 21:18
  • @Gerben - Thanks for the confirmation of the first question. I have edited my post to try to clarify what my second question is, which is "shouldn't the last argument to the typedef for the Mega board be Pb4 and not Pb0?" Maybe I need to recheck my understanding of the code, in the morning. Commented Jan 14, 2017 at 22:15
  • Trying to put both an Ethernet adapter and USB host adapter on an ATmega based Arduino is evidence of bad hardware selection. You should probably either consider something that does both natively (for example some of the STM32F4's, and likely choices from other vendors) or unless your needs are very narrow and never expected to change, more likely a more sophisticated system capable of running an actual operating system. Commented Jan 15, 2017 at 7:19
  • 1
    Like I said, pin PB0 is the SS of the ATMega. When using SPI you shouldn't use this pin as an INPUT. It's therefor a good idea of the library maker to choose that pin, so it's always an OUTPUT. Also pin 53 is close to the other SPI pins. Using pin 5 would be at the other side of the board, which make wiring messy pretty quick. No big reason to choose PB0, just a few small reasons.
    – Gerben
    Commented Jan 15, 2017 at 13:04
  • @Gerben - Thanks for pointing me in the right direction. At first I couldn't understand what you meant, but after re-reading SPI library, I see that the source of my confusion is that P53 (Mega) and P10 (Uno) are the Arduino's SS pin, which obviously must be set as an output, to maintain them as the SPI master. I was looking for the point in the code where pin 10 is set to select the USB shield's SS line, not the Arduino's SS line, if that makes sense... So the typedefs that I found in usbhost.h are not what I should be looking at. Commented Jan 15, 2017 at 19:01

1 Answer 1

3

In order to change the Arduino pin used to select the USB Host board, in order words, where the device's SS line is assigned to an Arduino pin (with the Arduino as the SPI Master and the USB host is the SPI slave), the line to change is at line 43 in UsbCore.h:

typedef MAX3421e<P10, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.), Intel Edison, Intel Galileo 2 or Teensy 2.0 and 3.x

So to use pin 5, for example, en lieu of pin 10, the line would become:

typedef MAX3421e<P5, P9> MAX3421E; // Official Arduinos (UNO, Duemilanove, Mega, 2560, Leonardo, Due etc.), Intel Edison, Intel Galileo 2 or Teensy 2.0 and 3.x

The clue was in the comment on line 27 in UsbCore.h

/* shield pins. First parameter - SS pin, second parameter - INT pin */

With this suggested modification to the code, Pin 5 would go to the USB Host SS line and then there would be no conflict with the Ethernet board that uses Pin 10 for its SS line.


This issue, I have subsequently discovered, is covered by the USB Host Shield Hardware Manual, under the Interface modifications section. I guess I should have just read the manual first! RTFM...


Clarification of the issue

I must be honest that my question was somewhat confused. After having read the SPI library, it states that

Note about Slave Select (SS) pin on AVR based boards

All AVR based boards have an SS pin that is useful when they act as a slave controlled by an external master. Since this library supports only master mode, this pin should be set always as OUTPUT otherwise the SPI interface could be put automatically into slave mode by hardware, rendering the library inoperative.

It is, however, possible to use any pin as the Slave Select (SS) for the devices. For example, the Arduino Ethernet shield uses pin 4 to control the SPI connection to the on-board SD card, and pin 10 to control the connection to the Ethernet controller.

With respect to the first paragraph, the Uno uses pin 10 and Mega uses pin 53 as the Arduino SS line - so that must be set as an output in order for the Arduino to be the Master. Are realising this as being my source of confusion, it became apparent that the typedef statements, in usbhost.h, were not where I should have been looking to change the device's Slave Select pin.

With respect to the second paragraph, I want to use pin 5 (for example) to control the Slave Select (SS) for the USB Host device, instead of the default pin 10.

5
  • The link seems to have died and this google site search finds nothing seemingly related Commented Mar 26 at 23:09
  • 1
    See section Interface modifications in the USB Host Shield Hardware Manual. Address updated. Commented Mar 28 at 1:15
  • So, it is the same link as was in my answer? Commented Mar 28 at 7:18
  • Yes, that is the only surviving link I can find. It is linked from the README of the library repo on GitHub. Commented Mar 29 at 15:44
  • Ah, ok. Thats a shame. I never got around to seeing the original link that you posted. I wonder if it was dramatically different. Commented Mar 29 at 15:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.