No SPI on Teensy4.1

JDC762

Member
There are a few posts on this subject but none that specific address the issue.
So I have a custom built PCB based on the Teensy4.1 with ethernet; schematic is exactly the same to the letter.
Chip fires up nicely and it connects to the ethernet and the internet.
Other functions I2C work nicely.
However, I can't the SPI to work.
I have write a basic bit-bang sketch and the results are spot on; see attached sketch and logic analyser output. Perfect in fact; not fast but spot.
This proves the pins are connected correctly, not shorted, and accessed by the firmware to control them.

However, when I use the SPI, see attached a DigPot control sketch, I get no SCK and nothing on the MOSI that means anything. Please I am not sure that the CS pin is doing what it should be doing either.

So I suspected the SPI library. Normally use Visual Studio Code, but just reverting to Arduino IDE 2 to keep it simple.
Teensy library is loaded and the Libraries being used as per the compile output is as below.

/Users/JDC/Library/Arduino15/packages/teensy/hardware/avr/1.60.0

I have been on this a while now and I have run individual pin tests (flip flop GPIO states and monitored the Logic Analyser) for all connected pins on the chip (status LEDs, I2C etc) and there is no cross connection and all seem to operate as expected.

Please can you help?
 

Attachments

  • BitBangTestOfSPI.ino
    1.1 KB · Views: 17
  • BitBangTestOfSPIPins.png
    BitBangTestOfSPIPins.png
    30.2 KB · Views: 26
  • BasicDigPotSPIControl.ino
    2.2 KB · Views: 23
  • SPIResultsUsingDigPotControlSketch.png
    SPIResultsUsingDigPotControlSketch.png
    23.1 KB · Views: 23
I adapted it for T4.0 (change CS to pin 4), and it worked OK, clocks and data going out on pins 13 and 11, at 4MHz as expected.
 
I have done this on a Teensy4.0 too and it works and use what ever CS pin you want.
I did all my development for the custom board on a Teensy4.0 and it was working an absolute treat.

I have now tried to run SPI
MOSI (Pin11) - White trace
MISO (Pin12) - Brown trace
SCK (Pin13) - Red trace
CS (Pin10) - Orange trace

And I get the same result, no SCK or MOSI, and a strange CS trace!!! However, the bit-bang works and so the pins are connected correctly.
I have uninstalled the Teensy from the Arduino IDE and reinstalled it to make sure that it has not been corrupted, but no change.

Really running out of ideas.
 
What sample rate do you have your Saleae set to? It’s noticeable that the bit banged SPI timebase is way slower than the LPSPI one.
 
I have tried a whole lot of sample rates on the Saleae and in the
SPI.beginTransaction(SPISettings(100000, MSBFIRST, SPI_MODE0));
It is not a case of it not quite working, there is just no SCK at all.
I have even written a direct LPSPI sketch, but I get the same issue; no clock.
I have rolled back to 1.58.2, 1.59.0, updated the Arduino IDE to 2.3.8, made sure that the path to the SPI library is correct and that it is using the __IMXRT1062__ and ARDUINO_TEENSY41
But nothing on SCK

Tried this on Bare board Teensy4.1 and my custom board (based on Teensy4.1) and get the same issue.

