Long SPI frames help

I am writing a custom application to interface with my own FPGA design. I am using an SPI bus to transfer data from an Arduino Uno to my FPGA board. The Arduino is the master and the FPGA is the slave. I have been trying to get this communication to work for almost 2 weeks now, and I am about to give up out of sheer frustration. =(

My application needs to transfer many words of data, so I am using an SPI frame that is 384 bits long. My understanding of the Arduino is that it should have no problem supporting this frame size. However, what I see during testing leads me to believe that the Arduino is not shifting out all 384 bits, even when I insert long delays in the send sequence. Please see below the sketch I’m using for debug. My only goal right now is to send bits one direction from the Arduino to the FPGA SPI slave. Note that I deliberately keep the SPI SS signal low at the end of the test sequence, because it allows me to see how many bits got shifted in using my special FPGA SPI debug design. Basically I show a count value of how many bits get shifted, and when SS goes high again I reset the controller.

A lot of people are going to tell me that it’s my FPGA design. The problem there is that when I use another FPGA as the SPI master, it works just fine. All the bits are shifted in, and everything looks just great. It’s only the Arduino as a master does all this stuff not work. I am using a CD4050 as the logic level shifter, since the FPGA is 3.3v only. I am certain the logic levels are fine, and there is no other part of the circuit that could really cause me any trouble.

When I modify the sketch to send only 8 or 16 bits (2 calls to SPI.transfer()), my slave counts the correct bits every time. When I increase the number of calls to SPI.transfer() beyond about 4 bytes, then the count I see varies wildly. More frustratingly, it’s never the same count from run to run. Every time I re-run it comes out differently. I’m about 90% sure there are no signal quality issues either, because: (1) I have tried 3 different logic shifter circuits and (2) my current one has only a CD4050 and nothing else (nothing else to cause problems).

All this brings me to the big question: Will the Arduino work with large SPI frames? Has anyone done this successfully? I don’t have access to a scope to prove this, but at this point the blame is squarely on the Arduino, and I have absolutely no idea how to debug this issue.

Sorry here’s an inline version of the code:

/*
  first SPI comms code.
 
*/


// inslude the SPI library:
#include <SPI.h>

// set pin 10 as the slave select for the digital pot:
const int slaveSelectPin = 10;

void setup() {
  // set the slaveSelectPin as an output:
  pinMode (slaveSelectPin, OUTPUT);
  // SPI settings --
  // Supertile design is positive edge clock, MSB first, slowest speed
  
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV32);
  
  // initialize SPI:
  SPI.begin();
  
  // Serial setup
  Serial.begin(9600);
  // print start banner
  Serial.println("Finished init, looping ...");  
  
  Serial.println("Sending first hard packet...");  
  
  unsigned long work[12] = {0x00000001, 0x2194261a, 0x75b7e64d, 0x9bfd9f0f,
                            // Init state
                            0x4169775f, 0x13aa475e, 0x9179af55, 0xab5791e0,
			    0x1f143094, 0x469c58ab, 0x38047ee7, 0x7bbe2aeb};
  
  // sendSPIBitFrame(work);
  // bitBangTest1(work);
  sendSPIFrame(work);
  // SPI.end();
  Serial.println("Packet done.");  
}

void loop() {
  

}


void sendSPIFrame(unsigned long work[12]) {

  // take the SS pin low to select the chip:
  digitalWrite(slaveSelectPin,LOW);
  
  for (int i = 0; i < 12; i++) {
    unsigned long word32 = work[i];
    // byte-reverse order
    for (int j = 3; j >= 0; j--) {
      byte wordb = (byte) (word32 >> (j * 8));
      SPI.transfer(wordb);
      Serial.print(wordb, HEX);
      Serial.print("j");
      // delay(1000);
    }
    Serial.print(" ");
  }

  // take the SS pin high to de-select the chip:
  // digitalWrite(slaveSelectPin,HIGH);
}

Running your test code through the logic analyzer doesn't indicate any real reason for your problems, except perhaps the gap between bytes.

First screenshot shows the 12 bytes arriving OK (I took out the serial prints to try to keep them together):

This shows the second-last byte which has the correct data in it (0x38047ee7):

It seems to me that the Arduino is pumping out the bits correctly. A possible problem is the gaps and delays.

Has anyone done this successfully? I don't have access to a scope to prove this, but at this point the blame is squarely on the Arduino, and I have absolutely no idea how to debug this issue.

My analysis would suggest that it is possibly a timing problem. The bits are going out, so the reason it is counting them incorrectly could be electrical, timing, voltage levels, that sort of thing.

Timing shouldn't be an issue for SPI unless the clocks are too fast - you could run it at one clock per day if you wanted!

That CD4050 is worrying, what supply voltage are you giving it? 3.3V?

Thank you both for having a look at my problem. I'm a little calmer now, and I was very frustrated when writing down my problem.

Nick: thanks for the scope traces, they are informative. Perhaps I do have a timing issue somewhere in my FPGA design. I think based on that plot, I will run more simulations and match the simulation input to the way Arduino is generating the bus traces.

Mark: I am under the impression a CD4050 is just fine for level shifting. It was recommended on the LadyAda site as being good for this purpose. The datasheet even says this is one of the primary applications. Can you be more specific about your worries? BTW, Vdd for the 4050 is 3.3v. Datasheet says input VIH has more than enough headroom for a Vout=3.3v. Only the SS and MOSI signals are being driven by the level shifter, and at least when SPI is quiescent the outputs are always within the 3.3v range.