Teensy 4.1 SPI below 1Mhz possible?

Dani Carbonell

New member
Hi, this is my first post.

I want to control a chain of x5 DRV8860 with SPI using a Teensy 4.1.
The problem is that the drivers limit speed is at 200kHz and I don't manage to make the Teensy SPI clock slower than 1Mhz (minimum speed at the specification)

Teensy41_SPI_1MHZproblem.png


  1. Is there a way to achive my purpose without having to use Bitbanging and blocking other time critical tasks?

I have done the same experiment with an ESP32 and verified that the DRV8860 works as expected at 200kHz but not at 1Mhz.

Here is the code:
Code:
#include "Arduino.h"
#include <SPI.h>

SPISettings settingsA(200000, MSBFIRST, SPI_MODE0);
const uint16_t DRV8860_LATCH_PIN = 38;


void setup() {
  
    pinMode(DRV8860_LATCH_PIN, OUTPUT);
    SPI1.begin();
    SPI1.setMOSI(26);
    SPI1.setSCK(27);
    //SPI1.setClockDivider(SPI_CLOCK_DIV32);

}

void loop() {
     
    SPI1.beginTransaction(settingsA);
    digitalWrite (DRV8860_LATCH_PIN, LOW);
    SPI1.transfer(0b01010101);
    digitalWrite (DRV8860_LATCH_PIN, HIGH);
    SPI1.endTransaction();

    delay(500);

    SPI1.beginTransaction(settingsA);
    digitalWrite (DRV8860_LATCH_PIN, LOW);
    SPI1.transfer(0b10101010);
    digitalWrite (DRV8860_LATCH_PIN, HIGH);
    SPI1.endTransaction();

    delay(500);
}

Thanks!
Dani
 
Yes it can go slower. It depends on what we set the internal clock settings to.

If for example your first part of the sketch looks like:
Code:
void setup() {

  pinMode(DRV8860_LATCH_PIN, OUTPUT);
  SPI1.begin();
  CCM_CBCMR = (CCM_CBCMR & ~(CCM_CBCMR_LPSPI_PODF_MASK | CCM_CBCMR_LPSPI_CLK_SEL_MASK)) |
    CCM_CBCMR_LPSPI_PODF(7) | CCM_CBCMR_LPSPI_CLK_SEL(3); // pg 1055
  SPI1.setMOSI(26);
  SPI1.setSCK(27);
  //SPI1.setClockDivider(SPI_CLOCK_DIV32);

}
The default one that is in SPI.begin is:
Code:
	CCM_CBCMR = (CCM_CBCMR & ~(CCM_CBCMR_LPSPI_PODF_MASK | CCM_CBCMR_LPSPI_CLK_SEL_MASK)) |
		CCM_CBCMR_LPSPI_PODF(2) | CCM_CBCMR_LPSPI_CLK_SEL(1); // pg 714
So if anyone calls SPI or SPI1 or SPI2.begin it will overwrite yours...

This overwrites the default clock and divider that is used in SPI (LPSPI). Warning this overwrites it for ALL LPSPI...
The CCM_CBCMR_LPSPI_CLK_SEL(3) says to use the 4th clock setting which maps to:
Code:
		static const uint32_t clk_sel[4] = {664615384,  // PLL3 PFD1
					     720000000,  // PLL3 PFD0
					     528000000,  // PLL2
					     396000000}; // PLL2 PFD2
So went from base clock of 720mhz to 396mhz
And the PODF is a divider (+1)

So went from 720mhz/3
to 396mhz/8
 
  1. Is there a way to achive my purpose [..] and blocking other time critical tasks?
No, not really. On Teensy, SPI is blocking. But you can use it in an interrupt ( But that is another challenge of its own ) or DMA (another challenge).
Then, by default, for Teensy, there is no concept like "Tasks". However, there are libs that can do that.

Edit: So for the normal, standard use, and low frequencies, bitbanging is as good as SPI.
 
Thank you for the comple answer KurtE.

I've tried the first snippet and it worked! Now SPI can work below 1Mhz.
I have to check if it also does along the NativeEthernet library and appleMIDI. I couldn't find any mention to SPI in their repositories, so I guess it should be fine.

In addition I am using two MAX11300 on the first SPI. In this case I could include your code in the MAX11300 library after it calls SPI.begin, right?

I imagine that the max allowed SPI clock is not anymore 100Mhz but arround 20Mhz (5x less). Correct?

Cheers
 
Thanks Frank for you insights,

I think I am going to use the method sugested by KurtE. I still haven't decided witch library I am going to use for the scheduled tasks, perhaps Metro.
I will study those options as well.
 
Is there a way to go below 200kHz? (I want to operate at 125k).
I tried to set CCM_CBCMR_LPSPI_PODF(8) to get a larger divider but that results in a clock speed of 1.5Mhz.
If CCM_CBCMR_LPSPI_PODF(7) the highest divider possible?

Cheers
 
Back
Top