← Índice del curso

Comunicación entre Dispositivos · Tema 12 · SPI

SPI: cuatro hilos y un maestro

Dejamos la UART y entramos en el bus de placa más rápido y más simple de los tres: SPI. Un reloj que genera el maestro, dos líneas de datos que trabajan a la vez y una línea de selección. Vamos a ver qué hace cada hilo, por qué el receptor es literalmente un registro de desplazamiento y cómo se arma una lectura o una escritura de registros.

01 · Del enlace asíncrono al bus síncrono

Del enlace asíncrono al bus síncrono

En los temas 7 a 11 trabajamos con la UART: dos hilos de datos, ningún reloj compartido, bits de inicio y parada para sincronizar y una velocidad que ambos lados tienen que acordar de antemano. Es un enlace flexible, pero lento y con una trama que gasta dos de cada diez bits en control.

SPI (Serial Peripheral Interface) resuelve el mismo problema, mover bytes entre un microcontrolador y un periférico, con la receta opuesta: el maestro agrega una línea de reloj (tema 3) y con ella desaparecen los bits de inicio y parada, los errores de baudios y la necesidad de que el esclavo tenga un oscilador preciso. A cambio, se pagan más cables y se renuncia a la distancia.

Es el bus que se encuentra en pantallas gráficas, tarjetas SD, memorias flash, conversores analógico-digitales, módulos de radio y muchos sensores. Lo diseñó Motorola a mediados de los años 80 y nunca tuvo un estándar formal: por eso hay pequeñas variantes de un fabricante a otro, que estudiaremos en el tema 13. Lo que sigue en este tema es el núcleo común a todos.

02 · El cableado

Las cuatro líneas

Un enlace SPI conecta un maestro (casi siempre el microcontrolador) con uno o varios esclavos (el periférico) mediante cuatro señales, más la masa común:

Las cuatro líneas de SPI y sus nombres alternativos.
LíneaSignificadoQuién la manejaOtros nombres
SCLKReloj serie: cada pulso mueve un bitMaestroSCK, CLK
MOSIMaster Out, Slave In: datos del maestro al esclavoMaestroSDO (del maestro), COPI, SDI en el esclavo
MISOMaster In, Slave Out: datos del esclavo al maestroEsclavoSDI (del maestro), CIPO, SDO en el esclavo
CSChip Select: avisa a qué esclavo se le habla (activa en nivel bajo)MaestroSS, nCS, CSn
Conexión entre un maestro y un esclavo SPI El maestro, a la izquierda, y el esclavo, a la derecha, se unen con cuatro líneas. SCLK, MOSI y CS salen del maestro hacia el esclavo; MISO va del esclavo al maestro. Además hay un cable de masa común. Maestromicrocontrolador Esclavosensor, memoria, pantalla SCLK (reloj) MOSI (maestro → esclavo) MISO (esclavo → maestro) CS (selección, activa en bajo) GND común (obligatoria)

Observá la diferencia con la UART: aquí los papeles no son simétricos. El maestro genera el reloj y decide cuándo hay una transferencia; el esclavo nunca puede iniciar una. Es la estructura maestro–esclavo del tema 6, en su forma más pura. Si el esclavo necesita avisar algo (un dato listo, una alarma), lo hace con una línea aparte tipo INT, que el maestro atiende y entonces lee.

En cuanto a niveles eléctricos, las cuatro salidas son push-pull (tema 5): flancos rápidos, sin resistencias de pull-up. Por eso conectar un periférico de 3,3 V a un maestro de 5 V requiere un adaptador de nivel en las tres líneas que van hacia el esclavo; el divisor resistivo que usamos en la UART es demasiado lento para relojes de varios megahertz.

03 · El mecanismo

Dos registros que giran juntos

La idea central de SPI cabe en una frase: el maestro y el esclavo tienen cada uno un registro de desplazamiento de 8 bits, y los dos están unidos en anillo. La salida del registro del maestro (MOSI) entra al registro del esclavo, y la salida del registro del esclavo (MISO) entra al del maestro.

Anillo de dos registros de desplazamiento El registro del maestro tiene su bit más significativo conectado a MOSI, que entra por el bit menos significativo del registro del esclavo. El bit más significativo del esclavo sale por MISO y entra por el bit menos significativo del maestro. El reloj SCLK llega a ambos registros. registro del maestro registro del esclavo bit 7bit 0 bit 7bit 0 MOSI MISO SCLKSCLK cada pulso: todos los bits se corren un lugar a la izquierda y el bit que entra es el que acaba de salir del otro registro

