SPI.end() causes SPI.transfer() to hang even after a new SPI.begin()

It appears that something SPI.end() changes isn't being reset by SPI.begin() on the Due. As a result, if SPI.end() is used to disable SPI, it can't be re-enabled later in the program. A simplified example is shown below.

This sequence works:

SPI.begin();
SPI.transfer(0);

This sequence hangs on the Due, but works on other Arduino boards:

SPI.end();
SPI.begin();
SPI.transfer(0);

I can confirm this. (The problem seems to be that SPI.end() calls SPI_Disable(), but SPI.begin doesn't call SPI_Enable() - it's called in the constructor.)

To fix this: open the file hardware/arduino/sam/libraries/SPI/SPI.cpp and at the beginning of the SPIClass::begin() method add the line
SPI_Enable(spi);
The method should now look like this:

void SPIClass::begin() {
        SPI_Enable(spi);
        // NPCS control is left to the user

        // Default speed set to 4Mhz
        setClockDivider(BOARD_SPI_DEFAULT_SS, 21);
        setDataMode(BOARD_SPI_DEFAULT_SS, SPI_MODE0);
        setBitOrder(BOARD_SPI_DEFAULT_SS, MSBFIRST);
}

I've added this issue to the Arduino github here: Due - SPI.end() causes SPI.transfer() to hang even after a new SPI.begin() · Issue #1406 · arduino/Arduino · GitHub

Thanks. That fixes the problem. Is there somewhere else I should be posting this to make sure this fix gets into the SPI release version?

I've already reported the issue in the official place and as it's a simple one-liner I expect it will get fixed pretty soon.

I am using the old AVR compatible api's.
I can confirm the above work around works for me too.

But after calling SPI.end(), I want to tristate SCK and MOSI. How do I do that? I tried adding

pinMode(MOSI, INPUT);
pinMode(SCK, INPUT);

But after that SPI.begin() does not work anymore.
I dare not configuring them as output before calling SPI.begin() because I noticed that SPIClass::begin() does not have code in it to do so, that is probably done for a reason.

Does it work if you add the line: SPI_Configure(spi, id, SPI_MR_MSTR | SPI_MR_PS | SPI_MR_MODFDIS); immediately before each call to SPI.begin(); ?

Almost, the initcb() (which is SPI_0_Init()) has to be called too.
Thanks!

Merged the fix upstream:

C

OMG, if only I could link all the times I have seen this.

Background: I am working on a project that, to work optimally, requires 2 micros (micro-controllers: a Due and an ESP8266 to be precise) to have access, ONE AT A TIME [shouty, but happy man], to the same SD card.

I incorrectly thought it [the init access issues I was having] was due to the 8266 (I read something, somewhere): From step 2 (see THIS, HERE, HELLO, OVER HERE, [waving hand]), I discovered that the Due was at fault; Even though step 2 was testing for MISO tri-state behaviour, the Due was holding MOSI high and SCK low! WHAT?

I tried setting (Arduino digital) pins 10 to 13 to inputs, but obviously that won't work, because the Due SPI is not mapped (duplicated) to these pins! (To maximise GPIOs, I guess).

In the end what worked for me was,

 //  pinMode(12, INPUT); // MISO OK
    pinMode(SS, INPUT);   // CS
    pinMode(MOSI, INPUT); // Due leaves HIGH (MOSI)
    pinMode(SCK, INPUT);  // Due leaves LOW

.

I don't think you need to set CS as an i/p, but it cannot hurt, unless you want it to do something else between SPI access.
Strange that the test for MISO tristate revealed one of the bus pins that actually worked properly! A great reference for any SPI, and perhaps other, interfaces!

It was due to the Due :wink:

As an aside, to use most Shields on the Due,

  1. You need to make sure they are 3V3 tolerant,
  2. Remove any bridge/short between the ICSP SPI header and pins 11 to 13 AND
  3. Remove any bridge/short between the I2C (IIC) bus on "SDA" & "SCL" to A4 & A5!

That is; to use SPI on a regular Shield, it must use the ICSP header, BUT pins (11 - 13 and possibly pin 10) should NOT BE CONNECTED (DISCONNECTED) TO THE SPI BUS.

The aforementioned (bottom layer) Shield, that has the ICSP connector, can be used to "bring" the SPI bus to the "regular" pins (11-13) for Shields above it, BUT you should make sure that pins 11 - 13 are not connected to the Due (bent out of the way or cut off).

AS per PeterVH's post above, one can force the Due SPI into tristate, but I can't work out how to initiate the SPI bus for reuse...
See here and here.