Arduino y las comunicaciones con el bus SPI

arduino-bus-spi
¡Haz clic para puntuar esta entrada!
(Votos: 1 Promedio: 5)

Por lo general, un microcontrolador utiliza muchos protocolos diferentes para comunicarse con varios sensores y periféricos, y de todos estos, los protocolos de comunicación en serie son quizá los más populares.

Uno de los protocolos de comunicación serial más utilizados, además del muy conocido I2C, es el Bus de Interfaz Periférica Serial (SPISerial Peripheral Interface), que se utiliza para la comunicación entre múltiples dispositivos en distancias cortas y a alta velocidad. En este artículo veremos cómo usar y configurar el bus SPI para comunicaciones con la placa Arduino.

 

¿Qué es el bus SPI?

El bus SPI, o Serial to Peripheral Interface, es una interfaz de comunicación en serie de cuatro hilos, de muy bajo consumo, diseñada para que el microcontrolador y los periféricos se comuniquen entre sí.

bus-spi-maestro-esclavo
Conexión entre dispositivos usando bus SPI

El bus SPI es un bus de comunicaciones full-duplex, que permite que la comunicación fluya hacia y desde el dispositivo maestro en forma simultánea, a velocidades de hasta 10Mbps. La interfaz de bus SPI fue desarrollada por Motorola (actualmente Lenovo) en el año 1970.

La interfaz del bus SPI se utiliza para la comunicación entre múltiples dispositivos en distancias cortas y a alta velocidad.

bus-spi-maestro-varios-esclavos
Dispositivo SPI maestro en conexión con varios SPI esclavos

La operación de alta velocidad del bus SPI generalmente limita su uso para comunicarse con componentes que tengan poca separación respecto al microcontrolador debido al aumento en la capacitancia, que en comunicaciones a altas velocidades impacta negativamente la calidad de la conexión, introduciendo errores en las transferencias de datos.

En el protocolo de bus SPI hay normalmente un solo dispositivo maestro, que inicia las comunicaciones y suministra la señal de reloj que controla la velocidad de transferencia de datos.

En el bus SPI puede haber uno o más esclavos. Para más de un esclavo, cada uno tiene su propia señal de selección de esclavo.

 

¿Cómo funciona el bus SPI?

Para entender mejor cómo funciona el bus SPI, inicialmente veremos de qué manera se diferencia este de otros métodos de comunicaciones seriales, por ejemplo, el puerto serie.

 

El bus SPI comparado con el puerto serie

El puerto serie basado en UART se denomina asíncrono porque no hay control sobre cuándo se envían los datos ni ninguna garantía de que ambos extremos estén a la misma velocidad de operación.

La base del problema es la sincronización del reloj, y en dos sistemas completamente separados, aunque nominalmente tengan ambos la misma velocidad de reloj, lo más probable es sus frecuencias sean ligeramente diferentes.

Esta es la razón por la cual los sistemas de comunicaciones asíncronos necesitan agregar señales adicionales, en este caso, bits de inicio y parada a cada byte que transmiten. Esto ayuda al receptor a re-sincronizar continuamente su reloj interno por cada byte que recibe.

Para que todo esto funcione, ambos lados también deben acordar previamente la velocidad de transmisión.

 

Funcionamiento del bus SPI

Por otro lado, el bus SPI funciona de una manera ligeramente diferente. Es un bus de datos síncrono, lo que significa que utiliza líneas separadas para datos y un reloj que mantiene ambos lados en perfecta sincronización.

La señal de reloj marca exactamente cuándo se debe muestrear los bits en la línea de datos. Esta marca puede ser el flanco ascendente (de bajo a alto) o descendente (de alto a bajo) de la señal del reloj.

bus-spi-ejemplo-de-funcionamiento
Ejemplo de funcionamiento del bus SPI

