TRouble getting SPI to function with Teensyduino

Status
Not open for further replies.

jakob

New member
Hello

This may eb a very basic question, but it has really puzzled me in the last couple of hours not being able to get SPI to work.

I am running teensyduino beta 7 from yesterday on MBP from last year.

I am running this sketch:

Code:
#include <SPI.h>
#define CS 10  // Digital 10
byte sample = 0;

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

void loop() {
  sample = random(255);
  digitalWrite(CS, LOW);
  SPI.transfer(sample);
  digitalWrite(CS, HIGH);
  delay(10);
}

and I can see from the Teensy 3.0 pin-sheet that came with the board that SPI should be:

CS0 = 10 (as I have defined above)
DOUT = 11
SCK = 13

When I measure pin 10 I get a buzz from the HIGH/LOW in the above code, but measuring on any other pin (except power pins) gives me no output/reaction.

To me the above code should at least spit something out on pin 11 and 13 if I am reading the pin-sheet correctly.

Is anybody able to see what I am doing wrong?

Best Regards,

Jakob
 
try explicitly setting the SPI clock divider

I confirm your example does not work for me either. It looks like Beta 7 has a missing default SPI clock setting. The below code does work for me.

Code:
#include <SPI.h>
#define CS 10  // Digital 10
byte sample = 0;

void setup() {
  SPI.begin();
  // SPI.setBitOrder(MSBFIRST);  // data is clocked in MSB first
  // SPI.setDataMode(SPI_MODE0);  // SCLK idle low (CPOL=0), MOSI read on rising edge (CPHI=0)
  SPI.setClockDivider(SPI_CLOCK_DIV16);  // T3_Beta7 requires this, no default? Set SPI clock to 1 MHz
  pinMode(CS, OUTPUT);
}

void loop() {
  sample = random(255);
  digitalWrite(CS, LOW);
  SPI.transfer(sample);
  digitalWrite(CS, HIGH);
  delay(10);
}
 
Last edited:
It worked!!!! Thank you so much :)
No it's on to figuring out how those interrupts works, and we got synth...

Jakob
 
FYI: I wired up a DS3234 (SPI) RTC to my T3 using the same pins as with the Nano:
Pin 13 SCK
Pin 12 MISO
Pin 11 MOSI
Pin 10 SS
I didn't need to override any defaults (*), just a vanilla SPI.begin() and it works fine (and the I2C DS3231 works fine too).

(*) Correction: Actually I did use this after SPI.begin():
Code:
  SPI.setBitOrder(MSBFIRST); 
  SPI.setDataMode(SPI_MODE1);

Pete
 
Last edited:
I'm working on this bug today. It'll be fixed in beta 9.

The AVR emulation was setting a default speed... something I've been looking at for the last hour. It turns out the problem was in the SPI library. After it configures the SPI port, pinMode() is called to configure the MOSI (DOUT) and SCK pins. On Teensy 3.0, the pins alternate functions for pins are explicitly set, not an automatic takeover of the pin like on AVR. So those pinMode calls in SPI.cpp were setting these 2 pins back to normal I/O mode.

Doing any additional configuration to the port by writing the SPE (enable bit) causes the AVR emulation code to configure the pins correctly again. That's why setting the speed makes it work. It wasn't the speed setting at all, but rather the pins being reconfigured away from SPI inside the SPI library.

Beta 9 will have a fixed SPI library.
 
Further inspect these SPI clock settings. Are these correct?

//SPI speed @ CPU Clock Teensy 3 @ 24 MHz @ 48 Mhz @ 96 MHz - (overclock)
//SPI.setClockDivider(SPI_CLOCK_DIV2); // ~1.738 MHz 3.039 MHz 3.275 MHz
//SPI.setClockDivider(SPI_CLOCK_DIV4); // ~1.211 MHz 2.202 MHz 2.351 MHz <-- Default Teensy 3 SPI ?
//SPI.setClockDivider(SPI_CLOCK_DIV8); // ~754 KHz 1.420 MHz 1.516 MHz
//SPI.setClockDivider(SPI_CLOCK_DIV16); // ~446 KHz 860 KHz 886 KHz
//SPI.setClockDivider(SPI_CLOCK_DIV32); // ~238 KHz 466 KHz 476 KHz
//SPI.setClockDivider(SPI_CLOCK_DIV64); // ~127 KHz 251 KHz 253 KHz
//SPI.setClockDivider(SPI_CLOCK_DIV128); // ~ 65 KHz 129 KHz 130 KHz
 