#include <Arduino.h>
#include <SPI.h>
void setup() {
Serial.begin(115200);
delay(2000);
Serial.println("Direct LPSPI4 clean test");
SPI.begin(); // Let Teensy core set clock/mux correctly
Serial.print("PIN13 CONFIG: 0x"); Serial.println(CORE_PIN13_CONFIG, HEX);
Serial.print("CR: 0x"); Serial.println(IMXRT_LPSPI4_S.CR, HEX);
Serial.print("CFGR1: 0x"); Serial.println(IMXRT_LPSPI4_S.CFGR1, HEX);
Serial.print("CCR: 0x"); Serial.println(IMXRT_LPSPI4_S.CCR, HEX);
Serial.print("TCR: 0x"); Serial.println(IMXRT_LPSPI4_S.TCR, HEX);
Serial.print("SR: 0x"); Serial.println(IMXRT_LPSPI4_S.SR, HEX);
// Clean reset of FIFOs/status, but do not reset the whole peripheral
IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF;
IMXRT_LPSPI4_S.SR = 0x3F00;
IMXRT_LPSPI4_S.CFGR1 = LPSPI_CFGR1_MASTER;
IMXRT_LPSPI4_S.CCR =
LPSPI_CCR_SCKDIV(100) |
LPSPI_CCR_DBT(50) |
LPSPI_CCR_PCSSCK(50) |
LPSPI_CCR_SCKPCS(50);
IMXRT_LPSPI4_S.TCR = LPSPI_TCR_FRAMESZ(7);
IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN;
Serial.println("Configured direct LPSPI4");
Serial.print("CCR now: 0x"); Serial.println(IMXRT_LPSPI4_S.CCR, HEX);
Serial.print("SR now: 0x"); Serial.println(IMXRT_LPSPI4_S.SR, HEX);
}
void loop() {
// Wait until TX data flag says we can write
if (IMXRT_LPSPI4_S.SR & LPSPI_SR_TDF) {
IMXRT_LPSPI4_S.TDR = 0xA4;
IMXRT_LPSPI4_S.TDR = 0xD2;
}
}
 
First, here's a simple program using the SPI library which does what your program in msg #5 looks like it should do.

Code:
#include <SPI.h>

void setup() {
  SPI.begin();
}

void loop() {
  SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
  SPI.transfer(0xA4);
  SPI.transfer(0xD2);
  SPI.endTransaction();
}

To verify, ran this on a Teensy 4.0 and connected my oscilloscope to pins 11 (MOSI) and 13 (SCK).

file.png


Here's another look with the scope capture stopped, so we can see just 1 copy of the waveform.

file.png
 
Next I ran your program from msg #5. It IS creating some output. Here's what my scope sees.

Notice this is with the scope still running. Your program is NOT continuing to generate output, but it definitely does do something initially!

My guess is you're running your program and then starting the logic analyzer capture, which leads you to believe your program has no output. If you reverse that order, start the logic analyzer capturing before your program begins, I'm sure you'll manage to see it is indeed creating a short burst of activity, but then stops.

file.png
 
Last edited:
To dig into the problem, I tried adding Serial.println("write") immediately before the 2 writes to the TDR register. Full code below.

This is the result I see in the Arduino Serial Monitor (after waiting plenty of time for more "write" to appear). The code is running 10 times, but then stops. My guess is your DIY driver code might be filling up the transmit FIFO and not handling that condition properly?

1777932669259.png


Here is the view seen on my oscilloscope with the time scale zoomed out.

file.png


And finally, here is the exact code I ran to get this result. It's exactly the same as msg #5 but with Serial.println("write") added.

Code:
#include <Arduino.h>
#include <SPI.h>
void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("Direct LPSPI4 clean test");
  SPI.begin(); // Let Teensy core set clock/mux correctly
  Serial.print("PIN13 CONFIG: 0x"); Serial.println(CORE_PIN13_CONFIG, HEX);
  Serial.print("CR: 0x"); Serial.println(IMXRT_LPSPI4_S.CR, HEX);
  Serial.print("CFGR1: 0x"); Serial.println(IMXRT_LPSPI4_S.CFGR1, HEX);
  Serial.print("CCR: 0x"); Serial.println(IMXRT_LPSPI4_S.CCR, HEX);
  Serial.print("TCR: 0x"); Serial.println(IMXRT_LPSPI4_S.TCR, HEX);
  Serial.print("SR: 0x"); Serial.println(IMXRT_LPSPI4_S.SR, HEX);
  // Clean reset of FIFOs/status, but do not reset the whole peripheral
  IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF;
  IMXRT_LPSPI4_S.SR = 0x3F00;
  IMXRT_LPSPI4_S.CFGR1 = LPSPI_CFGR1_MASTER;
  IMXRT_LPSPI4_S.CCR =
    LPSPI_CCR_SCKDIV(100) |
    LPSPI_CCR_DBT(50) |
    LPSPI_CCR_PCSSCK(50) |
    LPSPI_CCR_SCKPCS(50);
  IMXRT_LPSPI4_S.TCR = LPSPI_TCR_FRAMESZ(7);
  IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN;
  Serial.println("Configured direct LPSPI4");
  Serial.print("CCR now: 0x"); Serial.println(IMXRT_LPSPI4_S.CCR, HEX);
  Serial.print("SR now: 0x"); Serial.println(IMXRT_LPSPI4_S.SR, HEX);
}
void loop() {
  // Wait until TX data flag says we can write
  if (IMXRT_LPSPI4_S.SR & LPSPI_SR_TDF) {
    Serial.println("write");
    IMXRT_LPSPI4_S.TDR = 0xA4;
    IMXRT_LPSPI4_S.TDR = 0xD2;
  }
}