En cada pulso de SCLK ocurre lo mismo en los dos registros a la vez:

  1. Cada uno pone en su línea de salida su bit más significativo (bit 7).
  2. Todos los bits se desplazan un lugar hacia la izquierda.
  3. El lugar libre (bit 0) se llena con el bit que llegó por la línea de entrada.

Después de 8 pulsos, los bits del maestro dieron la vuelta completa y están en el esclavo, y los del esclavo están en el maestro: los dos registros intercambiaron su contenido. Eso es todo lo que hace SPI. Un byte enviado y un byte recibido son, en realidad, la misma operación.

Intercambio del maestro 0xA5 (10100101) con el esclavo 0x3C (00111100), pulso a pulso.
PulsoSale por MOSISale por MISOMaestro despuésEsclavo después
0 (inicio)——1010010100111100
1100100101001111001
2001001010011110010
3110010100111100101
4010101001111001010
…los pulsos 5 a 7 siguen el mismo patrón……
8 (fin)1000111100 (0x3C)10100101 (0xA5)

Dos consecuencias prácticas. Primero, el esclavo no necesita reloj propio: usa el que le entrega el maestro, así que los relojes nunca se desfasan (la ventaja del tema 3). Segundo, si el maestro deja de generar pulsos, la transferencia se congela en el punto en que estaba: no hay timeout ni pérdida de sincronía por una pausa, algo impensable en una UART.

04 · Quién escucha

La selección de chip

Si hay un solo esclavo, el reloj y los datos serían suficientes. Pero el bus de SCLK, MOSI y MISO suele estar compartido por varios periféricos, y alguien tiene que decir a cuál se le habla. Ese es el trabajo de CS (chip select), una línea individual por esclavo que el maestro maneja como un pin de salida cualquiera:

  • En reposo, CS está en nivel alto: el esclavo está ignorando el bus, con su salida MISO en alta impedancia (desconectada), para no pelearse con los demás.
  • Para empezar una transacción, el maestro baja CS. El esclavo se activa, reinicia su lógica interna y empieza a escuchar el reloj.
  • Mientras CS está bajo se envían todos los bytes de la transacción. Al terminar, el maestro sube CS.

CS cumple, además, un segundo rol que la UART resolvía con delimitadores: marca dónde empieza y termina el mensaje (el nivel de trama del tema 3). Es lo que permite al esclavo saber que el siguiente byte es un comando y no un dato, y descartar una transacción incompleta si hubo un error. Sin CS, un pulso de ruido en SCLK desalinearía al esclavo para siempre; con CS, la próxima transacción vuelve a empezar de cero.

Con varios esclavos hay una línea CS por cada uno, y el maestro mantiene en bajo solo una a la vez. Las variantes de conexión (varios CS, cadena en margarita) las vemos en el tema 14.

05 · Siempre de ida y vuelta

Full duplex y el byte de relleno

Como los dos registros giran juntos, en SPI no existe «solo enviar» ni «solo recibir»: cada vez que el maestro saca un byte por MOSI, entra un byte por MISO. Lo que el programador hace es decidir cuál de los dos le importa:

Cuando el maestro escribe

Los bytes que vuelven por MISO no tienen información útil y se ignoran. Lo habitual es leerlos igual (la función lo devuelve) y descartarlos.

Cuando el maestro lee

El esclavo solo puede hablar mientras hay pulsos de reloj, y los pulsos solo los genera el maestro al enviar algo. Por eso el maestro envía un byte de relleno (dummy byte, normalmente 0x00 o 0xFF) para «prestar» los ocho pulsos que el esclavo usa para contestar.

Esta es la fuente de confusión más común al empezar: para leer un byte hay que enviar un byte. No se «pide» un dato y se espera: se envían ocho pulsos, y el dato viaja durante esos mismos pulsos.

También hay una sutileza de orden. El esclavo no puede contestar un comando durante el mismo byte en que lo recibe: necesita ver los ocho bits del comando para saber qué se le pide. Por eso, en una lectura, el byte que vuelve durante el comando no tiene significado y el dato llega en el byte siguiente. Es la misma «latencia de un byte» que veremos en la sección siguiente.

06 · Cómo se arma una conversación

Transacciones: comando, dato y ráfaga

SPI no define formato de mensajes: cada fabricante diseña el suyo. Aun así, casi todos los periféricos con registros (sensores, conversores, controladores de radio) comparten un esquema muy parecido: el primer byte es un comando con el bit 7 que indica si es lectura o escritura y los bits 6 a 0 con la dirección del registro.