The AVR emulation code tries to give you the same speed as an AVR running at 16 MHz when Teensy 3.0 is at 48 or 96 MHz. It gives you half that speed at 24 MHz.

So SPI_CLOCK_DIV4 should give 4 MHz when Teensy 3.0 is at 48 or 96 MHz. Like AVR, this is the default speed.
 
So SPI_CLOCK_DIV4 should give 4 MHz when Teensy 3.0 is at 48 or 96 MHz. Like AVR, this is the default speed.

My Wavetek measured these values ?//SPI.setClockDivider(SPI_CLOCK_DIV4); // ~1.211 MHz 2.202 MHz 2.351 MHz <-- Default Teensy 3 SPI ?:confused:
There is no 4 Mhz?

Here is my loop code to measure the Teensy 3 SPI clock:

void loop() {
delay(10000); // wait tens seconds for T3
Serial.println("Start SPI Test");
// start the SPI library:
SPI.begin();
//SPI speed @ CPU Clock Teensy 3 @ 24 MHz @ 48 Mhz @ 96 MHz - (overclock)
//SPI.setClockDivider(SPI_CLOCK_DIV2); // ~1.738 MHz 3.039 MHz 3.275 MHz
SPI.setClockDivider(SPI_CLOCK_DIV4); // ~1.211 MHz 2.202 MHz 2.351 MHz <-- Default Teensy 3 SPI ?
//SPI.setClockDivider(SPI_CLOCK_DIV8); // ~754 KHz 1.420 MHz 1.516 MHz
//SPI.setClockDivider(SPI_CLOCK_DIV16); // ~446 KHz 860 KHz 886 KHz
//SPI.setClockDivider(SPI_CLOCK_DIV32); // ~238 KHz 466 KHz 476 KHz
//SPI.setClockDivider(SPI_CLOCK_DIV64); // ~127 KHz 251 KHz 253 KHz
//SPI.setClockDivider(SPI_CLOCK_DIV128); // ~ 65 KHz 129 KHz 130 KHz

SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE3);
start:
digitalWrite(cs, LOW);
SPI.transfer(-1);
SPI.transfer(0);
digitalWrite(cs, HIGH);
goto start;
}
 
Last edited:
My Wavetek measured these values ?//SPI.setClockDivider(SPI_CLOCK_DIV4); // ~1.211 MHz 2.202 MHz 2.351 MHz <-- Default Teensy 3 SPI ?:confused:
There is no 4 Mhz?

If you connect a frequency counter that measures by counting the number of pulses over a period of time, you'll get less than 4 MHz, because of software overhead between each SPI transfer.

Here's the the SS and SCK waveforms while running this code:

Code:
  digitalWrite(CS, LOW);
  SPI.transfer(sample);
  SPI.transfer(sample);
  SPI.transfer(sample);
  digitalWrite(CS, HIGH);

NewFile0.png

Notice the dead times between each byte? A frequency counter that measures the number of pulses over 1 second or 0.1 seconds will count fewer than 4 million (if the software keeps repeating SPI.transfer) because of these idle times.

If you use the 'scope to view the waveform, it's easy to see the SCK frequency really is 4 MHz (2.5 divisions at 100 ns per division).

NewFile1.png

The idles times between transfers also happen on AVR. With the Arduino SPI library, which was designed around AVR's simple SPI port, these idle times are unavoidable.

Bill Greiman has published a version of his SdFat library that uses Teensy 3.0's SPI port in native mode (not AVR emulation). There is a small hardware FIFO which allows Bill's code to do SPI transfers with no idle time. If you want to achieve the full 4 Mbit/sec (or 24 Mbit/sec... the fastest speed the native hardware supports), I'd recommend using Bill's code.
 
Status
Not open for further replies.
Back
Top