Cuando el receptor detecte ese flanco, inmediatamente observará la línea de datos para leer el siguiente bit. Debido a que el reloj se envía junto con los datos, especificar la velocidad no es importante, aunque los dispositivos tendrán una velocidad máxima a la que pueden operar.

Una razón por la que SPI es tan popular es que el hardware receptor puede ser un simple registro de cambios (shift register). Esta es una pieza de hardware mucho más simple (y más barata) que un UART.

 

Lineas y señales de un bus SPI

Un sistema SPI normal tendrá cuatro líneas de señal:

  • Master Out, Slave In (MOSI): es la información que va del maestro al esclavo
  • Master In, Slave Out (MISO): es la información que va del esclavo al maestro
  • Serial Clock (SCK): Los pulsos de reloj que sincronizan la transmisión de datos generados por el maestro.
  • Slave Select (SS): esto le dice a un esclavo en particular que se active.

Cuando se conectan varios esclavos a la señal MISO, se espera mantener en alta impedancia (Tri-State) la línea MISO hasta que sean seleccionados por la línea SS.

Normalmente, la línea SS confirma la selección en modo activo bajo (LOW). Cuando está en modo alto (HIGH) se ignora al maestro. Una vez que se selecciona un esclavo en particular, debe configurar la línea MISO como una salida para que pueda enviar datos al maestro.

Por cada flanco de subida o de bajada de la línea SCK, previa selección del modo de fase y polaridad, el maestro envía y recibe a la vez un bit del esclavo seleccionado.

bus-spi-señales-de-comunicaciones
Señales de comunicaciones del bus SPI

La secuencia de comunicaciones es la siguiente:

  • SS pasa a estado bajo (LOW) y activa el esclavo.
  • SCK alterna su estado para indicar cuándo se deben muestrear las líneas de datos
  • Los datos son muestreados por el maestro y el esclavo en la transición de flanco anterior de la línea SCK (usando la fase y polaridad de reloj predeterminada)
  • Tanto el maestro como el esclavo se preparan para el siguiente bit en el borde posterior de SCK (usando la fase y polaridad de de reloj predeterminada), cambiando MISO/MOSI si es necesario
  • Una vez que finaliza la transmisión (posiblemente después de que se hayan enviado varios bytes), la línea SS pasa a nivel alto (HIGH) y desactiva el esclavo.

Hay que tener en cuenta que:

  • El bit más significativo se envía primero (por defecto, pero se puede cambiar)
  • Los datos se envían y reciben en el mismo instante (dúplex completo)

Debido a que los datos se envían y reciben en el mismo pulso de reloj, no es posible que el esclavo responda al maestro inmediatamente. Los protocolos SPI generalmente esperan que el maestro solicite datos en una transmisión y obtenga una respuesta en una transmisión posterior.

El proceso de comunicaciones, esto es, la secuencia de bits enviados y recibidos, es completamente arbitraria y no sigue ningún patrón definido. La cantidad de datos que se va a intercambiar debe estar definida por programa.

 

Polaridad y fase de reloj en el bus SPI

Hay cuatro formas en que puede muestrear el reloj SPI. El protocolo SPI permite variaciones en la polaridad de los pulsos de reloj. CPOL es la polaridad del reloj y CPHA es la fase del reloj.

bus-spi-arduino-modos-polaridad-y-fase-de-reloj
Modos de polaridad y fases de reloj del bus SPI
  • Modo 0 (el valor predeterminado): el reloj es normalmente bajo (CPOL = 0), y los datos se muestrean en la transición de bajo a alto (borde delantero) (CPHA = 0)
  • Modo 1: el reloj es normalmente bajo (CPOL = 0), y los datos se muestrean en la transición de alto a bajo (borde de salida) (CPHA = 1)
  • Modo 2: el reloj es normalmente alto (CPOL = 1), y los datos se muestrean en la transición de alto a bajo (borde delantero) (CPHA = 0)
  • Modo 3: el reloj suele ser alto (CPOL = 1), y los datos se muestrean en la transición de bajo a alto (borde de salida) (CPHA = 1)
