Riferimenti
https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
- Abilitare SPI con raspi-config
Utilizzare wiringPi
Come installare la libreria: http://wiringpi.com/download-and-install/

L'API è molto limitata. Dobbiamo capire come:
- Disabilitare CS in modalità master, così da controllarlo tramite le API GPIO.
- Verificare la polarità di campionamento e trasmissione dei dati.
- In modalità slave, CS deve essere gestito dal driver.
- Possiamo trasferire esattamente 7 byte in una sola transazione? Potrebbe essere semplice in modalità master e più difficile in modalità slave.
Nei sorgenti, wiringPiSPISetup chiama internamente wiringPiSPISetupMode, con firma int wiringPiSPISetupMode(int channel, int speed, int mode).
La modalità viene quindi passata a un ioctl. Le macro sono documentate nei sorgenti Linux:
https://github.com/torvalds/linux/blob/master/include/linux/spi/spi.h
https://github.com/torvalds/linux/blob/master/drivers/spi/spidev.c
Le macro interessanti sono:

SPI_CS_HIGH permetterebbe di usare una polarità diversa per il chip select; SPI_NO_CS consentirebbe invece di gestire la sincronizzazione del trasferimento con un handshake esterno. SPI_CS_WORD dovrebbe riguardare i trasferimenti continui, nei quali CS non commuta dopo ogni frame. Verifichiamo queste ipotesi nell’implementazione SPI del Raspberry Pi, a partire da:
https://github.com/raspberrypi/linux/blob/rpi-3.6.y/drivers/spi/spi-bcm2708.c
Per prima cosa osserviamo come vengono configurati i pin:
bcm2708_init_pinmode...
define INP_GPIO(g) (gpio+((g)/10)) &= ~(7<<(((g)%10)3))
define SET_GPIO_ALT(g,a) (gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)3))
int pin;
u32 *gpio = ioremap(0x20200000, SZ_16K);
/* SPI is on GPIO 7..11 */
for (pin = 7; pin <= 11; pin++) {
INP_GPIO(pin); /* set mode to GPIO input first */
SET_GPIO_ALT(pin, 0); /* set mode to ALT 0 */
}
iounmap(gpio);
undef INP_GPIO
undef SET_GPIO_ALT
I pin 7, 8, 9, 10 e 11 sono quelli di SPI0:

Sembra che questa funzione bcm2708_init_pinmode abbia configurato solo una SPI. Ma wiringPi dovrebbe funzionare con entrambe. Come viene gestito questo problema?
Per capire se questo codice è davvero compilato nel kernel, eseguiamo lsmod e scopriamo che non lo è:

Esaminiamo questa versione 2835. Da qui:
https://github.com/notro/spi-bcm2708/wiki
La versione 2835 appare più snella. Dove si trova nei sorgenti? E quali sorgenti dobbiamo consultare?

Restiamo ai sorgenti ufficiali:
https://github.com/raspberrypi/linux
Alla fine abbiamo capito:
È interessante notare che non possiamo gestire più di un dispositivo slave:

Peccato! In questo progetto, per fortuna, dobbiamo comunicare con un solo dispositivo master o slave. L’opzione per controllare CS dal codice utente sembra disponibile, ma dobbiamo verificare che l’overlay SPI del Raspberry Pi non la impedisca.
Un primo test potrebbe essere quello di ricompilare wiringPi per passare la modalità NO_CS. Queste sono le principali modifiche al codice:
#define CUSTOM_MODE (SPI_CS_HIGH | SPI_NO_CS | SPI_CPOL| SPI_CPHA)
...
if(( myFd = wiringPiSPISetupMode( SPI_CHAN, speed, CUSTOM_MODE)) < 0)
...
wiringPiSPIDataRW (SPI_CHAN, myData, 8);
int idx = 0;
for(idx = 0; idx < MAX_SIZE; idx++)
{
myData[idx] = 0xaa;
}
L’ultima modifica serve perché wiringPiSPIDataRW scrive i dati ricevuti da MISO nello stesso buffer che contiene i dati da inviare su MOSI. Inoltre, SPI_CPHA e SPI_CPOL vengono impostati correttamente, mentre gli altri bit della modalità (SPI_CS_HIGH e SPI_NO_CS) no. Scorrendo i sorgenti vediamo infatti:

Rimuoviamo la limitazione e ricompiliamo: funziona! Sia SPI_CS_HIGH sia SPI_NO_CS hanno effetto. Resta da verificare se possiamo pilotare CS dal codice utente. Il CS da provare è il numero 10:

Funziona, ma emerge un problema di latenza. Quando CLK smette di commutare, passano circa 12 ms prima che venga eseguita l’istruzione successiva a wiringPiSPIDataRW. C’è un ritardo nascosto? Un secondo esperimento suggerisce che non dipenda dalla lunghezza del payload. Il wrapper di wiringPi non fa nulla di insolito. Proviamo a eliminare le scritture GPIO: non cambia nulla. Il ritardo sembra legato a SPI.
Esaminiamo il driver e la periferica stessa. Secondo il manuale della periferica Broadcom BCM2835,
https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
sezione “SPI Address Map”, i registri sono quelli definiti nel driver:


Nessun risultato. Torno al codice utente e riduco MAX_SIZE da 1048576 a 8: la latenza del Raspberry Pi scende a circa 2,4 ms. Non è poca, ma potrebbe essere accettabile.
SPI funziona anche con frame da 7 byte: ora possiamo provare un loopback con un dispositivo master SPI esterno.