El dispositivo que usaremos en el laboratorio tiene cuatro registros de 8 bits (R0 a R3, de valores iniciales 0x60, 0x2A, 0x00 y 0x7E) y sigue esa convención. Las tres transacciones posibles:

Bytes que se intercambian en cada tipo de transacción (CS en bajo durante toda la secuencia).
OperaciónMOSI (maestro envía)MISO (maestro recibe)
Leer R10x81 (lectura + dirección 1), 0x00 (relleno)sin significado, 0x2A (el dato)
Escribir 0x5A en R20x02 (escritura + dirección 2), 0x5Asin significado, sin significado
Leer ráfaga de 4 desde R00x80, 0x00, 0x00, 0x00, 0x00sin significado, 0x60, 0x2A, 0x00, 0x7E

Del cuadro se desprenden tres hechos:

  • Una lectura de n bytes lleva n + 1 bytes en el bus: el comando y n bytes de relleno. El primer byte recibido se descarta.
  • El bit 7 del comando decide el sentido. Es 0x80 + dirección para leer y la dirección sola para escribir (por eso 0x81 lee R1 y 0x01 lo escribe).
  • Una ráfaga (burst) lee o escribe varios registros consecutivos con un solo comando: el dispositivo incrementa la dirección solo después de cada byte. Ahorra el comando repetido y la bajada y subida de CS, y es lo que permite leer, por ejemplo, los seis bytes de un acelerómetro de tres ejes de una sola vez.

Esa comodidad tiene un riesgo: el dispositivo no avisa cuando la ráfaga se sale del mapa. En nuestro dispositivo, leer cuatro bytes desde R2 devuelve R2 y R3 y, después, 0xFF 0xFF: valores que no son datos. Un maestro que cuenta mal lee basura sin enterarse; la defensa es conocer el mapa de registros de la hoja de datos y no pedir de más.

07 · Cuánto tarda

Velocidad y comparación con UART e I²C

Como no hay bits de inicio, parada ni paridad, en SPI cada pulso de reloj mueve un bit útil. El tiempo de una transferencia es simple:

t = (bytes × 8) / fSCLK  velocidad útil ≈ fSCLK / 8 bytes por segundo

A 4 MHz (la frecuencia del laboratorio) el bit dura 250 ns y un byte tarda 2 µs. Una lectura de registro (2 bytes) toma 4 µs; una ráfaga de 5 bytes, 10 µs. Para comparar, una UART a 115 200 baudios necesita unos 87 µs para enviar un byte de datos (10 bits), unas 43 veces más.

La frecuencia máxima depende del dispositivo: de 1 MHz en sensores sencillos a 10–50 MHz en memorias, pantallas y conversores rápidos, y se limita además por el cableado (tema 13) y por lo que aguante el microcontrolador. En la práctica hay que sumar también el tiempo de CS y la pausa entre bytes que muchos microcontroladores dejan, así que la velocidad real queda algo por debajo de la ideal.

Comparación de las tres soluciones de bus de placa (se completa con I²C en los temas 16 a 20).
AspectoUARTSPII²C
Líneas2 (TX, RX)3 + una CS por esclavo2 (SDA, SCL), siempre
RelojNo (asíncrono)Sí, lo genera el maestroSí, lo genera el maestro
DúplexFull (dos líneas)Full (MOSI y MISO a la vez)Half (una línea de datos)
Selección de esclavoNo hay (punto a punto)Línea CS por esclavoDirección de 7 bits en el mensaje
Velocidad típica9600 a 115 200 baudios (hasta 1 a 3 Mbps)1 a 50 MHz100 kHz a 1 MHz (hasta 3,4 MHz)
Sobrecarga por byte25 % (2 bits de 10)Casi nula (el comando y el CS)~11 % (ACK) más direcciones
DistanciaMetros (con RS-232/RS-485, más)Centímetros a decenas de centímetrosDecenas de centímetros
Esclavo avisa por sí mismoSí, puede enviarNo (necesita línea INT)No (necesita línea INT)

Cuándo conviene SPI: cuando importa la velocidad (pantallas, tarjetas SD, memorias), cuando hay pocos esclavos y se pueden dedicar los pines, o cuando se quiere un esclavo muy simple de implementar. Cuándo conviene otra cosa: cuando faltan pines (I²C usa dos para todos los dispositivos), cuando la distancia pasa de unos pocos centímetros (RS-485, CAN) o cuando el esclavo tiene que hablar sin que le pregunten.

