Teensy 4.0 SPI Clock Speed

Ummm, you should not be using SPI clock dividers as those are deprecated for use on Teensys.

Instead you should use SPI transactions, which includes a SPIsettings object that you can specify the SPI bus speed, SPI bit order, and the SPI mode directly. On a 3.5, I used this to tune a SPI display to different spi speeds from 8Mhz to 21Mhz (19Mhz was the sweet spot for that particular configuration, until I put in pull-up resistors on the CS/DC pins).

In particular:

Transactional SPI configuration
A common problem used to be that different SPI devices needed different, incompatible settings. Your sketch had to take care of saving and restoring the SPI settings before communicating with each SPI device. If any SPI device was accessed from an interrupt, this could result in data corruption if another SPI device was communicating at the time.

With the new SPI library, configure each SPI device once as an SPISettings object. Also, if that device will be called from an interrupt, say so with SPI.usingInterrupt(interruptNumber). To communicate with a specific SPI device, use SPI.beginTransaction which automatically uses the settings you declared for that device. In addition, it will disable any interrupts that use SPI for the duration of the transaction. Once you are finished, use SPI.endTransaction() which re-enables any SPI-using interrupts.
 
I am working with the Teensy4.0 and compiling in both Arduino IDE and using Visual Studio with Visual Micro plugin (shame the debug does not work!!!)
Arduino 1.8.13 and TeensyDuino 1.53

Anyway using SPIClass to communicate on SPI channel0 to a DAC8775 development board. The SPI links are very short. The CS Pin is Pin 15
I think there is an issue with the SPI Library for Teensy and the SPI.BeginTransaction(SPISettings(spi_speed, bit_order, mode)) is not setting the SPI clock speed correctly.
This was found as using the Teensy4 at 150MHz and has a few issues. From using the Logic logic analyzer on the SPI and fixed a few timing issues by placing a delayMicroseconds(2) after setting CSPin LOW and then after SPI.Transfer(data) another delay delayMicroseconds(2) before setting the CSPin HIGH again. The code for writing (of course there is a method for readings):

void DAC8775Control::DAC8775SPIWrite(byte registryAdr, uint16_t data)
{
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE1));

#if DEEP_DEBUG_LEVEL_TWO
digitalWrite(_csPin, LOW); //Mark for Logic Analyzer for testing and speed of switching, not needed for normal use
digitalWrite(_csPin, HIGH);
delayMicroseconds(2);
#endif

digitalWrite(_csPin, LOW);
delayMicroseconds(2); //This delay is absolutely needed to ensure timings

SPI.transfer(registryAdr);
SPI.transfer16(data); //Data is always 16bit for the DAC8775

delayMicroseconds(2); //This delay is absolutely needed to ensure timings

digitalWrite(_csPin, HIGH);
SPI.endTransaction();
}

I can get this to work for 150MHz and confirm this by writing to a registry (UserBit) on the DAC8775 and then reading it back to confirm an SPI Comms check.

However, if I now crank up the Teensy speed up to above 150MHz it falls over. Does NOT work for 450MHz or 600MHz regardless of what speed I put in the SPISettings.
Played around for a long time (36 hours) with timings and delays and SPISettings. It always fails above 150Mhz.

So I then used the following:

SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE1));
SPI.setClockDivider(SPI_CLOCK_DIV64);

And I get it to consistently pass at 600Mhz, also works with SPI_CLOCK_DIV32. But fails at 600Mhz with SPI_CLOCK_DIV16 (not unexpected).

So in conclusion, I think that the SPI library and in particular the SPISettings is not setting the correct SPI clock speed.

atb Jim
 
SPI.BeginTransaction(SPISettings(spi_speed, bit_order, mode)) is not setting the SPI clock speed correctly
So what does your logic analyzer report for the SPI clock rate when your beginTrasaction() sets clock to 4mhz?

