SPI Data Rate Timings

How fast we run the SPI clock from the Pi is a compromise between the sample rate we want to achieve, the time the Pi spends processing and the quality of the wiring.

Looking at the transactions we have something like this:

The timing points here are
• Before t0: The ADC collects a" half complete" set of samples, and sets up the SPI DMA.
• t0: The STM takes the strobe line low.
• t1: The Pi sees this and starts the SPI transfer of 1024 samples.
• t2: The SPI transfer completes.
• tn: This process repeats for the upper half of the ADC sample buffer.
The transfer is limited by the
• SPI clock rate
• Processing Delay on the Pi
The SPI clock limits how fast data can move over the bus, the ADC conversion rate determines how much data we want to send. The processing delay on the Pi can increase the t0 to t1 gap, and if this too long then the SPI can still be transferring when the next strobe activates. This is simple enough to handle on the STM32 side, and the operation of the ADC DMA means some overlap is fine, but under particularly late transfer starts we could lose data.

SPI Clock

The SPI clock determines the maximum throughput of the bus. The Pi has a fairly fixed set of rates available. We're using SPI1, and the maximum is 54MHz (SPI1, SPI4, SPI5, and SPI6 can communicate at up to 54 Mbits/s, SPI2 and SPI3 can communicate at up to 25 Mbit/s)

So, if we request 16MHz then the Rpi clocks round this down to 15.6MHz. This is a bitclock so the transfer limit is 15600000 bits per second, or 1.95MByte/s. Since each sample is two bytes this would be 975KSample/s.

For the other clock rates

• 31.2 MHz = 1.95M Sample/S
• 15.6 MHz = 975K Sample/S
• 7.8 MHz = 487.5K Sample/S
• 3.9 MHz = 243.75K Sample/S

For the ADC conversion rate we care about the system clock, the peripheral clock, the ADC clock and then the conversion rate in ADC clock cycles.

• The STM system clock is set up in SystemClock_Config() as 216000000 (216MHz).
• AHB is set to the system clock (divider of 1)
• APB2 Prescaler is set to provide a peripheral clock of AHB/2 (216M/2 = 108M)
• ADC Clock is set to Peripheral Clock/4 (108M/4 = 27M, or ~37nS per cycle)

From the data sheet (section 15.5) then T conv = Sampling time + 12 cycles, so if we set the conversion time to ADC_SAMPLETIME_56CYCLES then we have 68 cycles per conversion, 2.52uS each, or ~397KSample/S.

At 28CYCLES then each conversion is 1.48uS, or ~675KSample/S. At 84CYCLES each is 3.56uS, or 281KSample/S.

An Example of Transfers

Looking at the sample transfers then there are three signals here: the top two are GPIO pin toggles that I fire when the ADC interrupts arrive (top is "half complete", second is "complete") and the bottom trace is the SPI clock. These traces are with 1024 sample (2048 byte) between ADC buffer interrupts, and the SPI clock is 16MHz.

The sample period is set to 56 clocks in the STM32 configuration, which is 2.52uS * 1024 = 2.58mS, with 5.16mS for all 2048 samples. The scope shows slightly over 2.5mS per half buffer, and just over 5 mS for the complete buffer. Slightly fast, but close enough.

The SPI clock burst is active for about 1.1mS. This is transferring 16 bits per sample, or 1024*16 = 16,384 bits in 1.1mS. We've requested 16MHz at the SPI, but the Rpi clocks round this down to 15.6MHz, which gives us an "ideal" transfer time of (1/(15.6*10^6))*1024*16, or ~1.05mS. Also close enough.

if we crank up the ADC clock to the next timing increment, of 28 cycles, we should push our sample interval up to 1.52mS per half buffer, which is what we see here:

At this point we're getting close to the ADC interval for the SPI transfer. This is workable, but this is around the upper limit for the transfer timing and this sample rate.

Winding back down to 84 cycles gets us 3.64mS per half buffer, and we see this:

However the "lashed together" wiring has a problem at these kind of SPI data rates. Occasionally stray clock pulses throw off the transfer. We can reduce the SPI clock rate, but this drops the maximum sample rate we can get from the ADC.

Fixing the wiring to use slightly better (i.e. shorter, soldered) links we can get good short transfers at faster rates (~31.2MHz), but YMMV. This is "good enough for me" though, and I can tune it on the Pi based on the sample rate I'm targeting.

Problems from the Pi Side

One problem that drops out of a running system is the delay in the Pi responding to the strobe signal. Although the traces above show fairly prompt responses this system is otherwise idle. When the Pi is under load then there can be a gap between the strobe signal firing and the Pi starting the transfer.

In these cases if the SPI clock is low enough then the transfer delay means that the SPI is transferring when the next strobe activates. This is simple enough to handle on the STM32 side, and the operation of the ADC DMA means some overlap is fine, but this is not ideal, and under particularly late transfer starts we could lose data. This is something that the extra memory to memory DMA mentioned earlier would handle.

Practically this means that the SPI link can become less reliable at lower speeds, as this leads to less overhead to cope with the possibility of late transfer starts. Although I'm happy that the correct SPI rate and ADC conversion rate combination will be reliable for the Pi side software, this is something that would need more careful checking for other combinations and processing software.