08 · Con el microcontrolador

Con el microcontrolador

En Arduino, la biblioteca SPI maneja el periférico de hardware. En un Uno los pines están fijos: SCK = 13, MISO = 12, MOSI = 11 y el pin 10 como CS por convención (puede ser cualquier otro pin digital). En el ESP32 hay dos buses de uso general (VSPI y HSPI) cuyos pines se pueden reasignar. La función clave es SPI.transfer(byte): envía un byte y devuelve el byte recibido, exactamente como el intercambio de los registros.

#include <SPI.h>

const byte PIN_CS = 10;
const SPISettings AJUSTES(4000000, MSBFIRST, SPI_MODE0);   // 4 MHz, bit 7 primero, modo 0 (tema 13)

byte leerRegistro(byte direccion) {
    SPI.beginTransaction(AJUSTES);
    digitalWrite(PIN_CS, LOW);                // selecciona el dispositivo
    SPI.transfer(0x80 | direccion);           // comando: lectura + dirección (lo recibido se descarta)
    byte dato = SPI.transfer(0x00);           // byte de relleno: durante estos 8 pulsos llega el dato
    digitalWrite(PIN_CS, HIGH);               // fin de la transacción
    SPI.endTransaction();
    return dato;
}

void escribirRegistro(byte direccion, byte valor) {
    SPI.beginTransaction(AJUSTES);
    digitalWrite(PIN_CS, LOW);
    SPI.transfer(direccion & 0x7F);           // bit 7 en cero = escritura
    SPI.transfer(valor);
    digitalWrite(PIN_CS, HIGH);
    SPI.endTransaction();
}

void leerRafaga(byte direccion, byte *destino, byte cantidad) {
    SPI.beginTransaction(AJUSTES);
    digitalWrite(PIN_CS, LOW);
    SPI.transfer(0x80 | direccion);
    for (byte i = 0; i < cantidad; i++) destino[i] = SPI.transfer(0x00);
    digitalWrite(PIN_CS, HIGH);
    SPI.endTransaction();
}

void setup() {
    Serial.begin(115200);
    pinMode(PIN_CS, OUTPUT);
    digitalWrite(PIN_CS, HIGH);               // CS inactivo desde el principio
    SPI.begin();
}

void loop() {
    byte r[4];
    leerRafaga(0, r, 4);
    Serial.print("R0..R3: ");
    for (byte i = 0; i < 4; i++) { Serial.print(r[i], HEX); Serial.print(' '); }
    Serial.println();
    delay(1000);
}

Cuatro detalles del código. SPISettings reúne frecuencia, orden de bits y modo, y beginTransaction los aplica solo mientras dura esta conversación (necesario si otro código usa el bus con otros ajustes, como una pantalla y una tarjeta SD juntas). El pin CS se configura como salida y se deja en alto antes de SPI.begin(), para que el dispositivo no vea un CS bajo espurio al arrancar. En leerRegistro, el valor de retorno de la primera transfer se ignora: no tiene significado. Y todo el bloque está entre dos cambios de CS: las funciones no se pueden mezclar con otras transacciones a medias.

Para entender qué hace el periférico de hardware, esta es la misma transferencia hecha «a mano» con tres pines, por manejo directo de bits (bit banging), más lenta, pero idéntica en el resultado:

byte transferirManual(byte salida) {              // modo 0, MSB primero
    byte entrada = 0;
    for (byte i = 0; i < 8; i++) {
        digitalWrite(PIN_MOSI, (salida & 0x80) ? HIGH : LOW);   // el bit 7 sale por MOSI
        salida <<= 1;
        digitalWrite(PIN_SCK, HIGH);              // flanco de subida: el esclavo muestrea MOSI y pone su bit en MISO
        entrada = (entrada << 1) | digitalRead(PIN_MISO);   // el bit que llega entra por el bit 0
        digitalWrite(PIN_SCK, LOW);               // flanco de bajada: se prepara el siguiente bit
    }
    return entrada;
}

Es el algoritmo de la sección 03 hecho código: ocho veces, sacar el bit 7, desplazar, dar un pulso y recoger el bit entrante. Con digitalWrite el reloj queda en decenas de kHz; el hardware llega a megahertz. El orden exacto de las operaciones respecto de los flancos (¿en cuál se muestrea?) es la cuestión de los modos SPI del tema siguiente.

