Para usar SPI en un PLC ESP32, conecta el dispositivo a los bornes SO (MISO, GPIO 19), SI (MOSI, GPIO 23) y SCK (GPIO 18), usa un pin lógico libre como GPIO 0 como chip select y envía los datos con la librería SPI de Arduino dentro de SPI.beginTransaction() y SPI.endTransaction(). El puerto SPI externo del PLC ESP32 es el bus VSPI (SPI3) del ESP32 y trabaja a 3,3 V.
El mismo bus da servicio también al controlador Ethernet y a la tarjeta µSD del PLC. Por eso cada dispositivo necesita su propio chip select, y tu código no debe cambiar la configuración del bus fuera de una transacción. Esta guía explica las señales y los modos SPI, los controladores SPI y los pines por defecto del ESP32, los bornes SPI del PLC ESP32, las reglas de un bus compartido, el código Arduino y una lista de comprobación para la primera transferencia. Las secciones sobre modos SPI y pines del ESP32 sirven para cualquier placa ESP32.
| SPI en el PLC ESP32 | Valor |
|---|---|
| Bus del ESP32 | VSPI (SPI3), el objeto SPI por defecto en Arduino |
| MISO (entrada del maestro) | Borne SO, GPIO 19 |
| MOSI (salida del maestro) | Borne SI, GPIO 23 |
| Reloj | Borne SCK, GPIO 18 |
| Chip select | Sin pin fijo. Usa un pin lógico libre, por ejemplo el borne GPIO 0 |
| Nivel lógico | 3,3 V, directo del ESP32 |
| Función | Maestro. La librería SPI de Arduino no admite el modo esclavo |
| Compartido con | Controlador Ethernet y tarjeta µSD |

¿Cómo funciona la comunicación SPI?
SPI (Serial Peripheral Interface) es un bus serie síncrono y full duplex con un maestro y uno o varios esclavos. El maestro genera el reloj. En cada pulso de reloj sale un bit por MOSI y entra un bit por MISO. Una transferencia siempre envía y recibe el mismo número de bits, así que para leer un byte el maestro envía un byte, a menudo un 0x00 de relleno.
- SCK (también SCLK): el reloj del maestro. Los esclavos nunca lo controlan.
- MOSI (Master Out Slave In): datos del maestro al esclavo.
- MISO (Master In Slave Out): datos del esclavo al maestro. Solo el esclavo seleccionado controla esta línea.
- CS (Chip Select, también SS de Slave Select): una línea por esclavo, activa a nivel bajo. El esclavo solo escucha mientras su CS está a nivel bajo.
Algunas hojas de datos recientes usan otros nombres para las mismas líneas: COPI y CIPO, o SDO y SDI vistas desde cada dispositivo.

