Author Topic: Best way to run and terminate SPI (32F4xx)  (Read 2695 times)

0 Members and 1 Guest are viewing this topic.

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6029
  • Country: gb
  • Doing electronics since the 1960s...
Best way to run and terminate SPI (32F4xx)
« on: August 28, 2026, 07:16:29 pm »
I have so far run it with no special precautions but now I am doing a new project where it is running about 15cm.

The issue is obviously the clock.

There is AFAICT no obvious characteristic impedance. One can config the driver "slew rate" but AFAIK this is merely configuring the Rds(on) of the MOSFETs, so for a given value of load cap you are controlling the slew rate.

With USB, STM recommend 0.008" tracks and that has worked great for me. But that must be based on some PCB property.

I am thinking about putting in an RC (series) on the end of the clock line, to GND, and there is a 22R in series close to the driver. I was going to start with 100R and 10pF... buit only if needed and if the series 22R (maybe increased to get a clean edge) does not do it.

SPI clock is from 600kHz to 21MHz and about 10 peripherals are sitting on it. I've run the clock as a daisy chain, not as a star topology.

This thread
https://www.eevblog.com/forum/microcontrollers/32f4xx-lan8742-phy-rj45-best-location-for-phy/
is sort of relevant but there one had a known Z to design to.
« Last Edit: August 28, 2026, 08:18:15 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline Doctorandus_P

  • Super Contributor
  • ***
  • Posts: 5360
  • Country: nl
Re: Best way to run and terminate SPI (32F4xx)
« Reply #1 on: August 29, 2026, 12:29:47 am »
The issue is obviously the clock.

No, not obvious at all. With high speed and longer tracks, also beware of the Slave Select wire. If that arrives a little bit too late, then all communication is out of sync and it won't work either. And if your data lines are still bouncing around when the clock flank arrives then that also completely messes up things.

With USB, STM recommend 0.008" tracks and that has worked great for me. But that must be based on some PCB property.

The magic search words here are:

https://html.duckduckgo.com/html?q=pcb+controlled+impedance

Having a good GND plane is also extremely important here. Without a good (uninterrupted) GND plane, you mess up the impedance of your tracks and you get unexpected delays and reflections.

Series resistors close to the output of each pin can help, but if you combine them with termination resistors at the other end you create a voltage divider. Maybe your attempt to "fix" that with a capacitor works. I lack a bit of experience here.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6029
  • Country: gb
  • Doing electronics since the 1960s...
Re: Best way to run and terminate SPI (32F4xx)
« Reply #2 on: August 29, 2026, 05:33:56 am »
That is why the termination resistor has a series capacitor - to avoid creating a divider on DC.

The /CS and data setup and hold times are huge in this case. I am just trying to clean up the clock edges.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 11230
  • Country: fi
Re: Best way to run and terminate SPI (32F4xx)
« Reply #3 on: August 29, 2026, 05:44:26 am »
Parallel termination halves the voltage, so don't do that.

Series termination is the correct term to look for, also called source termination. Check it out. It is a perfectly valid concept for unidirectional point-to-point transmission lines which SPI usually is (single slave, or chained slaves. Parallel slaves do not apply here).

So, a series resistor at the pin driving the signal. So, MOSI, SCK, NSS series resistors at the master, MISO series resistor at the slave.

Set R = characteristic impedance of the transmission line. You can approximate the impedance of a PCB track with various online calculators. The caveat is, you need to subtract the resistance of the driving transistor, which is not well controlled. Assume ~30 ohms or so. Good starting point for the external series resistor is 33R. Adjust from there, based on measurements. Too low, and you still have ringing (not well terminated). Too high, and you are creating additional RC filtration and slowing the edge. Possibly better to err on that side; that's why 47R is a popular value.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6029
  • Country: gb
  • Doing electronics since the 1960s...
Re: Best way to run and terminate SPI (32F4xx)
« Reply #4 on: August 29, 2026, 05:58:48 am »
Interesting. I wonder why 22R is so often used then, given that one won't normally make a PCB track with 22 ohm Z. Typical values are a lot higher.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 11230
  • Country: fi
Re: Best way to run and terminate SPI (32F4xx)
« Reply #5 on: August 29, 2026, 06:08:03 am »
Interesting. I wonder why 22R is so often used then, given that one won't normally make a PCB track with 22 ohm Z. Typical values are a lot higher.

Habit, although I guess 47R is a very usual value too, and that (when added with the ~15-50 ohms of the IO pin Rds_on) would be closer to the typical microstrip characteristic impedance.

