Teensy 4.1 - change SPI clock speed during runtime?

tjaekel

Well-known member
Have you realized that it is almost impossible to modify the SPI clock during runtime?
I have a command on UART shell which should change the SPI clock for next SPI transactions.
Not so easy as you might think:

1. SPISettings is an instance and NOT possible to be changed:
Usually do you this as code:


SPISettings SPIsettings(16000000, LSBFIRST, SPI_MODE3);
int SPI_transaction(int num, unsigned char *tx, unsigned char *rx, int len) {
SPI1.beginTransaction(SPIsettings);


There is no way to modify SPIsettings, because it is an instance of SPISettings, which does not support to modify its parameters
(e.g. to set a new SPI clock speed).

2. Even "new" does not help:
OK, you create SPIsettings as a pointer of SPISettings, via "new".
But even this one fails!
The "new" calls just the default descriptor, even you do this:


SPISettings *SPIsettings = NULL;
SPIsettings = new SPISettings(SPIClkSpeed, LSBFIRST, SPI_MODE3); //it calls just the default constructor, clock is wrong!


3. The only way...
Only via creating a temporary instance of SPISetting it works:


TsyDMASPI0.begin(ssPin, SPISettings(SPIClkSpeed, LSBFIRST, SPI_MODE3));


Also, what I have figured out for the SPI clock speed:
  • maximum SPI clock: 41.667 MHz (approx. 41 MHz)
  • minimum SPI clock: 932.836 KHz (approx. 1 MHz)
  • Clock Resolution: the faster the more inaccurate, e.g. jumping to next speed with 2.4 MHz difference (OK: due to dividers used only)

So, as example, I can get:
16000000 Hz set = 16.129 MHz
15000000 Hz set = 15.152 MHz
1000000 Hz set = 933 Hz - minimum
35000000 Hz set = 33.333 MHz
39000000 Hz set = 35.714 MHz
40000000 Hs set (and anything larger) = 41.667 MHz - maximum

So,
for a SPI master: the minimum speed is approx. 933 KHz, the maximum 41.5 MHz.
The resolution (and correctness) of clock gets worse with higher frequencies (larger jumps to next, not fine granular anymore).

Why there is NOT any support to modify the SPI clock speed during runtime?
Why the PLLs cannot be trimmed more fine granular to get a "requested" SPI clock speed?
(it works only based on divider, why not on changing also the PLL functional clock accordingly?)

In order to "measure" the max. SPI clock possible on an external device (as DUT) - I want to sweep the SPI clock speed in 500 KHz steps,
even at the higher frequencies. But not possible.

The Arduino IDE is already a nightmare, the LIBs meanwhile as well. LOL
 
Why there is NOT any support to modify the SPI clock speed during runtime?

What's wrong with having multiple instancses of SPISettings? I believe that is the intended purpose of SPI::begin/endTransaction().

Code:
SPISettings SPIsettings1( 16000000, LSBFIRST, SPI_MODE3 );
SPISettings SPIsettings2( 20000000, MSBFIRST, SPI_MODE0 );

SPI1.beginTransaction(SPIsettings1);
...
SPI1.endTransaction();

SPI1.beginTransaction(SPIsettings2);
...
SPI1.endTransaction();

Why the PLLs cannot be trimmed more fine granular to get a "requested" SPI clock speed? (it works only based on divider, why not on changing also the PLL functional clock accordingly?)

Perhaps that could be done, but is that what the standard SPI library should do? I'm not expert in all of the clock issues, but if setting the SPI clock changed the CPU frequency, that would affect many other frequencies, and would change UART baud rates, PWM frequencies, etc. Do you care only about the SPI frequency? You could experiment with changing the CPU frequency in order to get a desired SPI clock frequency.

The Arduino IDE is already a nightmare, the LIBs meanwhile as well. LOL

Many of us are using it successfully. I'm sure you could, too, though it might take some time and effort.
 
The T_4.1 has a number of clocks independent of the main clock driving the CPU.

One was selected that gave the best overall range of needed values - but the granularity for fine tuning is determined by the clock multipliers and the table of MHz in p#1 shows the effect of that.
 
Back
Top