Teensy 4.1 SPI Clock Rate

cgeber24

Member
I am starting an SPI transaction on a Teensy 4.1 with:

SPI.beginTransaction(SPISettings(100000, MSBFIRST, SPI_MODE0));

I am expecting that the SPI clock rate would be 100KHz, as specified. However, my scope and Logic Analyzer both indicate an SPI clock rate of 934KHz. Changing the specified rate to 10000 does not change the observed SPI clock rate.

What am I doing wrong here? Or is there a minimum SPI clock rate that the Teensy 4.1 can generate???

Thanks,
Chuck Geber
 
There has been some discussion lately of how high the SPI clock can go. I'm not sure how low it can go. Can you provide a working sketch to show the issue?
 
The sketch is a demo program from an LCD vendor which is overly complex to demonstrate this problem...

I have increased my requested SPI Data Rate from 100KHz....after I get up to 1MHZ the resulting clock waveform tracks my requested value. Thus it seems that for Teensy 4.1, 1MHz is the lowest achievable SPI clock frequency, and this lower-bound doesn't seem to change with CPU clock frequency. (I tried 600MHz and 150MHz.)

On the upper bound, with a 150MHz CPU clock, the highest SPI clock is about 7MHz; with a 600MHz CPU clock, I got 20 MHz but didn't try any higher...
 
For T4.x, the clock source for LPSPI is 240 MHz, and it's not the system clock, so that's why it doesn't change when you reduce the system clock rate. The max divisor is 257, so that's where the minimum SCLK of a bit less than 1 MHz comes from. 20 MHz implies divisor of 12. The only rates you can actually get are the results of 240/divisor, where divisor can be 2..257. See the link below for more discussion of this.

https://forum.pjrc.com/threads/72055-LPSPI-speed-limit-and-QSPI?p=319847&viewfull=1#post319847
 
Some of the CPU speeds are multiples of 150 MHz, others are multiples of 132 MHz. You should see the minimum SPI clock change by approx 13% if you change between those 2 groups of CPU speeds.
 
Note: The SPI library is setup to allow you to choose a different Clock setting for base of it.

It is all controlled by the clock register: CCM_CBCMR

Which the SPI library inits each time you call SPI.begin() (on any of the SPI objects>
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
//		CCM_CBCMR_LPSPI_PODF(6) | CCM_CBCMR_LPSPI_CLK_SEL(2); // pg 714
So CLK_SEL(1) gets is 720mhz, the PODF(2) means divide by 3. so 240mhz
PODF can be set from 0-7 (so divide by 1 to 8)
So you could easily set PODF(5) /6 and base would then be 120 mhz.
 
Note: The SPI library is setup to allow you to choose a different Clock setting for base of it.

It is all controlled by the clock register: CCM_CBCMR

Which the SPI library inits each time you call SPI.begin() (on any of the SPI objects>
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
//		CCM_CBCMR_LPSPI_PODF(6) | CCM_CBCMR_LPSPI_CLK_SEL(2); // pg 714
So CLK_SEL(1) gets is 720mhz, the PODF(2) means divide by 3. so 240mhz
PODF can be set from 0-7 (so divide by 1 to 8)
So you could easily set PODF(5) /6 and base would then be 120 mhz.

Good to know Kurt. Perhaps both PODF and the other divisor could be set to get as close as possible to requested speed. Or is that to much to do in each beginTransaction()?
 
If you are going to muck with the register, I would do it right after you did any/all SPI.begin() (including SPI1 and/or SPI2...) as they all use the same underlying clock.

Note: the code was setup to try to avoid doing the computations for what the registers should be set to, and only does it if your beginTransaction has a different speed than the previous call.
It does setup the SPI registers on each call to beginTransaction, as we ran into issues where some code still does not use beginTransaction and mucks with the Speed directly.
 
If you are going to muck with the register, I would do it right after you did any/all SPI.begin() (including SPI1 and/or SPI2...) as they all use the same underlying clock.

Note: the code was setup to try to avoid doing the computations for what the registers should be set to, and only does it if your beginTransaction has a different speed than the previous call.
It does setup the SPI registers on each call to beginTransaction, as we ran into issues where some code still does not use beginTransaction and mucks with the Speed directly.

I think PODF(2) works very well, and SPI clock >= 1 MHz is what virtually everyone wants. I'm not sure whether the OP had a specific reason to want 100 kHz, or was more of an accidental discovery that it can't be set that low.
 
Back
Top