Arduino Due only: Wrong initialisation of SPI SS pins causes failure

Using the Arduino Ethernet Shield R3 e.g. on an Due you may/will run in the following fault:
(Arduino 1.5.6-r2 BETA with the standard libs.)

The Problem:

With the bug I could run the SD-card and the Ethernet separately, but curiously not on calling shortly one after the other.
I found the bug when I checked the CS signals with a scope.

The Reason:

Ethernet access:
Pin 102 (PC29) (!) AND (!) pin 111 (PA28) of the controller is connected to pin 10(ETH-CS) of the board connector.
The Arduino Due system software maps the two pins of the controller to the logical pins 10 and 77. The user starts
the Ethernet access via “Ethernet.begin(…)”, that calls “W5100.init();” and “SPI.begin(SPI_CS);” where “SPI_CS = 10”.
Nothing is done with pin 77.

SD-card access:
Pin 137 (PC26) (!) AND (!) pin 112 (PA29) of the controller is connected to pin 4(SD-CS) of the board connector.
The Arduino Due system software maps the two pins of the controller to the logical pins 4 and 87.
The user starts the SD-card access via “SD.begin(4)” using the logical pin 4 only. Nothing is done with pin 87.

Pin 77 and pin 87 are not controlled by any of the drivers. Both pins must be initialised properly on startup.

Initialisation of the Controller SAM3X8E:

In the file “variant.h” line 58 and “variant.cpp” line 382:

// Disable pull-up on every pin
for (int i = 0; i < PINS_COUNT; i++) // with “#define PINS_COUNT (79u)”
digitalWrite(i, LOW);

Pin 77 (ETH-CS) is initialized as Output low !!!
Pin 87 (SD-CS) looks not to be initialized on startup and at all !!!

Pin 77 initialized to low causes an CS output for the Ethernet W5100 between zero and around 1.65V.
The W5100 chip requires a minimum high signal of 2 volt as noted in the data sheet.

Pin 87 may be output LOW or HIGH or may be an INPUT or INPUT_PULLUP:

  • If output LOW it would never reach a valid low signal.
  • If output HIGH it would never reach a valid high signal.
  • If INPUT or INPUT_PULLUP it will work properly.

(In addition, if one of the CS signals is low, the other must be high to disable the other device.
And on startup, all devices on the SPI bus must be disabled to keep them inactive.)

The Fix:

Do a proper initialisation in “variant.cpp”. Set all above four pins to INPUT_PULLUP.
With this fix, nothing is to do within the SPI, SD, Ethernet driver.

A Workaround:

Add the following code at the very beginning:

void setup()
{
pinMode(SDPinCS,INPUT_PULLUP); // SD Pin 4
pinMode(SDPinCS2,INPUT_PULLUP); // SD Pin 87
pinMode(EthPinCS,INPUT_PULLUP); // Eth Pin 10
pinMode(EthPinCS2,INPUT_PULLUP); // Eth Pin 77

}

Stability and Benchmarks:

With this patch I got my application running very well and with speeds of:

  • WrToWebIf(4830byte)=30ms – Transfer via the WebDuino interface using a 14MHz clock on the SPI bus
  • FilesReadBin: “CMOS.cfg” (Read=56byte): 3ms – time from open to close: using the default 42MHz clock
    (The speed for SD-card access varies significantly depending on the SD-card. The first access may take
    longer. With one of my SD-cards I got sometimes around 2 seconds for a mkdir. I think it is
    a hardware problem of this SD-card.)

How many users may be affected by this problem?

Some users will see that their application work, others will see that it is instable, a very few will see
dependencies with boards, temperature, or runtime. I am sure a lot of users will give up.
But nobody can give a true answer how many this are, but a lot.

And as I could see, the Arduino development team is working on the SPI driver.
But they are looking for different things.

Interesting topic, but I do not agree with this, after a reading of the registers this command
pinMode(EthPinCS,INPUT_PULLUP); // Eth Pin 10
converts pin 10 CS in INPUT

Thank you for your question!

That is correct. What I wrote, to set alle four pins to INPUT_PULLUP initially only that does mean on power up of the Arduino Due and only then.

If you start working with Ethernet or SD-Card (calling begin()) the software controls EthPinCS and SDPinCS properly and set them to OUTPUT and controls them properly.

But the standard routines do nothing with EthPinCS2 and SDPinCS2. At his time, these two additional pins must be switched to an input and never to an output as it is done by the standard intialisation or left undefined and that may result also to an output high or low.

The best to do is to set all 4 pins to INPUT_PULLUP initially. So you have a proper high signal that disables both SPI devices on startup..