bus-spi-polaridad-y-fase-de-reloj
Polaridad y fases de reloj en bus SPI

 

Ventajas y desventajas del bus SPI

Algunas de las ventajas más importantes del bus SPI.

  • Tiene total flexibilidad para los bits transferidos, es decir, no se limita a una palabra de 8 bits.
  • Tiene una interfaz de hardware muy simple.
  • No se limita a ninguna velocidad de reloj máxima, lo que permite una velocidad potencialmente alta.
  • Es más rápido que el serial asíncrono (UART).
  • Soporta múltiples esclavos.
  • Soporta comunicaciones full duplex.
  • Tiene una señal de bus única por dispositivo llamada SS y todas las demás señales se comparten.
  • No hay modos de fallo de arbitraje.
  • No necesita de transceptores (adaptadores).

Por otro lado, entre las desventajas más importantes del bus SPI.

  • Requiere más pines de conexión con respecto al bus I2C.
  • No admite nodos en forma dinámica (en caliente).
  • Solo soporta un dispositivo maestro.
  • No hay protocolo de comprobación de errores.
  • El bus SPI requiere generalmente de líneas SS separadas para cada esclavo, lo que puede ser problemático si se necesitan numerosos esclavos.

 

Como usar el bus SPI en la placa Arduino

Los microcontroladores Atmega incluidos en las placas Arduino disponen de soporte del bus SPI por hardware, reservando para ello ciertos pines. También es posible usar el bus SPI emulado por software, mediante el uso de librerías. Esta última alternativa solo debe ser reservada para el caso de no poder disponer de los pines nativos SPI por estar estos ocupados en algún otro uso, y solo si se planea usar en dispositivos periféricos que no requieran de altas velocidades.

En las placas Arduino UNO R3 o Arduino Duemilanove, los pines utilizados son:

  • SS: digital 10. Puede usar otros pines digitales, pero 10 es generalmente el valor predeterminado. Si se piensa usar el bus SPI en modo esclavo, este pin es de uso obligatorio.
  • MOSI: digital 11
  • MISO: digital 12
  • SCK: digital 13
bus-spi-arduino-uno_pins
Pines del bus SPI en Arduino UNO

Por otro lado, la placa Arduino Mega usa los siguientes pines:

  • SS: pin 53
  • MOSI: pin 51
  • MISO: pin 50
  • SCK: pin 52
bus-spi-arduino-mega-pins
Pines del bus SPI en Arduino MEGA

En la placa Arduino Leonardo, los pines SPI están ubicados en los pines del encabezado de programación ICSP.

bus-spi-conector-icsp-arduino-uno
Conector de programación ICSP en Arduino UNO
bus-spi-conector-icsp
Detalles de los pines en el conector de programación ICSP

 

Configuración del bus SPI en Arduino

Usar el bus SPI con la placa Arduino es bastante sencillo. Solo es necesario incluir en el encabezado del programa la librería SPI.h. Esta librería contiene toda la funcionalidad para configurar y controlar el hardware del microcontrolador.

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.

 

Inicialización del bus SPI

 

Configuración el orden de transmisión de bits del bus SPI

 

Configurar la polaridad del reloj del bus SPI

 

Establecer la velocidad del bus SPI

Para versiones de anteriores a Arduino IDE 1.60:

Para versions Arduino IDE 1.60 en adelante:

 

Ejemplos de uso del bus SPI en Arduino

A pesar de lo practico que poder ser usar el bus SPI con cualquier dispositivo que soporte dicho bus, es necesario disponer de la respectiva librería de control.

Esto se debe a que el bus SPI solo crea el canal de comunicaciones, pero no hace nada respecto a cómo darle formato a los datos y mucho menos como interpretarlos.

