01 · Punto de partida
Velocidad a cambio de cables
I2C ahorra cables, pero paga con velocidad: las resistencias de pull-up limitan los flancos y cada byte lleva un bit de confirmación. SPI (Serial Peripheral Interface, de Motorola) elige el camino opuesto. Cada línea tiene una sola función, las salidas son activas (empujan tanto a alto como a bajo) y no hay direcciones ni ACK. Eso lo hace sencillo en hardware y capaz de llegar a decenas de megahertz.
Sus usos típicos son los que necesitan ancho de banda: pantallas gráficas TFT y OLED rápidas, tarjetas SD, memorias Flash y EEPROM, conversores analógico-digitales y DAC como el MCP4921 del tema 29, módulos de radio, y cadenas de registros de desplazamiento para sacar muchos pines de salida. A cambio, hay que dedicar pines: tres compartidos más uno por cada dispositivo.
No existe un estándar oficial de SPI: cada fabricante lo describe a su manera y los detalles (modo, orden de bits, longitud de palabra) están en cada hoja de datos. Por eso saber leer un diagrama de tiempos importa más que memorizar valores.
02 · El principio
Cuatro líneas y un anillo
El bus tiene cuatro líneas:
- SCK (reloj): lo genera el maestro. Un pulso por cada bit.
- MOSI (master out, slave in): del maestro al esclavo.
- MISO (master in, slave out): del esclavo al maestro.
- CS o SS (chip select, selección de chip): el maestro la baja para elegir al esclavo. Con CS en alto, el esclavo ignora el bus y deja su salida MISO en alta impedancia.
La idea central: el maestro y el esclavo tienen cada uno un registro de desplazamiento de 8 bits, y los dos forman un anillo. En cada pulso de SCK, el bit más significativo del maestro sale por MOSI y entra por el extremo bajo del registro del esclavo, mientras el bit más significativo del esclavo sale por MISO y entra en el del maestro. Después de 8 pulsos, ambos registros han intercambiado su contenido. Por eso SPI es dúplex completo: siempre que se envía un byte, se recibe otro, aunque uno de los dos sea irrelevante.
Si querés leer del esclavo, el maestro envía un byte «de relleno» (por ejemplo 0x00) solo para generar los 8 pulsos; si querés escribir y no te interesa la respuesta, descartás el byte recibido. Esa simetría explica por qué la función básica de SPI se llama transferir y no enviar o recibir.
03 · Cuándo se lee
Los cuatro modos de reloj
Como no hay un estándar, los dispositivos difieren en cuándo cambian y cuándo leen los datos. Se describe con dos parámetros:
- CPOL (polaridad del reloj): nivel de SCK en reposo. 0 = bajo, 1 = alto.
- CPHA (fase del reloj): en cuál de los dos flancos de cada pulso se lee el dato. 0 = en el primero (el de salida del reposo); 1 = en el segundo.
| Modo | CPOL | CPHA | SCK en reposo | Se lee en | El dato cambia en |
|---|---|---|---|---|---|
| 0 | 0 | 0 | Bajo | Subida | Bajada |
| 1 | 0 | 1 | Bajo | Bajada | Subida |
| 2 | 1 | 0 | Alto | Bajada | Subida |
| 3 | 1 | 1 | Alto | Subida | Bajada |
Un truco para no memorizarlo: si CPOL ⊕ CPHA = 0 (modos 0 y 3), se lee en el flanco de subida; si es 1 (modos 1 y 2), en el de bajada. Los modos 0 y 3 son los más comunes. La primera herramienta del laboratorio dibuja los cuatro.
Las dos puntas deben usar el mismo modo. Si no, el maestro lee los bits en el momento en que el esclavo los está cambiando, y el resultado son datos corridos un bit o basura. La hoja de datos de un dispositivo dice cosas como «el reloj es alto en reposo y los datos se capturan en el flanco de subida» (modo 3) o simplemente «modo 0».
Otros dos parámetros importan: el orden de los bits (casi siempre el más significativo primero, MSB; algunos pocos chips usan LSB primero) y la longitud de la palabra (8 bits en el ATmega328P; muchos dispositivos usan 16, y se envían como dos bytes seguidos).
04 · Varios dispositivos
Selección de chip y varios esclavos
SPI no tiene direcciones: el maestro elige al esclavo con una línea dedicada. Con CS en alto, el esclavo está desconectado: ignora SCK y MOSI y deja MISO en alta impedancia (Hi-Z), de modo que no interfiere con los demás. Al bajar CS, empieza una transacción, y al subirla, termina. La mayoría de los dispositivos reinician su estado interno con el flanco de CS: subir CS en medio de un comando lo aborta.
Hay dos formas de conectar varios esclavos:
- Independientes (estrella): SCK, MOSI y MISO se comparten y cada esclavo tiene su CS. Es lo habitual. Necesita 3 + n pines. Cuando faltan pines, se usa un decodificador (un 74HC138 maneja 8 esclavos con 3 pines) o un expansor.
- En cadena (daisy chain): la salida del primer esclavo (MISO) se conecta a la entrada del siguiente, y todos comparten un único CS. El maestro envía n bytes seguidos y cada uno queda en el esclavo que le corresponde (el primero que se envía acaba en el último de la cadena). Es la conexión de los registros de desplazamiento 74HC595 y de ciertos controladores de LED. Usa 4 pines sin importar la cantidad.
Una advertencia clásica: solo un esclavo debe tener CS en bajo a la vez. Si dos están seleccionados, ambos manejan MISO y se pelean por la línea. Y al iniciar el programa, todas las líneas CS deben ponerse en alto antes de configurar el bus, para que ningún dispositivo reciba basura mientras los pines están indefinidos.
05 · Periférico
El módulo SPI del ATmega328P
| Señal | Pin del chip | Arduino Uno |
|---|---|---|
| SCK | PB5 | 13 (también el LED integrado) |
| MISO | PB4 | 12 |
| MOSI | PB3 | 11 |
| SS | PB2 | 10 |
El módulo se controla con tres registros. SPDR es el registro de datos: escribirlo inicia la transferencia de ese byte y, al terminar, contiene el byte recibido. SPSR tiene la bandera SPIF (transferencia completa, se borra al leer SPSR y luego SPDR), la bandera de colisión de escritura WCOL y el bit de doble velocidad SPI2X. SPCR configura el resto:
| Bit | Nombre | Función |
|---|---|---|
| 7 | SPIE | Habilita la interrupción de fin de transferencia |
| 6 | SPE | Habilita el módulo SPI |
| 5 | DORD | Orden de datos: 0 = MSB primero; 1 = LSB primero |
| 4 | MSTR | 1 = maestro; 0 = esclavo |
| 3 | CPOL | Polaridad del reloj |
| 2 | CPHA | Fase del reloj |
| 1:0 | SPR1:SPR0 | Divisor del reloj (con SPI2X) |
| SPI2X | SPR1:0 | Divisor | SCK con 16 MHz |
|---|---|---|---|
| 1 | 00 | 2 | 8 MHz |
| 0 | 00 | 4 | 4 MHz |
| 1 | 01 | 8 | 2 MHz |
| 0 | 01 | 16 | 1 MHz |
| 1 | 10 | 32 | 500 kHz |
| 0 | 10 | 64 | 250 kHz |
| 0 | 11 | 128 | 125 kHz |
El mínimo es 2 porque el módulo necesita al menos dos ciclos del procesador por bit: a 8 MHz, un byte tarda 1 µs. El reloj del módulo SPI sale del mismo oscilador que la CPU, de modo que cambiar la frecuencia de la CPU cambia también la de SCK.
06 · Primer programa
Código de maestro
La función básica es de tres líneas: escribir el byte, esperar la bandera y devolver lo recibido.
#define F_CPU 16000000UL
#include <avr/io.h>
#include <stdint.h>
#define CS_DAC_BAJO() (PORTB &= ~(1 << PB2))
#define CS_DAC_ALTO() (PORTB |= (1 << PB2))
#define CS_MEM_BAJO() (PORTB &= ~(1 << PB1))
#define CS_MEM_ALTO() (PORTB |= (1 << PB1))
static void spi_init(void) {
PORTB |= (1 << PB2) | (1 << PB1); // todos los CS en alto primero
DDRB |= (1 << PB3) | (1 << PB5) | (1 << PB2) | (1 << PB1); // MOSI, SCK, SS y CS de la memoria
SPCR = (1 << SPE) | (1 << MSTR); // maestro, modo 0, MSB primero, f/4
SPSR = (1 << SPI2X); // f/2 = 8 MHz
}
static uint8_t spi_transferir(uint8_t dato) {
SPDR = dato; // inicia la transferencia
while (!(SPSR & (1 << SPIF))) { } // 8 pulsos de SCK
return SPDR; // el byte que llegó por MISO
}
Con eso se manejan los dispositivos reales. El DAC MCP4921 del tema 29 recibe una palabra de 16 bits en una sola transacción (CS en bajo durante los dos bytes):
static void dac_escribir(uint16_t valor12) {
uint16_t palabra = 0x3000 | (valor12 & 0x0FFF); // configuración + 12 bits de dato
CS_DAC_BAJO();
spi_transferir((uint8_t)(palabra >> 8));
spi_transferir((uint8_t)(palabra & 0xFF));
CS_DAC_ALTO(); // al subir CS el DAC actualiza la salida
}
Una memoria EEPROM o Flash serie (del tipo 25LC256) se lee con un comando de un byte, una dirección y tantos bytes de relleno como datos se pidan. Para recibir se envía 0x00: lo que importa es el byte que vuelve.
#define MEM_LEER 0x03
#define MEM_WREN 0x06
#define MEM_ESCRIBIR 0x02
static void mem_leer(uint16_t dir, uint8_t *destino, uint8_t n) {
CS_MEM_BAJO();
spi_transferir(MEM_LEER);
spi_transferir((uint8_t)(dir >> 8));
spi_transferir((uint8_t)(dir & 0xFF));
while (n--) *destino++ = spi_transferir(0x00); // relleno para generar los pulsos
CS_MEM_ALTO();
}
static void mem_escribir_byte(uint16_t dir, uint8_t dato) {
CS_MEM_BAJO(); spi_transferir(MEM_WREN); CS_MEM_ALTO(); // habilitar escritura (transacción propia)
CS_MEM_BAJO();
spi_transferir(MEM_ESCRIBIR);
spi_transferir((uint8_t)(dir >> 8));
spi_transferir((uint8_t)(dir & 0xFF));
spi_transferir(dato);
CS_MEM_ALTO(); // al subir CS comienza el ciclo interno de escritura
/* esperar unos milisegundos o consultar el registro de estado (bit WIP) antes de la próxima escritura */
}
La memoria enseña dos hábitos de SPI. Primero: el flanco de subida de CS es una orden: en la escritura, es el que arranca el ciclo interno. Segundo: algunos comandos exigen su propia transacción (WREN va con un CS completo antes del comando de escritura). La hoja de datos define cuál es cuál.
Un caso curioso: una cadena de tres registros de desplazamiento 74HC595 (24 salidas con 4 pines). Se envían los tres bytes seguidos y se da un pulso al pin de latch (RCLK) que copia el contenido a las salidas. El primer byte enviado termina en el último registro de la cadena.
static void cadena_escribir(const uint8_t *datos, uint8_t n) {
for (uint8_t i = 0; i < n; i++) spi_transferir(datos[i]); // el primero llega al último registro
PORTB |= (1 << PB2); // latch (RCLK): salidas = registros
PORTB &= ~(1 << PB2);
}
07 · En un sistema real
Compartir el bus
Cuando varios dispositivos cuelgan del mismo bus, aparecen cuestiones de convivencia:
- Modos y velocidades distintos. Un dispositivo puede pedir modo 0 a 10 MHz y otro modo 3 a 1 MHz. Entonces se reconfiguran
SPCRySPSRal comenzar cada transacción (la bibliotecaSPIde Arduino lo hace conbeginTransaction()). - Tarjetas SD. Se inicializan a 400 kHz o menos, con CS en alto y al menos 74 pulsos de reloj, y recién después se sube la velocidad.
- Interrupciones. Si una ISR usa el mismo bus que el programa principal, hay que protegerse: una transferencia interrumpida por otra rompe ambas (tema 21). Lo normal es no usar SPI desde las ISR, o desactivar las interrupciones durante la transacción.
- Niveles de tensión. Un dispositivo de 3,3 V no tolera 5 V en MOSI, SCK ni CS. La señal de 3,3 V en MISO hacia un chip de 5 V suele funcionar, porque supera el umbral de 3 V. Los conversores de nivel o los divisores resuelven la dirección de 5 V a 3,3 V.
- Cables. A varios megahertz, los flancos son rápidos y los cables largos producen rebotes y diafonía. SPI está pensado para distancias de decenas de centímetros: para más hay que bajar el reloj, o cambiar de bus.
08 · Elegir
SPI, I2C y UART frente a frente
| Característica | UART | I2C | SPI |
|---|---|---|---|
| Cables | 2 | 2 | 3 + una CS por esclavo |
| Reloj | Sin reloj | SCL del maestro | SCK del maestro |
| Dispositivos | 2 | Muchos, por dirección | Muchos, por CS |
| Velocidad típica | Hasta ~1 Mbit/s | 100 a 400 kbit/s | 1 a 20 Mbit/s o más |
| Sobrecarga | 20 % (8N1) | 1 bit por byte más dirección | Prácticamente nula |
| Confirmación | No (paridad opcional) | ACK por byte | No hay |
| Sentido | Dúplex completo | Semidúplex | Dúplex completo |
| Circuito | Salidas activas | Colector abierto y pull-ups | Salidas activas |
| Estandarización | Formato claro, niveles aparte | Especificación formal | Sin estándar: modos a mano |
La falta de ACK es la diferencia que más se nota al depurar: si el esclavo no está conectado, SPI no se queja. El maestro envía bytes y recibe 0xFF (la línea MISO flota en alto) o 0x00 sin saber que nadie contesta. Por eso suele hacerse una lectura de identificación (un registro con valor conocido) al arrancar, para comprobar que el dispositivo está presente.
09 · Diagnóstico
Cuando no responde
| Síntoma | Causa probable |
|---|---|
| Siempre se lee 0xFF o 0x00 | Esclavo sin alimentación o desconectado, MISO sin conectar, CS que nunca baja |
| Los datos llegan corridos un bit o con basura | Modo (CPOL/CPHA) equivocado o velocidad excesiva para el dispositivo |
| Funciona una vez y después se bloquea | PB2 (SS) configurado como entrada: el módulo pasó a modo esclavo |
| Escritura aparentemente correcta, memoria sin cambios | Falta el comando de habilitación (WREN) o CS no subió al final para disparar la escritura |
| Uno de dos dispositivos falla cuando ambos están conectados | Dos CS activos a la vez, o un dispositivo sin alta impedancia en MISO que interfiere |
| Falla solo con cables largos | Rebotes y diafonía: bajar SCK, acortar, agregar resistencias en serie (22 a 100 Ω) |
| La pantalla muestra colores o píxeles erróneos | Orden de bytes de 16 bits (alto primero o bajo primero) o palabra de comando mal formada |
El instrumento ideal es un analizador lógico con decodificador SPI (el tema 35 lo usa): muestra CS, SCK, MOSI y MISO y reconstruye los bytes, de modo que se ve qué envió el maestro y qué contestó el esclavo. Sin él, un osciloscopio de dos canales sobre SCK y MOSI ya revela si el modo y la velocidad son los esperados.
10 · Analogía con programación
Simular dos registros de desplazamiento
Este programa implementa el intercambio SPI entre un maestro y un esclavo con los cuatro modos, prueba qué combinaciones se entienden, calcula las velocidades del ATmega328P, compara el tiempo de leer 64 bytes con SPI, I2C y UART, y simula la conexión en cadena de tres registros de desplazamiento.
Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.
import random
random.seed(3)
# 1) intercambio SPI entre un maestro y un esclavo, con el reloj que genera el maestro
def bits(valor):
return [(valor >> (7 - i)) & 1 for i in range(8)] # MSB primero
def a_byte(lista):
return sum(b << (7 - i) for i, b in enumerate(lista))
def intercambio(byte_m, byte_e, modo_m, modo_e):
cpol_m, cpha_m = modo_m >> 1, modo_m & 1
cpol_e, cpha_e = modo_e >> 1, modo_e & 1
salida_m, salida_e = bits(byte_m), bits(byte_e)
# el maestro genera 8 pulsos: sale del reposo y vuelve
flancos, nivel = [], cpol_m
for _ in range(8):
for _ in range(2):
nivel ^= 1
flancos.append(nivel)
estado = {"m": {"idx": 0, "linea": None, "rx": []}, "e": {"idx": 0, "linea": None, "rx": []}}
# con CPHA=0 el primer bit ya esta en la linea cuando baja CS
if cpha_m == 0:
estado["m"]["linea"] = salida_m[0]; estado["m"]["idx"] = 1
if cpha_e == 0:
estado["e"]["linea"] = salida_e[0]; estado["e"]["idx"] = 1
previo = cpol_m
params = {"m": (cpol_m, cpha_m, salida_m), "e": (cpol_e, cpha_e, salida_e)}
conflicto = []
for nivel_nuevo in flancos:
acciones = {}
for clave, (cpol, cpha, salida) in params.items():
principal = nivel_nuevo != cpol # flanco que sale del reposo del dispositivo
acciones[clave] = "muestrea" if (principal if cpha == 0 else not principal) else "desplaza"
lineas_antes = {k: estado[k]["linea"] for k in estado} # los dos actuan a la vez
for clave, (cpol, cpha, salida) in params.items():
s = estado[clave]
otra = "e" if clave == "m" else "m"
if acciones[clave] == "muestrea":
if acciones[otra] == "desplaza" and estado[otra]["idx"] < 8:
conflicto.append(1) # el otro cambia su salida justo cuando se lee
s["rx"].append(lineas_antes[otra])
elif s["idx"] < 8:
s["linea"] = salida[s["idx"]]
s["idx"] += 1
ok_m = len(estado["m"]["rx"]) == 8 and None not in estado["m"]["rx"] and a_byte(estado["m"]["rx"]) == byte_e
ok_e = len(estado["e"]["rx"]) == 8 and None not in estado["e"]["rx"] and a_byte(estado["e"]["rx"]) == byte_m
return ok_m and ok_e and not conflicto
def pruebas(modo_m, modo_e, n=40):
return all(intercambio(random.randrange(256), random.randrange(256), modo_m, modo_e) for _ in range(n))
print("maestro \\ esclavo modo 0 modo 1 modo 2 modo 3")
for m in range(4):
fila = [" si " if pruebas(m, e) else " NO " for e in range(4)]
print(f" modo {m} " + " ".join(fila))
# 2) velocidad de SCK del ATmega328P con 16 MHz
print()
print("divisor SCK bit byte")
for div in (2, 4, 8, 16, 32, 64, 128):
f = 16e6 / div
print(f"{div:7d} {f / 1e6:6.3f} MHz {1e9 / f:7.0f} ns {8e6 / f:6.2f} us")
# 3) tiempo para leer 64 bytes de una memoria (comando + direccion de 2 bytes), SPI frente a I2C y UART
datos, cabecera = 64, 3
spi = 8 * (cabecera + datos) / 4e6
i2c = (9 * (3 + datos) + 3) / 400e3 # direccion+W, registro, direccion+R y datos
uart = 10 * (cabecera + datos) / 115200
print()
print(f"leer {datos} bytes: SPI 4 MHz {spi * 1e6:.0f} us, I2C 400 kHz {i2c * 1e6:.0f} us, UART 115200 {uart * 1e6:.0f} us")
# 4) conexion en cadena: tres registros de desplazamiento de 8 bits en serie
def cadena(bytes_a_enviar, n=3):
registros = [0] * n
for byte in bytes_a_enviar: # el primer byte enviado termina en el ultimo registro
for b in bits(byte):
salida = registros[0]
for i in range(n - 1, 0, -1):
registros[i] = ((registros[i] << 1) & 0xFF) | (registros[i - 1] >> 7)
registros[0] = ((registros[0] << 1) & 0xFF) | b
return registros
enviado = [0xA1, 0xB2, 0xC3]
final = cadena(enviado)
print("cadena de 3 registros, enviando A1 B2 C3 ->", " ".join(f"{r:02X}" for r in final), "(del ultimo al primero de la cadena)")
Resultado: el intercambio funciona cuando el maestro y el esclavo usan el mismo modo (diagonal de la tabla) y falla con cualquier otra combinación. Con 16 MHz, la velocidad va de 8 MHz (divisor 2, 1 µs por byte) a 125 kHz (divisor 128). Leer 64 bytes de una memoria cuesta 134 µs por SPI a 4 MHz, 1515 µs por I2C a 400 kHz y 5816 µs por UART a 115 200 baudios. Y en la cadena de tres registros, al enviar A1 B2 C3 el primer byte (A1) termina en el último registro.
El modelo exige que no haya cambios de la línea en el mismo flanco en que el otro extremo lee (violaría el tiempo de retención). En dispositivos reales, algunas combinaciones, como los modos 0 y 3, a veces funcionan según el chip; no conviene depender de eso.
11 · Exploración interactiva
Modos, registros y tiempos
El visualizador dibuja una transferencia de un byte para el modo elegido, con los datos de MOSI y MISO. La segunda herramienta calcula los registros y la velocidad. La tercera estima el tiempo y el costo en pines de una transacción.
Banco del bus SPI
1. Una transferencia en la línea
2. Registros y velocidad
3. Presupuesto de una transacción
Recorrido guiado
- Con modo 0 (CPOL = 0, CPHA = 0) y el byte 0xB2 el dato ya está en la línea cuando SCK sube por primera vez; los puntos rojos marcan los flancos de subida. Pasá a CPHA = 1 (modo 1): los datos cambian en la subida y se leen en la bajada, y el primer bit se retrasa medio pulso.
- Con CPOL = 1 el reposo de SCK es alto. Compará modo 2 con modo 0: se lee en el flanco opuesto.
- Con «LSB primero», el mismo byte se envía invertido: 0xB2 pasa a 01001101.
- En la herramienta 2, 16 MHz con divisor 4 y modo 0 dan
SPCR = 0x50, 4 MHz y 2 µs por byte. Con divisor 2 apareceSPSR = 0x01y 8 MHz. Con el modo 3:SPCR = 0x5C. - Con un dispositivo máximo de 2 MHz y divisor 4, la nota avisa que el reloj lo supera.
- En la herramienta 3, 64 bytes con 3 de comando a 4 MHz tardan 139 µs. Subí los esclavos a 8: la nota sugiere un decodificador.
Desafío: una pantalla de 128 × 64 píxeles
Una pantalla monocromática de 128 × 64 píxeles necesita 128 × 64 / 8 = 1024 bytes por cuadro. ¿Cuántos cuadros por segundo se pueden enviar por SPI a 8 MHz y por I2C a 400 kHz? Por SPI: 1024 × 8 / 8 MHz = 1,02 ms, unos 980 cuadros por segundo en el mejor caso. Por I2C a 400 kHz: (1024 + 2) × 9 / 400 kHz = 23 ms, unos 43 cuadros por segundo. Una animación fluida pide 30 cuadros por segundo, de modo que I2C alcanza justo; con una pantalla a color (16 bits por píxel) ya no sería posible, y por eso las pantallas TFT usan SPI.
12 · Comprensión
Confusiones frecuentes
«SPI tiene un ACK como I2C»
No. El maestro nunca sabe si el esclavo existe. Sin dispositivo, MISO flota o está en 0 y el maestro lee 0xFF o 0x00 sin error. Hay que verificar la presencia con una lectura de identificación.
«Para leer solo tengo que recibir»
En SPI cada pulso envía y recibe. Para leer hay que transmitir algo (el relleno), porque el maestro es el único que genera SCK.
«Todos los dispositivos SPI usan el modo 0»
Muchos sí, pero otros usan 1, 2 o 3. Debe leerse la hoja de datos. Un modo equivocado da datos corridos, no un error.
«Puedo subir CS entre bytes para ir más tranquilo»
Subir CS termina la transacción: el esclavo reinicia su estado y descarta el comando. CS debe mantenerse en bajo durante todo el comando, dirección y datos.
«Si no uso el pin 10, lo dejo como entrada»
En modo maestro, el pin SS debe ser salida. Si queda como entrada y se pone en bajo, el módulo pasa a esclavo y el SPI se bloquea.
13 · Práctica guiada
Predecí antes de comprobar
1. La velocidad
Con 16 MHz y divisor 8, ¿cuánto vale SCK y cuánto tarda un byte?
Ver solución
SCK = 16 MHz / 8 = 2 MHz; un bit dura 0,5 µs y un byte, 4 µs.
2. El registro
¿Qué valores de SPCR y SPSR configuran el maestro en modo 3, MSB primero, divisor 16?
Ver solución
SPE (0x40) + MSTR (0x10) + CPOL (0x08) + CPHA (0x04) + SPR0 (0x01) = SPCR = 0x5D. SPI2X = 0, por lo que SPSR = 0x00. SCK = 1 MHz.
3. Leer una hoja de datos
Un dispositivo dice: «el reloj está en alto en reposo y los datos se capturan en el flanco de subida». ¿Qué modo es?
Ver solución
Reposo en alto: CPOL = 1. Con reposo alto, el primer flanco es de bajada y el segundo (subida) es el de captura: CPHA = 1. Es el modo 3.
4. Una lectura de memoria
A 8 MHz, ¿cuánto tarda leer 256 bytes de una memoria con un comando de 3 bytes (sin contar gestión)?
Ver solución
(3 + 256) × 8 bits / 8 MHz = 259 µs. Eso son unos 1,0 MB/s efectivos, el 99 % de los bytes de datos.
5. Los pines
Se quieren conectar 4 dispositivos SPI. ¿Cuántas líneas hacen falta y cómo se reducen?
Ver solución
3 compartidas + 4 CS = 7 líneas. Con un decodificador 74HC138 (3 líneas de dirección para hasta 8 CS) bajan a 3 + 3 = 6, y con más dispositivos el ahorro crece. Si los dispositivos aceptan conexión en cadena, bastan 4.
14 · Síntesis
Ideas para recordar
- SPI usa cuatro líneas (SCK, MOSI, MISO, CS) y dos registros de desplazamiento en anillo: cada pulso envía y recibe un bit, y cada byte enviado es también un byte recibido.
- El maestro genera el reloj y elige al esclavo bajando CS; con CS en alto, el esclavo ignora el bus y suelta MISO.
- Los modos 0 a 3 combinan CPOL (reposo de SCK) y CPHA (flanco de lectura); ambos extremos deben usar el mismo modo.
- En el ATmega328P,
SPCRySPSRconfiguran el bus; SCK = fosc / 2, 4, 8, … 128; con 16 MHz, el máximo es 8 MHz. - El pin SS (PB2) debe ser una salida en modo maestro; si no, el módulo puede pasar a esclavo.
- Sin ACK ni direcciones, SPI es rápido y simple, pero exige una línea CS por esclavo y no avisa si el dispositivo falta: se verifica leyendo un identificador.
- CS debe mantenerse en bajo durante toda la transacción, y su flanco de subida suele ser una orden (por ejemplo, iniciar la escritura de una memoria).
¿Listo para el tema 35?
Antes de avanzar, dibujá el diagrama de tiempos de un byte en el modo 0, calculá SPCR para un modo y una velocidad, y explicá qué hace cada línea. Si podés justificar las tres respuestas, tenés el bus bajo control.
En el próximo tema, un taller: depurar buses con el analizador lógico. Capturaremos y decodificaremos tramas reales de UART, I2C y SPI para diagnosticar problemas con los tres.