SPI Write Speed

So I've managed to control my SPI slave device at a 2MHz write speed. However, I could do with it being faster. I've tried a write speed of 4MHz and a write speed of 8MHz. Neither seem to work. Now could it be the Arduino I'm using (Arduino Nano) or the SPI Slave device or my code?

This is the datasheet for the SPI slave device. Scroll down to 6.6 Timing Requirements (Page 12). It says the write speed can be anything below 75MHz. Am I reading this wrong?

https://www.ti.com/lit/ds/snas736c/snas736c.pdf?ts=1593432967028&ref_url=https%253A%252F%252Fwww.google.com%252F

Here is a snippet of the code I'm trying to send. The whole thing is too long.

#include "SPI.h"
int ss=10;
int del=0.1;


void setup() {
  // put your setup code here, to run once:
pinMode (ss, OUTPUT);
Serial.begin(115200);
SPI.begin();



}

void loop() {
  // put your main code here, to run repeatedly:


SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
digitalWrite(ss, LOW);
SPI.transfer(0x4E); 
SPI.transfer(0x00);
SPI.transfer(0x03); 
digitalWrite(ss, HIGH);
delay(del);
digitalWrite(ss, LOW);
SPI.transfer(0x4D); 
SPI.transfer(0x00);
SPI.transfer(0x00); 
digitalWrite(ss, HIGH);
delay(del);
digitalWrite(ss, LOW);
SPI.transfer(0x4C); 
SPI.transfer(0x00);
SPI.transfer(0x0C); 
digitalWrite(ss, HIGH);
delay(del);
digitalWrite(ss, LOW);
SPI.transfer(0x4A); 
SPI.transfer(0x00);
SPI.transfer(0x00); 
digitalWrite(ss, HIGH);
delay(del);
digitalWrite(ss, LOW);
SPI.transfer(0x49); 
SPI.transfer(0x00);
SPI.transfer(0x3F); 
digitalWrite(ss, HIGH);
delay(del);
SPI.endTransaction;
}
int del=0.1;
delay(del);

delay() takes an unsigned long as its parameter but why are the delays()s there in the first place ?

If you must have a very short delay then look to using delayMicroseconds()

Callum_Austin11: int del=0.1;

...

delay(del);

'delay' takes in INTEGER values and generates a millisecond delays.

if you want 0.1ms delay (ie 100us), you should be using delayMicroseconds(us).

see if that makes a difference for you...

hope that helps...

The delay in between each spi transfer shouldn't make a difference to the SPI write speed should it? I can write SPI to the slave using the 2MHz clock, just can't using the 4MHz or 8MHz clocks.

The delay in between each spi transfer shouldn't make a difference to the SPI write speed should it?

No, but I find it ironic that you are trying to speed things up whilst at the same time slowing things down by using delay()

So you are saying if I use the delayMicroseconds(us) function I can use a SPI write speed at 4MHz?

Callum_Austin11: So you are saying if I use the delayMicroseconds(us) function I can use a SPI write speed at 4MHz?

No. All I am saying is that if you use delayMicroseconds() then the delay between SPI writes() will work

I note that in SPISettings it says

The maximum speed of communication. For a SPI chip rated up to 20 MHz, use 20000000.

Which Arduino are you using ?

I'm using the Arduino Nano board.

Try putting a scope on the SPI clock and data lines to see what the signals look like.

I've put a scope on it, seems as though I get gibberish out, however I believe that could be a scope issue. I'm using the Saleae logic analyzer.

Managed to get a scope reading and it all seems to be ok at 4Mhz and 8MHz

Why do you have these?

SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); SPI.endTransaction;

I would leave those out. If you want to change the clock speed, use the clock divisor command after SPI.begin() in setup. The other commands are not needed if you not changing the settings during loop().

CrossRoads: Why do you have these?

Using SPI Transactions is the correct modern and portable way to do this.

The purpose of the useless delay()s in OP's code is still unclear.

Callum_Austin11: Managed to get a scope reading and it all seems to be ok at 4Mhz and 8MHz

So there doesn't not appear to be a code problem.

I have now changed the delay to be in microseconds. That didn't make it run at 4MHz, don't worry about the delay in between each SPI transfer. Its more the command that needs sending at 4MHz.

So this is a single command for the SPI slave device. I need this command to be sent at 4MHz so the command takes 10us to send. I've done it at 2MHz so the command takes 20us however this is too slow.

digitalWrite(ss, LOW);
SPI.transfer(0x2D); 
SPI.transfer(0xC8);
SPI.transfer(0xDF); 
digitalWrite(ss, HIGH);

Callum_Austin11:
Its more the command that needs sending at 4MHz.

