Unlocking ESP32 Magic: Boot Button Message Control with SSD1306 Delight


In the world of IoT and embedded systems, the ESP32 has emerged as a stalwart, driving innovation with its versatility and power-packed features. One such functionality that can truly elevate your project is mastering message control on boot button press using the ESP-IDF framework, coupled with the dynamic SSD1306 display. In this blog post, we’ll dive into the art of seamlessly integrating these components and provide you with the full code to kickstart your journey.

Harnessing the Power of ESP32 and SSD1306: A Symphony of Innovation

The ESP32: If microcontrollers had a rockstar, the ESP32 would be on the top of the charts. With its dual-core processing, Wi-Fi and Bluetooth capabilities, and a treasure trove of GPIO pins, it’s the perfect canvas for creative IoT endeavors.
The SSD1306 Display: Enter the SSD1306, a compact and crisp OLED display that can add a touch of visual flair to your projects. Its high contrast, wide viewing angle, and low power consumption make it a go-to choice for showcasing crucial information.


Unveiling the Concept: Message Control on Boot Button Press

Imagine a scenario where your ESP32-based device boots up and displays a welcome message, but only when a designated button is pressed. This concept is the crux of our exploration – controlling the message flow using the boot button. Users will have the satisfaction of an interactive experience, receiving messages on their terms.

The Blueprint: Implementing the Solution

Here’s a step-by-step guide on how to achieve this feat using the ESP-IDF framework:

Step 1: Set Up Your Development Environment
Ensure you have the ESP-IDF (Espressif IoT Development Framework) installed. This comprehensive toolset will be your trusty sidekick throughout the journey.

Step 2: Wiring the Components
Connect the SSD1306 display to the ESP32 using the appropriate GPIO pins. Make sure you have a reliable power supply – no artist wants a flickering canvas.

Step 3: Code Crafting
Now comes the exciting part – writing the code! Below is the code snippet that showcases the magic. This code assumes you have basic familiarity with C/C++ programming and the ESP-IDF.


 * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
 * SPDX-License-Identifier: CC0-1.0

#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_ops.h"
#include "driver/i2c.h"
#include "esp_err.h"
#include "esp_log.h"
#include "lvgl.h"
#include "esp_lvgl_port.h"

#include "esp_lcd_sh1107.h"
#include "esp_lcd_panel_vendor.h"

static const char *TAG = "example";

#define I2C_HOST 0

//////////////////// Please update the following configuration according to your LCD spec //////////////////////////////
#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (400 * 1000)
#define EXAMPLE_I2C_HW_ADDR 0x3C

// The pixel number in horizontal and vertical
#define EXAMPLE_LCD_H_RES 128
#define EXAMPLE_LCD_V_RES 64
#define EXAMPLE_LCD_H_RES 64
#define EXAMPLE_LCD_V_RES 128
// Bit number used to represent command and parameter

void example_lvgl_demo_ui(lv_disp_t *disp, char *message);

/* The LVGL port component calls esp_lcd_panel_draw_bitmap API for send data to the screen. There must be called
lvgl_port_flush_ready(disp) after each transaction to display. The best way is to use on_color_trans_done
callback from esp_lcd IO config structure. In IDF 5.1 and higher, it is solved inside LVGL port component. */
static bool notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
    lv_disp_t *disp = (lv_disp_t *)user_ctx;
    return false;
