Arduino SPI, comunicazione seriale tra componenti

Arduino SPI: in questo tutorial impareremo cos’è lo standard SPI e impareremo a usarlo con la nostra scheda Arduino.

Serial Peripheral Interface

Lo standard Serial Peripheral Interface (SPI) è un bus di comunicazione sincrono, full duplex, con architettura master/slave, originariamente sviluppato da Motorola.

Arduino SPI - Collegamento Base
Collegamenti base del protocollo SPI

Esso di basa su dei piccoli registri, generalmente da 8 bit, posizionati uno sul dispositivo Master e uno per ogni dispositivo slave.

La comunicazione avviene attraverso lo “shift” (spostamento) dei bit di questi registri e un collegamento che vedremo dopo permette di vedere questi 2 registri come se fossero contigui l’uno all’altro.

Possiamo vedere quindi i registri sopra citati come un unico registro da 16 bit, dove l’ultimo bit è collegato con il primo.

Il master può leggere e scrivere dati solo nei primi 8 bit del registro,  lo slave lo può fare solo negli ultimi 8.

Grazie a una linea riservata al segale di clock che sincronizza la comunicazione, lo shift può avvenire tra i 2 registri.

Interfaccia Hardware

SPI (Serial Peripheral interface) presenta una interfaccia hardware composta da 4 pin principali:

  • SCLK (Searial CLocK): Questo canale passa il segnale di clock è generato della scheda e serve per la sincronizzazione dei canali usati per lo scambio di messaggi
  • MISO (Master Input Slave Output): Serve per rendere il primo bit del registro Master contiguo all’ultimo bit del registro slave
  • MOSI (Master Output Slave Input): Serve per rendere l’ultimo bit del registro Master contiguo al primo bit del registro slave
  • SS (Slave Select): Questo pin viene utilizzato per selezionare lo slave desiderato

Arduino SPI Collegamento

SPI permette 2 modalità architetturali per la connessione di più slave allo stesso master.

La prima modalità è utilizzando più pin di slave select (SS), nella seconda maniera, invece,detta daisy chain, il pin slave select è condiviso e gli slave sono connessi tra di loro formando una catena:

Collegamento con più slave select

Arduino SPI - Collegamento parallelo
Collegamento con più Slave Select

In questo tipo di collegamento si può notare che il canale SCLK, MISO e MOSI sono condivisi, ma i canali SS sono uno per ogni slave.

Questa modalità permette di selezionare un singolo slave e comunicare solo con quello.

Il vantaggio è che questo metodo ha una elevata velocità di trasmissione dei dati.

Il limite di questo collegamento è dato dal numero di pin che nostro controllore può dedicare per la selezione degli slave.

Collegamento a catena (daisy chain)

Arduino SPI - Collegamento Daisy Chain
Schema del collegamento Daisy Chain

Il metodo “daisy chain” ha la particolarità che tutti gli slave sono connessi uno dopo l’altro tra di loro, formando appunto una catena.

Come illustrato dall’immagine il canale MISO del primo slave è connesso al canale MOSI dello slave successivo e così via per tutti gli slave ad esclusione del MISO dell’ultimo slave che è connesso con il MISO del master.

A differenza della precedente modalità, qui dobbiamo comunicare simultaneamente con tutti gli slave.

Questa modalità ha un tasso di trasferimento dati più basso rispetto al precedente.

Le funzioni SPI di Arduino

SPI è facilmente utilizzabile su arduino grazie alla libreria SPI.h facilmente importabile dall’IDE di Arduino. Le principali funzioni della libreria sono descritte di seguito:

  • SPISetting(speed, dataOrder, dataMode): Impostazioni della connessione. Queste impostazioni possono variare da dispositivo a dispositivo e li possiamo trovare nei datasheet dei componenti con cui dobbiamo comunicare;
  • SPI.beginTransaction(settings): si attiva la connessione con le impostazioni precedentemente dichiarate;
  • SPI.transfer(val): trasferisce il valore inserito tra parentesi e restituisce il valore presente nel dispositivo con cui stiamo comunicando.
  • SPI.endTransaction(): pone la fine della connessione precedentemente aperta.

Una volta fatti i collegamenti, come mostrato in figura (vedere figura del collegamento a più slave), tra la vostra scheda e il vostro sensore che supporta SPI o tra la vostra scheda e un’altra scheda potete provare a eseguire il codice presentato di seguito.

#include <SPI.h>