09 · Analogía con programación

El anillo y los registros en Python

Modelar los dos registros y el dispositivo con registros es la mejor forma de entender qué ocurre en el bus. El programa siguiente implementa el intercambio pulso a pulso, un dispositivo con cuatro registros que obedece la convención de comando de la sección 06, y calcula el tiempo de las transferencias. Es el mismo modelo que usa el laboratorio.

Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.

def intercambiar(maestro, esclavo, bits=8):
    """Un byte SPI: 8 pulsos de reloj, y los dos registros giran juntos."""
    for _ in range(bits):
        mosi = (maestro >> (bits - 1)) & 1
        miso = (esclavo >> (bits - 1)) & 1
        maestro = ((maestro << 1) & 0xFF) | miso
        esclavo = ((esclavo << 1) & 0xFF) | mosi
    return maestro, esclavo


class Dispositivo:
    """Cuatro registros. Comando: bit 7 = lectura, bits 6-0 = dirección, con autoincremento."""
    def __init__(self):
        self.regs = [0x60, 0x2A, 0x00, 0x7E]

    def transaccion(self, enviados):
        salida, direccion, lectura = 0x00, 0, False
        recibidos = []
        for i, byte in enumerate(enviados):
            al_maestro, al_esclavo = intercambiar(byte, salida)
            recibidos.append(al_maestro)
            if i == 0:
                lectura = bool(al_esclavo & 0x80)
                direccion = al_esclavo & 0x7F
            elif not lectura:
                if direccion < len(self.regs):
                    self.regs[direccion] = al_esclavo
                direccion += 1
            if lectura:
                salida = self.regs[direccion] if direccion < len(self.regs) else 0xFF
                direccion += 1
            else:
                salida = 0x00
        return recibidos


def tiempo_us(bytes_, frecuencia_hz):
    return bytes_ * 8 / frecuencia_hz * 1e6


m, e = intercambiar(0xA5, 0x3C)
print(f"Maestro 0xA5 y esclavo 0x3C -> maestro {m:#04x}, esclavo {e:#04x}")

d = Dispositivo()
print("Lectura R1:      ", [f"{b:#04x}" for b in d.transaccion([0x81, 0x00])])
print("Ráfaga R0..R3:   ", [f"{b:#04x}" for b in d.transaccion([0x80, 0, 0, 0, 0])])
print("Ráfaga R2..R5:   ", [f"{b:#04x}" for b in d.transaccion([0x82, 0, 0, 0, 0])])
d.transaccion([0x02, 0x5A])
print("Tras escribir 0x5A en R2:", [f"{r:#04x}" for r in d.regs])

print()
print("bytes  1 MHz    4 MHz    10 MHz   (tiempo de la transferencia)")
for n in (2, 5, 64):
    print(f"{n:5d}  " + "  ".join(f"{tiempo_us(n, f):6.1f} µs" for f in (1e6, 4e6, 10e6)))

Resultado: el intercambio de 0xA5 y 0x3C deja al maestro con 0x3C y al esclavo con 0xA5. La lectura de R1 devuelve ['0x00', '0x2a']: el primer byte no tiene significado y el dato (0x2A) llega en el segundo. La ráfaga de cuatro desde R0 entrega 0x60 0x2a 0x00 0x7e detrás de un primer byte vacío. La ráfaga desde R2 pide cuatro y el mapa solo tiene dos registros útiles: 0x00 0x7e 0xff 0xff, es decir, R2, R3 y dos bytes sin valor. Después de escribir 0x5A en R2, los registros quedan [0x60, 0x2a, 0x5a, 0x7e]. En el cuadro de tiempos, 2 bytes cuestan 4,0 µs a 4 MHz, 5 bytes 10,0 µs y 64 bytes 128,0 µs; a 10 MHz los tiempos bajan a 1,6, 4,0 y 51,2 µs.

Probá cambiar el comando de la ráfaga de 0x80 a 0x00: en lugar de leer, el dispositivo interpreta que se está escribiendo, guarda los ceros de relleno en los registros y se borran. Un único bit del comando separa «consultar» de «destruir los datos».

10 · Exploración interactiva

Laboratorio: el anillo y los registros

El laboratorio tiene dos herramientas. En la primera, tomás el control del reloj: cada pulso desplaza los dos registros y podés ver cómo los bits dan la vuelta por MOSI y MISO. En la segunda hay un dispositivo con cuatro registros: ejecutás lecturas, escrituras y ráfagas y mirás el diálogo byte a byte, con el tiempo que tardaría a 4 MHz.