Modos SPI: polaridad y fase del reloj
El maestro y el esclavo deben coincidir en cuándo es válido el dato. Lo definen dos parámetros. CPOL es el nivel del reloj cuando el bus está en reposo. CPHA indica si el dato se muestrea en el primer o en el segundo flanco de reloj. Juntos dan cuatro modos SPI. La hoja de datos del esclavo indica el modo, como número de modo, como valores de CPOL y CPHA o como diagrama de tiempos.
| Modo | CPOL | CPHA | Reloj en reposo | Dato muestreado en | Constante de Arduino |
|---|---|---|---|---|---|
| 0 | 0 | 0 | Bajo | Flanco de subida | SPI_MODE0 |
| 1 | 0 | 1 | Bajo | Flanco de bajada | SPI_MODE1 |
| 2 | 1 | 0 | Alto | Flanco de bajada | SPI_MODE2 |
| 3 | 1 | 1 | Alto | Flanco de subida | SPI_MODE3 |
Los otros dos parámetros son la frecuencia de reloj y el orden de los bits. La mayoría de dispositivos envían primero el bit más significativo (MSBFIRST). En Arduino, SPISettings agrupa los tres valores: reloj, orden de bits y modo.
Controladores SPI del ESP32: SPI0 y SPI1 para la flash, HSPI y VSPI para tus dispositivos
El ESP32 original tiene cuatro controladores SPI. SPI0 y SPI1 conectan el chip con su memoria flash (y con la PSRAM, si la hay), así que no puedes usarlos para tus dispositivos. SPI2 y SPI3 son controladores SPI de uso general. En Arduino se llaman HSPI y VSPI.
| Controlador | Nombre en Arduino | Uso | SCK | MISO | MOSI | CS |
|---|---|---|---|---|---|---|
| SPI0, SPI1 | ninguno | Flash interna y PSRAM | No disponible para tus dispositivos | |||
| SPI2 | HSPI | Uso general | GPIO 14 | GPIO 12 | GPIO 13 | GPIO 15 |
| SPI3 | VSPI | Uso general, objeto SPI por defecto | GPIO 18 | GPIO 19 | GPIO 23 | GPIO 5 |
Pines por defecto de SPI2 y SPI3 (pines IO_MUX), según la documentación SPI Master de ESP-IDF.
Estos pines por defecto conectan con el controlador directamente a través del IO_MUX. Espressif indica hasta 80 MHz en estos pines. El ESP32 también puede llevar el SPI a otros pines a través de la matriz GPIO, pero entonces el límite es de 40 MHz, y de unos 26 MHz en transferencias full duplex. En la práctica, el esclavo y el cableado fijan un límite mucho más bajo que el ESP32. Otros chips de la familia, como el ESP32-S3, usan otros pines y llaman FSPI al bus de uso general. Consulta la documentación SPI Master de ESP-IDF para ver los detalles.
Bornes SPI del PLC ESP32
La familia ESP32 PLC (modelos 19R a 58 de la hoja de datos de la familia ESP32 PLC) tiene un puerto SPI externo conectado a VSPI (SPI3). La hoja de datos indica que el puerto SPI es de 3,3 V, directo de la CPU ESP32. No hace falta cambiar ningún interruptor DIP para usarlo. El PLC necesita su alimentación normal de 12 a 24 Vcc.
| Función | Borne del PLC | Pin del ESP32 | Nivel |
|---|---|---|---|
| MISO | SO | GPIO 19 | 3,3 V |
| MOSI | SI | GPIO 23 | 3,3 V |
| Reloj | SCK | GPIO 18 | 3,3 V |
| Chip select | A elegir, por ejemplo GPIO 0 | Se define en tu código | Depende del pin (GPIO 0 es de 5 V) |
No hay un borne para el chip select. Eliges un pin lógico libre y lo controlas desde tu código, como en los ejemplos de abajo. No uses una salida digital de 24 V (un borne Q) como chip select: su nivel y su tiempo de conmutación no son adecuados para un dispositivo SPI.
Comprueba el nivel del chip select. En nuestro análisis de tiempos de los pines del PLC ESP32, el borne GPIO 0 trabaja a 5 V, con tiempos de subida y bajada de unos 5 µs. Las líneas SI, SO y SCK trabajan a 3,3 V. Si tu dispositivo tiene una entrada de chip select de 3,3 V que no tolera 5 V, añade un adaptador de nivel en CS. Los pines del ESP32 tampoco toleran 5 V: un dispositivo de 5 V necesita un adaptador de nivel en su salida MISO.
Cuando no usas SPI ni Ethernet, los bornes SO, SI y SCK también pueden funcionar como entradas o salidas digitales generales. El mismo análisis de pines da sus tiempos de subida y bajada (unos 100 ns).

