El bus SPI es un protocolo de comunicación síncrono, full-duplex y basado en una arquitectura Maestro-Esclavo. A diferencia de I2C, SPI no tiene un estándar formal estricto sobre el protocolo a nivel de software, operando esencialmente como un gran registro de desplazamiento (Shift Register) continuo entre dos dispositivos.
Al ser síncrono, cuenta con una línea de reloj dedicada, cuya velocidad máxima se calcula en función del reloj del bus periférico ($f_{PCLK}$) y un pre-escalador:
$$ f_{SPI} = \frac{f_{PCLK}}{Prescaler} $$
A diferencia de I2C, SPI utiliza circuitos Push-Pull, lo que significa que no requiere resistencias Pull-Up externas en las líneas de datos (MOSI, MISO, SCK). Alcanza velocidades de decenas de Megahercios (MHz). Es importante configurar la Polaridad (CPOL) y la Fase (CPHA) del reloj para que coincidan con la hoja de datos del esclavo.
| Línea | Tipo de GPIO (Maestro) | Consideración de Diseño |
|---|---|---|
| SCK, MOSI | Alternate Function (Push-Pull) | Pistas cortas en el PCB, alejar de señales analógicas sensibles. |
| MISO | Input (Floating / Pull-Up) | El esclavo toma control de esta línea cuando su CS es bajo. |
| CS / SS | Output (Push-Pull) | Se requiere 1 pin GPIO dedicado por cada esclavo adicional en el bus. |
El código para SPI debe controlar primero el pin Chip Select (CS), enviar y recibir los bytes simultáneamente, y luego liberar el CS. Observa cómo por cada byte que sale, obligatoriamente entra un byte.
#include <stdint.h>
#include <stdbool.h>
// Prototipos simulados (En la realidad llamarían a HAL_SPI_TransmitReceive, etc.)
extern void GPIO_WritePin(uint8_t pin, bool state);
extern uint8_t SPI_Hardware_ShiftByte(uint8_t data_out);
// Definiciones
#define PIN_CS_SD_CARD 10
#define LOW false
#define HIGH true
/**
* @brief Envía y recibe un buffer de datos a través del bus SPI.
* @param tx_buffer Puntero a los datos a enviar.
* @param rx_buffer Puntero donde se guardarán los datos recibidos.
* @param length Cantidad de bytes en la trama.
*/
void SPI_TransferirTrama(uint8_t* tx_buffer, uint8_t* rx_buffer, uint16_t length) {
// 1. Iniciar transacción: Bajar el Chip Select para seleccionar el esclavo
GPIO_WritePin(PIN_CS_SD_CARD, LOW);
// Pequeño retardo si el esclavo lo requiere (Setup Time)
// delay_us(1);
// 2. Bucle de transmisión de la trama completa
for (uint16_t i = 0; i < length; i++) {
// En SPI, por cada byte que el Maestro empuja, recibe uno de vuelta
uint8_t byte_enviado = tx_buffer[i];
uint8_t byte_recibido = SPI_Hardware_ShiftByte(byte_enviado);
// Almacenamos lo que respondió el esclavo en ese mismo ciclo
if (rx_buffer != NULL) {
rx_buffer[i] = byte_recibido;
}
}
// 3. Finalizar transacción: Subir el Chip Select para liberar al esclavo
GPIO_WritePin(PIN_CS_SD_CARD, HIGH);
}
// --- EJEMPLO DE USO ---
int main(void) {
// Trama de comando (Ejemplo ficticio para leer un registro de SD)
uint8_t comando_tx[4] = {0x50, 0x00, 0x00, 0xFF};
uint8_t respuesta_rx[4] = {0}; // Buffer limpio para la respuesta
// Ejecutar transferencia
SPI_TransferirTrama(comando_tx, respuesta_rx, 4);
// Ahora 'respuesta_rx' contiene los 4 bytes devueltos por el esclavo.
while(1) {
// Súper bucle
}
}
Registro de Transacciones e Interfaz Gráfica (SPI).
El diseño del HMI principal avanzó sólidamente cuando completaste el esquemático y el PCB del teclado 4x4 capacitivo utilizando KiCad. Ahora, para complementar ese hardware y crear una experiencia de usuario completa y segura, requieres mostrar datos (precio, litros, alertas) y registrar las transacciones. El bus SPI te permite conectar una pantalla gráfica rápida para la interfaz o un módulo de memoria SD para llevar la bitácora (Data Logger) del despachador, todo interactuando armónicamente con tu matriz capacitiva en el sistema central.
1. Tienes 3 dispositivos esclavos SPI en tu placa. ¿Cuántos pines totales del microcontrolador ocupará el bus?
Respuesta: Ocupará 6 pines. Tres pines se comparten para todos (SCK, MOSI, MISO) y necesitas 3 pines GPIO individuales adicionales para los Chip Selects (CS1, CS2, CS3).
2. ¿Qué ocurre si intentas enviar datos por SPI sin haber bajado (puesto a 0V) el pin CS del esclavo?
Respuesta: El esclavo ignorará los pulsos de reloj (SCK) y mantendrá su línea MISO en estado de alta impedancia (desconectada), por lo que tu microcontrolador solo leerá ruido o 0xFF.