I don't have time to dive into this code to troubleshoot what's actually wrong.

But hopefully the program with confirmed good continuous output in msg #7 gives you a way to troubleshoot your hardware, and this test showing brief output that stops and the addition of Serial.println() helps you see what's actually happening software-wise with your program from msg #5.
 
Last edited:
To dig into the problem, I tried adding Serial.println("write") immediately before the 2 writes to the TDR register. Full code below.

This is the result I see in the Arduino Serial Monitor (after waiting plenty of time for more "write" to appear). The code is running 10 times, but then stops. My guess is your DIY driver code might be filling up the transmit FIFO and not handling that condition properly?

View attachment 39288

Here is the view seen on my oscilloscope with the time scale zoomed out.

View attachment 39289

And finally, here is the exact code I ran to get this result. It's exactly the same as msg #5 but with Serial.println("write") added.

Code:
#include <Arduino.h>
#include <SPI.h>
void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("Direct LPSPI4 clean test");
  SPI.begin(); // Let Teensy core set clock/mux correctly
  Serial.print("PIN13 CONFIG: 0x"); Serial.println(CORE_PIN13_CONFIG, HEX);
  Serial.print("CR: 0x"); Serial.println(IMXRT_LPSPI4_S.CR, HEX);
  Serial.print("CFGR1: 0x"); Serial.println(IMXRT_LPSPI4_S.CFGR1, HEX);
  Serial.print("CCR: 0x"); Serial.println(IMXRT_LPSPI4_S.CCR, HEX);
  Serial.print("TCR: 0x"); Serial.println(IMXRT_LPSPI4_S.TCR, HEX);
  Serial.print("SR: 0x"); Serial.println(IMXRT_LPSPI4_S.SR, HEX);
  // Clean reset of FIFOs/status, but do not reset the whole peripheral
  IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN | LPSPI_CR_RRF | LPSPI_CR_RTF;
  IMXRT_LPSPI4_S.SR = 0x3F00;
  IMXRT_LPSPI4_S.CFGR1 = LPSPI_CFGR1_MASTER;
  IMXRT_LPSPI4_S.CCR =
    LPSPI_CCR_SCKDIV(100) |
    LPSPI_CCR_DBT(50) |
    LPSPI_CCR_PCSSCK(50) |
    LPSPI_CCR_SCKPCS(50);
  IMXRT_LPSPI4_S.TCR = LPSPI_TCR_FRAMESZ(7);
  IMXRT_LPSPI4_S.CR = LPSPI_CR_MEN;
  Serial.println("Configured direct LPSPI4");
  Serial.print("CCR now: 0x"); Serial.println(IMXRT_LPSPI4_S.CCR, HEX);
  Serial.print("SR now: 0x"); Serial.println(IMXRT_LPSPI4_S.SR, HEX);
}
void loop() {
  // Wait until TX data flag says we can write
  if (IMXRT_LPSPI4_S.SR & LPSPI_SR_TDF) {
    Serial.println("write");
    IMXRT_LPSPI4_S.TDR = 0xA4;
    IMXRT_LPSPI4_S.TDR = 0xD2;
  }
}

I don't have time to dive into this code to troubleshoot what's actually wrong.

But hopefully the program with confirmed good continuous output in msg #7 gives you a way to troubleshoot, and this test showing brief output that stops and the addition of Serial.println() helps you see what's actually happening with your program from msg #5.
Thanks for all your support it is really appriciated.
Knowing that I was on the right track helped me to diagnose this down to a corruption possible of files after a MACOS update and also settings on the Logic Analyser.
I now have it all running as smooth as silk!
Also managed to get the FlexIO_SPI working too.

Thanks to you all.
 
For info FlexIO sketch below.
Question is, is there any advantage to using FlexIO over using SPI?

#include <Arduino.h>
#include <SPI.h>
#include <FlexIO_t4.h>
#include <FlexIOSPI.h>

#define PIN_MOSI 11
#define PIN_MISO 12
#define PIN_SCK 13
#define PIN_CS 10

FlexIOSPI flexSPI(PIN_MOSI, PIN_MISO, PIN_SCK, -1); // -1 = no hardware CS
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("FlexIOSPI test");
pinMode(PIN_CS, OUTPUT);
digitalWrite(PIN_CS, HIGH);
if (flexSPI.begin()) {
Serial.println("FlexIOSPI begin OK");
} else {
Serial.println("FlexIOSPI begin FAILED");
}
}
void loop() {
digitalWriteFast(PIN_CS, LOW);

// SPI_MODE0 → Mode 0 → CPOL=0, CPHA=0
// SPI_MODE1 → Mode 1 → CPOL=0, CPHA=1
// SPI_MODE2 → Mode 2 → CPOL=1, CPHA=0
// SPI_MODE3 → Mode 3 → CPOL=1, CPHA=1
// flexSPI.beginTransaction(FlexIOSPISettings(1000000, MSBFIRST, SPI_MODE0));
// flexSPI.beginTransaction(FlexIOSPISettings(2000000, MSBFIRST, SPI_MODE0));
// flexSPI.beginTransaction(FlexIOSPISettings(4000000, MSBFIRST, SPI_MODE0));
// flexSPI.beginTransaction(FlexIOSPISettings(8000000, MSBFIRST, SPI_MODE0));
// flexSPI.beginTransaction(FlexIOSPISettings(10000000, MSBFIRST, SPI_MODE0));
flexSPI.beginTransaction(FlexIOSPISettings(12000000, MSBFIRST, SPI_MODE0));

for (int i = 0; i < 2; i++) {
flexSPI.transfer(0xA4);
flexSPI.transfer(0xD2);
}
digitalWriteFast(PIN_CS, HIGH);
flexSPI.endTransaction();
delay(2000);
}
 

Attachments

  • FlexIO_SPI_Test(12Mhz).png
    FlexIO_SPI_Test(12Mhz).png
    30.7 KB · Views: 13
FlexIO would give you a bigger choice of pins to use, or potentially allow higher speeds and/or more flexible modes (like quad/octal io) but in most cases LPSPI will give "smoother" performance due to the hardware FIFOs.
 
I’m not convinced FlexIOSPI actually honours the requested mode, so if you need anything other than MODE0 you’re possibly out of luck. I asked @KurtE (the library author) about it, and the response was
Actually your entire Issue was:

SPI mode setting appears to be ignored​

...or am I wrong about that?
Sorry, but there simply was not enough information to go on. I have not touched this code for a couple years now, and a lot of it, was done something like 8 years ago. And you are probably right that the mode SPI_MODEx was probably never implemented. The only thing I see is that it checks for transmit only flag...

If my foggy memory is correct, they only had the one mode in their example stuff in the manuals, so that is all I implemented, as when I first created the library, I mainly did it to test out the subsystem.
 
OK. So the whole reason for getting the logic analyser out in the first place was because SPI_MODE1 locks the firmware.
I had a few devices on the SPI bus and I have debugged them all individually and they are all working a absolute treat (thanks for all your help), devices include ADG1414, Digpot AD5206, RM05-8A. So quite busy. So now they work, turned my attention to the DAC8775.
However, the DAC8775 needs SPI_MODE1

So I call
_spiBus.beginTransaction(SPISettings(DAC8775_SPI_CLK_SPEED, MSBFIRST, SPI_MODE1));

Despite the speed tried 1Mhz, 2MHz, 4Mhz and 8Mhz
Does not matter, if I use SPI_MODE1 it just hangs on the uint8_t _return = _spiBus.transfer(registryAdr);

If I use SPI_MODE0 or SPI_MODE2 it does not hang, but clearly does not work. Interestingly SPI_MODE3 hangs too.
Using SPI_MODE0, I get very nice logic on both MISO and MOSI, SCK is good form and CS is going LOW as expected.
All as expected as I have all the other devices working.
However, as said, it hangs on my custom Teensy4.1 (also tried on original Teensy4.1); note that I did not get this problem on the Teensy4.0 dev board.

//************************************
// Method: DAC8775SPIWrite
// FullName: DAC8775Control::DAC8775SPIWrite
// Access: private
// Returns: void
// Qualifier: DAC8775 is 24-bit, 8-bit address and 16-bit data
// Parameter: byte registryAdr
// Parameter: uint16_t data
//************************************
void DAC8775Control::DAC8775SPIWrite(byte registryAdr, uint16_t data)
{
PrintMsgToSerialMqtt("DAC8775SPIWrite - beginTransaction");
_spiBus.beginTransaction(SPISettings(DAC8775_SPI_CLK_SPEED, MSBFIRST, SPI_MODE1));
#if SPI_CLOCKDIV_NEEDED
_spiBus.setClockDivider(SPI_CLOCK_DIV_SET); //Needed until the SPI Library is fixed
#endif
#if DEBUG_DAC8775_SPI
_tempMsg.clear();
_tempMsg.concat("DAC8775SPIWrite - SPI registerAdr:");
_tempMsg.concat(registryAdr);
_tempMsg.concat(" using data:");
_tempMsg.concat(data);
PrintMsgToSerialMqtt(_tempMsg);
#endif
#if DEBUG_LOGIC_MARKER
digitalWriteFast(DAC8775_CS_PIN, LOW); //Mark for Logic for testing and speed of switching, not needed for normal use
digitalWriteFast(DAC8775_CS_PIN, HIGH);
delayMicroseconds(1);
#endif
digitalWriteFast(DAC8775_CS_PIN, LOW);
delayMicroseconds(1); //This delay is absolutely needed to ensure timings

#if DEBUG_DAC8775_SPI
PrintMsgToSerialMqtt("DAC8775SPIWrite - before transfer to Reg:", true, false);
PrintMsgToSerialMqtt(registryAdr, false, true);
uint8_t _return = _spiBus.transfer(registryAdr);
PrintMsgToSerialMqtt("DAC8775SPIWrite - return from Reg write:", true, false);
PrintMsgToSerialMqtt(_return, false, true);
PrintMsgToSerialMqtt("DAC8775SPIWrite - before transfer16:", true, false);
PrintMsgToSerialMqtt(data, false, true);
_return = _spiBus.transfer16(data); //Data is always 16bit for the DAC8775
PrintMsgToSerialMqtt("DAC8775SPIWrite - return from data write:", true, false);
PrintMsgToSerialMqtt(_return, false, true);
#else
_spiBus.transfer(registryAdr);
_spiBus.transfer16(data); //Data is always 16bit for the DAC8775
#endif

delayMicroseconds(1); //This delay is absolutely needed to ensure timings
digitalWriteFast(DAC8775_CS_PIN, HIGH);
_spiBus.endTransaction();

#if DEBUG_DAC8775_SPI
PrintMsgToSerialMqtt("DAC8775SPIWrite - completed");
#endif

}
 
Unlike msg #5, this isn't a complete program. I can't just quickly copy it into Arduino IDE and view the waveforms with my scope.
 
Hi Paul

The code for the project is quite large and too complex to be sending on this forum.
However, just a simple SPI sketch does the same thing.

// include the SPI library:
#include <SPI.h>
// set pin 10 as the slave select for the SPI device
const int slaveSelectPin = 10;

void setup() {
Serial.begin(115200);
delay(1000);
// set the slaveSelectPin as an output:
pinMode (slaveSelectPin, OUTPUT);
digitalWrite (slaveSelectPin, HIGH);

Serial.println("Before SPI.begin");

// initialize SPI:
SPI.begin();

delay(2000);
}

void loop() {
Serial.println("Before SPI.beginTransaction");
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE1));

// take the CS pin low to select the device
digitalWrite(slaveSelectPin,LOW);

// send in the address and value via SPI:
Serial.println("Before SPI.transfer");
SPI.transfer(0x05);

Serial.println("Before SPI.transfer16");
SPI.transfer16(0x3840);

// take the CS pin high to de-select the device
digitalWrite(slaveSelectPin,HIGH);

// release control of the SPI port
Serial.println("Before SPI.endTransaction");
SPI.endTransaction();
delay(5000);
}

Output on the monitor:
23:02:23.024 -> Before SPI.begin
23:02:25.032 -> Before SPI.beginTransaction
23:02:25.032 -> Before SPI.transfer (last entry)

Change SPI_MODE1 to SPI_MODE0 or SPI_MODE2 and it does not hang.
And I get the correct output on the logic analyser.

It compiles in VSC and Arduino IDE.
It seems to be referencing the correct SPI.h library as I modified the file with a #error in it to see if the error came up on compile
/Users/JDC/Library/Arduino15/packages/teensy/hardware/avr/1.60.0

I have also run this on a original Teensy4.1 with nothing connected, and despite what I said before, it does run ok.

Not sure what the difference is between SPI_MODE1/3 to SPI_MODE0/2 that would make it hang.
I do have a lot of devices on the SPI bus, but they are all operating fine.
Note that if I change the SPI.beginTransaction to SPI_MODE1 for the other devices, then it will hang.
I have double checked every pin can toggle correctly by having a dedicated sketch and using the logic analyser on each pin on the SPI bus and each of the CS pins.

The schematic for the DAC8775 is below, but I am not sure that is the issue.

I did read a post about capacitance on the bus and how it can affect the signals, but it did not really relate to MODEs and the firmware hanging.


1778279030480.png
 
To update you.

I have taken a original Teensy4.1 with ethernet, and a DAC8775 EVM board.
Connected them up and SPI_MODE1 does NOT hang the code.
And also the comms is perfect and the method written to do a comms check with the DAC8775 comes back GOOD.
So that means that firmware and the SPI library etc are fine.

The next job is to start adding in the other devices on SPI to see if they affect the firmware running.

The short answer is, it must be the electrical connections on the custom board - more investigation needed.

Thanks for your ongoing support.
 
Is the problem reported in msg #17 resolved?

I copied the code into Arduino IDE and ran it on a Teensy 4.0 with nothing connected to the pins. So far it's been running for a few minutes without any sign of stopping or "locks the firmware" described in msg #15.

1778417293607.png
 
Is the problem reported in msg #17 resolved?

I copied the code into Arduino IDE and ran it on a Teensy 4.0 with nothing connected to the pins. So far it's been running for a few minutes without any sign of stopping or "locks the firmware" described in msg #15.

View attachment 39312
Msg#19 is the update and I am still connecting up devices one by one. I still have not had any lock ups.
So I suspect that there is an error on the custom board somewhere. Or there is ringing on the SPI that could be causing it.
Please can we put this on hold and I will report my findings.
Thanks again for your support.
 
Back
Top