Ethernet, la tarjeta µSD y tu dispositivo SPI comparten un bus
Dentro del PLC ESP32, el controlador Ethernet, la tarjeta µSD y el puerto SPI externo usan el mismo bus SPI (SPI3). Las placas de comunicación de las ranuras de expansión también pueden usar SPI con su propio chip select: la guía de la placa CAN SPI usa CS 32 en la ranura de expansión 1 y CS 2 en la ranura 2. Un bus compartido funciona bien si todos los dispositivos siguen las mismas reglas.
- 1 · Tomar el busbeginTransaction()Carga el reloj, el orden de bits y el modo de tu dispositivo. En el core Arduino del ESP32 también bloquea el bus hasta endTransaction().
- 2 · SeleccionarCS a nivel bajoSolo escucha tu dispositivo. Los CS de Ethernet y de la tarjeta µSD siguen a nivel alto.
- 3 · Intercambiartransfer()Envía y recibe los bytes de un comando, como indica la hoja de datos del dispositivo.
- 4 · LiberarCS a nivel alto, endTransaction()Tu dispositivo deja el bus y Ethernet y la tarjeta µSD pueden volver a usarlo.
Regla Mantén CS a nivel bajo solo entre beginTransaction() y endTransaction().
- Pon CS a nivel alto antes que nada. En
setup(), configura tu pin CS como salida y ponlo a nivel alto antes de iniciar Ethernet, la tarjeta µSD o SPI. Un CS al aire puede hacer que tu dispositivo responda durante el tráfico Ethernet. - Usa una transacción en cada acceso. Ethernet y la tarjeta µSD usan su propio reloj y su propio modo. Si tu código cambia la configuración fuera de una transacción, el siguiente acceso a Ethernet o a la µSD puede fallar.
- No llames a
SPI.end()ni aSPI.begin()con otros pines mientras Ethernet o la tarjeta µSD estén en uso. Detiene el bus para todos los dispositivos. - Comprueba que tu dispositivo libera MISO. Con su CS a nivel alto, el dispositivo debe dejar MISO en alta impedancia. Algunos dispositivos siguen controlando MISO. En un bus compartido bloquean Ethernet y la tarjeta µSD, y necesitan un buffer triestado con entrada de habilitación.
- Haz transferencias cortas. Mientras tu dispositivo ocupa el bus, Ethernet y la tarjeta µSD esperan. Lee un valor por transacción en lugar de un bloque largo.
La tarjeta µSD es un caso típico: el PLC guarda los datos en la tarjeta mientras la red no funciona, y Ethernet o MQTT los envían después. La Solution Library muestra este patrón en registro de datos en tarjeta SD con un PLC ESP32 y archivos diarios.
Código Arduino para un dispositivo SPI en el PLC ESP32
Instala el paquete de placas ESP32 de Industrial Shields en el IDE de Arduino (consulta cómo instalar las placas de Industrial Shields en el IDE de Arduino) y selecciona tu modelo de PLC ESP32 en Herramientas. La librería SPI.h del paquete es la librería SPI de Arduino para el ESP32. Solo funciona como maestro.
Ejemplo básico de maestro: enviar un byte e imprimir la respuesta
Este sketch envía el carácter '0' cada 100 ms e imprime el byte que devuelve el esclavo. La librería no controla CS, así que lo hace el sketch. Cambia el reloj, el orden de bits y el modo por los valores de la hoja de datos de tu dispositivo.
// SPI master example for the ESP32 PLC family
#include <SPI.h>
const int csPin = GPIO_0; // chip select: GPIO 0 terminal (5 V)
const uint32_t spiClock = 1000000; // 1 MHz: start low, raise it after the first tests
SPISettings deviceSettings(spiClock, MSBFIRST, SPI_MODE0);
uint8_t spiExchange(uint8_t out) {
SPI.beginTransaction(deviceSettings); // take the bus with the settings of this device
digitalWrite(csPin, LOW); // select the device
delayMicroseconds(10); // GPIO 0 edges take about 5 us
uint8_t in = SPI.transfer(out); // send one byte and receive one byte
digitalWrite(csPin, HIGH); // release the device
delayMicroseconds(10); // let CS reach the high level
SPI.endTransaction(); // free the bus for Ethernet and the uSD card
return in;
}
void setup() {
Serial.begin(115200);
pinMode(csPin, OUTPUT);
digitalWrite(csPin, HIGH); // keep the device off the bus during start-up
SPI.begin(); // VSPI: SCK GPIO 18, MISO GPIO 19, MOSI GPIO 23
}
void loop() {
uint8_t answer = spiExchange('0');
Serial.print("Received: 0x");
Serial.println(answer, HEX);
delay(100);
}
Si Ethernet o la tarjeta µSD ya han iniciado el bus, SPI.begin() no lo vuelve a iniciar, así que el orden en setup() no es crítico. Lo importante es que CS esté a nivel alto antes de la primera transferencia en el bus.
Leer un registro de 16 bits
La mayoría de dispositivos SPI funcionan con comandos: el maestro envía un comando o una dirección de registro y después envía bytes de relleno para recibir la respuesta. El byte de comando y la longitud de la respuesta salen de la hoja de datos del dispositivo. Esta función reutiliza la configuración del ejemplo anterior.
uint16_t readRegister16(uint8_t command) {
SPI.beginTransaction(deviceSettings);
digitalWrite(csPin, LOW);
delayMicroseconds(10);
SPI.transfer(command); // send the command or register address
uint8_t high = SPI.transfer(0x00); // dummy byte: clock in the first byte
uint8_t low = SPI.transfer(0x00); // dummy byte: clock in the second byte
digitalWrite(csPin, HIGH);
delayMicroseconds(10);
SPI.endTransaction();
return (uint16_t(high) << 8) | low;
}
Algunos dispositivos necesitan CS a nivel bajo durante todo el comando y otros necesitan un pulso en CS entre comandos. Sigue el diagrama de tiempos del dispositivo. Es la causa más habitual de lecturas erróneas.
Un segundo bus SPI con SPIClass en otras placas ESP32
En el PLC ESP32, el puerto SPI externo es VSPI, así que usas el objeto SPI por defecto. En una placa ESP32 con HSPI libre puedes crear un segundo bus con su propia instancia de SPIClass. Así cada bus tiene su propio reloj y sus propias líneas de datos.
#include <SPI.h>
SPIClass hspi(HSPI); // second SPI bus (SPI2)
const int hspiCs = 15;
void setup() {
Serial.begin(115200);
pinMode(hspiCs, OUTPUT);
digitalWrite(hspiCs, HIGH);
hspi.begin(14, 12, 13, hspiCs); // SCK, MISO, MOSI, SS
}
void loop() {
hspi.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(hspiCs, LOW);
uint8_t in = hspi.transfer(0x00);
digitalWrite(hspiCs, HIGH);
hspi.endTransaction();
Serial.println(in, HEX);
delay(100);
}
Revisa los pines de arranque antes de usar HSPI: en el ESP32, GPIO 12 y GPIO 15 son pines de configuración de arranque (strapping), y un dispositivo que los lleve al nivel equivocado durante el reset puede impedir que la placa arranque.
Cableado SPI en un armario de control
SPI es un bus para conexiones cortas entre chips. No tiene señales diferenciales ni comprobación de errores en el protocolo. En un PLC es la opción adecuada para un dispositivo situado junto al controlador, como un ADC externo, un convertidor de termopar o de RTD, una pantalla o un chip de memoria.
- Mantén el dispositivo cerca. Móntalo en el mismo armario que el PLC, con cables cortos. Los cables largos añaden capacidad y reflexiones, y los flancos del reloj empeoran.
- Baja el reloj cuando los cables son más largos. Empieza con 1 MHz o menos, comprueba los datos y después sube el reloj paso a paso.
- Comparte la masa. Conecta el GND del dispositivo al GND del PLC y llévalo junto a los cables de señal.
- Aleja el SPI del ruido. Pasa los cables lejos de las salidas de relé, los contactores y los cables de motor.
- Usa un bus de campo para distancias largas. Si la señal sale del armario, usa RS-485 con Modbus RTU, Ethernet o un lazo de 4-20 mA en lugar de SPI.
Primera transferencia SPI: qué revisar cuando los datos no son correctos
| Síntoma | Causa probable | Qué revisar |
|---|---|---|
| Siempre lees 0xFF | Nadie controla MISO | Cableado de CS y pin CS en el código, alimentación del dispositivo, cable MISO en el borne SO |
| Siempre lees 0x00 | MISO fijo a nivel bajo, o el dispositivo está en reset o sin configurar | Cableado de MISO, pines de reset o de habilitación del dispositivo, tiempo de arranque tras la alimentación |
| Los valores casi cuadran, pero desplazados un bit | Modo SPI incorrecto | CPOL y CPHA en la hoja de datos y después el modo en SPISettings |
| Valores erróneos al azar | Reloj demasiado rápido para el cableado, o ruido | Baja el reloj, acorta los cables, revisa la masa |
| Tu dispositivo funciona, pero fallan Ethernet o la tarjeta µSD | El dispositivo responde sin estar seleccionado, o la configuración cambia fuera de una transacción | CS a nivel alto en setup, transacciones en cada acceso, MISO liberado con CS a nivel alto, sin SPI.end() |
| Tu dispositivo funciona solo, pero falla con Ethernet activo | CS a nivel bajo fuera de la transacción, o sin bloqueo entre tareas | CS a nivel bajo solo entre beginTransaction() y endTransaction(), todos los accesos SPI dentro de transacciones |
Un analizador lógico o un osciloscopio en SCK, MOSI, MISO y CS muestra la mayoría de estos problemas en una sola captura. Con la prueba de conexión Ethernetpuedes comprobar que Ethernet sigue funcionando después de añadir tu dispositivo.
Resumen de SPI en el PLC ESP32

