arduino-spi

El bus SPI en Arduino

En esta entrada vamos a ver el bus SPI, una de las principales formas de comunicación disponibles en Arduino. En entradas anteriores ya vimos el puerto serie, y en la próxima entrada veremos el bus I2C.

El bus SPI tiene interés como medio de comunicación porque una gran variedad de sensores y dispositivos comerciales disponen de un interfaz SPI como medio de comunicación.

El bus SPI

El bus SPI (Serial Peripheral Interface) fue desarrollado por Motorola en 1980. Sus ventajas respecto a otros sistemas han hecho que se convierta en un standard de facto en el mundo de la electrónica y automatización.

El bus SPI tiene una arquitectura de tipo maestro-esclavo. El dispositivo maestro (master) puede iniciar la comunicación con uno o varios dispositivos esclavos (slave), y enviar o recibir datos de ellos. Los dispositivos esclavos no pueden iniciar la comunicación, ni intercambiar datos entre ellos directamente.

En el bus SPI la comunicación de datos entre maestros y esclavo se realiza en dos líneas independientes, una del maestro a los esclavos, y otra de los esclavos al maestro. Por tanto la comunicación es Full Duplex, es decir, el maestro puede enviar y recibir datos simultáneamente.

Otra característica de SPI es que es bus síncrono. El dispositivo maestro proporciona una señal de reloj, que mantiene a todos los dispositivos sincronizados. Esto reduce la complejidad del sistema frente a los sistemas asíncronos.

Por tanto, el bus SPI requiere un mínimo de 3 líneas.

arduino-spi-esquema-basico

  • MOSI (Master-out, slave-in) para la comunicación del maestro al esclavo.
  • MISO (Master-in, slave-out) para comunicación del esclavo al maestro.
  • SCK (Clock) señal de reloj enviada por el maestro.

Además, se requiere una línea adicional SS (Slave Select) para cada dispositivo esclavo conectado, para seleccionar el dispositivo con el que se va a realizar la comunicación.

arduino-spi-esquema

Sin embargo, esto tiene la desventaja de requerir una línea por cada dispositivo esclavo. En caso de disponer muchos dispositivos esclavos esto puede no ser práctico, por lo que es posible adoptar una conexión en cascada, donde cada esclavo trasmite datos al siguiente.

arduino-spi-esquema-cascada

Por contra, en esta configuración la información debe llegar a todos los esclavos para que la comunicación sea finalizada por lo que, en general, la velocidad de respuesta del bus es menor.

Funcionamiento del bus SPI

El funcionamiento del bus SPI es sencillo.

arduino-spi-funcionamiento

Por defecto el maestro mantiene en estado HIGH todas las líneas SS. Cuando el maestro quiere establecer comunicación con esclavo pone a LOW la línea SS correspondiente, lo que indica al esclavo que debe iniciar la comunicación.

En cada pulso de la señal de reloj, normalmente en el flanco de subida, el dispositivo maestro envía un bit del esclavo y a la vez que recibe un bit del esclavo seleccionado.

La trama (los datos enviados) no sigue ninguna regla, es decir, podemos enviar cualquier secuencia arbitraria de bits. Esto hace que los dispositivos conectados necesiten tener pre-acordado la longitud y significado de los que van a enviar y recibir.

La electrónica requerida para implementar el bus SPI es sencilla y barata, incluso un único registro de desplazamiento puede ser suficiente. Además, como la señal de reloj es proporcionada por el maestro, los esclavos ni siquiera necesitan disponer de un reloj propio.

Ventajas y desventajas del SPI

Ventajas

  • Alta velocidad de trasmisión (hasta 8 Mhz en Arduino) y Full Duplex
  • Los dispositivos necesarios son sencillos y baratos, lo que hace que esté integrado en muchos dispositivos.
  • Puede mandar secuencias de bit de cualquier tamaño, sin dividir y sin interrupciones.

Desventajas

  • Se requiere 3 cables (SCK, MOSI y MISO) + 1 cable adicional (SS) por cada dispositivo esclavo.
  • Solo es adecuado a corta distancias (unos 30cm)s
  • No se dispone de ningún mecanismo de control, es decir, no podemos saber si el mensaje ha sido recibido y menos si ha sido recibido correctamente.
  • La longitud de los mensajes enviados y recibidos tiene que ser conocida por ambos dispositivos.

El bus SPI en Arduino

Hardware

Arduino dispone de soporte SPI por hardware vinculado físicamente a ciertos pines. También es posible emplear cualquier otro grupo de pines como bus SPI a través de sofware, pero en ese caso la velocidad será mucho menor.

