Arduino Uno R4 - SPI speed configuration

Hi Arduino folks,

I have been working with Arduino Uno R4 Wifi and SPI by making a quick SPI speed test and figured out I can't go beyond 5MHz when configuring SPISettings:

This is the test code:

#include <SPI.h>
#define CS		6

void setup() {
  SPI.begin();
  pinMode(CS, OUTPUT);
}

void loop() {
  unsigned char Data = 0xab;
  
  SPI.beginTransaction(SPISettings(5000000, MSBFIRST, SPI_MODE0));

  digitalWrite(CS, LOW);
  SPI.transfer(Data);
  digitalWrite(CS, HIGH);

  SPI.endTransaction();

  delayMicroseconds(500000);
}

This is the normal SCLK when working below 5MHz:

But if I try any other speed beyond 5MHz (6MHz, 8MHz, 10MHz, 12MHz, 15MHz), I start to lose SCLK ticks. The following is an example running at 12MHz:

I'm supposed to run this board up to 24MHz, but I cannot go beyond 5MHz. Is there something I should try or fix to have complete SCLK ticks?

Thanks,
Daniel.

What is the sampling frequency you are using?

2 Likes

Thanks, @Rintin, for stepping in! It was a sampling frequency issue, indeed.

It looks like my Logic 2 software lost its settings after the updates. I was working before with signals in the range of 20MHz without issues. I moved the sampling frequency from 10MS/s to 250MS/s, and now I can exercise the full SPI speed range.

It looks very strange, but when working with SD library of Arduino UNO R4 WIFI I find that SCL frequency in my case is only 4MHz! Why is it so low?

/*
 *** OVERWRITE THE FILE  and time to writing measure ***
 *
 * SPI pins for SD module connection:
 * SCK - pin 13
 * MISO - pin 12
 * MOSI - pin 11
 * CS - pin 4 
 */

#include <SPI.h>
#include <SD.h>

#define PIN_SPI_CS  4   // 
#define StrobPin    5   // Pin to trigger scope for time measures

File myFile;

void setup() 
{
  Serial.begin(115200);

  pinMode(PIN_SPI_CS, OUTPUT);
  pinMode(StrobPin, OUTPUT);

  if (!SD.begin(PIN_SPI_CS)) 
    {
      Serial.println(F("SD Card is either missing or has failed!"));
      while (1); // don't do anything more:
    }

  Serial.println(F("SD Card is ready"));
  SD.remove("arduino.txt");                 // delete the file if existed

  // create new file by opening file for writing
  myFile = SD.open("arduino.txt", FILE_WRITE);
  myFile.close();
}

void loop() 
{
  delay(20);
  digitalWrite (StrobPin, HIGH);
  myFile = SD.open("arduino.txt", FILE_WRITE);
  if (myFile) 
    {
      myFile.println("Created a new Line");       // write a line to SD
    } 
  else 
    {
      Serial.println(F("Error: Unable to open file arduino.txt"));
    }
  myFile.close();
  digitalWrite (StrobPin, LOW);
}

You should try the SDFat library instead.

I believe the author of the library made some significant improvements in
the performance.

Some of this was discussed on the thread:
Uno R4 Poor SPI Performance - UNO R4 / UNO R4 Minima - Arduino Forum

You may connect a UNOR4WiFi with a UNOR3 to test the actual speed of the SPI network.

Thanks KurtE, I'll try it.
Yes, I read that thread, but it seems to have no outcome: the Arduino team still hasn't released a new version of the SPI library. However, something is fundamentally wrong with me: the clock frequency is not even 24 MHz, as I expected, but only 4!

I don't have UNO R3, but I don't need it. I'm sure the speed would increase significantly if the clock was at least 24 MHz.

UNOR3 supports upto 8 MHz SPI speed. UNOR4 is virtually a UNOR3. You can connect two UNOR4 to test the SPI speed.

I did a quick and dirty sketch on the Minima:

#include <SPI.h>
void setup() {
    // put your setup code here, to run once:
    SPI.begin();
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);
    SPI.beginTransaction(SPISettings(20000000, LSBFIRST, SPI_MODE0));
}

uint8_t loop_count = 0;
void loop() {
    // put your main code here, to run repeatedly:
    digitalWrite(10, LOW);
    SPI.transfer(loop_count++);
    digitalWrite(10, HIGH);
}

And it is showing me that the clock is bumped up to about 12mhz...

Note: if I changed the main loop to output a few bytes at a time
uint8_t loop_count = 0;
void loop() {

    // put your main code here, to run repeatedly:
    digitalWrite(10, LOW);
    SPI.transfer(loop_count++);
    SPI.transfer(loop_count++);
    SPI.transfer(loop_count++);
    SPI.transfer(loop_count++);
    digitalWrite(10, HIGH);
}

You still don't get great throughput with their API


In this case it is spending twice as much time between the output of bytes as the time it takes to output...

Although you can output using buffer like:

 uint8_t buffer[4] = {1, 2, 3, 4};
  SPI.transfer(buffer, 4);

And that helps some...

And note: If I ask for 30mhz I get about 25-30 mhz...

Thank you. It turns out it was enough to write
if (!SD.begin(24000000, PIN_SPI_CS))
instead of
if (!SD.begin(PIN_SPI_CS))
to increase SCK from 4MHz to 24MHz. By the way, if I wrote the number 20000000, then I also got a frequency of 12 MHz.
However, this did not affect the recording speed in any way, precisely because, as you noticed, there are huge gaps between the packets, and in the case of working with SD they are even larger.
Right now I don't have an alternative to the SD library, at least not one that I can master quickly. I read that I need to use a ring buffer and also allocate space for the file on the memory card in advance, but I'm not ready for that yet...

Which clock -- are you talking about the Serial Clock (SCK) associated with MOSI/MISO pin of the SPI Port?

Yes the SPI clock pin (SCK)
image
Or as Arduino labeled it on their Pinout diagram.
Which is the bottom line shown in my screen shots from the logic analyzer

Then it must be equal to the data rate what you have declared in the following -- 2 MHz.

Actually, that is 20mhz. (20,000,000)

And yes that is what is setting the data speed here:

SPI.beginTransaction() - Arduino Reference

SPISettings - Arduino Reference

Where from the SPISetting page you will see:
speedMaximum : The maximum speed of communication. For a SPI chip rated up to 20 MHz, use 20000000.

The SPI software will use the number you passed in, to find the best setting of it's internal clock, such that the generated speed does not exceed the value you passed in.
My guess from the above is the SPI clock can run up to 24 MHZ (maybe more), but the possible dividers are that if you ask for anything from 12mhz to under 24, it will give you 12MHZ. 24 to ??? will give you 24... Again maybe 36 works, maybe 48... not sure...