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:
| Línea | Significado | Quién la maneja | Otros nombres |
|---|---|---|---|
SCLK | Reloj serie: cada pulso mueve un bit | Maestro | SCK, CLK |
MOSI | Master Out, Slave In: datos del maestro al esclavo | Maestro | SDO (del maestro), COPI, SDI en el esclavo |
MISO | Master In, Slave Out: datos del esclavo al maestro | Esclavo | SDI (del maestro), CIPO, SDO en el esclavo |
CS | Chip Select: avisa a qué esclavo se le habla (activa en nivel bajo) | Maestro | SS, nCS, CSn |
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.
En cada pulso de SCLK ocurre lo mismo en los dos registros a la vez:
- Cada uno pone en su línea de salida su bit más significativo (bit 7).
- Todos los bits se desplazan un lugar hacia la izquierda.
- 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.
| Pulso | Sale por MOSI | Sale por MISO | Maestro después | Esclavo después |
|---|---|---|---|---|
| 0 (inicio) | — | — | 10100101 | 00111100 |
| 1 | 1 | 0 | 01001010 | 01111001 |
| 2 | 0 | 0 | 10010100 | 11110010 |
| 3 | 1 | 1 | 00101001 | 11100101 |
| 4 | 0 | 1 | 01010011 | 11001010 |
| … | los pulsos 5 a 7 siguen el mismo patrón | … | … | |
| 8 (fin) | 1 | 0 | 00111100 (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:
| Operación | MOSI (maestro envía) | MISO (maestro recibe) |
|---|---|---|
| Leer R1 | 0x81 (lectura + dirección 1), 0x00 (relleno) | sin significado, 0x2A (el dato) |
| Escribir 0x5A en R2 | 0x02 (escritura + dirección 2), 0x5A | sin significado, sin significado |
| Leer ráfaga de 4 desde R0 | 0x80, 0x00, 0x00, 0x00, 0x00 | sin 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:
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.
| Aspecto | UART | SPI | I²C |
|---|---|---|---|
| Líneas | 2 (TX, RX) | 3 + una CS por esclavo | 2 (SDA, SCL), siempre |
| Reloj | No (asíncrono) | Sí, lo genera el maestro | Sí, lo genera el maestro |
| Dúplex | Full (dos líneas) | Full (MOSI y MISO a la vez) | Half (una línea de datos) |
| Selección de esclavo | No hay (punto a punto) | Línea CS por esclavo | Dirección de 7 bits en el mensaje |
| Velocidad típica | 9600 a 115 200 baudios (hasta 1 a 3 Mbps) | 1 a 50 MHz | 100 kHz a 1 MHz (hasta 3,4 MHz) |
| Sobrecarga por byte | 25 % (2 bits de 10) | Casi nula (el comando y el CS) | ~11 % (ACK) más direcciones |
| Distancia | Metros (con RS-232/RS-485, más) | Centímetros a decenas de centímetros | Decenas de centímetros |
| Esclavo avisa por sí mismo | Sí, puede enviar | No (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
Elegí los valores de los dos registros y presioná «Un pulso de reloj».
2. Dispositivo con cuatro registros
| Byte | MOSI (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
- 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.
- 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.
- 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.
- 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.
- 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».
- 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.
- 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.
- 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.
- 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:
- 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.
- 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. - 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.
- 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.
- 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íntoma | Causa probable |
|---|---|
| Todas las lecturas dan 0xFF | El esclavo no responde: CS no baja, MISO desconectado o alimentación caída |
| Todas las lecturas dan 0x00 | MISO 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 corrido | Se leyó la respuesta durante el byte del comando, o falta un byte de relleno |
| Funciona lento y falla rápido | Frecuencia mayor a la que aguantan el cable o el dispositivo |
| Dos dispositivos se interfieren | Dos CS en bajo a la vez, o un esclavo no suelta MISO al estar deseleccionado |
| Falla solo al arrancar | CS 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.