22R would take most of the ringing out, so maybe it's that: good enough, no more. Remember, after all, short SPI link on a PCB is not something most designers think about as a transmission line they need to terminate, at all. Usually these go without any termination and ring somewhat, and it still passes (their own requirements + EMC). 22R is already an improvement. I have also used 22R by default. Maybe some magical feeling with the number itself.
 

Online mtwieg

  • Super Contributor
  • ***
  • Posts: 1793
  • Country: us
Re: Best way to run and terminate SPI (32F4xx)
« Reply #6 on: August 29, 2026, 11:34:17 am »
I always add series/source termination to SCLK.

Interesting. I wonder why 22R is so often used then, given that one won't normally make a PCB track with 22 ohm Z. Typical values are a lot higher.

The driver inside the chip will have an effective output impedance (IME of 20-50 ohms), and this sums with the external resistance. So the right resistor value is the characteristic impedance of the trace, minus the effective output impedance of the driver. You don't have to be super precise though, a value of 22-47ohms is usually in the ballpark, just check it with a scope on your first article boards.

If the SPI bus has multiple slaves spread across the board, I might split SCLK into multiple traces at the source, each with their own series termination. Not perfect, but usually works out better than a daisy chain (or even worse, if the trace branches midway between the source and slaves). Depends on the distances compared to the driver's rise/fall time.
« Last Edit: August 29, 2026, 12:00:38 pm by mtwieg »
 

Online langwadt

  • Super Contributor
  • ***
  • Posts: 5786
  • Country: dk
Re: Best way to run and terminate SPI (32F4xx)
« Reply #7 on: August 29, 2026, 12:19:53 pm »
I always add series/source termination to SCLK.

Interesting. I wonder why 22R is so often used then, given that one won't normally make a PCB track with 22 ohm Z. Typical values are a lot higher.

The driver inside the chip will have an effective output impedance (IME of 20-50 ohms), and this sums with the external resistance. So the right resistor value is the characteristic impedance of the trace, minus the effective output impedance of the driver. You don't have to be super precise though, a value of 22-47ohms is usually in the ballpark, just check it with a scope on your first article boards.

If the SPI bus has multiple slaves spread across the board, I might split SCLK into multiple traces at the source, each with their own series termination. Not perfect, but usually works out better than a daisy chain (or even worse, if the trace branches midway between the source and slaves). Depends on the distances compared to the driver's rise/fall time.

with a daisy chaining, for example shiftregisters, routing the clock in the opposite direction of the data can help because it adds hold time

 

Offline hans

  • Super Contributor
  • ***
  • Posts: 1969
  • Country: 00
Re: Best way to run and terminate SPI (32F4xx)
« Reply #8 on: August 29, 2026, 12:37:10 pm »
I've no absolute expertise in this area, nor have I got access to equipment for accurate measurements
But I've made some boards with HyperRAM @ 100MHz and USB ULPI @ 60MHz with some educated guessing (from various appnotes)..

What I've done is make an estimation of the output impedance of the driver pin. I do this by looking up the datasheet drive strength at a given voltage drop. R=U/I even at exotic frequencies, so say a pin drops 0.6V at 12mA, then its output impedance is 50Ohms.

For STM32F407; it actually specifies them as VSS+0.4V / VDD-0.4V  @ 8mA, and VSS+1.3V / VDD-1.3V @ 20mA
So thats 50-65Ohm's (some non-linear behaviour as its a FET).

Then I calculate the characteristic impedance of the PCB traces (often microstrip). This indeed needs the trace width, copper thickness, layer prepreg thickness and permittivity of the core/prepreg material. Lets say a 0.2mm trace gives you a characteristic (single ended) impedance of 70 Ohms.

Then you want the source (the 50Ohm GPIO) to match the PCB transmission line of 70Ohms. With source matching, you add a 20R resistor to match it to the 70Ohm transmission line. At DC it should not matter because its still an "open circuit".. (unless you terminate at the destination but that burns a lot of power)
I'm guessing here many applications would be fine with a 10-40R resistor. You aren't going to run 100+ Ohm traces across many 4L boards (<0.1mm width). Neither will you see many MCUs with a 10Ohm GPIO driver. 