1. Maestro y esclavo, pulso a pulso

Maestro—
Esclavo—
CS—
Pulsos de SCLK—
Último bit por MOSI—
Último bit por MISO—
Maestro (hex)—
Esclavo (hex)—

Elegí los valores de los dos registros y presioná «Un pulso de reloj».

2. Dispositivo con cuatro registros

R0—
R1—
R2—
R3—
Pulsos de SCLK—
Tiempo a 4 MHz—
Bytes de la última transacción, con CS en bajo.
ByteMOSI (maestro envía)MISO (maestro recibe)Qué ocurre
Todavía no se ejecutó ninguna transacción.

Elegí una operación y presioná «Ejecutar transacción».

En la primera herramienta, los bits resaltados son los que ya llegaron del otro registro; después del octavo pulso, todos los bits de cada registro vinieron del otro. La segunda aplica la convención de la sección 06: bit 7 del primer byte = lectura, dirección en los bits 6 a 0 y autoincremento. El tiempo se calcula a 4 MHz, sin contar el cambio de CS.

Recorrido guiado

  1. Con los valores iniciales (maestro 165 = 0xA5, esclavo 60 = 0x3C), presioná «Un pulso de reloj» una vez: salió un 1 por MOSI (el bit 7 de 10100101) y un 0 por MISO (el bit 7 de 00111100). Cada registro se desplazó y recibió el bit del otro en el extremo derecho.
  2. Seguí con los pulsos hasta el 8. Los registros están intercambiados: el maestro tiene 0x3C y el esclavo 0xA5. Compará cada paso con la tabla de la sección 03.
  3. Reiniciá con el esclavo en 0: ahora el maestro recibe ocho ceros y el esclavo termina con una copia de lo que tenía el maestro. Es lo que ocurre en una escritura: el dato llega y lo que vuelve no sirve.
  4. Probá con el maestro en 0 y el esclavo en 42: el maestro termina con una copia del dato del esclavo. Es una lectura: el byte de relleno nulo «presta» los pulsos. Ponelo en 255 y verás lo mismo con otro relleno.
  5. En la herramienta 2, ejecutá «Leer un registro» en R1. La transacción lleva dos bytes (16 pulsos, 4,0 µs). El segundo byte recibido es 0x2A; el primero se marca «sin significado».
  6. Elegí «Escribir un registro» en R2 con el valor 90 (0x5A). El comando enviado es 0x02 y los registros muestran el cambio. Lo que vuelve por MISO no tiene significado.
  7. Pasá a «Leer ráfaga» desde R0 con 4 bytes: con un solo comando se leen R0, R1, R2 y R3 (el R2 ahora es 0x5A). La transacción tiene 5 bytes y tarda 10,0 µs.
  8. Pedí una ráfaga de 6 bytes desde R2: el dispositivo se queda sin registros y devuelve 0xFF. El maestro no recibe ningún aviso: es responsabilidad del programa saber cuántos registros hay.
  9. Con «Restaurar registros» volvés a los valores iniciales y repetís las pruebas con el mismo punto de partida.
Desafío: la escritura que borra

En la herramienta 2, ejecutá una ráfaga de lectura. Ahora pensá: si el maestro enviara 0x00 en lugar de 0x80 como comando, seguido de cuatro bytes en cero, ¿qué le pasaría a los registros? El dispositivo interpretaría una escritura desde R0 y guardaría los cuatro ceros de relleno: R0 a R3 quedarían en 0x00. El bit 7 del comando es todo lo que separa una consulta inofensiva de una orden que destruye los datos, y por eso la hoja de datos siempre dice cuál es el valor de lectura y cuál el de escritura.

11 · Puesta en marcha

Cómo se depura un enlace SPI

