DÍA 171 DE 365

Fase 3: Comunicaciones y Redes Industriales

📖 Teoría a Estudiar

El Bus SPI y el Pin DC (Data/Command)

Una pantalla a color de 240x240 píxeles necesita que le envíes **115,200 bytes** para dibujar una sola imagen a pantalla completa. El bus I2C tardaría un segundo entero en hacerlo. El bus SPI (Serial Peripheral Interface) puede correr a más de 40 Megabits por segundo (MHz), dibujando la pantalla al instante.

El SPI usa un reloj (SCK) y una línea de datos (MOSI). Pero la pantalla ST7789 es estúpida: si le envías el byte 0x29, no sabe si le estás ordenando "Enciende la pantalla" (Comando), o si le estás enviando un trozo de un pixel de color rojo oscuro (Dato). Para resolver esto, los ingenieros agregaron un pin extra llamado DC (Data/Command):

Color RGB565: Comprimiendo el Arcoíris

El color "True Color" de tu PC usa 24 bits (3 bytes) por píxel: 8 rojo, 8 verde, 8 azul. Para los microcontroladores, transmitir 3 bytes por cada puntito de la pantalla es excesivo. El estándar industrial es el RGB565. Comprime los colores en solo 16 bits (2 bytes):

ARQUITECTURA DE INTERFAZ GRÁFICA: BUS SPI Y CONTROLADOR ST7789 STM32 (SPI Master) PA5 (SCK) PA7 (MOSI) PA4 (CS) PA3 (DC) PA2 (RST) 240x240 RGB Controlador ST7789 SCL SDA CS DC RES Clock (Máx 40 MHz) DC (Data / Command) DC=0 -> 0x2A (Set Column) DC=1 -> 0xF800 (Color Red) 1 Píxel = 16 bits (RGB565) R (5b) G (6b) B (5b)

⚙️ Ejercicios Prácticos

Ejercicio 1: Inicializaremos el periférico SPI1 en modo Maestro (Master). Crearemos las funciones de bajo nivel ST7789_SendCmd() y ST7789_SendData() manejando el pin DC manualmente. Luego, enviaremos la rigurosa secuencia mágica de inicialización (Sleep Out, Color Mode, Orientation, Display On) requerida para despertar al chip gráfico de su estado de coma inicial.


/**
 * @file st7789_driver.c
 * @brief Driver Bare-Metal para Pantalla TFT Color ST7789 vía SPI
 */

#include "stm32f401xe.h"
#include <stdint.h>

// =========================================================================
// DEFINICIÓN DE PINES Y MACROS (Conexión Hardware)
// SCK  -> PA5
// MOSI -> PA7
// CS   -> PA4
// DC   -> PA3
// RST  -> PA2
// =========================================================================

#define CS_LOW()   (GPIOA->BSRR = (1 << 20)) // Reset PA4
#define CS_HIGH()  (GPIOA->BSRR = (1 << 4))  // Set PA4

#define DC_CMD()   (GPIOA->BSRR = (1 << 19)) // Reset PA3 (DC=0)
#define DC_DATA()  (GPIOA->BSRR = (1 << 3))  // Set PA3 (DC=1)

#define RST_LOW()  (GPIOA->BSRR = (1 << 18)) // Reset PA2
#define RST_HIGH() (GPIOA->BSRR = (1 << 2))  // Set PA2

/**
 * @brief Inicializa el hardware SPI1 y los GPIOs de control.
 */
void ST7789_HW_Init(void) {
    // 1. Activar relojes (GPIOA y SPI1)
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
    
    // 2. Configurar PA5(SCK) y PA7(MOSI) como Función Alternativa (AF5)
    GPIOA->MODER &= ~((3 << 10) | (3 << 14));
    GPIOA->MODER |=  ((2 << 10) | (2 << 14));
    
    GPIOA->AFR[0] &= ~((0xF << 20) | (0xF << 28));
    GPIOA->AFR[0] |=  ((5 << 20) | (5 << 28));
    
    // Configurar a muy alta velocidad (Very High Speed)
    GPIOA->OSPEEDR |= (3 << 10) | (3 << 14);
    
    // 3. Configurar pines de control PA2, PA3, PA4 como Salidas Generales
    GPIOA->MODER &= ~((3 << 4) | (3 << 6) | (3 << 8));
    GPIOA->MODER |=  ((1 << 4) | (1 << 6) | (1 << 8));
    
    // 4. Configurar el SPI1 en Modo Master, 8 bits, Software Slave Management (SSM)
    // Prescaler /2 (84MHz bus = 42MHz SPI), CPOL=1, CPHA=1 (ST7789 soporta Mode 3)
    SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_CPOL | SPI_CR1_CPHA;
    SPI1->CR1 |= SPI_CR1_SPE; // Enable SPI
}