- El puerto SPI externo del PLC ESP32 es VSPI (SPI3): SO es MISO (GPIO 19), SI es MOSI (GPIO 23) y SCK es el reloj (GPIO 18), todos a 3,3 V.
- El chip select es un pin que eliges y controlas desde tu código. Comprueba que su tensión sea compatible con el dispositivo.
- Ethernet, la tarjeta µSD y tu dispositivo comparten el bus: CS a nivel alto al arrancar, una transacción por acceso y sin
SPI.end(). - SPI es para dispositivos dentro del armario. Para señales de campo, usa RS-485, Ethernet o 4-20 mA.
Del bus SPI a una instalación real. El caso de monitorización de vagones de tren usa un ESP32 PLC 57R que guarda los datos a bordo cuando se cae el enlace 4G y los envía cuando vuelve.
Leer el caso de los vagones de tren
Para comparar modelos y E/S, consulta la familia ESP32 PLC.
Más sobre SPI y buses en PLC industriales
- Bus SPI en un PLC Arduino (M-Duino)
- Bus SPI en un PLC Raspberry
- Cómo usar la placa CAN SPI con la familia ESP32 PLC
- Prueba de comunicación CAN SPI en el ESP32 PLC 14
- Análisis de la respuesta temporal de los pines del PLC ESP32
- Librería Ethernet mejorada para PLC M-Duino y ESP32
- Uso básico de la tarjeta SD en un PLC industrial
- Bus I2C en un PLC industrial
- Conceptos básicos de RS-485 en un PLC industrial
- PLC Solution Library: funciones probadas para ESP32 PLC, Arduino PLC y Raspberry PLC
Preguntas frecuentes sobre SPI en el ESP32 y en el PLC ESP32
¿Cuáles son los pines SPI por defecto del ESP32?
Para VSPI (SPI3), el bus del objeto SPI por defecto en Arduino: SCK GPIO 18, MISO GPIO 19, MOSI GPIO 23 y CS GPIO 5. Para HSPI (SPI2): SCK GPIO 14, MISO GPIO 12, MOSI GPIO 13 y CS GPIO 15. SPI0 y SPI1 son para la flash interna.
¿Qué bus SPI usa el PLC ESP32?
El puerto SPI externo de la familia ESP32 PLC es VSPI (SPI3): el borne SO es MISO (GPIO 19), SI es MOSI (GPIO 23) y SCK es el reloj (GPIO 18). El controlador Ethernet y la tarjeta µSD usan el mismo bus.
¿Puede el PLC ESP32 funcionar como esclavo SPI?
No con la librería SPI de Arduino, que solo funciona como maestro. En el PLC ESP32, el ESP32 también es el maestro de Ethernet y de la tarjeta µSD en el mismo bus. Para conectar dos PLC, usa RS-485, Ethernet o CAN.
¿Puedo conectar un dispositivo SPI de 5 V al PLC ESP32?
No directamente. Las líneas SPI del PLC trabajan a 3,3 V y los pines del ESP32 no toleran 5 V, así que una señal MISO de 5 V necesita un adaptador de nivel. Además, algunos dispositivos de 5 V no leen 3,3 V como nivel alto válido en sus entradas.
¿Por qué deja de funcionar Ethernet al añadir un dispositivo SPI?
Las causas habituales son un CS al aire o fijo a nivel bajo, un dispositivo que sigue controlando MISO sin estar seleccionado, una llamada a SPI.end() o una configuración cambiada fuera de SPI.beginTransaction(). Pon CS a nivel alto en setup() y haz cada acceso dentro de una transacción.
¿Qué diferencia hay entre SPI e I2C en un PLC?
SPI usa una línea de datos para cada sentido, un reloj y una línea CS por dispositivo, y trabaja a frecuencias de reloj más altas. I2C usa dos líneas compartidas y selecciona cada dispositivo por su dirección. En el PLC ESP32, I2C trabaja a 5 V y SPI a 3,3 V. Los dos son para dispositivos dentro del armario.
¿A qué velocidad puede funcionar SPI en el ESP32?
Espressif indica hasta 80 MHz en los pines IO_MUX por defecto. A través de la matriz GPIO el límite es de 40 MHz, y de unos 26 MHz en transferencias full duplex, que es como trabaja la librería SPI de Arduino. En un PLC, la hoja de datos del esclavo y el cableado fijan el límite real. Empieza con 1 MHz o menos y sube el reloj mientras los datos sigan siendo correctos.