Forced to divide SPI Clock to get devices working. Not sure why.

Hoping to gain some knowledge as to if this is how it's supposed to be or if something is wrong.

I have a Leonardo with 3 can bus chips working. One is built on board and I added 2 more to a breadboard.

When I added the second chip I had to divide SPI by 2 to get second chip working. Then when I added the 3rd chip I had to divide it again by 4. If I didn't the added chips didn't initialise.

I'm using the Fowler library and one of his examples showed dividing the SPI or I probably never would have gotten this far.

Just confused though as I thought the SPI could handle multiple devices and dividing the clock isn't making a lot of sense to me and hoping someone can provide some insight.

Do to the size of the code I have variables/declarations and other functions of the code split up onto different tabs but I'll try and post anything relevant together.

#include <mcp_can.h>
#include <SPI.h>
#include "Variables.h"
#include "Panel_Sync.h"
#include "GatewayMonitor.h"

//Define CS and INT pins for CAN
#define CAN0_INT 7                              // Set INT to pin 7
MCP_CAN CAN0(17);                              // Set CS to pin 17

#define CAN1_INT 10                             // Set INT to pin 10
MCP_CAN CAN1(11);                              // Set CS to pin 11

#define CAN2_INT 5                               // Set INT to pin 5
MCP_CAN CAN2(6);                                // Set CS to pin 6

//Configure CAN
void setup()                    
{
    
	Serial1.begin(9600);         

  // Initialize CAN  at 16MHz, 500kb/s

  if(CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ) == CAN_OK) 
    Serial1.println("CAN0 Init!");
  else
    Serial1.println("Error Init CAN0..."); 
  CAN0.setMode(MCP_NORMAL);                     
  pinMode(CAN0_INT, INPUT);                      // Configuring pin for INT input


if(CAN1.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ) == CAN_OK)  
    Serial1.println("CAN1 Init");
  else
    Serial1.println("Error Init CAN1...");

  CAN1.setMode(MCP_NORMAL);                      
  pinMode(CAN1_INT, INPUT);                      

if(CAN2.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ) == CAN_OK) 
    Serial1.println("CAN2 Init");
  else
    Serial1.println("Error Init CAN2...");
  CAN2.setMode(MCP_NORMAL);                      
  pinMode(CAN2_INT, INPUT);                      


SPI.setClockDivider(SPI_CLOCK_DIV4);         // Set SPI clock
}

Hope that is enough for figuring out why I have to divide SPI. I don't see others doing it when using multiple devices so maybe there is something wrong with how I have the board setup or coding.
I have MISO, MOSI and SCK wired direct from the ISP header for the 2 additional chips for the time being. Eventually everything will be built onto a new PCB.

What sets these as outputs?

MCP_CAN CAN0(17); // Set CS to pin 17
MCP_CAN CAN1(11); // Set CS to pin 11
MCP_CAN CAN2(6); // Set CS to pin 6

and the SS pin (I don't know what that pin in on the 32U4) to an output so the Leonard is SPI master?

You should use some { } around the sections for clarity also

  if(CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ) == CAN_OK) {
    Serial1.println("CAN0 Init!");
}
  else {
    Serial1.println("Error Init CAN0..."); 
  }  // here ??
  CAN0.setMode(MCP_NORMAL);          
  }  // or here??           
  pinMode(CAN0_INT, INPUT);                      // Configuring pin for INT input
   } // or here? 

// what is to run in the else, what is to run every time?

As you add more stuff to the SPI network, you add more capacitance which slows down the rise-time of the signals. Usually this isn't a problem until you have several meters of closely-spaced wires. (Smaller distance and more area between MOSI and ground increases the capacitance.) But you could imagine the fast signals on the SPI network charging up a big capacitor takes time and it may not have reached HIGH by the time the next bit starts.

As you add more stuff you also add more ends. Each end of a wire terminating at a SPI device is not matched to the cable's characteristic impedance. It will generate reflections off those ends. If the cables are short then the reflections (which travel close to light speed) will bounce several times and even themselves out before the SPI bit is completed. Long cables - once again several meters - this does become more important.

As you add more stuff you add more load. The single output for MOSI has to drive a lot of inputs. This takes current which the output may not be able to provide. Once again, the signals take more time to reach HIGH or LOW and in the worst case, they never get there.

So yes, a larger SPI network will often work at a slower speed.

Have you reached "large" yet? I would not expect this to be a problem with only 3-4 devices. You would have to probe the signals with an oscilloscope to find out what's really going on.

After some searching it seems the SS pin of the Leonardo is pin 17. This is the hardwired pin of the board I'm using for the first can bus CS.

Not sure if it's a cause of issue since the example the JFowler provides in his documentation divides his SPI and he isn't using the same CS as I am. But if I knew the answers I wouldn't be here.

The CS pins are defined by Library.

From the mcp_can.h file:

public:
    MCP_CAN(INT8U _CS);
.
..
};

From the mcp_can.cpp file:

/*********************************************************************************************************
** Function name:           set CS
** Descriptions:            init CS pin and set UNSELECTED
*********************************************************************************************************/
MCP_CAN::MCP_CAN(INT8U _CS)
{
    SPICS = _CS;
    pinMode(SPICS, OUTPUT);
    MCP2515_UNSELECT();
}

From mcp_can_dfs.h:

//#define SPICS 10
#define MCP2515_SELECT()   digitalWrite(SPICS, LOW)
#define MCP2515_UNSELECT() digitalWrite(SPICS, HIGH)

As far as function goes the setup is working but there are hardware/software issues like this. I also can't get the 2 CAN on the breadboard to share a clock but that is another post and issue I'll deal with later. All of which I need to sort out before designing the PCB...

Interesting...

I ported my 2 breadboard can-bus to an UNO and used 10 and 8 for CS and commented out the Divide. It works. I can't try with 3 can-bus yet as I don't have another crystal to clock a 3rd. For some reason I couldn't get the 2 on board to share a clock yet.

I was planning on trying a DSAM chip instead of 32U4 so I may just wait a day or two until my Zero board arrives so I can start with that instead. A lot of issues being 3.3v but the smallest and fastest option.
Program memory is getting slim so need to change for larger projects. Still would like to figure out the SPI issue on the 32U4 though as that does work well for some of my application with can-bus.