SPI falla de formas distintas a la UART. Como el reloj siempre lo pone el maestro, no hay problemas de baudios; en cambio, hay que cuidar los niveles, el orden y el sentido de los hilos. Una receta por etapas:

  1. Verificá el cableado contra la hoja de datos: MOSI con el pin de datos de entrada del esclavo (SDI) y MISO con el de salida (SDO). Aquí no se cruza TX con RX: cada nombre se conecta con el mismo nombre en maestro y esclavo (las etiquetas del fabricante pueden ser confusas, por eso conviene usar MOSI/MISO del lado del maestro). Masa común y alimentación correcta.
  2. Prueba de lazo: uní MOSI con MISO del maestro con un cable y enviá un byte. Si SPI.transfer(0x5A) devuelve 0x5A, el periférico del microcontrolador funciona, aunque el esclavo no esté conectado.
  3. Leé un registro conocido. Casi todos los dispositivos tienen un registro de identificación («WHO_AM_I») con un valor fijo. Si lo leés bien, el cableado, el modo SPI y los niveles son correctos. Si da 0x00 o 0xFF, sospechá de: CS que no baja, MISO sin conectar (0xFF por el pull-up interno o 0x00 por el pull-down), modo SPI equivocado o frecuencia demasiado alta.
  4. Observá con el analizador lógico los cuatro canales a la vez: ver CS bajar, los pulsos de SCLK, el byte de comando en MOSI y la respuesta en MISO resuelve casi cualquier duda. Los analizadores decodifican SPI directamente, mostrando los bytes en hexadecimal.
  5. Subí la frecuencia de a poco. Empezá en 100 kHz o 1 MHz, y subí hasta el valor de la hoja de datos solo cuando todo funciona. Un cable largo o un protoboard con contactos flojos deja de funcionar al subir.
Síntomas comunes en SPI y su causa más probable.
SíntomaCausa probable
Todas las lecturas dan 0xFFEl esclavo no responde: CS no baja, MISO desconectado o alimentación caída
Todas las lecturas dan 0x00MISO unido a masa, esclavo sin alimentar o salida deshabilitada
El dato llega desplazado un bit (valores x2 o /2)Modo SPI incorrecto (tema 13) o primer byte descartado de más
El dato llega un byte corridoSe leyó la respuesta durante el byte del comando, o falta un byte de relleno
Funciona lento y falla rápidoFrecuencia mayor a la que aguantan el cable o el dispositivo
Dos dispositivos se interfierenDos CS en bajo a la vez, o un esclavo no suelta MISO al estar deseleccionado
Falla solo al arrancarCS flotante antes de configurarlo como salida: se debe poner en alto desde el inicio

12 · Comprensión

Confusiones frecuentes

«SPI envía y después recibe, como una UART»

No. Envía y recibe al mismo tiempo, con los mismos ocho pulsos: es un intercambio de dos registros. Para leer hay que enviar un byte, y lo que se recibe mientras se escribe suele descartarse.

«Para leer un dato el maestro solo tiene que escuchar»

El esclavo no puede hablar sin reloj, y el reloj lo pone el maestro. Por eso una lectura se hace enviando bytes de relleno: sin ellos, el esclavo no tiene pulsos con los cuales contestar.

«MOSI del maestro va con MISO del esclavo (cruzado, como TX con RX)»

No: en SPI los nombres coinciden. MOSI es la salida del maestro y la entrada del esclavo; MISO es la entrada del maestro y la salida del esclavo. Las etiquetas de un módulo (SDI, SDO, DIN, DOUT) son las que inducen a error: se leen siempre desde el punto de vista del propio dispositivo.

«CS es opcional si solo tengo un esclavo»

Muchos esclavos lo exigen igual: es lo que les marca el comienzo y el final de cada mensaje. Algunos módulos lo traen fijo a masa y funcionan, pero pierden la capacidad de recuperarse de un error de sincronía. Lo normal es manejarlo siempre.

«Más velocidad siempre es mejor»

Se limita por el esclavo (hoja de datos), el microcontrolador y, sobre todo, el cableado: a varios megahertz un cable largo o un protoboard distorsionan los flancos. Se sube la frecuencia con cuidado y se comprueba con un registro de valor conocido.

«SPI es un estándar con reglas fijas»

Define solo las líneas y el principio del registro de desplazamiento. El modo (tema 13), el orden de bits, el formato de los comandos y los tiempos varían según el fabricante y se encuentran siempre en la hoja de datos.

13 · Práctica guiada

Predecí antes de comprobar

1. Tres pulsos

El maestro tiene 0xA5 (10100101) y el esclavo 0x3C (00111100). ¿Qué valores tienen los registros después de tres pulsos de reloj?

Ver solución

Cada registro se corrió tres lugares a la izquierda y recibió en la derecha los tres primeros bits del otro. Maestro: 00101000 | 001 = 00101001 = 0x29. Esclavo: 11100000 | 101 = 11100101 = 0xE5. Coincide con la fila del pulso 3 de la tabla. Comprobalo en la herramienta 1.

2. Cuánto tarda