Por esta razón, las fases de formato e interpretación de datos, quedan a cargo del código de programa. No será lo mismo comunicarse con un sensor o con una pantalla LCD. Aunque usen y compartan el mismo bus SPI, los datos que intercambian con el microcontrolador no serán los mismos.

Se explicará como ejemplos de programa como comunicar dos placas Arduino, una como maestro, y la otra como esclavo.

La razón de ello es para explicar con claridad los aspectos relativos a conexiones y configuración de la librería SPI.h, y posteriormente hacer un código más sencillo de intercambio de datos que funcione sobre esta configuración base.

La base de esta explicación será también válida para usar el bus SPI con otros dispositivos, pero en esos casos, se haría necesario profundizar en la forma como funciona e intercambia información este con el microcontrolador. Para esos casos es mejor dedicar una publicación aparte.

 

Conectar dos placas Arduino usando el bus SPI

Este es quizá el paso más fácil de todos. Para interconectar ambas placas Arduino solo es necesito usar 6 hilos de conexión: SS, MOSI, MISO, SCK, 5V y GND. De esta manera, una de las placas Arduino proporciona energía de alimentación a la otra.

bus-spi-dos-arduinos-maestro-esclavo
Ejemplo de conexión de dos placas Arduino UNO en modo maestro/esclavo

Conecte las dos placas Arduino con los siguientes pines conectados entre sí:

  • Pin 10 (SS)
  • Pin 11 (MOSI)
  • Pin 12 (MISO)
  • Pin 13 (SCK)
  • Pin 5v (si es necesario, también es posible darle alimentación independiente)
  • GND (para retorno de señal)

En cualquier caso, MOSI en un extremo está conectado a MOSI en el otro, no se deben intercambiar (es decir, no conectar MOSI <-> MISO). El programa configura MOSI de un extremo en modo maestro, como salida, y el otro extremo (extremo esclavo) como entrada.

 

Ejemplo de programa para el bus SPI en modo maestro

 

Ejemplo de programa para el bus SPI en modo esclavo

En este ejemplo, el esclavo está completamente controlado por interrupciones, por lo que la placa Arduino receptora puede hacer otras cosas.

Los datos SPI entrantes se recopilan en un búfer y se establece un indicador (flag) cuando llega un byte significativo (en este caso, una nueva línea). Esto le dice al esclavo que comience a procesar los datos.

 

Comunicación bidireccional del bus SPI

El siguiente ejemplo muestra cómo enviar datos a un esclavo, hacer que haga algo con él y posteriormente devolver una respuesta.

El código del SPI maestro es similar al ejemplo anterior. Sin embargo, un punto importante es que necesitamos agregar un ligero retraso (unos 20 microsegundos). De lo contrario, el esclavo no tiene la oportunidad de reaccionar a los datos entrantes y hacer algo con ellos.

El ejemplo muestra el envío de una orden o comando. En este caso «s» (sumar algo) o «r» (restar algo). Esto es para mostrar que el esclavo en realidad está haciendo algo con los datos.

Después de confirmar la selección del esclavo (SS) para iniciar la transmisión, el maestro envía el comando, seguido de cualquier número de bytes, y luego levanta SS para terminar la transmisión.

Un punto muy importante es que el esclavo no puede responder a un byte entrante en el mismo momento. La respuesta tiene que estar en el siguiente byte. Esto se debe a que los bits que se envían y los bits que se reciben se envían simultáneamente.

 

Ejemplo de programa bidireccional para el bus SPI en modo maestro

 

Ejemplo de programa bidireccional para el bus SPI en modo esclavo

El código para el esclavo básicamente hace casi todo en la rutina de interrupción (esta se llama cuando llegan datos entrantes por el bus SPI). Toma el byte entrante, y suma o resta según la orden del byte de comando.

Hay que tener en cuenta que la respuesta a la actividad anterior será recuperada en el siguiente ciclo. Esta es la razón por la que el maestro envía una transferencia final ficticia para obtener la respuesta final.

 

También te puede interesar