if i run your SPI transfers, scope on SPI CLK (pin 13) shows 4 mhz clock for various MCU speeds.

if the DAC is not keeping up, maybe try sending the 16-bit data item with two 8-bit transfers
 
Last edited:
A couple of different things...

Visual Studio and VisualMicro... There are some capabilities for debug using GDBStubs... More details up on VisualMicro and in a few threads here like:
https://forum.pjrc.com/threads/61499-Teensy-GDBStub-Debugging-via-Serial-with-VS-Integration

Code:
SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE1))
Tries to set SPI clock speed to be the fastest speed it can be that does not exceed 4mbs (4000000)

SPI.setClockDivider(SPI_CLOCK_DIV64) says:
Code:
	void setClockDivider(uint8_t clockDiv) {
		if (clockDiv == SPI_CLOCK_DIV2) {
			setClockDivider_noInline(12000000);
		} else if (clockDiv == SPI_CLOCK_DIV4) {
			setClockDivider_noInline(4000000);
		} else if (clockDiv == SPI_CLOCK_DIV8) {
			setClockDivider_noInline(2000000);
		} else if (clockDiv == SPI_CLOCK_DIV16) {
			setClockDivider_noInline(1000000);
		} else if (clockDiv == SPI_CLOCK_DIV32) {
			setClockDivider_noInline(500000);
		} else if (clockDiv == SPI_CLOCK_DIV64) {
			setClockDivider_noInline(250000);
		} else { /* clockDiv == SPI_CLOCK_DIV128 */
			setClockDivider_noInline(125000);
		}
	}
Max SPI speed is .25mbs or about 1/16th the speed you asked for in the beginTransaction.
Likewise the SPI_CLOCK_DIV32 is .5mbs ...

I believe regardless of speed you run the processor SPI is setup to be using the 720mhz ( // PLL3 PFD0) clock as the main clock so I don't believe CPU speed should influence it.

Note: I ran simple program:
Code:
#include <SPI.h>
void setup () {
  SPI.begin();
  pinMode(10, OUTPUT);
}

void loop() {
  
  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE1));
  digitalWrite(10, LOW);
  for (uint8_t i = 0; i< 8; i++) SPI.transfer(i);
  digitalWrite(10, HIGH);
  SPI.endTransaction();
  delay(250);
}

And it shows:
screenshot.jpg
And you will see in the anotation that the clock is running at about 4mhz as expected. I believe the spec sheet for that chip says it can go up to about 25mhz.
 
SPI Clock Speeds

OK, like all digital problems there seems to analog gremlin.
Thanks to some of the replies, and one asking for logic anlayser outputs, it seems I can not reproduce the issue.
Using the code
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE1));
without any follow on SPI.setClockDivider(SPI_CLOCK_DIV64);
I have had this compiled and running satisfactory; strange.
The logic analyser attached shows approx 8Mhz

Teensy@600Mhz_SPI@8Mhz.jpg

I have also compiled and run at 816Mhz and SPI is showing 8MHz

Teensy@816Mhz_SPI@8Mhz.jpg

However, in my defence, as I don't normally go into writing unless I really need to, the screenshot of the Teensy at 150Mhz and SPI set to 4MHz does not show 4MHz on the Logic Analyser but approx 1Mhz

Teensy@150Mhz_SPI@4Mhz.jpg

Oh and by the way, I did test with and without logic analyser connected, just in case we were getting a probe effect!!!

It seems this issue has digitally disappeared, which is not logical!!!
 
However, in my defence, as I don't normally go into writing unless I really need to, the screenshot of the Teensy at 150Mhz and SPI set to 4MHz does not show 4MHz on the Logic Analyser but approx 1Mhz

For me, T4@150mhz and SPI @4mhz, my scope still sees 4 mhz on pin 13 (nothing connected to SPI pins except scope to pin 13). As KurtE noted, T4 SPI clock is independent of MCU clock.
 
Back
Top