Bug with SPI

jerenrich

Member
Hi, I encountered an error using SPI on my Teensy 3.0 with the beta 9 Arduino software. Specifically, SCLK was not properly going to ground between successive reads:
SPI.transfer(byteA);
SPI.transfer(byteB);

As you can see in this image, there is a weird bounce in SCLK right after the 8th bit, where the signal only drops slightly.

View attachment IMAGE003.BMP

I was able to fix this and get correct data by adding a small delay:
SPI.transfer(byteA);
delayMicroseconds(10);
SPI.transfer(byteB);

Note that I was running the CPU at 24mhz, and had an SPI clock divisor of 128, in SPI_MODE0.

-Jordan Erenrich
 
@jerenrich

Good find - I hope Paul will chime in on this one. I am also having SPI timing issues on the Teensy 3.
It could be a combination of SPI problems but putting a "delay patch" to fix one problem might not be a cure for the other SPI problems?
 
Please post a complete sample program which reproduces the problem. I'll investigate, but if you give me a ready-to-run sample, it saves time!
 
Here's the code I got via email, slightly modified...

Code:
#include <SPI.h>

const int chipSelectPin = 10;
const int REG_WHOAMI = 0x0F;
const int REG_CTRL_REG1 = 0x20;
const int REG_CTRL_REG4 = 0x23;
const int REG_OUT_X_L = 0x28;

byte byteBuffer[6];

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

  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockDivider(SPI_CLOCK_DIV128); //SPI_CLOCK_DIV32
  SPI.begin();  //Start the SPI library:
  pinMode(chipSelectPin, OUTPUT);  //Initalize the data ready and chip select pins:
  while (!Serial); //Wait for serial port to be open
  delay(100);
}

void loop() {
  readRegister(REG_WHOAMI, 1, byteBuffer);
  Serial.println(byteBuffer[0], BIN);
  delay(10);
}

void readRegister(byte registerBits, int numBytes, byte *byteBuffer) {
  const byte READ = B11000000;  //Read and increment

  byte registerToSend = registerBits | READ;

  digitalWrite(chipSelectPin, LOW);  //Take the chip select low to select the device:
  delayMicroseconds(1);
  SPI.transfer(registerToSend);
  for(int i = 0; i < numBytes; i++) {
    //delayMicroseconds(0);
    byteBuffer[i] = SPI.transfer(0xFF);  //Send dummy value to read output
  }
  digitalWrite(chipSelectPin, HIGH);
}
 
Here are the waveforms I'm seeing.

scope_2.png

It looks like SPI.transfer() ends the instant the clock goes low, without waiting half the clock period.

Here's a zoom in to that very narrow pulse.

scope_3.png

It's only 200 ns wide! This Agilent scope can see it easily, but a low bandwidth scope will completely miss it.

I'm not quite sure what to do about this. I'll look over the SPI documentation again. Perhaps there's a way to get a different status from the hardware?

Anyway, I am looking at this. I just wanted to post what I've got so far.....
 
It's only 200 ns wide! This Agilent scope can see it easily, but a low bandwidth scope will completely miss it.

It pays to have quality test equipment. :cool:


This calls for some humor ... no offense jerenrich.

If you are drowning and someone throws you two floats, one that says "Dupont" and the other one says "Dandee float" on the float's ring donut, which float would you swim to - to save your life?

If you have a "Agilent" scope or a "SING" scope and wanted to make precision waveform timings which would you use? :)

BTW ... I don't have enough money to buy either scope. I can only afford a Teensy 3.:cool:
 
Last edited:
Thanks guys. 200ns seems like approx 5mhz or the default bus speed of 5mhz. Just throwing this out there but maybe the clock divisor isn't being used for the last bit at the end
 
I think your scope bandwidth needs to be at least 2x of your measurement. Since the max SPI default is 4 Mhz, then you would need a 8 Mhz scope.

scope bandwidth = Nyquist sampling theorem:(

Cheap plug ...

Saleae Digital Logic Analyzer

http://www.saleae.com/logic
 
Last edited:
Just throwing this out there but maybe the clock divisor isn't being used for the last bit at the end

Yes, it seems SPI.transfer() is returning immediately after the clock goes low and not waiting for 1/2 clock cycle. I'm looking for another way to implement this, but so far not finding anything.

Edit: I'm working on a solution.......
 
Last edited:
I have the same problem with the native SPI for SdFat. It appears that clock goes high too soon at the start of the second byte.

If I set a value in the SPI_CTAR_CSSCK field that about matches the baud rate divisors in SPI_CTAR_BR and SPI_CTAR_PBR I get a nice looking clock.

There is also the SPI_CTAR_PCSSCK field. Some combination of SPI_CTAR_CSSCK and SPI_CTAR_PCSSCK might do it.

Looking forward to your solution.
 
Looking forward to your solution.

Ditto ... I have two SPI DS3234 real time clocks gathering dust due to this problem. Paul, take your time, and stomp this SPI bug out!
 
Should have used the ds3231.... ;-D
I am using both the I2C DS3231 and the SPI DS3234. My application calls for both.
On the SPI DS3234 you can adjust/sync on the SECOND.
On the I2C DS3231 you can adjust/sync ONLY on the "zero" rollover at 59 seconds.
This means alot in applications where you are constantly adjusting your time to other clock sources likes Atomic WWVB, network time and GPS.
So to say I should have used the DS3231 is really avoiding the real issue - SPI on the Teensy 3 is not 100% compatible with the Arduino, in which Paul is working on now.

@Constantin ... In case you did not see my other link ...
http://forum.pjrc.com/threads/1090-Has-anyone-got-the-DS3234-SPI-RTC-working-on-the-Teensy-3-(Beta8)
 
Last edited:
... dear t3andy, I was just pulling your leg, hence the emoticon. Have a great holiday. Cheers, Constantin
 
Was a fix ever developed for this? I'm just wondering if it's something I should be concerned about when using SPI. This is ages ago, so I'm assuming this isn't an issue.
 
Back
Top