i2c-oled.c
El protocolo I2C del SSD1306 se resume en dos bytes de control: 0x00 para orden, 0x40 para datos. Este programa envía la secuencia de inicialización y una imagen de prueba, sin librería: la mejor forma de entender el I2C maestro.
Hardware
Una STM32F407G-DISC1 (Discovery F4, Cortex-M4 @ 168 MHz) con ST-LINK integrado, pines de 3,3 V. 1 módulo OLED SSD1306 I2C (0x3C), alimentación de 3,3 V.
Cableado
SDA a PB7, SCL a PB6 (pines I2C1 típicos de las Nucleo, confírmalo en el .ioc), VCC 3,3 V, GND.
Funcionamiento
Cada trama I2C empieza con el byte de dirección 0x78 y luego el byte de control. La secuencia configura la bomba de carga y el barrido; 0xAF enciende el panel y la trama de 1024 bytes rellena la GDDRAM.
Ejecución
Proyecto STM32CubeIDE « STM32F407G-DISC1 »: pega el codigo en main.c, configura el .ioc, Run. La placa tiene 4 LED (PD12-PD15) y el boton USER en PA0.
Variantes
Añade una fuente 5x7 para imprimir cadenas (printf → bitmap), o pasa a DMA I2C para liberar la CPU durante el refresco.
i2c-oled.c
// OLED SSD1306 (0x3C) : envoi de commandes/data en I2C HAL.
#include "main.h"
#include <string.h>
extern I2C_HandleTypeDef hi2c1;
#define SSD1306_ADDR 0x78 // 0x3C << 1 (format HAL)
static void cmd(uint8_t c) {
uint8_t d[2] = { 0x00, c }; // 0x00 = byte de commande
HAL_I2C_Master_Transmit(&hi2c1, SSD1306_ADDR, d, 2, 10);
}
static void data(const uint8_t *p, uint16_t n) {
uint8_t buf[129];
buf[0] = 0x40; // 0x40 = byte de donnees
memcpy(buf + 1, p, n);
HAL_I2C_Master_Transmit(&hi2c1, SSD1306_ADDR, buf, n + 1, 100);
}
static void init(void) {
const uint8_t seq[] = { 0xAE, 0xD5, 0x80, 0xA8, 0x3F, 0xD3, 0x00,
0x40, 0x8D, 0x14, 0x20, 0x00, 0xA1, 0xC8,
0xDA, 0x12, 0x81, 0xFF, 0xD9, 0xF1, 0xDB,
0x40, 0xA4, 0xA6, 0xAF }; // AF = on
for (unsigned i = 0; i < sizeof(seq); i++) cmd(seq[i]);
}
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init(); // SCL/PB6, SDA/PB7 dans le .ioc (400 kHz)
init();
uint8_t trame[1024];
memset(trame, 0xAA, sizeof(trame)); // damier de test 128x64
data(trame, sizeof(trame));
for (;;);
}