Con referencia a Arduino Uno, Mega2560, Leonardo y tableros similares:
- ¿Cómo funciona SPI?
- ¿Qué tan rápido es SPI?
- ¿Cómo me conecto entre un maestro y un esclavo?
- ¿Cómo hago un esclavo SPI?
Tenga en cuenta: esto pretende ser una pregunta de referencia.
arduino-uno
arduino-mega
c++
arduino-leonardo
spi
Nick Gammon
fuente
fuente
Respuestas:
Introducción a SPI
La interfaz del bus de interfaz periférica en serie (SPI) se utiliza para la comunicación entre múltiples dispositivos en distancias cortas y a alta velocidad.
Por lo general, hay un único dispositivo "maestro", que inicia las comunicaciones y proporciona el reloj que controla la velocidad de transferencia de datos. 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", que se describe más adelante.
Señales SPI
En un sistema SPI completo, tendrá cuatro líneas de señal:
Cuando se conectan múltiples esclavos a la señal MISO, se espera que tripliquen (mantengan a alta impedancia) esa línea MISO hasta que sean seleccionados por Slave Select. Normalmente, Slave Select (SS) baja para afirmarlo. Es decir, está activo bajo. Una vez que se selecciona un esclavo en particular, debe configurar la línea MISO como salida para que pueda enviar datos al maestro.
Esta imagen muestra la forma en que se intercambian los datos cuando se envía un byte:
Tenga en cuenta que tres señales son salidas del maestro (MOSI, SCK, SS) y una es una entrada (MISO).
Sincronización
La secuencia de eventos es:
SS
baja para afirmarlo y activar el esclavoSCK
línea alterna para indicar cuándo se deben muestrear las líneas de datosSCK
(usando la fase de reloj predeterminado)SCK
(usando la fase de reloj predeterminada), cambiandoMISO
/MOSI
si es necesarioSS
va alto para desactivarlaTenga en cuenta que:
Debido a que los datos se envían y reciben en el mismo pulso de reloj, el esclavo no puede responder al maestro de inmediato. Los protocolos SPI generalmente esperan que el maestro solicite datos en una transmisión y obtenga una respuesta en una posterior.
Usando la biblioteca SPI en Arduino, hacer una sola transferencia se ve así en el código:
Código de muestra
Ejemplo de envío solamente (ignorando cualquier dato entrante):
Cableado para SPI de solo salida
El código anterior (que solo envía) podría usarse para controlar un registro de desplazamiento en serie de salida. Estos son dispositivos de solo salida, por lo que no debemos preocuparnos por los datos entrantes. En su caso, el pin SS podría llamarse el pin "store" o "latch".
Ejemplos de esto son el registro de desplazamiento en serie 74HC595 y varias tiras de LED, solo por mencionar un par. Por ejemplo, esta pantalla LED de 64 píxeles impulsada por un chip MAX7219:
En este caso, puede ver que el fabricante de la placa ha utilizado nombres de señal ligeramente diferentes:
La mayoría de los tableros seguirán un patrón similar. A veces DIN es solo DI (entrada de datos).
Aquí hay otro ejemplo, esta vez una placa de pantalla LED de 7 segmentos (también basada en el chip MAX7219):
Esto usa exactamente los mismos nombres de señal que la otra placa. En ambos casos, puede ver que la placa solo necesita 5 cables, los tres para SPI, más alimentación y tierra.
Fase de reloj y polaridad
Hay cuatro formas de probar 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.
Estos se ilustran en este gráfico:
Debe consultar la hoja de datos de su dispositivo para obtener la fase y la polaridad correctas. Por lo general, habrá un diagrama que muestra cómo muestrear el reloj. Por ejemplo, de la hoja de datos para el chip 74HC595:
Como puede ver, el reloj normalmente está bajo (CPOL = 0) y se muestrea en el borde de ataque (CPHA = 0), por lo que este es el modo SPI 0.
Puede cambiar la polaridad del reloj y la fase en un código como este (elija solo uno, por supuesto):
Este método está en desuso en las versiones 1.6.0 en adelante del IDE de Arduino. Para versiones recientes, cambia el modo de reloj en la
SPI.beginTransaction
llamada, así:Orden de datos
El valor predeterminado es el bit más significativo primero, sin embargo, puede indicarle al hardware que procese el bit menos significativo primero de esta manera:
Nuevamente, esto está en desuso en las versiones 1.6.0 en adelante del IDE de Arduino. Para las versiones recientes, cambia el orden de bits en la
SPI.beginTransaction
llamada, así:Velocidad
La configuración predeterminada para SPI es utilizar la velocidad del reloj del sistema dividida por cuatro, es decir, un pulso de reloj SPI cada 250 ns, suponiendo un reloj de CPU de 16 MHz. Puede cambiar el divisor del reloj usando
setClockDivider
así:Donde "divisor" es uno de:
La tasa más rápida es "dividir por 2" o un pulso de reloj SPI cada 125 ns, suponiendo un reloj de CPU de 16 MHz. Por lo tanto, esto llevaría 8 * 125 ns o 1 µs para transmitir un byte.
Este método está en desuso en las versiones 1.6.0 en adelante del IDE de Arduino. Para versiones recientes, cambia la velocidad de transferencia en la
SPI.beginTransaction
llamada, así:Sin embargo, las pruebas empíricas muestran que es necesario tener dos pulsos de reloj entre bytes, por lo que la velocidad máxima a la que se pueden sincronizar los bytes es de 1.125 µs cada uno (con un divisor de reloj de 2).
Para resumir, cada byte se puede enviar a una velocidad máxima de uno por 1.125 µs (con un reloj de 16 MHz), lo que proporciona una tasa de transferencia máxima teórica de 1 / 1.125 µs, o 888,888 bytes por segundo (excluyendo la sobrecarga, como configurar SS bajo y así en).
Conectando a Arduino
Arduino Uno
Conexión a través de pines digitales 10 a 13:
Conexión a través del encabezado ICSP:
Arduino Atmega2560
Conexión a través de pines digitales 50 a 52:
También puede usar el encabezado ICSP, similar al Uno de arriba.
Arduino Leonardo
Leonardo y Micro no exponen los pines SPI en los pines digitales, a diferencia del Uno y Mega. Su única opción es usar los pines del encabezado ICSP, como se ilustra arriba para el Uno.
Esclavos múltiples
Un maestro puede comunicarse con múltiples esclavos (sin embargo, solo uno a la vez). Lo hace afirmando SS para un esclavo y desaprendizándolo para todos los demás. El esclavo que ha afirmado SS (generalmente esto significa BAJO) configura su pin MISO como una salida para que el esclavo, y ese esclavo solo, pueda responder al maestro. Los otros esclavos ignoran los pulsos de reloj entrantes si no se afirma SS. Por lo tanto, necesita una señal adicional para cada esclavo, así:
En este gráfico puede ver que MISO, MOSI, SCK se comparten entre ambos esclavos, sin embargo, cada esclavo tiene su propia señal SS (selección de esclavo).
Protocolos
La especificación SPI no especifica los protocolos como tales, por lo que corresponde a los emparejamientos maestro / esclavo individuales acordar lo que significan los datos. Si bien puede enviar y recibir bytes simultáneamente, el byte recibido no puede ser una respuesta directa al byte enviado (ya que se ensamblan simultáneamente).
Por lo tanto, sería más lógico que un extremo envíe una solicitud (por ejemplo, 4 podría significar "enumerar el directorio del disco") y luego hacer transferencias (tal vez simplemente enviando ceros hacia afuera) hasta que reciba una respuesta completa. La respuesta puede terminar con una nueva línea o un carácter 0x00.
Lea la hoja de datos de su dispositivo esclavo para ver qué secuencias de protocolo espera.
Cómo hacer un esclavo SPI
El ejemplo anterior muestra al Arduino como el maestro, enviando datos a un dispositivo esclavo. Este ejemplo muestra cómo Arduino puede ser un esclavo.
Configuración de hardware
Conecte dos Arduino Unos junto con los siguientes pines conectados entre sí:
13 (SCK)
+ 5v (si es necesario)
En el Arduino Mega, los pines son 50 (MISO), 51 (MOSI), 52 (SCK) y 53 (SS).
En cualquier caso, MOSI en un extremo está conectado a MOSI en el otro, no los intercambia (es decir , no tiene MOSI <-> MISO). El software configura un extremo de MOSI (extremo maestro) como salida y el otro extremo (extremo esclavo) como entrada.
Ejemplo maestro
Ejemplo esclavo
El esclavo está completamente controlado por interrupciones, por lo que puede hacer otras cosas. Los datos SPI entrantes se recopilan en un búfer y se establece un indicador cuando llega un "byte significativo" (en este caso, una nueva línea). Esto le dice al esclavo que se suba y comience a procesar los datos.
Ejemplo de conectar maestro a esclavo usando SPI
Cómo obtener una respuesta de un esclavo
Siguiendo con el código anterior que envía datos de un maestro SPI a un esclavo, el siguiente ejemplo muestra el envío de datos a un esclavo, que haga algo con él y devuelva una respuesta.
El maestro es similar al ejemplo anterior. Sin embargo, un punto importante es que necesitamos agregar un ligero retraso (algo así como 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 un "comando". En este caso, "a" (agregar algo) o "s" (restar algo). Esto es para mostrar que el esclavo realmente está haciendo algo con los datos.
Después de afirmar que el esclavo-select (SS) inicia la transacción, el maestro envía el comando, seguido de cualquier número de bytes, y luego levanta el SS para terminar la transacció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 próximo byte. Esto se debe a que los bits que se envían y los bits que se reciben se envían simultáneamente. Por lo tanto, para agregar algo a cuatro números, necesitamos cinco transferencias, como esta:
Primero solicitamos una acción sobre el número 10. Pero no recibimos una respuesta hasta la próxima transferencia (la del 17). Sin embargo, "a" se establecerá en la respuesta a 10. Finalmente, terminamos enviando un número "ficticio" 0, para obtener la respuesta de 42.
Maestro (ejemplo)
El código para el esclavo básicamente hace casi todo en la rutina de interrupción (llamado cuando llegan los datos SPI entrantes). Toma el byte entrante y suma o resta según el "byte de comando" recordado. Tenga en cuenta que la respuesta se "recopilará" la próxima vez a través del ciclo. Es por eso que el maestro tiene que enviar una transferencia final "ficticia" para obtener la respuesta final.
En mi ejemplo, estoy usando el bucle principal para detectar simplemente cuándo SS sube y borrar el comando guardado. De esa manera, cuando SS se baja nuevamente para la próxima transacción, el primer byte se considera el byte de comando.
Más confiablemente, esto se haría con una interrupción. Es decir, conectaría físicamente SS a una de las entradas de interrupción (por ejemplo, en el Uno, conectaría el pin 10 (SS) al pin 2 (una entrada de interrupción), o usaría una interrupción de cambio de pin en el pin 10.
Luego, la interrupción podría usarse para notar cuándo SS se está bajando o bajando.
Esclavo (ejemplo)
Salida de ejemplo
Analizador lógico de salida
Esto muestra el tiempo entre el envío y la recepción en el código anterior:
Nueva funcionalidad en IDE 1.6.0 en adelante
La versión 1.6.0 del IDE ha cambiado la forma en que funciona SPI, hasta cierto punto. Usted todavía tiene que hacer
SPI.begin()
antes de utilizar SPI. Eso configura el hardware SPI. Sin embargo ahora, cuando está a punto de comenzar la comunicación con un esclavo que también se haceSPI.beginTransaction()
para establecer SPI (en este esclavo) con el correcto:Cuando termines de comunicarte con el esclavo, llamas
SPI.endTransaction()
. Por ejemplo:¿Por qué usar SPI?
Esta es una excelente pregunta. Mis respuestas son:
Ambos métodos tienen su lugar. I 2 C le permite conectar muchos dispositivos a un solo bus (dos cables, más tierra), por lo que sería la opción preferida si necesitara interrogar a un número considerable de dispositivos, quizás con poca frecuencia. Sin embargo, la velocidad de SPI podría ser más relevante para situaciones en las que necesita emitir rápidamente (por ejemplo, una tira de LED) o ingresar rápidamente (por ejemplo, un convertidor ADC).
Referencias
Mi página sobre SPI : también tiene detalles sobre SPI con bit bitged y el uso del USART para obtener un segundo SPI de hardware en el chip Atmega328.
Bus de interfaz de periféricos en serie - Wikipedia
Páginas de referencia de la biblioteca Arduino SPI
Documentación de SPI en PJRC
Protocolo SPI - Sparkfun
fuente
Are you going to cover the weirdness that is the Due's SPI?
- No sé nada sobre el SPI de Due (aparte de suponer que el protocolo general es el mismo). Le invitamos a agregar una respuesta que cubra ese aspecto.