El bus SPI en Arduino


arduino-spi

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.

Anuncio:

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
Uno10111213
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.

Si te ha gustado esta entrada y quieres leer más sobre Arduino puedes consultar la sección Tutoriales de Arduino

Descarga el código

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



4.6 20 votes
Article Rating

Anuncio:

Previous Como solucionar el brillo bajo de pantalla en Windows 10
Next El bus I2C en Arduino
10 Comments
oldest
newest
Inline Feedbacks
View all comments
Albert
6 years ago

Excelente como siempre!. Un tutorial de manejo de pantallas tactiles TFT?. Otro de comunicación con tarjetas GSM para comunicarse a distancia?. Otro de manejo de cámaras de video…? Muy bien Luis. Claro y concreto como buen ingeniero.

luisllamas
5 years ago

SI miras en ventajas, verás que una del bus SPI es “Puede mandar secuencias de bit de cualquier tamaño, sin dividir y sin interrupciones”

Fly Man
5 years ago
Reply to  luisllamas

Muchas gracias Luis.
Precisamente esto: “secuencias de bit de cualquier tamaño” es lo que me hizo pensar en aquel momento si existiría algún tipo de límite, pero como bien expusiste en el tutorial, no existe. Lo he podido comprobar en múltiples pruebas y en un pequeño proyecto que he desarrollado.
Saludos.

Juan Reina
5 years ago

hola buenas! enhorabuena por los post y los tutoriales en general, personalmente son de gran ayuda. Estoy con un proyecto de enviar datos de 2 sensores de temperatura ( dht22 y sonda termopar k con amplificador max31856 ). Tengo arduino UNO con la shield Ethernet w5100( comunicación con UNO a través de SPI) el problema viene cuando intento ver los datos del amplificador max31856, que tambien tiene comunicación por SPI. No llego a entender muy bien la manera de hacer el código para que los la shield y el amplificador puedan enviar los datos, no me hace falta que sean… Read more »

GERMAN RAMIREZ
5 years ago

Hola,

Trabajando con SPI me queda claro su uso, pero quisiera explicaras un poco mas como se usan RES y RS, actualmente uso un NodeMCU8266 v3 (Lolin) como master y un Arduino Nano como secundario y trabajan correcto, el problema empieza cuando pongo una tarjeta catalex SD, si conecto Vcc de la SD, Lolin “ve” y trabaja con la SD, envia datos a Nano pero recibe solo el caracter null, si desconecto Vcc de la SD, las comunicaciones entre Lolin y Nano funcionan correcto y posiblemente mi problema va por no usar estas dos opciones

Luis
4 years ago

Muy buenas Luis:
En todos los tenas de Arduino, tus tutoriales, son de consulta permanente.
Felicitaciones x tu esmero.
Te consulto sobre el bus SPI: recibo datos en un mdulo NRF24l01, guardo datos en una SD alojada en la Shield Ethernet y pretendo monitorizar todo x la web, estas tres acciones ejecutadas por un Arduino Mega 2560.
Como ya me has advertido en otro de tus tutoriales, tengo muchos conflictos.
Seguiré leyendo e investigando el tema para encontrar una solución.
Estaré atento a tu comentario. Muchas gracias Luis

jaun
4 years ago

excelente información gracias por compartirla

jesus
4 years ago

Estupendo aporte y de gran utilidad, sin duda un sitio de referencia, gracias por el tiempo que le empleas, saludos.

ESP8266 y los protocolos serie: SPI, I2C y TTL – Multicóptero X
3 years ago

[…] El Bus SPI en Arduino. […]