Los pines asociados a SPI varían de un modelo a otro. La siguiente tabla muestra la disposición en alguno de los principales modelos. Para otros modelos, consultar el esquema de patillaje correspondiente.

MODELOSSMOSIMISOSCK
Uno10
11
1213
Nano10111213
Mini Pro10111213
Mega53515052

El pin SS por hardware se emplea al usar Arduino como esclavo. En caso de usar Arduino como maestro, podemos usar cualquier pin como SS, o varios en caso de disponer de varios esclavos.

Conectar el bus SPI es sencillo. Casi la mayor dificultad será encontrar la función de cada pin en el dispositivo que queremos conectar, ya que no todos los fabricantes emplean la misma designación para los pines que participan en el bus SPI.

Para que os sea más sencillo, la siguiente tabla muestra algunos de los pines habituales que encontraremos en dispositivos SPI con designaciones que podéis encontrar según el fabricantes. Los marcados en color rojo son alimentación, en amarillo los propios del bus SPI, y en azul otros pines que aparecen con frecuencia en dispositivos SPI, aunque no forman parte del bus SPI.

NombreAliasPin (en Arduino Uno o Nano)Descripcion
VCC+3.3 … 5 Volt
GNDGroundGround
SCLKCLK/SCK/SCLKD13 (hardware)Clock (SPI)
MISOMISO/SDO/DOUTD12 (hardware)Master In Slave Out (SPI)
MOSIMOSI/SDI/DIND11 (hardware)Master Out Slave In (SPI)
SSSS/CS/SDA/D10 (hardware, solo en esclavo)Slave/Chip Select (SPI)
RESRST/RES/RESTD9 (variable, se fija por software)Controller Reset
RSRS/DCD8 (variable, se fija por software)Mode: Command/Data

Software

Para usar el puerto SPI en Arduino el IDE Standard proporciona la librería “SPI.h” que contiene las funciones necesarias para controlar el hardware integrado de SPI.

Asimismo, el entorno de programación de Arduino define las constantes SCK, MOSI, MISO, y SS para los pines de SPI. Usar estos “alias” en nuestro código hace que sea más fácil de intercambiar programas entre modelos placas.

Las funciones básicas para hacer funcionar el bus SPI son las siguientes:

SPI.begin();            // Inicia el bus SPI
SPI.transfer(c);        // Envía un byte
SPI.attachInterrupt();  // Activar la interrupción para recibir datos

También se dispone de otras funciones para configurar las opciones del bus SPI. Para cambiar el orden de los bit enviados, disponemos de la función setBitOrder.:

setBitOrder (LSBFIRST);   // least significant bit first
setBitOrder (MSBFIRST);   // more significant bit first

Para cambiar la polaridad y la fase del reloj tenemos la función SPI.setDataMode:

setDataMode (SPI_MODE0);  // clock normalmente LOW, muestreo en flanco subida
setDataMode (SPI_MODE1);  // clock normalmente LOW, muestreo en flanco bajada
setDataMode (SPI_MODE2);  // clock normalmente HIGH, muestreo en flanco subida
setDataMode (SPI_MODE3);  // clock normalmente HIGH, muestreo en flanco bajada

Finalmente, podemos cambiar la velocidad del bus con la función SPI.setClockDivider() divisores de 2 a 128. La frecuencia del bus será la velocidad de reloj dividido por el divisor elegido.

setClockDivider(SPI_CLOCK_DIV2);   //8 MHz (considerando un modelo de 16 Mhz)
setClockDivider(SPI_CLOCK_DIV4);   //4 MHz
setClockDivider(SPI_CLOCK_DIV8);   //2 MHz
setClockDivider(SPI_CLOCK_DIV16);  //1 MHz
setClockDivider(SPI_CLOCK_DIV32);  //500 KHz
setClockDivider(SPI_CLOCK_DIV64);  //250 KHz
setClockDivider(SPI_CLOCK_DIV128); //125 KHz

Sin embargo, estas funciones están obsoletas desde la versión de Arduino 1.6.0., prefiriéndose la función beginTransaction, como muestra el siguiente ejemplo.

SPI.beginTransaction (SPISettings (2000000, MSBFIRST, SPI_MODE0));  // 2 MHz clock, MSB first, mode 0

No obstante, al ser la trama de datos específica de cada dispositivo, lo más frecuente es que no usemos directamente estas funciones, y que nuestro uso del bus SPI se realice de forma indirecta a través de la librería del componente.

En próximas entradas cómo conectar dos Arduino mediante puerto I2C, e introduciremos el bus I2C.

Descarga el código

Todo el código de esta entrada está disponible para su descarga en Github. github-full