Getting a SPI bus to run at high frequency distance is often held back by the MISO line. The SCK master to slave is a single propagation across the board. CS and MOSI travel in the same direction and are sync'ed to the master edges.
MISO on the other hand has to wait for SCK, account for propagation in the slave device, and then propagate back across the PCB and adhere to the setup/hold time of the master MISO pin.
The velocity factor on PCBs is often around 0.6-0.7 times speed of light, so around 2E8 m/s. A bus of 15cm in round trip then adds ~0.8ns each way. That doesn't sound like much, but lets say I have an ENC28J60 (Rated for max SPI 20MHz) and a STM32F407:

SCK period: 50ns
Assuming 50% duty cycle there is 25ns between SCK edges

STM32F4 GPIO rise/fall time at max speed, 30pF load: 4ns
SCK PCB trace: 0.8ns
ENC28J60 SCK rise/fall to SDO valid delay 30pF load: 10ns
MISO PCB trace: 0.8ns
STM32F4 MISO setup time: 6.5ns
Total: 22.1ns

But is your PCB trace actually a 30pF load? When you have 10 I/O pads each adding 5pF then obviously not :) .
Seeing a 1ns extra I/O delay gets ever so closer to timing violations..

Also some SPI slave devices are absolutely horrible spec'ed. Whilst typing this post I opened the MCP3911 ADC datasheet which says it supports a 20MHz SPI bus. But they spec'ed the SDO output delay at "max 25ns". So it can do 20MHz if you have a SPI master with a negative setup time. But otherwise the maximum frequency is 1 / 2 / (25ns + everything else), so in this example of ~12ns of the PCB+MCU, the max SPI clock would actually be closer to 13.5MHz.
With 10 slaves, all those stubs can also be a giant issue.

Maybe my calculation is not 100% correct or spot on, but usually it gets me in the ballpark.
« Last Edit: September 01, 2026, 07:24:09 am by hans »
 

Offline EE_Audio

  • Contributor
  • Posts: 31
  • Country: us
Re: Best way to run and terminate SPI (32F4xx)
« Reply #9 on: August 29, 2026, 02:23:33 pm »
I would not use an RC termination. Use a small series resistor place near the driver pin. You can determine the resistor value experimentally, just start with 10 ohms and adjust from based on the waveforms.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6029
  • Country: gb
  • Doing electronics since the 1960s...
Re: Best way to run and terminate SPI (32F4xx)
« Reply #10 on: August 29, 2026, 08:41:32 pm »
Quote
For STM32F407; it actually specifies them as VSS+0.4V / VDD-0.4V  @ 8mA, and VSS+1.3V / VDD-1.3V @ 20mA
So thats 50-65Ohm's (some non-linear behaviour as its a FET).

I think you refer to this table



It is interesting that they do not spec different values for different pin "speeds" which suggests that the "speed" does not really change Rds(on). Or maybe it does and they just picked the highest "speed" setting.

75 ohm works out at roughly 0.005" track. For 50 ohms it would be around 0.010". But another variable is that I am using a 2mm FR4 material, not 1.6mm, and 6 layer, so I need to work this out properly, because some of the layer thicknesses vary greatly. The likely stack-up will be the 2 planes in the middle and the 4 signal layers on the outside, but I can choose the SPI signals between the two layers, to minimise radiation. I have the Saturn PCB toolkit.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 30222
  • Country: nl
    • NCT Developments
Re: Best way to run and terminate SPI (32F4xx)
« Reply #11 on: August 29, 2026, 09:01:26 pm »
I have so far run it with no special precautions but now I am doing a new project where it is running about 15cm.

The issue is obviously the clock.

There is AFAICT no obvious characteristic impedance. One can config the driver "slew rate" but AFAIK this is merely configuring the Rds(on) of the MOSFETs, so for a given value of load cap you are controlling the slew rate.

With USB, STM recommend 0.008" tracks and that has worked great for me. But that must be based on some PCB property.

I am thinking about putting in an RC (series) on the end of the clock line, to GND, and there is a 22R in series close to the driver. I was going to start with 100R and 10pF... buit only if needed and if the series 22R (maybe increased to get a clean edge) does not do it.
What you are looking for is AC termination (which should go at the end of the transmission line). There are rule of thumb formulas to calculate the proper R & C values. Just trying something likely isn't going to work. Also consider terminating the other SPI bus signals. IIRC good old parallel PCI was designed to work as a bus without any termination. You might want to look into how that was designed from a signal integrity POV.
« Last Edit: August 29, 2026, 09:05:41 pm by nctnico »
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6029
  • Country: gb
  • Doing electronics since the 1960s...