//Pin slave select
#define SLAVE_PIN 20

uint8_t  val1, val2;
char valori[] = "ciao";

/*  Impostazione della velocità, dell'ordine dei bit, e della modalità.
 *  Ordine dei bit indica in quale ordine devono essere shiftati i bit
 *  (ogni dispositivo li shifta in modo diverso, quindi si consiglia di
 *  controllare i datasheet per vedere quale bit viene shiftato prima):
 *    
 *    MSBFIRST = I bit più significativi vengono shiftati prima di quelli
 *               meno significativi
 *    LSBFIRST = Il contrario di quello sopra.
 *  
 *  Modalità: Non tutti i dispositivi usano la stessa modalità. La modalità
 *  la si può trovare sul datasheet del dispositivo che userete
 *  |---------------------------------------------------------------|
 *  |     MODE    |  CPOL  |  CPHA  |  Output Edge  |  Data Capture |
 *  |---------------------------------------------------------------|
 *  |  SPI_MODE0  |   0    |    0   |    Falling    |     Rising    |
 *  |---------------------------------------------------------------|
 *  |  SPI_MODE1  |   0    |    1   |    Rising     |     Falling   |
 *  |---------------------------------------------------------------|
 *  |  SPI_MODE2  |   1    |    0   |    Rising     |     Falling   |
 *  |---------------------------------------------------------------|
 *  |  SPI_MODE3  |   1    |    1   |    Falling    |     Rising    |
 *  |---------------------------------------------------------------|
 *  
*/
SPISettings settings(2000000, MSBFIRST, SPI_MODE1); 

void setup() {
  pinMode (SLAVE_PIN, OUTPUT);
  // Inizializzazione SPI:
  SPI.begin(); 
  Serial.begin(9600);
}
void loop() {
  /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>PARTE 1<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
  
  /* La prima parte del codice fa la lettura di 2 byte. Se si usa questo
   * standard per comunicare con i sensori, generalmente i valori li si 
   * assumono in questo modo.
  */
  SPI.beginTransaction(settings);
  /* Quando il pin SS è basso significa che si è selezionato quello slave
  */
  digitalWrite (SLAVE_PIN, LOW);
  /* Visto che è solo lettura non ci interessa che valore 
   *  passare allo slave quidi mettiamo 0
  */
  val1 = SPI.transfer(0);
  val2 = SPI.transfer(0);
  digitalWrite (SLAVE_PIN, HIGH);
  SPI.endTransaction();
  
  Serial.println("Valore 1 = " + val1);
  Serial.println("Valore 2 = " + val2);

/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>PARTE 2<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/

  /* Trasmissione: Visto che questo standard permette la comunicazione anche
   *  tra 2 dispositivi come and esempio 2 Arduino, allora sotto metto un esempio
   *  di trasmissione di dati che si vogliono inviare all'altra scheda. Notare che
   *  la funzione usata è la stessa della lettura, in quanto le azioni compiute in
   *  lettura sono le stesse della scrittura.
  */
  SPI.beginTransaction(settings);
  digitalWrite (SLAVE_PIN, LOW);
  /* Scrittura dei valori della stringa
  */
  for(int i = 0; i < sizeof(valori)/sizeof(char); i++){
    SPI.transfer(valori[i]);
  }
  digitalWrite (SLAVE_PIN, HIGH);
  SPI.endTransaction();
}

Come potete vedere, il codice è diviso in 2 parti: una relativa alla lettura dei dati (usata principalmente per la lettura di valori dai sensori), la seconda relativa alla  trasmissione dei dati.

Nel codice ci sono i commenti passo passo che spiegano quello che fanno le relative funzioni.

Ci tengo a ribadire ulteriormente che i valori della velocità di comunicazione, il primo bit da trasmettere e la modalità di trasmissione variano da dispositivo a dispositivo e potete reperire queste informazioni nei datasheet dei relativi dispositivi.

In fine se riscontrate qualche problema o dubbio, non esitate a scrivere un commento !

Reference libreria SPI
Wikipedia: SPI
Spiegazione come funziona SPI a livello fisico


1 commento su “Arduino SPI, comunicazione seriale tra componenti”

  1. Buonasera, ho recentemente acquistato il display e-ink 5.65 7 colori di waveshare e sto avendo delle difficoltà a programmarlo attraverso Arduino, voi potete aiutarmi? Grazie!

    Rispondi

Lascia un commento