lv_disp_t *oled_display_start()
    ESP_LOGI(TAG, "Initialize I2C bus");
    i2c_config_t i2c_conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = EXAMPLE_PIN_NUM_SDA,
        .scl_io_num = EXAMPLE_PIN_NUM_SCL,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
    ESP_ERROR_CHECK(i2c_param_config(I2C_HOST, &i2c_conf));
    ESP_ERROR_CHECK(i2c_driver_install(I2C_HOST, I2C_MODE_MASTER, 0, 0, 0));

    ESP_LOGI(TAG, "Install panel IO");
    esp_lcd_panel_io_handle_t io_handle = NULL;
    esp_lcd_panel_io_i2c_config_t io_config = {
        .dev_addr = EXAMPLE_I2C_HW_ADDR,
        .control_phase_bytes = 1,               // According to SSD1306 datasheet
        .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,   // According to SSD1306 datasheet
        .lcd_param_bits = EXAMPLE_LCD_CMD_BITS, // According to SSD1306 datasheet
        .dc_bit_offset = 6, // According to SSD1306 datasheet
        .dc_bit_offset = 0, // According to SH1107 datasheet
        .flags =
                .disable_control_phase = 1,
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)I2C_HOST, &io_config, &io_handle));

    ESP_LOGI(TAG, "Install SSD1306 panel driver");
    esp_lcd_panel_handle_t panel_handle = NULL;
    esp_lcd_panel_dev_config_t panel_config = {
        .bits_per_pixel = 1,
        .reset_gpio_num = EXAMPLE_PIN_NUM_RST,
    ESP_ERROR_CHECK(esp_lcd_new_panel_ssd1306(io_handle, &panel_config, &panel_handle));
    ESP_ERROR_CHECK(esp_lcd_new_panel_sh1107(io_handle, &panel_config, &panel_handle));

    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));

    ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));

    ESP_LOGI(TAG, "Initialize LVGL");
    const lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG();

    const lvgl_port_display_cfg_t disp_cfg = {
        .io_handle = io_handle,
        .panel_handle = panel_handle,
        .buffer_size = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES,
        .double_buffer = true,
        .hres = EXAMPLE_LCD_H_RES,
        .vres = EXAMPLE_LCD_V_RES,
        .monochrome = true,
        .rotation = {
            .swap_xy = false,
            .mirror_x = false,
            .mirror_y = false,
    lv_disp_t *disp = lvgl_port_add_disp(&disp_cfg);
    /* Register done callback for IO */
    const esp_lcd_panel_io_callbacks_t cbs = {
        .on_color_trans_done = notify_lvgl_flush_ready,
    esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, disp);

    /* Rotation of the screen */
    lv_disp_set_rotation(disp, LV_DISP_ROT_180);

    ESP_LOGI(TAG, "Display LVGL Scroll Text");
    // example_lvgl_demo_ui(disp, message);
    return disp;
void app_main(void)
    lv_disp_t *disp = oled_display_start();
    gpio_set_direction(GPIO_NUM_0, GPIO_MODE_INPUT);
    int count = 0;
    example_lvgl_demo_ui(disp, "ASHISH SAINI");
    while (1)
        if (!gpio_get_level(GPIO_NUM_0))         // boot button - GPIO0 or GPIO_NUM_0
            printf("button pressed");
            if (count == 0)               // boot button initially
                example_lvgl_demo_ui(disp, "ASHISH SAINI");
            else if (count == 1)         // boot button on first press
                example_lvgl_demo_ui(disp, "INNOVATE YOURSELF");
            else if (count == 2)         // boot button on second press
                example_lvgl_demo_ui(disp, "LIKE, SHARE, COMMENT");
            else if (count == 3).         // boot button on third press
                example_lvgl_demo_ui(disp, "SUBSCRIBE NOW");
            else if (count == 4)         // boot button on fourth press
                example_lvgl_demo_ui(disp, "TAKE CARE");
                count = 0;


 * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
 * SPDX-License-Identifier: CC0-1.0

#include "lvgl.h"

void example_lvgl_demo_ui(lv_disp_t *disp, char * message)
    lv_obj_t *scr = lv_disp_get_scr_act(disp);
    // Clear the screen
    lv_obj_t *label = lv_label_create(scr);
    lv_label_set_long_mode(label, LV_LABEL_LONG_WRAP); /* Circular scroll */
    lv_label_set_text(label, message);
    /* Size of the screen (if you use rotation 90 or 270, please set disp->driver->ver_res) */
    lv_obj_set_width(label, disp->driver->hor_res);
    lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 30);
    // Refresh the display

Step 4: Building and Flashing
Run idf.py menuconfig to configure your project settings, then compile and flash your code to the ESP32.

Step 5: Witness the Marvel
Power up your ESP32, press the designated boot button, and voilà! The SSD1306 display will light up with the welcoming message.

Download Full Code

In Closing: Empowerment through Innovation

Message control on boot button press using ESP32 and SSD1306 is more than a technical feat; it’s a testament to the boundless possibilities of creativity and technology. As you embark on your journey, remember that every line of code you write is a stroke on the canvas of innovation. So, code fearlessly, create relentlessly, and let your ESP32 masterpiece shine!

In the realm of IoT, it’s not just about hardware and software – it’s about the stories you tell through your creations. Boot Button With ESP32, SSD1306, and the ESP-IDF framework in your toolkit, you’re equipped to tell stories that captivate, engage, and inspire.

Now, go forth and make your ESP32 dance in harmony with boot Button and the SSD1306 – where messages come to life at the tap of a button, and innovation knows no bounds. Happy coding!

Also, check out our other playlist Rasa ChatbotInternet of thingsDockerPython ProgrammingMQTTTech News, ESP-IDF etc.
Become a member of our social family on youtube here.
Stay tuned and Happy Learning. ✌🏻😃
Happy tinkering! ❤️🔥

Leave a Reply