Un sensor se lee en una transacción de 6 bytes a 2 MHz. ¿Cuánto dura, sin contar el cambio de CS? ¿Y a 8 MHz?

Ver solución

6 bytes = 48 bits. A 2 MHz: 48 / 2 000 000 = 24 µs. A 8 MHz: 48 / 8 000 000 = 6 µs. El tiempo es inversamente proporcional a la frecuencia.

3. Armar los bytes

Con la convención del laboratorio, ¿qué bytes envía el maestro para (a) leer R3, (b) escribir 0x10 en R1?

Ver solución

(a) 0x83 (bit 7 en 1 + dirección 3) y 0x00 de relleno; el dato llega en el segundo byte recibido. (b) 0x01 (bit 7 en 0 + dirección 1) y 0x10. En (b) lo que vuelve por MISO se ignora.

4. Una ráfaga que se pasa

Se piden 4 bytes en ráfaga desde R2, con el mapa de este tema (R0 a R3). ¿Qué recibe el maestro, byte por byte, y cuál es el problema?

Ver solución

Se envían 5 bytes: 0x82 y cuatro de relleno. El maestro recibe: un byte sin significado, 0x00 (R2), 0x7E (R3), 0xFF y 0xFF. Los dos últimos no son datos: el dispositivo no avisa que se acabó el mapa, así que hay que pedir como máximo los 2 registros que existen.

5. Cuántos pines

Un microcontrolador maneja cinco periféricos SPI en el mismo bus. ¿Cuántas líneas necesita para ellos con SPI? ¿Y con I²C?

Ver solución

SPI: SCLK, MOSI y MISO compartidas más una CS por esclavo: 3 + 5 = 8 líneas. I²C: 2 líneas (SDA y SCL) para todos, porque cada uno tiene su dirección. SPI gana en velocidad y simplicidad del esclavo; I²C, en cantidad de pines (se verá en los temas 16 a 20).

6. ¿Por qué un byte de relleno?

Un compañero propone leer un sensor SPI «sin enviar nada, solo escuchando MISO» para ahorrar tiempo. ¿Qué le respondés?

Ver solución

No funciona: el reloj lo genera el maestro y solo hay pulsos cuando envía un byte, aunque sea de relleno. Sin pulsos de SCLK, el esclavo no desplaza su registro y MISO se queda quieto. La lectura es siempre un intercambio: se envían ocho bits de relleno (típicamente 0x00) y, durante esos pulsos, el dato viaja de vuelta.

14 · Síntesis

Ideas para recordar

  • SPI usa cuatro líneas: SCLK (reloj del maestro), MOSI (datos hacia el esclavo), MISO (datos desde el esclavo) y CS (selección, activa en bajo), más masa común.
  • El maestro y el esclavo tienen un registro de desplazamiento unido en anillo: en ocho pulsos intercambian sus bytes. Enviar y recibir son una sola operación.
  • El esclavo no tiene reloj propio ni puede iniciar nada: todo ocurre con los pulsos del maestro, y una pausa congela la transferencia sin perder sincronía.
  • CS delimita la transacción: se baja antes del primer pulso, se sube después del último, y deja al esclavo listo para empezar de nuevo.
  • Para leer hay que enviar un byte de relleno que preste los pulsos; para escribir, lo que vuelve se ignora. En una lectura con comando, el primer byte recibido no tiene significado.
  • Una convención muy común: primer byte con bit 7 = lectura/escritura y bits 6 a 0 = dirección; la ráfaga incrementa la dirección sola, y salirse del mapa devuelve basura sin aviso.
  • Sin bits de control, la velocidad útil es fSCLK / 8 bytes por segundo: de 1 a 50 MHz, mucho más rápido que UART e I²C, pero a corta distancia y con una línea CS por esclavo.
  • SPI no es un estándar rígido: el modo, el formato de comandos y los tiempos dependen del dispositivo y están en la hoja de datos.

¿Listo para el siguiente tema?

Antes de avanzar, explicá con un dibujo cómo se intercambian 0x5C (maestro) y 0xA3 (esclavo) en ocho pulsos, escribí la secuencia de bytes de una lectura de dos registros consecutivos desde la dirección 5 y calculá el tiempo que tarda a 8 MHz. Si podés justificar las tres respuestas, tenés clara la base de SPI.

En el próximo tema vemos lo que dejamos pendiente: los cuatro modos SPI (CPOL y CPHA), cómo elegir la frecuencia máxima y cómo leer una hoja de datos para configurar el bus sin probar a ciegas.