ESP32 OLED SSD1306 I2C interface
ESP32 OLED SSD1306 I2C interface

ESP32

A series of low-cost, low-power system on a chip microcontrollers with integrated Wi-Fi and dual-mode Bluetooth. It has Xtensa dual-core (or single-core) 32-bit LX6 microprocessor, operating at 160 or 240 MHz and performing at up to 600 DMIPS Ultra low power (ULP) co-processor and supports wide range of peripheral such as i2c, spi, uart, dac, etc.

SSD1306

SSD1306 is a single-chip CMOS OLED/PLED driver with controller for organic / polymer light emitting diode dot-matrix graphic display system. It consists of 128 segments and 64 commons. This IC is designed for Common Cathode type OLED panel. The SSD1306 embeds with contrast control, display RAM and oscillator, which reduces the number of external components and power consumption. It has 256-step brightness control. It is suitable for many compact portable applications, such as Smart watch,real-time image display of camera on smart car,Battery management device, etc.

Features of OLED display:

  • Monochrome 4-pin SSD1306 0.96” OLED display.
  • 128×64 pixel resolution with 160° viewing angle.
  • Supply voltage 3V – 5V (supports both 5V and 3.31v logic devices).
  • Uses SSD1306 for interfacing hence can communicate through SPI or IIC.
  • Screen saving continuous scrolling function in both horizontal and vertical direction
  • Row Re-mapping and Column Re-mapping

In this tutorial, the oled display is interfaced with ESP32Dev kit through I2C protocol. Here ESP-IDF is used for programming ESP32 using C language.

SSD1306 Connections

  • GND ——— GND
  • VCC ——- 5V
  • SCL ——- GPIO 2
  • SDA ——- GPIO 15

I2C Address of OLED display

If the oled slave address SA0 bit is 0, then microcontroller can do read/write operation with OLED display using below I2C address.

  • I2C write address is 0x78
  • I2C read address is 0x79

There is two kinds of data need to send to the oled in order to properly initilize and display the characters. Those are commands and pixel data.

//Wrapper to send commands to oled through i2c interface
void ssd1306SendCmd(uint8_t command)
{

        esp_err_t espRc; 
        i2c_cmd_handle_t cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
        i2c_master_write_byte(cmd,0x00, true);
        i2c_master_write_byte(cmd,command, true);
        i2c_master_stop(cmd);
        espRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10/portTICK_PERIOD_MS);
        if (espRc != ESP_OK)
        {
                ESP_LOGE(tag, "Cmd send failed code: 0x%.2X", espRc);
        }
        i2c_cmd_link_delete(cmd);

}

//Wrapper to send data to oled through i2c interface
void ssd1306SendData(uint8_t *data,uint16_t size)
{
        esp_err_t espRc; 
        i2c_cmd_handle_t cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true);
        i2c_master_write_byte(cmd,0x40, true);
        i2c_master_write(cmd,data,size, true);
        i2c_master_stop(cmd);
        espRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10/portTICK_PERIOD_MS);
        if (espRc != ESP_OK)
        {
                ESP_LOGE(tag, "Data send failed code: 0x%.2X", espRc);
        }
        i2c_cmd_link_delete(cmd);

}

By using above wrappers, commands and pixel data can be sent to oled. The oled resolution is 128 x 64 means the total of 8192 pixel. Each pixel is turned on or off by writing 1 or 0 on their corresponding GDRAM location.
Therefore 8192 / 8 = 1024 byte array represent the whole oled panel.

Initilization

void ssd1306_init() {


        ssd1306SendCmd(0xAE);   //Turn the OLED panel display OFF.

        ssd1306SendCmd(0x20);   //Set Memory Addressing Mode as
        ssd1306SendCmd(0x00);   //Horizontal Addressing Mode

        ssd1306SendCmd(0xB0);   //Page Start Address for Page Addressing Mode

        ssd1306SendCmd(0xC8);   //COM Output Scan Direction as normal

        ssd1306SendCmd(0x00);   //Lower Column Start Address for Page Addressing Mode
        ssd1306SendCmd(0x10);   //Higher Column Start Address for Page Addressing Mode

        ssd1306SendCmd(0x40);   //Display Start Line 0 - 63

        ssd1306SendCmd(0x81);   //Contrast Control
        ssd1306SendCmd(0xFF);   //256

        ssd1306SendCmd(0xA1);   //Segment Re-map - column address 127 is mapped to SEG0

        ssd1306SendCmd(0xA6);   //Normal display

        ssd1306SendCmd(0xA8);   //Multiplex Ratio
        ssd1306SendCmd(0x3F);   // 64MUX

        ssd1306SendCmd(0xA4);   //Entire Display ON - Resume to RAM content display

        ssd1306SendCmd(0xD3);   //Display Offset
        ssd1306SendCmd(0x00);   //Set vertical shift by COM from 0d~63d

        ssd1306SendCmd(0xD5);   //Display Clock Divide Ratio/Oscillator Frequency
        ssd1306SendCmd(0xF0);

        ssd1306SendCmd(0xD9);   //Pre-charge Period
        ssd1306SendCmd(0x22);


        ssd1306SendCmd(0xDA);   //COM Pins Hardware Configuration 
        ssd1306SendCmd(0x12);   //Alternative

        ssd1306SendCmd(0xDB);   //VCOMH Deselect Level
        ssd1306SendCmd(0x20);   //0.77 x VCC

        ssd1306SendCmd(0x8D);   //Charge Pump Setting
        ssd1306SendCmd(0x14);   //Enable charge pump during display on
        ssd1306SendCmd(0xAF);   //Turn the OLED panel display ON.
}
void app_main(void)
{
        i2c_master_init();
        ssd1306_init();
        ssd1306DisplayClear();
//      ssd1306FillDisplay();
        xTaskCreate(ssd1306_display_text, "ssd1306_display_clear",  2048,"Welcome to \nEmbedded Diaries\n1 2 3 4 5", 6, NULL);
}

In this tutorial the font size is about 8×8 pixel and all the characters in ascii table and its corresponding pixel bits is hardcoded in font8x8_basic.h header file.

This project can be conpiled just like other example project in ESP32-idf.
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/

The project source code is available in github.