// =========================================================================
// RUTINAS DE COMUNICACIÓN DE BAJO NIVEL
// =========================================================================

/**
 * @brief Envía 1 byte por SPI de forma bloqueante
 */
void SPI_WriteByte(uint8_t dato) {
    while (!(SPI1->SR & SPI_SR_TXE)); // Esperar Buffer TX vacío
    SPI1->DR = dato;                  // Escribir dato
    while (SPI1->SR & SPI_SR_BSY);    // Esperar fin de transmisión real
}

/**
 * @brief Envía un Comando a la pantalla (DC=0)
 */
void ST7789_SendCmd(uint8_t cmd) {
    DC_CMD();
    CS_LOW();
    SPI_WriteByte(cmd);
    CS_HIGH();
}

/**
 * @brief Envía Datos/Parámetros a la pantalla (DC=1)
 */
void ST7789_SendData(uint8_t data) {
    DC_DATA();
    CS_LOW();
    SPI_WriteByte(data);
    CS_HIGH();
}

// =========================================================================
// INICIALIZACIÓN LÓGICA DE LA PANTALLA (Wake Up)
// =========================================================================

// Simple delay bloqueante por software (Solo para la inicialización)
void delay_ms_simple(uint32_t ms) {
    for(volatile uint32_t i = 0; i < (ms * 8400); i++);
}

void ST7789_Init(void) {
    ST7789_HW_Init();
    
    // 1. Reset por Hardware (Obligatorio)
    RST_HIGH(); delay_ms_simple(10);
    RST_LOW();  delay_ms_simple(10);
    RST_HIGH(); delay_ms_simple(120);
    
    // 2. Secuencia Mágica de Configuración
    ST7789_SendCmd(0x01); // Software Reset
    delay_ms_simple(150);
    
    ST7789_SendCmd(0x11); // Sleep Out (Despierta el oscilador interno)
    delay_ms_simple(120);
    
    ST7789_SendCmd(0x3A); // COLMOD: Definir formato de color
    ST7789_SendData(0x55); // 0x55 = 16 bits/píxel (RGB565)
    
    ST7789_SendCmd(0x36); // MADCTL: Memory Data Access Control (Orientación)
    ST7789_SendData(0x00); // Orientación por defecto (0 grados)
    
    ST7789_SendCmd(0x21); // Inversion ON (Las ST7789 modernas requieren esto para negros correctos)
    
    ST7789_SendCmd(0x29); // Display ON (Enciende los píxeles)
    delay_ms_simple(100);
}

int main(void) {
    // Configurar Relojes a 84MHz (Requerido para el delay simple)
    // SystemClock_Config();
    
    ST7789_Init();
    
    while(1) {
        // La pantalla ahora debería mostrar basura estática o color negro, 
        // indicando que el panel se ha encendido correctamente.
    }
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Interfaz Gráfica Avanzada y Experiencia de Usuario.

Una pantalla verde de texto de 16x2 (como la de las calculadoras viejas) es suficiente para leer números. Pero para una máquina expendedora moderna que debe procesar códigos QR de facturación, mostrar barras de progreso verde brillantes mientras despacha el fluido y emitir alertas visuales rojas gigantes si ocurre un error metrológico (Día 158), requieres un panel gráfico a color.

Al programar el **Driver ST7789 Bare-Metal**, has sentado los cimientos gráficos de tu equipo. Configurar un bus SPI a altísima velocidad (42 MHz) manipulando registros de Hardware no es tarea fácil, pero garantiza que en los próximos días podamos dibujar rectángulos, fuentes tipográficas y menús de cobro con una fluidez (Frames per Second) que sería imposible usando librerías lentas como las de Arduino. Tu máquina ha despertado a todo color.

📝 Resumen del Día