SPI e I2C son los protocolos de comunicación serie comunes utilizados por los sensores para comunicarse con microcontroladores y microcomputadoras. Ambos protocolos son protocolos maestro-esclavo. Los sensores suelen formar parte de un dispositivo esclavo dentro de un ecosistema integrado. La mayoría de las veces, un sensor solo requiere enviar datos al microcontrolador/microcomputadora. Esto sigue siendo cierto incluso si un sensor determinado está habilitado para interrupción.
Muchos dispositivos integrados incluyen muchos sensores que requieren comunicación full-duplex con el controlador. Suelen ser sensores sofisticados y módulos integrados con su propio conjunto de comandos explícitos y un alcance de configuración más amplio o aquellos capaces de transmitir una amplia gama de datos variados. Estos sensores y módulos integrados se basan en el protocolo SPI full-duplex, que permite al controlador intercambiar datos con múltiples dispositivos en un bus común, para la comunicación de datos con el controlador. SPI también es un protocolo de comunicación síncrono que permite un enlace de chip a chip de alta velocidad. La velocidad de datos en el bus SPI puede alcanzar un máximo de 10 Mbps.
SPI vs. I2C
SPI significa Interfaz periférica serie. Es un protocolo de comunicación serie full-duplex a diferencia de I2C, un protocolo serie half-duplex. Por full-duplex significa que el bus SPI permite simultáneamente la transmisión y recepción de datos entre el controlador y el esclavo. Hay líneas de datos separadas en el bus SPI para transferir datos de un controlador a otro. A diferencia de esto, I2C tiene una única línea de datos, por lo que cualquiera de los controladores puede enviar o recibir datos a la vez, pero no ambos. Mientras que el bus I2C tiene sólo dos líneas (una línea de datos y una línea de reloj), un bus SPI tiene tres o cuatro líneas. Hay dos líneas de datos, MISO (para transferencia de datos de esclavo a controlador) y MOSI (para transferencia de datos de controlador a esclavo), una línea de reloj SCK y una línea de selección de chip CS o de selección de esclavo /SS. En el protocolo I2C, se pueden conectar varios esclavos a dos líneas donde los esclavos se reconocen y seleccionan para la comunicación de datos mediante un mecanismo de direccionamiento. En SPI, si hay varios esclavos conectados, se requiere la línea Chip Select. Cada esclavo tiene su propia línea de selección de chips. Esto aumenta la cantidad de pines de datos involucrados en el controlador a medida que se agregan más dispositivos esclavos al bus SPI. Si bien el protocolo I2C garantiza una transmisión de datos exitosa mediante acuses de recibo, el protocolo SPI no tiene tal mecanismo. La transmisión de datos no está garantizada en el protocolo SPI.
Aunque el requisito de líneas de selección de chips adicionales y la falta de verificación de datos son las principales desventajas del protocolo SPI. Tiene mucho que ofrecer en el entorno integrado. Permite la comunicación de datos full-duplex a altas velocidades de hasta 10 Mbps. La velocidad de transmisión de datos en el bus I2C puede alcanzar un máximo de 3,4 Mbps. El bus SPI requiere menos energía para la comunicación de datos y es muy eficiente en distancias cortas. Si es necesario integrar un bloque integrado en el controlador, SPI estará ligeramente por encima de I2C.
Módulo de máquina MicroPython
El módulo de la máquina MicroPython está escrito para manejar funciones de hardware de los puertos compatibles. El módulo incluye clases para controlar entrada/salida digital, controlar señales de salida de dispositivos externos, modulación de ancho de pulso, conversión analógica a digital, control de periféricos ADC, UART, SPI, I2C, I2S, temporizador, RTC, temporizador Watchdog y gestión de tarjetas SD. Tiene clase SPI para la gestión de hardware I2C y SoftSPI para implementar software SPI en puertos compatibles.
Clase SPI
La clase SPI del módulo de máquina es responsable de implementar el protocolo SPI en los puertos compatibles con MicroPython. El autobús SPI tiene tres líneas: MOSI, MISO y SCK. El protocolo síncrono requiere una línea CS adicional por esclavo, siempre que haya varios esclavos conectados al bus SPI. La señal CS se gestiona con la ayuda de la clase PIN del módulo de la máquina. El hardware y el software SPI están disponibles en MicroPython. El hardware SPI utiliza el periférico SPI subyacente de los puertos admitidos. Los pines SPI en la mayoría de los puertos son fijos. Aunque no es tan eficiente, el software SPI se puede aplicar a todos los pines de un puerto con capacidad de salida. La clase SPI se incluye en un script MicroPython mediante la siguiente declaración.
Importar máquina SPI, Pin
Después de importar las clases SPI y PIN, se debe crear una instancia de un objeto de la clase SPI utilizando el método constructor. El método constructor de la clase SPI tiene el siguiente prototipo.
máquina de clase.SPI(id,…)
Una llamada al método constructor requiere esencialmente un argumento, el id. La identificación es la identificación del bloque SPI de hardware. Puede ser un número o una cadena según el puerto específico. Normalmente, los bloques SPI se identifican con números como 0, 1, 2, etc. Los otros argumentos que se pueden pasar en una llamada al método constructor son parámetros de configuración. Los parámetros de configuración definidos en el método constructor incluyen velocidad en baudios, polaridad, fase, bits, primer bit, sck, mosi, miso y pines. La velocidad en baudios es la velocidad del reloj SCK. La velocidad máxima en baudios que se puede configurar depende del puerto específico. La polaridad define el nivel de la línea de reloj inactivo. Se puede configurar en 0 o 1. La fase determina si los datos se muestrearán en el primer o segundo flanco del reloj. Si la fase se establece en 0, los datos se muestrearán en el primer flanco del reloj; si se establece en 1, los datos se muestrearán en el segundo flanco del reloj. Firstbit determina si el primer bit de los datos es LSB o MSB. Puede definirse como SPI.LSB o SPI.MSB. Algunos puertos permiten pines alternativos para MOSI, MISO y SCK. Los argumentos mosi, miso y sck definen los pines MOSI, MISO y SCK, respectivamente, en dichos puertos. Si no se especifica, se definirán los pines MOSI, MISO y SCK predeterminados. El argumento pins sólo se permite para el puerto WiPy. Le permite especificar una tupla para definir los pines MOSI, MISO y SCK. Algunos de los ejemplos válidos de creación de objetos SPI son los siguientes.
sp = SPI(0)
spi = SPI(0, velocidad en baudios=400000)
hsp = SPI(1, 10000000)
hspi = SPI(1, 10000000, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
vspi = SPI(2, velocidad en baudios=80000000, polaridad=0, fase=0, bits=8, primer bit=0, sck=Pin(18), mosi=Pin(23), miso=Pin(19))
Después de crear un objeto SPI, se puede inicializar utilizando el método SPI.init. Toma los mismos argumentos que el método constructor, excepto el id. El método SPI.init tiene el siguiente prototipo.
SPI.init(tasa de baudios=1000000, *, polaridad=0, fase=0, bits=8, primer bit=SPI.MSB, sck=Ninguno, mosi=Ninguno, miso=Ninguno, pines=(SCK, MOSI, MISO ))
Los otros métodos disponibles en la clase SPI son los siguientes:
SPI.deinit : este método desactiva el bus SPI.
SPI.read(nbytes, write=0x00) : este método lee el número de bytes nbytes al escribir un solo byte especificado por el argumento de escritura en la línea MOSI. Devuelve un objeto de bytes que contiene los bytes leídos de la línea MISO.
SPI.readinto(buf, write=0x00) : este método lee bytes de la línea MISO en un objeto de búfer mientras escribe un solo byte especificado por el argumento de escritura en la línea MOSI. Los bytes leídos se almacenan en el objeto del búfer. El número de bytes leídos depende del tamaño del objeto del búfer. El método no devuelve nada.
SPI.write(buf) : este método escribe los bytes almacenados en un objeto de búfer buffy en la línea MOSI. No devuelve nada.
SPI.write_readinto(write_buf, read_buf) : este método escribe bytes desde un objeto de búfer write_buf en la línea MOSI y lee bytes en un objeto de búfer read_buf . Ambos objetos de búfer pueden ser iguales, pero deben tener la misma longitud. El método no devuelve nada. La cantidad de bytes en write_buf se escribe en el bus, y la cantidad de bytes igual a la longitud de read_buf se lee y almacena en el objeto read_buf .
Clase SoftSPI
El software SPI se implementa mediante bits. La clase SoftSPI se importa a un script MicroPython mediante la siguiente declaración.
Pin de importación de máquina, SoftSPI
SoftSPI tiene los mismos métodos que la clase SPI de hardware. El método constructor SoftSPI tiene el siguiente prototipo.
clase machine.SoftSPI(velocidad en baudios=500000, *, polaridad=0, fase=0, bits=8, primer bit=MSB, sck=Ninguno, mosi=Ninguno, miso=Ninguno)
El siguiente es un ejemplo válido de creación de instancias de objetos SPI de software.
spi = SoftSPI (tasa de baudios = 100000, polaridad = 1, fase = 0, sck = Pin (0), mosi = Pin (2), miso = Pin (4))
Hardware SPI en ESP8266
Hay dos bloques SPI en ESP8266: SPI0 y SPI1. SPI0 permanece reservado para Flash ROM y no se puede utilizar en el programa de usuario. SPI1 tiene pines MISO, MOSI y SCK fijados a GPIO12, GPIO13 y GPIO14 respectivamente.

Pines SPI estándar en ESP8266
La frecuencia máxima de reloj se puede configurar en 80 MHz. A continuación se muestra un ejemplo válido de creación de un objeto SPI de hardware en ESP8266.
Importación de máquina de pines, SPI
hspi = SPI(1, velocidad en baudios=80000000, polaridad=0, fase=0)
Software SPI en ESP8266
El software SPI es uno de los dos controladores SPI disponibles en el ESP8266. El software SPI se puede implementar en todos los pines del ESP8266. A continuación se muestra un ejemplo válido del uso del software MicroPython SPI en ESP8266.
Pin de importación de máquina, SoftSPI
spi = SoftSPI (tasa de baudios = 100000, polaridad = 1, fase = 0, sck = Pin (0), mosi = Pin (2), miso = Pin (4))
spi.init(tasa de baudios=800000)
spi.read(3) # lee 3 bytes en MISO
spi.read(3, 0xff) # lee 3 bytes mientras genera 0xff en MOSI
buf = bytearray(10) # objeto de búfer
spi.readinto(buf) # lee 10 bytes en el buffer dado
spi.readinto(buf, 0xff) # lee 10 bytes en el búfer proporcionado y genera 0xff en MOSI
spi.write(b'12345′) # escribe el objeto de búfer especificado en MOSI
buf = bytearray(5) # crear un búfer
spi.write_readinto(b'12345′, buf) # escribe en MOSI y lee desde MISO en el búfer
spi.write_readinto(buf, buf) # escribe buf en MOSI y lee MISO nuevamente en buf
Hardware SPI en ESP32
Hay dos bloques SPI de hardware en ESP32: HSPI (SPI1) y VSPI (SPI2). Los pines predeterminados para MOSI, MISO y SCK de HSPI son GPIO13, GPIO12 y GPIO14, respectivamente. Los pines predeterminados para MOSI, MISO y SCK de VSPI son GPIO23, GPIO19 y GPIO18, respectivamente. La frecuencia máxima de reloj SPI puede ser de 80 MHz en los pines estándar. ESP32 permite la multiplexación GPIO de bloques SPI de hardware, siempre que los pines estén habilitados para entrada o salida de acuerdo con los requisitos de la línea SPI. Sin embargo, la frecuencia máxima de reloj SPI en pines multiplexados sólo puede ser de 40 MHz.

Pines SPI estándar en ESP32
El siguiente es un ejemplo válido de creación de un objeto SPI de hardware en ESP32.
Importación de máquina de pines, SPI
hsp = SPI(1, 80000000)
hspi = SPI(1, 40000000, sck=Pin(14), mosi=Pin(13), miso=Pin(12))
vspi = SPI(2, velocidad en baudios=80000000, polaridad=0, fase=0, bits=8, primer bit=0, sck=Pin(18), mosi=Pin(23), miso=Pin(19))
Software SPI en ESP32
El software SPI está disponible en todos los pines del ESP32. La frecuencia de reloj máxima del software SPI puede ser de 40 MHz. A continuación se muestra un ejemplo válido de software SPI en ESP32.
Pin de importación de máquina, SoftSPI
spi = SoftSPI (tasa de baudios = 100000, polaridad = 1, fase = 0, sck = Pin (0), mosi = Pin (2), miso = Pin (4))
spi.init(tasa de baudios=800000)
spi.read(3) # lee 3 bytes en MISO
spi.read(3, 0xff) # lee 3 bytes mientras genera 0xff en MOSI
buf = bytearray(10) # objeto de búfer
spi.readinto(buf) # lee 10 bytes en el buffer dado
spi.readinto(buf, 0xff) # lee 10 bytes en el buffer proporcionado y genera 0xff en MOSI
spi.write(b'12345′) # escribe el objeto de búfer especificado en MOSI
buf = bytearray(5) # crear un búfer
spi.write_readinto(b'12345′, buf) # escribe en MOSI y lee desde MISO en el búfer
spi.write_readinto(buf, buf) # escribe buf en MOSI y lee MISO nuevamente en buf
Algunos ejemplos de SPI
Se pueden encontrar algunos buenos ejemplos del uso de la clase MicroPython SPI en los siguientes proyectos.
- Proyecto – MicroPython SSD1351 por el autor rdagger
- Proyecto – MicroPython nanoGUI por el autor peterhinch
- Proyecto – uPySensors por el autor lemariva
- Proyecto – ubble del autor dmazzella
Consulte los proyectos integrados anteriores y explore su código fuente para aprender cómo se utiliza la clase SPI del módulo de máquina MicroPython.