If you like, you can look into the Eagle Reference Design of the Arduino Due and you can see the pins connected together.
You can also look into the "Arduino Due Pinout Diagram". There you can also see the pins connected together.

Here also my short comment as I wrote for me in my code regarding this topic:
//-------------------------------------------------------------------------------------------------------------
// SD chip select: SAM3X8E: PA29+PC26 => Arduino:D4+D87 (Two controler pins tied together!)
// Pin 4 is used by default for the SD as defined by software.
// D87 cannot be used for other purpose, must be disabled and set as INPUT_PULLUP initially
#define SDPinCS 4
#define SDPinCS2 87
// Eth chip select: SAM3X8E: PA28+PC29 => Arduino:D10+D77 (Two controler pins tied together!)
// Pin 10 is used by default for the W5100 as defined by software.
// D77 cannot be used for other purpose, must be disabled and set as INPUT_PULLUP initially
#define EthPinCS 10
#define EthPinCS2 77
// Initially all 4 pins must be set to high. One can use defining the four pins as out and set to high
// and disable SD and Eth. This will conflict with current SD and Eth software. For full compatibility,
// initially set the 4 pins as INPUT_PULLUP. After that, you can call "begin(...)" for SD and Eth.
// (Never set one of the 4 pins as an output in your code as described in some examples.)
//=============================================================================================================
// Define initial state of the board on power up:
void setup()
{
pinMode(SDPinCS,INPUT_PULLUP); // SD Pin 4
pinMode(SDPinCS2,INPUT_PULLUP); // SD Pin 87
pinMode(EthPinCS,INPUT_PULLUP); // Eth Pin 10
pinMode(EthPinCS2,INPUT_PULLUP); // Eth Pin 77
...
}

Can you please post a small but complete, ready-to-run program which demonstrates the problem?

(I am working on a very big project and use the Atmel Studio with the Arduino libraries. Sorry, this is not a good example and would not run with the Arduino IDE.)

But you can use any code examples from the Arduino homepage for the Ethernet and/or SD-card communication or any code you have already on your computer. You will have the bug. (Keep in mind: only on the Arduino Due.)

The bug will show to the user:

  • Completely not working
  • Working only with reduced speed
  • Working only within a specific temperature range.
  • Most time it is working but after some ten thousand transfers it fails.
  • Ethernet alone is working as well as SD-card, but not both (I got this variant.)
  • Working all the time: I cannot believe that.

If you use one of the examples from the Arduino homepage or your have any program, you can clearly see the bug with the scope if you check the ETH-CS (Ethernet) Arduino board pin 10. The high level will reach only around 1.65V. The specification of the W5100 defines a high level of 3.0V.

For the SD-card it is more difficult: Pin 87 (SD-CS) is not initialized at all and may be an input or an output and may be set to high or low. So it may work, or you can have a low level of 1.65V and a high level of 3.3 Volt or you can have a low level of 0Volt and a high level of 1.65V at Arduino board pin 4. Also here the specification defines a high value of 90% of the supply voltage that is around 3 Volt.

(I think you ask yourself, why is it mostly working? The specification from the chip producer defines a voltage range for high and low that fit under each manufacturing process and also when the completely change their chip development libraries. To define a low level of 10% of the supply voltage and a high level of 90% of the supply voltage is okay, because the controllers supply this. But the real IC have other low and high levels.)

To fix this problem it would be the best if the initialization in “…\hardware\arduino\sam\variants\arduino_due_x\variant.cpp” would be fixed. (Please not: Alternatively, the description for the Ethernet and SD-card should be enhanced in the Arduino homepages.)

I just tested with Arduino 1.5.7 and Arduino Due & Arduino Ethernet Shield, with my oscilloscope connected to pin 10. I loaded File > Examples > Ethernet > WebClient and clicked upload.

Here is the pin 10 waveform as the board starts up.

I do not see 1.65 volts. The voltage appears to be floating at approx 2.5 volts before the sketch begins. While the program is running, it’s usually 3.3V and goes to 0 volts while using the ethernet chip.

Here’s a zoom in view during the time while the sketch is transferring data.

I was not able to reproduce the problem you've described. I would have to conclude your hardware is faulty.

Your report of this problem is also lacking detail. If you really expect anyone to help, perhaps you could document the problem using an oscilloscope screenshot, as I have just done.

I tested now also using the Arduino 1.5.7 Beta and the Arduino IDE:

Your are right. This bug does not exist anymore. After long investigation today I am shure that the fix did come into 1.5.7 with the big revise of the SPI interface.

Our comunication did went wrong multiple times not only here.

But thanks for your effort and also for the fix.

Best Regards,

Dieter Burandt