SPI Chip Select Woes - SD Card and CAN Shield

Having issues getting a microSD card breakout module and seeedstudio v1.2 CAN shield to play nice on an Uno. On their own, I have them working, but not at the same time.

The seeedstudio v1.2 CAN shield has the hardware solder tabs set to use the default D9 CS pin. Then the microSD breakout module has its CS pin on D10. Both devices are connected to D11-13 for MOSI, MISO, and SCK.

Here's how I understand it, the default SPI.begin() will use D10 as SS. In setup(), I should set arduino as the Master for SPI mode with:

void setup()
{
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);
    SPI.begin();

    ....
}

After it is set to master mode, pin 10 can now act as the CS for the SD card and pin 9 acts as the CS for the CAN shield. Now to initialize the shields. So I should disable SD CS/enable CAN CS, initialize CAN shield, then enable SD CS/disable CAN CS and initialize SD card.

void setup()
{
    ....

    digitalWrite(10, HIGH); // disable SD
    digitalWrite(9, LOW); // enable CAN

    // initialize CAN shield
    while (CAN_OK != CAN.begin(CAN_500KBPS))              // init can bus : baudrate = 500k
    {
        delay(500);
    }


    digitalWrite(9, HIGH); // disable CAN
    digitalWrite(10, LOW); // enable SD

    // initialize SD card
    while (!sd.begin(SDChipSelect, SPI_HALF_SPEED))
    {
        delay(500);
    }
}

And then each time the SD or CAN is needed in loop(), I have to disable the unused one and enable the one to be used. Such as:

void ReceiveCAN()
{
    digitalWrite(10, HIGH); // disable SD
    digitalWrite(9, LOW); // enable CAN

    if (CAN_MSGAVAIL == CAN.checkReceive())
    {
         // do CAN stuff
    }
}

void ReadSD()
{
    digitalWrite(9, HIGH); // disable CAN
    digitalWrite(10, LOW); // enable SD

    // do SD stuff
}

EDIT: It looks like CAN.checkReceive() does select/deselect the CS pin, but this doesn't handle disabling the other SPI devices (for me, the SD card). Maybe this is my problem.

many cheap SD card adapters with 5 V level conversion (SD card uses 3.3 V) block other SPI devices on bus and can be used only as single SPI device

Ahhh how do you tell if this is the case? Likewise, how do you tell when purchasing a new microSD breakout card?

For example, currently I’m using this for development, but have these on order for the more permanent build.

dtbingle:
Ahhh how do you tell if this is the case? Likewise, how do you tell when purchasing a new microSD breakout card?

For example, currently I’m using this for development, but have these on order for the more permanent build.

the Adafruit module is supposedly good. I will have it tomorrow.

The problem with those SD mpdules is that the MISO signal is, unecessarily, run through the level shifter chip. The MISO signal is not relased when it shou!d be. The Adafruit module MISO signal bypasses the level shifter so does not have the problem.

Thanks to both of you. Would have been frustrated for eternity and never have figured this out. Looking into the sdfat and seeedstudio CAN libraries, it seems the SPI transactions are handled appropriately upon SD and CAN commands - setting SPI speed, datamode, MSB/LSB, and controlling CS pin. So it shouldn't need any manual control of CS or SPI settings prior to using these devices.

Hopefully this means that dropping in the Adafruit SD module will solve this issue.

As an update, the Adafruit SD card allows shared use of the SPI pins with the CAN shield (like how it should work).

Original setup that didn't work for both SD and CAN at same time:
Arduino Uno + Seeed studio can shield v1.2 + HONG MicroSD breakout (here)

New setup that does work for both SD and CAN at same time:
Arduino Nano + MCP2515 CAN shield (here) + Adafruit SD module

One other minor thing ran into is that the cheap MCP2515 CAN shields commonly use an 8 MHz oscillator opposed to the 16 MHz on many Arduinos. Some people replace the crystal oscillator with a 16 MHz, but an easier fix is to download the latest MCP2515 arduino drivers and then use proper initialization settings:

mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ);