Fastest way to send 6 bytes over SPI on Teensy 3.2

Status
Not open for further replies.

ryanrs

Active member
What's the fastest way to send 6 bytes over SPI? I see DmaSpi, SPIFIFO, and some other libs.

I am using a Teensy 3.2. My application is transmit only, always 6 bytes, and no other devices/libs will be using SPI. No chip selects needed. No completion callback needed. Transmissions are on a fixed timer, so the tx fifo is guaranteed to be empty. I do need to use the alternate SCK pin, though.

I want to do this inside a 5us interval timer, if possible.
 
SPIFIFO isn't really recommended anymore, but I decided to give it a quick try just to see how much of the CPU time on a Teensy 3.2 would remain unused if an IntervalTimer uses it every 5 microseconds.

Here's the code I tried. Hopefully this is pretty obvious. It toggles a pin in loop(), so we can see how much of the time is spent in the main loop versus the IntervalTimer interrupt.

Code:
#include <SPIFIFO.h>

IntervalTimer mytimer;

void setup() {
  SPIFIFO.begin(10, SPI_CLOCK_24MHz);
  mytimer.begin(transmit, 5);
  pinMode(2, OUTPUT);
}

void transmit() {
  SPIFIFO.clear();
  SPIFIFO.write16(0x5AA5);
  SPIFIFO.write16(0x5AA5);
  SPIFIFO.write16(0x5AA5);
}
void loop() {
  while (1) {
    digitalToggleFast(2);
  }
}

And here's the result my oscilloscope sees. Better than I thought it would be. ;)

file.png
 
Hi Paul. The bottom trace looks like 64 clocks @ 16 MHz, is that right?

The bottom (green) trace isn't SPI at all. It's from this:

Code:
void loop() {
  while (1) {
    digitalToggleFast(2);
  }
}

The idea is to gauge how much of the CPU time is spent inside the interrupt versus the main program.
 
Oh wow, that's even better! I thought you were probing SCK, not MOSI. So it's more like 20% CPU usage in the interrupt.
 
What do I need to change in SPIFIFO.h to use Teensy 3.2 alternate SCK on pin 14? I tried looking through SPI.cpp, but I'm having trouble understanding how the pin mux(?) is setup.

I'm just looking to hardcode SCK to the alternate pin 14, not add arbitrary setSCK() functionality.
 
Answering my own question:

Code:
    // We don't care about CS, so set it to unused pin 24 (bottom side smd pad)
    SPIFIFO.begin(24, SPI_CLOCK_24MHz);

    // assign SCK to alternate pin 14
    CORE_PIN14_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);

    // restore pin 13 digital functionality
    pinMode(PIN_LED, OUTPUT);

Incidentally, assigning SCK to pin 14 is why I'm using a Teensy 3.2 for this project instead of a Teensy 4.0. This is for a light controller, and the T4.0 can't do SPI without glowing in the dark!
 
And the transmit code:

Code:
const uint16_t* p = framebuffer.phases[y][ph].data.shorts;
KINETISK_SPI0.PUSHR = p[0] | SPI_PUSHR_CTAS(1);
KINETISK_SPI0.PUSHR = p[1] | SPI_PUSHR_CTAS(1);
KINETISK_SPI0.PUSHR = p[2] | SPI_PUSHR_CTAS(1);

I do not check the fifo status because I know it is empty when I start. This code runs so fast that I can increase my interrupt rate from 5us to 2.5us.
 
Incidentally, assigning SCK to pin 14 is why I'm using a Teensy 3.2 for this project instead of a Teensy 4.0.

With Teensy 4.0 / 4.1 you could do this using SPI1 on pins 26 & 27.

But with Teensy 4.0 those pins are on the bottom side pads which aren't as convenient as the outside edge pins. The SPI hardware registers are very different on Teensy 4 also, so completely different code would be needed. On the plus side, the SPI FIFO on Teensy 4 is larger and supports 32 bit words.

Whether transmitting 200,000 or 400,000 times per second for lighting controller is worthwhile is of course a completely different question. If you're sending to addressable LEDs, they internally use PWM at a much slower rate, and the rate at which humans can perceive changes in light is much slower still.
 
They're just plain old red LEDs in a 25x11 matrix. I use 2x 595s + mosfets as row drivers, and 2x CAT4016 current sinks to drive the columns.

1.0 / (5us * 255 brightness levels * 11 rows) = 71.3 Hz

71 Hz looks pretty smooth, but you can see a bit of strobing/flicker in your peripheral vision for certain patterns. Speeding it up a bit should take care of it. There's also a huge speedup to be had by splitting up the longer duration pulses to reduce that 255 factor, but I haven't done that yet.
 
My main complaint right now is that the first prototype worked so well that it was put into use 2 days after I built it. So now I'm waiting on a digikey order so I can make another one and continue firmware development.

Teensy has been an amazing tool for the R&D work I do at my company. It makes board bringup so much faster and more predictable.
 
Status
Not open for further replies.
Back
Top