The SPI protocol is well described many other places so I won’t get into that, but here are a few main points

  • It’s fast – the nucleo and the Raspberry Pi can communicate at up to 16 MHz.
  • There’s a master and a slave (and the Raspberry Pi insists on being the master, and it insists on 8bit transactions).
  • The master initiates the transfers, and for every byte sent by the master, the slave sends one back.
  • Once the SPI+DMA is set up on the nucleo board there’s nothing left to do on the nucleo side.

The linux SPI driver has a default maximum buffer size of 4096 bytes, which is too small as the TCD1304 has 3694 pixels (dummies included) and the ADC is 12 bit, so the total amount of data to transfer is 7388 bytes.

To fix it permanently append the following to the line in the file /boot/cmdline.txt and reboot:


The next problem is related to endianness. The Raspberry Pi’s SPI peripheral only allows for 8-bit transfers, so the 12 bit data from the ADC  (stored in a 16-bit array) is sent 8-bits at a time. However, since the processor is little-endian the bits get mixed up like this:

A 16-bit number like this:  0x1122
is transmitted as the two 8 bit numbers: 0x22 and 0x11
and recombined in memory to: 0x2211

Again it’s quite an easy fix. You pretend the two 8 bit numbers are 16 bit. Then you multiply the most significant number with 256 and add them together:

0x11  =  0x0011   and   0x22  =  0x0022
0x0011·0x0100  +  0x0022  =  0x1100  +  0x0022  =  0x1122

This is done on the Raspberry Pi side.

With a speed of 16 MHz a transfer should take 3.7 ms, but in reality the transfer-time is around 4.3 ms:


Speed test of a 7.4kB SPI-transfer at 16 MHz.

The original posts at erossel.wordpress.com:
First words – setting up SPI
SPI revisited
SPI speed test