Re: Best way to run and terminate SPI (32F4xx)
« Reply #12 on: August 29, 2026, 09:22:36 pm »
Taking that table in the 32F4xx DS, one gets about 50 ohms, so adding my 22R resistor gives 72 ohms for Zout, and that is achievable on the very assymetric JLC stackup where you have 0.55mm one side and 0.1mm the other side (putting the SPI tracks as the only signal layer between the two planes).

If one were looking at say 80 ohms then the track width becomes too thin (for FR4).

This is probably overkill for what I am doing :) but I want to do it as best as I can given that I have a choice.

Using the Saturn software, 0.003" gives 72 ohms but that is very thin for manufacture.



0.004" gives 64 ohms.

But also the typical Rds(on) is going to be lower than the worst case DS spec, so this difference is in the right direction.
« Last Edit: August 29, 2026, 09:38:28 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 30222
  • Country: nl
    • NCT Developments
Re: Best way to run and terminate SPI (32F4xx)
« Reply #13 on: August 29, 2026, 10:27:10 pm »
I'd be careful modelling the output impedance from pins from DC performance. Designing IC I/O pads is a black art in itself. Often the way a pin is driven on/off is along somewhat defined current profiles in order to reduce EMI by making the edges less steep at the start. IOW: the output impedance isn't constant and the pin driver has already been designed to minimise reflections from fast edges. If you want to be sure, you'll need to get the IBIS models and simulate your circuit using those. Actually, I think that if you have mostly capacitive traces (wide), you will have an RC filter effect together with the driver's output impedance.
« Last Edit: August 29, 2026, 10:51:14 pm by nctnico »
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3529
  • Country: ca
Re: Best way to run and terminate SPI (32F4xx)
« Reply #14 on: August 29, 2026, 11:19:24 pm »
I don't think you need resistors on the output lines. The STM32 pins have 4 settings with different driver impedance. The slowest one will probably be too much impedance already, so you will be able to over-dump the line without external resistors.

MISO is driven by the peripheral, so the driver will be different. They should have recommended design document. It may be worth following.

If you want to fight EMI, make sure that there's a continuous ground (or power) plain underneath the traces, preferably not too far beneath.

Once you build it, take a scope and look at the signal at various STM32 speed settings and select the one that gives you the best results - fast enough edges with minimal overshoot. This might be not what they recommend for your signaling frequency.

Do not run MISO too close to CLK or MOSI. MISO will be somewhat delayed. Therefore you don't want them to couple on each other.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6029
  • Country: gb
  • Doing electronics since the 1960s...
Re: Best way to run and terminate SPI (32F4xx)
« Reply #15 on: August 30, 2026, 06:43:28 am »
I did a test a while ago and got this data:

Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 
The following users thanked this post: mtwieg

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 11230
  • Country: fi
Re: Best way to run and terminate SPI (32F4xx)
« Reply #16 on: August 30, 2026, 06:50:18 am »
One thing you could add to the test is to keep VERY_HIGH or HIGH, and add a series resistor of 33R close to the driving source. Adjust the R until the ringing is just barely gone.

And take the measurement always from the receiving pin!

My hypothesis is that by adjusting R optimally, you almost get the benefits of both: lack of ringing combined with nearly the edge rate of the VERY_HIGH/HIGH. IO pin slew control isn't a replacement for termination.

And series (source) termination is the right shape for unidirectional, single driver, single receiver configuration. The caveat is that the signal is well-defined only at exactly the receiving pin (so you need to probe there).

Biggest challenge in probing is the ground clip. You need to use the springy little thing and even that won't be 100% perfect.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 6029
  • Country: gb
  • Doing electronics since the 1960s...
Re: Best way to run and terminate SPI (32F4xx)
« Reply #17 on: August 30, 2026, 02:12:15 pm »
Yes; I have the LeCroy ZS1000 probe. The ground connection is 1cm away from the tip. And on a ground plane board one can usually find a pin which goes straight to the plane.

Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3529
  • Country: ca
Re: Best way to run and terminate SPI (32F4xx)
« Reply #18 on: August 30, 2026, 03:38:40 pm »
I did a test a while ago and got this data:

GPIO_SPEED_FREQ_LOW looks OK to me for 20 MHz clock. It has less than 10 ns rise/fall times. The slow edges may introduce a small skew between CLK and MOSI because the receiving pins may have different thresholds, but this is a few ns at most, which should be fine unless the slave requires large setup/hold. This will also increases MISO delays by a few ns because the slave will receive the clock later. If slave delays are too long, it will not work. It would be easy to fix if your SPI module had a late sample feature, but I don't think it does. For that reason the slowest speed might be unacceptable.

