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 Blue Pill STM32F103C8T6 (Cortex-M3 @ 72 MHz, 64 KB flash) alimentada por micro-USB o 3,3 V externo; programacion SWD o bootloader serie. 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 (STM32F103C8) o Arduino (core STM32): programar por SWD (ST-LINK, adaptador DAPLink) o por el bootloader serie (BOOT0 a 1). Atencion: el LED PC13 es activo LOW.
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 (;;);
}