You said the scope shot shows that it is. So, what’s the problem?

Callum_Austin11: So this is a single command for the SPI slave device. I need this command to be sent at 4MHz so the command takes 10us to send. I've done it at 2MHz so the command takes 20us however this is too slow.

SPI is a byte oriented protocol; where, data/command is exchanged 1-byte (8-bit) at a time. There is no START/STOP bit like UART.

At 4 MHz data transfer rate, a command will take (1/4000000)*8 = 2 us time to reach at the Slave.

At 2 MHz data transfer rate, a command will take (1/2000000)*8 = 4 us time to reach at the Slave

Callum_Austin11: Here is a snippet of the code I'm trying to send. The whole thing is too long.

Try the following sketch (yours one with slight modification):

#include "SPI.h"

void setup() 
{
  
  Serial.begin(115200);
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV4); //16 MHz/4 = 4 MHz
  pinMode(SS, OUTPUT);    //SS is DPin-10; the definition is in SPI.h Library
  digitalWrite(SS, LOW);   //Slave is selected
}

void loop() 
{
    byte x = SPI.transfer(0x4E); //you use or not, collect the return value
    delayMicroseconds(5);  //theoretically  2 us

    x = SPI.transfer(0x00);
    delayMicroseconds(5);  //theoretically  2 us

    x = SPI.transfer(0x03); 
    delayMicroseconds(5);  //theoretically  2 us
    digitalWrite(SS, HIGH);
    //-------------------------
    delay(100);                   //100 ms why?
    digitalWrite(SS, LOW);
    //------------------------
    x = SPI.transfer(0x4D); 
    delayMicroseconds(5);  //theoretically  2 us

    x = SPI.transfer(0x00);
    delayMicroseconds(5);  //theoretically 2 us

   x = SPI.transfer(0x00);
   delayMicroseconds(5);  //theoretically =ly 2 us 
   digitalWrite(SS, HIGH);
   //--------------------------
   delay(100);
   digitalWrite(SS, LOW);
   x = SPI.transfer(0x4C);
   delayMicroseconds(5);  //theoretically  2 us

   x = SPI.transfer(0x00);
   delayMicroseconds(5);  //theoretically  2 us

   x = SPI.transfer(0x0C); 
   delayMicroseconds(5);  //theoretically  2 us
   digitalWrite(SS, HIGH);
   //-----------------------
   delay(100);
   digitalWrite(SS, LOW);
   x = SPI.transfer(0x4A);
   delayMicroseconds(5);  //theoretically  2 us

   x = SPI.transfer(0x00);
   delayMicroseconds(5);  //theoretically 2 us

   x = SPI.transfer(0x00);
   delayMicroseconds(5);  //theoretically  2 us 
   digitalWrite(SS, HIGH);
   //-------------------------
   delay(100);
   digitalWrite(SS, LOW);
   x = SPI.transfer(0x49);
   delayMicroseconds(5);  //theoretically  2 us

   x = SPI.transfer(0x00);
   delayMicroseconds(5);  //theoretically  2 us

   x = SPI.transfer(0x3F);
   delayMicroseconds(5);  //theoretically  2 us 
   digitalWrite(SS, HIGH);
  //---------------------------
   delay(100);
   SPI.end();
}

SPI.setClockDivider(SPI_CLOCK_DIV4); //16 MHz/4 = 4 MHz <<< Default value, unless you change it
pinMode(SS, OUTPUT); //SS is DPin-10; the definition is in SPI.h Library
digitalWrite(SS, LOW); //Slave is selected << Use HIGH here as most devices are selected with a LOW to start a transfer.

4 MHz is the clock rate - data starts going to the slave as soon as SPI.transfer is executed.
The delay between CS low to high transitions is not needed, there is sufficient delay introduced just from the code executing the commands for the digitalWrite HIGH to end one transfer and then LOW to start the next one - unless the datasheet says more time between transfers is needed.
CS/ only needs to be high for 10nS, which <1/6 of a clock period, quicker than any code can toggle a signal.
So this
digitalWrite (ssPIN, HIGH); // end one transfer
digitalWrite (ssPIN, LOW); // start next transfer
will result in CS/ being high for at least 62.5nS and more likely 125nS or more.

CrossRoads:
digitalWrite(SS, LOW); //Slave is selected << Use HIGH here as most devices are selected with a LOW to start a transfer.

When SPI.h file is included in the IDE, the SS-signal (which is the DPin-10 of UNO) is set to HIGH state (the default value), then do we really need to make it HIGH in the sketch before asserting LOW on it? However, I do agree that it looks pretty good to keep it HIGH explicitly in the sketch and then make it LOW just before data transfer.