GPIO_SPEED_FREQ_MEDIUM produces a very small overshoot and practically no riging. Since it has faster edges, it will reduce MISO delays (compared to low speed). It might be the best in this situation.

GPIO_SPEED_FREQ_HIGH and GPIO_SPEED_FREQ_VERY_HIGH produce somewhat larger overshoot and no measurable benefits compared to medium.

But the results would depend on many factors, such as receiver capacitance, not to mention the capacitance of your probe.


 

Online mtwieg

  • Super Contributor
  • ***
  • Posts: 1793
  • Country: us
Re: Best way to run and terminate SPI (32F4xx)
« Reply #19 on: August 30, 2026, 03:48:34 pm »
Important to keep in mind that the primary purpose of termination isn't to delay the clock, it's about getting clean transitions while minimizing delay (also plays a role in EMI). In the worst case, the clock can get so messy that edge edge can look like multiple edges to the slaves.

What I've done is make an estimation of the output impedance of the driver pin. I do this by looking up the datasheet drive strength at a given voltage drop. R=U/I even at exotic frequencies, so say a pin drops 0.6V at 12mA, then its output impedance is 50Ohms.
Anecdotally, I've found that the effective output impedance is generally lower than what the static output specs suggest. Should always confirm it with actual measurements of the clock waveform. IBIS models might also be helpful, if they're available and you know how to use them.

I don't think you need resistors on the output lines. The STM32 pins have 4 settings with different driver impedance. The slowest one will probably be too much impedance already, so you will be able to over-dump the line without external resistors.
The variable IO settings are definitely worth using, and might eliminate any need for series termination at all. Depends on a variety of things like the bus length, clock period, setup and hold times, etc. Personally I'm always in the habit of putting an 0402 series termination resistor at every clock output (SPI, I2C, oscillators, etc). Sometimes they're not necessary, but when they are I'm glad I put it there.
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 4842
  • Country: us
Re: Best way to run and terminate SPI (32F4xx)
« Reply #20 on: August 30, 2026, 05:23:59 pm »
Interesting. I wonder why 22R is so often used then, given that one won't normally make a PCB track with 22 ohm Z. Typical values are a lot higher.

Habit, although I guess 47R is a very usual value too, and that (when added with the ~15-50 ohms of the IO pin Rds_on) would be closer to the typical microstrip characteristic impedance.

22R would take most of the ringing out, so maybe it's that: good enough, no more. Remember, after all, short SPI link on a PCB is not something most designers think about as a transmission line they need to terminate, at all. Usually these go without any termination and ring somewhat, and it still passes (their own requirements + EMC). 22R is already an improvement. I have also used 22R by default. Maybe some magical feeling with the number itself.

22 Ohm is a fairly good compromise for a lot of real world situations.  If your SPI bus has some branching, has some bidirectional pins, or just multiple slaves driving MISO perfectly matched source termination is not necessarily optimal.  22 ohm somewhere will provide significant damping without limiting the drive strength too much.  Many SPI peripherals run at 10-20 MHz max, and assuming the total bus length is < 50 cm or so, your clock frequency will be 20x lower than the fundamental resonance, so absorbing 50% of the energy on each bounce is enough.

Higher speed SPI such as for high speed flash chips is generally point-to-point and over much shorted distances, so the 20x frequency ratio still applies.  Here an optimized source termination is possible and may be helpful, so a 47R resistor may be a better choice.  Although you still have to watch out for QSPI and other extensions that still use bidirectional signalling on some pins.

If you do want to run SPI over a longer distance with a high clock speed, it's probably best to do proper impedance matching.  But then you probably want to stick to a single device standard 4-wire spi.
 

Offline Unixon

  • Frequent Contributor
  • **
  • Posts: 762
Re: Best way to run and terminate SPI (32F4xx)
« Reply #21 on: September 01, 2026, 07:14:00 am »
I have a little bit crazy idea about automated impedance matching.
It would be interesting to test this setup:
Run SPI signals through MOSFETs with all gates tied together and controlled by a single channel high resolution DAC.
Then loop through all DAC levels and all GPIO speeds and just count the number of pass/fail outcomes for data integrity test.
Then try to replace MOSFETs back with resistors of a value matching to discovered optimal value.
Obviously this would require low lead inductance parts in QFNs and good routing.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

-->