Display Drivers

ESPP contains a reusable set of display-controller implementations in the display_drivers component.

The drivers use the shared object-style display_drivers::Controller / display_drivers::MipiDbiDisplayDriver architecture so controller state is owned per instance instead of hidden behind static helpers.

The component also provides SpiPanelIo / SpiCommandData, a SPI-backed implementation of the shared display_drivers::PanelIo transport interface for command/data display panels, in components/display_drivers/include/spi_panel_io.hpp.

API Reference

Header File

Classes

class PanelIo

SPI/parallel/DSI panel transport interface for object-style display controllers.

Subclassed by espp::SpiPanelIo

Public Functions

virtual ~PanelIo() = default

Virtual destructor.

virtual bool initialized() const = 0

Check whether the transport has been initialized successfully.

Returns:

True if the transport is ready for use.

virtual void write_command(uint8_t command, std::span<const uint8_t> parameters, uint32_t flags = 0) = 0

Send a command and optional parameter payload immediately.

Parameters:
  • command – Command byte to transmit.

  • parameters – Optional command payload bytes.

  • flags – Optional transport-specific user flags.

virtual void queue_command(uint8_t command, uint32_t flags = 0) = 0

Queue a command byte for asynchronous transmission.

Parameters:
  • command – Command byte to transmit.

  • flags – Optional transport-specific user flags.

virtual void queue_data(std::span<const uint8_t> data, uint32_t flags = 0) = 0

Queue a non-pixel data payload for asynchronous transmission.

Parameters:
  • data – Payload bytes to transmit.

  • flags – Optional transport-specific user flags.

virtual void queue_pixels(const uint8_t *data, size_t size, uint32_t flags = 0, uint32_t transaction_flags = 0) = 0

Queue a pixel payload for asynchronous transmission.

Parameters:
  • data – Pointer to the pixel payload.

  • size – Payload size in bytes.

  • flags – Optional transport-specific user flags.

  • transaction_flags – Optional low-level transaction flags.

virtual void wait() = 0

Wait for all queued transfers to complete.

class Controller

Object-style base class for display controllers.

Subclassed by espp::display_drivers::MipiDbiDisplayDriver

Public Functions

inline explicit Controller(const Config &config)

Construct a controller from the shared display configuration.

Parameters:

configDisplay configuration.

virtual ~Controller() = default

Virtual destructor.

virtual bool initialize() = 0

Initialize the concrete display controller.

Returns:

True on success.

inline virtual void set_rotation(const DisplayRotation &rotation)

Update the controller rotation state.

Parameters:

rotation – New display rotation.

inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)

Write an area of pixel data without implicitly notifying LVGL.

Parameters:
  • disp – LVGL display pointer, used when synchronous flush completion is needed.

  • area – Area to update.

  • color_map – Pixel buffer for the area.

  • flags – Transport/user flags passed through to the write path.

inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)

Flush an area of pixel data and notify LVGL when appropriate.

Parameters:
  • disp – LVGL display pointer.

  • area – Area to flush.

  • color_map – Pixel buffer for the area.

virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) = 0

Clear a rectangular region to a solid color.

Parameters:
  • x – Starting X coordinate.

  • y – Starting Y coordinate.

  • width – Width in pixels.

  • height – Height in pixels.

  • color – RGB565 color value.

inline virtual void set_offset(int x, int y)

Update the controller’s logical top-left pixel offset.

Parameters:
  • x – X offset in pixels.

  • y – Y offset in pixels.

inline virtual void get_offset(int &x, int &y) const

Read the controller’s logical top-left pixel offset.

Parameters:
  • x – Filled with the current X offset.

  • y – Filled with the current Y offset.

class MipiDbiDisplayDriver : public espp::display_drivers::Controller

Shared base for command/data/window-based MIPI DBI panels.

Subclassed by espp::Gc9a01, espp::Ili9341, espp::Ili9881, espp::Sh8601, espp::Ssd1351, espp::St7123, espp::St7789, espp::St7796

Public Functions

inline explicit MipiDbiDisplayDriver(const Config &config, const Protocol &protocol)

Construct a shared MIPI DBI-style controller base.

Parameters:
  • config – Shared display configuration.

  • protocol – Controller-specific command mapping.

inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override

Clear a rectangular region to a solid color.

Parameters:
  • x – Starting X coordinate.

  • y – Starting Y coordinate.

  • width – Width in pixels.

  • height – Height in pixels.

  • color – RGB565 color value.

virtual bool initialize() = 0

Initialize the concrete display controller.

Returns:

True on success.

inline virtual void set_rotation(const DisplayRotation &rotation)

Update the controller rotation state.

Parameters:

rotation – New display rotation.

inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)

Write an area of pixel data without implicitly notifying LVGL.

Parameters:
  • disp – LVGL display pointer, used when synchronous flush completion is needed.

  • area – Area to update.

  • color_map – Pixel buffer for the area.

  • flags – Transport/user flags passed through to the write path.

inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)

Flush an area of pixel data and notify LVGL when appropriate.

Parameters:
  • disp – LVGL display pointer.

  • area – Area to flush.

  • color_map – Pixel buffer for the area.

inline virtual void set_offset(int x, int y)

Update the controller’s logical top-left pixel offset.

Parameters:
  • x – X offset in pixels.

  • y – Y offset in pixels.

inline virtual void get_offset(int &x, int &y) const

Read the controller’s logical top-left pixel offset.

Parameters:
  • x – Filled with the current X offset.

  • y – Filled with the current Y offset.

struct Protocol

DBI protocol commands used by a concrete controller.

Public Members

uint8_t column_address_command = {0}

CASET-equivalent command.

uint8_t row_address_command = {0}

RASET-equivalent command.

uint8_t memory_write_command = {0}

RAMWR-equivalent command.

bool use_8bit_coordinates = {false}

Whether region coordinates are encoded as 8-bit values.

Header File

Classes

class Gc9a01 : public espp::display_drivers::MipiDbiDisplayDriver

Display driver for the GC9A01 display controller.

SmartKnob Config

  static constexpr std::string_view dev_kit = "Smartknob-HA";
  int clock_speed = 80 * 1000 * 1000;
  gpio_num_t mosi = GPIO_NUM_6;
  gpio_num_t sclk = GPIO_NUM_5;
  gpio_num_t spics = GPIO_NUM_15;
  gpio_num_t reset = GPIO_NUM_4;
  gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM;
  gpio_num_t backlight = GPIO_NUM_7;
  size_t width = 240;
  size_t height = 240;
  size_t pixel_buffer_size = width * 50;
  bool backlight_on_value = true;
  bool reset_value = false;
  bool invert_colors = true;
  int offset_x = 0;
  int offset_y = 0;
  bool mirror_x = true;
  bool mirror_y = true;
  auto rotation = espp::DisplayRotation::LANDSCAPE;

Gc9a01 Example

    spi_bus = std::make_unique<espp::Spi>(espp::Spi::Config{
        .host = spi_num,
        .sclk_io_num = sclk,
        .mosi_io_num = mosi,
#ifdef CONFIG_DISPLAY_QUAD_SPI
        .miso_io_num = miso,
        .quadwp_io_num = data2,
        .quadhd_io_num = data3,
#else
        .miso_io_num = GPIO_NUM_NC,
#endif
        .max_transfer_sz = SPI_MAX_TRANSFER_BYTES,
    });
    if (!spi_bus->initialized()) {
      fmt::print("Failed to initialize SPI bus\n");
      return;
    }

#ifdef CONFIG_DISPLAY_QUAD_SPI
    std::error_code ec;
    spi_device = spi_bus->add_device(
        espp::Spi::DeviceConfig{
            .command_bits = 8,
            .address_bits = 24,
            .mode = 0,
            .clock_speed_hz = clock_speed,
            .input_delay_ns = 0,
            .cs_io_num = spics,
            .queue_size = spi_queue_size,
            .flags = SPI_DEVICE_HALFDUPLEX,
#ifndef CONFIG_T_ENCODER_PRO
            .pre_cb = lcd_spi_pre_transfer_callback,
#endif
            .post_cb = lcd_spi_post_transfer_callback,
        },
        ec);
    if (ec || !spi_device) {
      fmt::print("Failed to initialize SPI device: {}\n", ec.message());
      return;
    }
#else
    panel_io = std::make_unique<espp::SpiPanelIo>(espp::SpiPanelIo::Config{
        .spi = spi_bus.get(),
        .device_config =
            {
                .mode = 0,
                .clock_speed_hz = clock_speed,
                .input_delay_ns = 0,
                .cs_io_num = spics,
                .queue_size = spi_queue_size,
#ifdef CONFIG_HARDWARE_BYTE90
                .flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_3WIRE,
#endif
            },
        .data_command_io = dc_pin,
        .data_command_bit_mask = DC_LEVEL_BIT,
        .post_transaction_callback_bit_mask = FLUSH_BIT,
        .post_transaction_callback = lcd_spi_flush_ready,
    });
    if (!panel_io->initialized()) {
      fmt::print("Failed to initialize SPI panel I/O\n");
      return;
    }
#endif

    auto display_driver = std::make_shared<DisplayDriver>(espp::display_drivers::Config{
        .panel_io =
#ifdef CONFIG_DISPLAY_QUAD_SPI
            nullptr,
        .write_command = write_command,
#else
            panel_io.get(),
        .write_command = nullptr,
#endif
        .read_command = nullptr,
#ifdef CONFIG_DISPLAY_QUAD_SPI
        .lcd_send_lines = lcd_send_lines,
#else
        .lcd_send_lines = nullptr,
#endif
        .reset_pin = reset,
#ifndef CONFIG_T_ENCODER_PRO
        .data_command_pin = dc_pin,
#endif
        .reset_value = reset_value,
        .invert_colors = invert_colors,
        .offset_x = offset_x,
        .offset_y = offset_y,
        .mirror_x = mirror_x,
        .mirror_y = mirror_y,
    });
    display_driver->initialize();
    // initialize the display / lvgl
    auto display = std::make_shared<Display>(
        Display::LvglConfig{
            .width = width,
            .height = height,
            .flush_callback =
                [display_driver](lv_display_t *disp, const lv_area_t *area, uint8_t *color_map) {
                  display_driver->flush(disp, area, color_map);
                },
            .rotation_callback =
                [display_driver](const espp::DisplayRotation &rotation) {
                  display_driver->set_rotation(rotation);
                },
            .rotation = rotation},
#if DISPLAY_IS_OLED
        Display::OledConfig{
            .set_brightness_callback =
                [display_driver](float brightness) { display_driver->set_brightness(brightness); },
            .get_brightness_callback =
                [display_driver]() { return display_driver->get_brightness(); }},
#else
        Display::LcdConfig{.backlight_pin = backlight, .backlight_on_value = backlight_on_value},
#endif
        Display::DynamicMemoryConfig{.pixel_buffer_size = pixel_buffer_size,
                                     .double_buffered = true});

    display->set_brightness(1.0f);

    // initialize the gui
    Gui gui({});
    size_t iterations = 0;
    while (true) {
      auto label = fmt::format("Iterations: {}", iterations);
      gui.set_label(label);
      gui.set_meter(iterations % 100);
      iterations++;
      std::this_thread::sleep_for(100ms);
    }

Public Functions

inline virtual bool initialize() override

Initialize the concrete display controller.

Returns:

True on success.

inline virtual void set_rotation(const DisplayRotation &rotation) override

Update the controller rotation state.

Parameters:

rotation – New display rotation.

inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override

Clear a rectangular region to a solid color.

Parameters:
  • x – Starting X coordinate.

  • y – Starting Y coordinate.

  • width – Width in pixels.

  • height – Height in pixels.

  • color – RGB565 color value.

inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)

Write an area of pixel data without implicitly notifying LVGL.

Parameters:
  • disp – LVGL display pointer, used when synchronous flush completion is needed.

  • area – Area to update.

  • color_map – Pixel buffer for the area.

  • flags – Transport/user flags passed through to the write path.

inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)

Flush an area of pixel data and notify LVGL when appropriate.

Parameters:
  • disp – LVGL display pointer.

  • area – Area to flush.

  • color_map – Pixel buffer for the area.

inline virtual void set_offset(int x, int y)

Update the controller’s logical top-left pixel offset.

Parameters:
  • x – X offset in pixels.

  • y – Y offset in pixels.

inline virtual void get_offset(int &x, int &y) const

Read the controller’s logical top-left pixel offset.

Parameters:
  • x – Filled with the current X offset.

  • y – Filled with the current Y offset.

Header File

Classes

class Ili9341 : public espp::display_drivers::MipiDbiDisplayDriver

Display driver for the ILI9341 display controller.

WROVER-KIT ILI9341 Config

  static constexpr std::string_view dev_kit = "ESP-WROVER-DevKit";
  int clock_speed = 20 * 1000 * 1000;
  gpio_num_t mosi = GPIO_NUM_23;
  gpio_num_t sclk = GPIO_NUM_19;
  gpio_num_t spics = GPIO_NUM_22;
  gpio_num_t reset = GPIO_NUM_18;
  gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM;
  gpio_num_t backlight = GPIO_NUM_5;
  size_t width = 320;
  size_t height = 240;
  size_t pixel_buffer_size = 16384;
  bool backlight_on_value = false;
  bool reset_value = false;
  bool invert_colors = false;
  int offset_x = 0;
  int offset_y = 0;
  bool mirror_x = false;
  bool mirror_y = false;
  auto rotation = espp::DisplayRotation::LANDSCAPE;

ili9341 Example

    spi_bus = std::make_unique<espp::Spi>(espp::Spi::Config{
        .host = spi_num,
        .sclk_io_num = sclk,
        .mosi_io_num = mosi,
#ifdef CONFIG_DISPLAY_QUAD_SPI
        .miso_io_num = miso,
        .quadwp_io_num = data2,
        .quadhd_io_num = data3,
#else
        .miso_io_num = GPIO_NUM_NC,
#endif
        .max_transfer_sz = SPI_MAX_TRANSFER_BYTES,
    });
    if (!spi_bus->initialized()) {
      fmt::print("Failed to initialize SPI bus\n");
      return;
    }

#ifdef CONFIG_DISPLAY_QUAD_SPI
    std::error_code ec;
    spi_device = spi_bus->add_device(
        espp::Spi::DeviceConfig{
            .command_bits = 8,
            .address_bits = 24,
            .mode = 0,
            .clock_speed_hz = clock_speed,
            .input_delay_ns = 0,
            .cs_io_num = spics,
            .queue_size = spi_queue_size,
            .flags = SPI_DEVICE_HALFDUPLEX,
#ifndef CONFIG_T_ENCODER_PRO
            .pre_cb = lcd_spi_pre_transfer_callback,
#endif
            .post_cb = lcd_spi_post_transfer_callback,
        },
        ec);
    if (ec || !spi_device) {
      fmt::print("Failed to initialize SPI device: {}\n", ec.message());
      return;
    }
#else
    panel_io = std::make_unique<espp::SpiPanelIo>(espp::SpiPanelIo::Config{
        .spi = spi_bus.get(),
        .device_config =
            {
                .mode = 0,
                .clock_speed_hz = clock_speed,
                .input_delay_ns = 0,
                .cs_io_num = spics,
                .queue_size = spi_queue_size,
#ifdef CONFIG_HARDWARE_BYTE90
                .flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_3WIRE,
#endif
            },
        .data_command_io = dc_pin,
        .data_command_bit_mask = DC_LEVEL_BIT,
        .post_transaction_callback_bit_mask = FLUSH_BIT,
        .post_transaction_callback = lcd_spi_flush_ready,
    });
    if (!panel_io->initialized()) {
      fmt::print("Failed to initialize SPI panel I/O\n");
      return;
    }
#endif

    auto display_driver = std::make_shared<DisplayDriver>(espp::display_drivers::Config{
        .panel_io =
#ifdef CONFIG_DISPLAY_QUAD_SPI
            nullptr,
        .write_command = write_command,
#else
            panel_io.get(),
        .write_command = nullptr,
#endif
        .read_command = nullptr,
#ifdef CONFIG_DISPLAY_QUAD_SPI
        .lcd_send_lines = lcd_send_lines,
#else
        .lcd_send_lines = nullptr,
#endif
        .reset_pin = reset,
#ifndef CONFIG_T_ENCODER_PRO
        .data_command_pin = dc_pin,
#endif
        .reset_value = reset_value,
        .invert_colors = invert_colors,
        .offset_x = offset_x,
        .offset_y = offset_y,
        .mirror_x = mirror_x,
        .mirror_y = mirror_y,
    });
    display_driver->initialize();
    // initialize the display / lvgl
    auto display = std::make_shared<Display>(
        Display::LvglConfig{
            .width = width,
            .height = height,
            .flush_callback =
                [display_driver](lv_display_t *disp, const lv_area_t *area, uint8_t *color_map) {
                  display_driver->flush(disp, area, color_map);
                },
            .rotation_callback =
                [display_driver](const espp::DisplayRotation &rotation) {
                  display_driver->set_rotation(rotation);
                },
            .rotation = rotation},
#if DISPLAY_IS_OLED
        Display::OledConfig{
            .set_brightness_callback =
                [display_driver](float brightness) { display_driver->set_brightness(brightness); },
            .get_brightness_callback =
                [display_driver]() { return display_driver->get_brightness(); }},
#else
        Display::LcdConfig{.backlight_pin = backlight, .backlight_on_value = backlight_on_value},
#endif
        Display::DynamicMemoryConfig{.pixel_buffer_size = pixel_buffer_size,
                                     .double_buffered = true});

    display->set_brightness(1.0f);

    // initialize the gui
    Gui gui({});
    size_t iterations = 0;
    while (true) {
      auto label = fmt::format("Iterations: {}", iterations);
      gui.set_label(label);
      gui.set_meter(iterations % 100);
      iterations++;
      std::this_thread::sleep_for(100ms);
    }

Public Functions

inline virtual bool initialize() override

Initialize the concrete display controller.

Returns:

True on success.

inline virtual void set_rotation(const DisplayRotation &rotation) override

Update the controller rotation state.

Parameters:

rotation – New display rotation.

inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override

Clear a rectangular region to a solid color.

Parameters:
  • x – Starting X coordinate.

  • y – Starting Y coordinate.

  • width – Width in pixels.

  • height – Height in pixels.

  • color – RGB565 color value.

inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)

Write an area of pixel data without implicitly notifying LVGL.

Parameters:
  • disp – LVGL display pointer, used when synchronous flush completion is needed.

  • area – Area to update.

  • color_map – Pixel buffer for the area.

  • flags – Transport/user flags passed through to the write path.

inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)

Flush an area of pixel data and notify LVGL when appropriate.

Parameters:
  • disp – LVGL display pointer.

  • area – Area to flush.

  • color_map – Pixel buffer for the area.

inline virtual void set_offset(int x, int y)

Update the controller’s logical top-left pixel offset.

Parameters:
  • x – X offset in pixels.

  • y – Y offset in pixels.

inline virtual void get_offset(int &x, int &y) const

Read the controller’s logical top-left pixel offset.

Parameters:
  • x – Filled with the current X offset.

  • y – Filled with the current Y offset.

Header File

Classes

class Ili9881 : public espp::display_drivers::MipiDbiDisplayDriver

Display driver for the ILI9881C display controller (DSI/DCS style).

This follows the same interface as the other display drivers and relies on a lower-level transport to execute write_command and bulk color transfers.

The initialization sequence includes the comprehensive M5Stack Tab5 setup with GIP (Gate In Panel) timing control, power management, and gamma correction for optimal display quality.

Public Functions

inline virtual bool initialize() override

Initialize the concrete display controller.

Returns:

True on success.

inline virtual void set_rotation(const DisplayRotation &rotation) override

Update the controller rotation state.

Parameters:

rotation – New display rotation.

inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override

Clear a rectangular region to a solid color.

Parameters:
  • x – Starting X coordinate.

  • y – Starting Y coordinate.

  • width – Width in pixels.

  • height – Height in pixels.

  • color – RGB565 color value.

inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)

Write an area of pixel data without implicitly notifying LVGL.

Parameters:
  • disp – LVGL display pointer, used when synchronous flush completion is needed.

  • area – Area to update.

  • color_map – Pixel buffer for the area.

  • flags – Transport/user flags passed through to the write path.

inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)

Flush an area of pixel data and notify LVGL when appropriate.

Parameters:
  • disp – LVGL display pointer.

  • area – Area to flush.

  • color_map – Pixel buffer for the area.

inline virtual void set_offset(int x, int y)

Update the controller’s logical top-left pixel offset.

Parameters:
  • x – X offset in pixels.

  • y – Y offset in pixels.

inline virtual void get_offset(int &x, int &y) const

Read the controller’s logical top-left pixel offset.

Parameters:
  • x – Filled with the current X offset.

  • y – Filled with the current Y offset.

Header File

Classes

class Sh8601 : public espp::display_drivers::MipiDbiDisplayDriver

Display driver for the SH8601 display controller.

SmartKnob Config

  static constexpr std::string_view dev_kit = "Lilygo T-Encoder-Pro";
  int clock_speed = 80 * 1000 * 1000;
  constexpr gpio_num_t mosi = GPIO_NUM_11;
  constexpr gpio_num_t miso = GPIO_NUM_13;
  constexpr gpio_num_t data2 = GPIO_NUM_7;
  constexpr gpio_num_t data3 = GPIO_NUM_14;
  constexpr gpio_num_t sclk = GPIO_NUM_12;
  constexpr gpio_num_t spics = GPIO_NUM_10;
  constexpr gpio_num_t reset = GPIO_NUM_4;
  constexpr gpio_num_t enable = GPIO_NUM_3;
  constexpr size_t width = 390;
  constexpr size_t height = 390;
  constexpr size_t pixel_buffer_size = width * height / 10;

  bool reset_value = false;
  bool invert_colors = false;
  int offset_x = 0;
  int offset_y = 0;
  bool mirror_x = false;
  bool mirror_y = false;
  auto rotation = espp::DisplayRotation::LANDSCAPE;

Sh8601 Example

    spi_bus = std::make_unique<espp::Spi>(espp::Spi::Config{
        .host = spi_num,
        .sclk_io_num = sclk,
        .mosi_io_num = mosi,
#ifdef CONFIG_DISPLAY_QUAD_SPI
        .miso_io_num = miso,
        .quadwp_io_num = data2,
        .quadhd_io_num = data3,
#else
        .miso_io_num = GPIO_NUM_NC,
#endif
        .max_transfer_sz = SPI_MAX_TRANSFER_BYTES,
    });
    if (!spi_bus->initialized()) {
      fmt::print("Failed to initialize SPI bus\n");
      return;
    }

#ifdef CONFIG_DISPLAY_QUAD_SPI
    std::error_code ec;
    spi_device = spi_bus->add_device(
        espp::Spi::DeviceConfig{
            .command_bits = 8,
            .address_bits = 24,
            .mode = 0,
            .clock_speed_hz = clock_speed,
            .input_delay_ns = 0,
            .cs_io_num = spics,
            .queue_size = spi_queue_size,
            .flags = SPI_DEVICE_HALFDUPLEX,
#ifndef CONFIG_T_ENCODER_PRO
            .pre_cb = lcd_spi_pre_transfer_callback,
#endif
            .post_cb = lcd_spi_post_transfer_callback,
        },
        ec);
    if (ec || !spi_device) {
      fmt::print("Failed to initialize SPI device: {}\n", ec.message());
      return;
    }
#else
    panel_io = std::make_unique<espp::SpiPanelIo>(espp::SpiPanelIo::Config{
        .spi = spi_bus.get(),
        .device_config =
            {
                .mode = 0,
                .clock_speed_hz = clock_speed,
                .input_delay_ns = 0,
                .cs_io_num = spics,
                .queue_size = spi_queue_size,
#ifdef CONFIG_HARDWARE_BYTE90
                .flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_3WIRE,
#endif
            },
        .data_command_io = dc_pin,
        .data_command_bit_mask = DC_LEVEL_BIT,
        .post_transaction_callback_bit_mask = FLUSH_BIT,
        .post_transaction_callback = lcd_spi_flush_ready,
    });
    if (!panel_io->initialized()) {
      fmt::print("Failed to initialize SPI panel I/O\n");
      return;
    }
#endif

    auto display_driver = std::make_shared<DisplayDriver>(espp::display_drivers::Config{
        .panel_io =
#ifdef CONFIG_DISPLAY_QUAD_SPI
            nullptr,
        .write_command = write_command,
#else
            panel_io.get(),
        .write_command = nullptr,
#endif
        .read_command = nullptr,
#ifdef CONFIG_DISPLAY_QUAD_SPI
        .lcd_send_lines = lcd_send_lines,
#else
        .lcd_send_lines = nullptr,
#endif
        .reset_pin = reset,
#ifndef CONFIG_T_ENCODER_PRO
        .data_command_pin = dc_pin,
#endif
        .reset_value = reset_value,
        .invert_colors = invert_colors,
        .offset_x = offset_x,
        .offset_y = offset_y,
        .mirror_x = mirror_x,
        .mirror_y = mirror_y,
    });
    display_driver->initialize();
    // initialize the display / lvgl
    auto display = std::make_shared<Display>(
        Display::LvglConfig{
            .width = width,
            .height = height,
            .flush_callback =
                [display_driver](lv_display_t *disp, const lv_area_t *area, uint8_t *color_map) {
                  display_driver->flush(disp, area, color_map);
                },
            .rotation_callback =
                [display_driver](const espp::DisplayRotation &rotation) {
                  display_driver->set_rotation(rotation);
                },
            .rotation = rotation},
#if DISPLAY_IS_OLED
        Display::OledConfig{
            .set_brightness_callback =
                [display_driver](float brightness) { display_driver->set_brightness(brightness); },
            .get_brightness_callback =
                [display_driver]() { return display_driver->get_brightness(); }},
#else
        Display::LcdConfig{.backlight_pin = backlight, .backlight_on_value = backlight_on_value},
#endif
        Display::DynamicMemoryConfig{.pixel_buffer_size = pixel_buffer_size,
                                     .double_buffered = true});

    display->set_brightness(1.0f);

    // initialize the gui
    Gui gui({});
    size_t iterations = 0;
    while (true) {
      auto label = fmt::format("Iterations: {}", iterations);
      gui.set_label(label);
      gui.set_meter(iterations % 100);
      iterations++;
      std::this_thread::sleep_for(100ms);
    }

Public Functions

inline virtual bool initialize() override

Initialize the concrete display controller.

Returns:

True on success.

inline virtual void set_rotation(const DisplayRotation &rotation) override

Update the controller rotation state.

Parameters:

rotation – New display rotation.

inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override

Clear a rectangular region to a solid color.

Parameters:
  • x – Starting X coordinate.

  • y – Starting Y coordinate.

  • width – Width in pixels.

  • height – Height in pixels.

  • color – RGB565 color value.

inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)

Write an area of pixel data without implicitly notifying LVGL.

Parameters:
  • disp – LVGL display pointer, used when synchronous flush completion is needed.

  • area – Area to update.

  • color_map – Pixel buffer for the area.

  • flags – Transport/user flags passed through to the write path.

inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)

Flush an area of pixel data and notify LVGL when appropriate.

Parameters:
  • disp – LVGL display pointer.

  • area – Area to flush.

  • color_map – Pixel buffer for the area.

inline virtual void set_offset(int x, int y)

Update the controller’s logical top-left pixel offset.

Parameters:
  • x – X offset in pixels.

  • y – Y offset in pixels.

inline virtual void get_offset(int &x, int &y) const

Read the controller’s logical top-left pixel offset.

Parameters:
  • x – Filled with the current X offset.

  • y – Filled with the current Y offset.

Header File

Classes

class SpiPanelIo : public espp::display_drivers::PanelIo, public espp::BaseComponent

LCD-style command/data helper built on top of `Spi`.

`queue_command()` transmits with D/C low. `queue_data()` and `queue_pixels()` always transmit with D/C high, so callers should treat them as payload helpers rather than manually setting the D/C bit for normal panel data transactions.

Public Types

using post_transaction_callback_t = void (*)(uint32_t user_flags)

IRQ-safe callback invoked after matching queued transactions finish.

Public Functions

explicit SpiPanelIo(const Config &config)

Construct a panel-I/O helper for SPI command/data displays.

Parameters:

config – Panel transport configuration.

virtual bool initialized() const override

Check whether the helper has a registered SPI device.

Returns:

True if initialization succeeded.

std::shared_ptr<Spi::Device> device() const

Get the underlying SPI device wrapper.

Returns:

Shared pointer to the attached SPI device.

virtual void wait() override

Wait for all queued transactions to complete.

virtual void write_command(uint8_t command, std::span<const uint8_t> parameters, uint32_t user_flags = 0) override

Send a command byte and optional parameter payload.

Parameters:
  • command – Command byte sent with D/C low.

  • parameters – Optional payload bytes sent with D/C high.

  • user_flags – Additional user-defined flags passed to callbacks.

virtual void queue_command(uint8_t command, uint32_t user_flags = 0) override

Queue a command transaction with D/C low.

Parameters:
  • command – Command byte to transmit.

  • user_flags – Additional user-defined flags passed to callbacks.

virtual void queue_data(std::span<const uint8_t> data, uint32_t user_flags = 0) override

Queue a non-pixel data payload with D/C high.

Parameters:
  • data – Data bytes to transmit.

  • user_flags – Additional user-defined flags passed to callbacks.

virtual void queue_pixels(const uint8_t *data, size_t size, uint32_t user_flags = 0, uint32_t transaction_flags = 0) override

Queue a pixel payload with D/C high.

Parameters:
  • data – Pointer to the pixel buffer.

  • size – Pixel payload size in bytes.

  • user_flags – Additional user-defined flags passed to callbacks.

  • transaction_flags – Optional SPI transaction flags overriding the default pixel flags.

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns:

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters:

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns:

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters:

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters:

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns:

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters:

rate_limit – The rate limit to use for the logger

struct Config

Configuration for `SpiPanelIo`.

Public Members

Spi *spi = nullptr

Bus on which to register the display device.

Spi::DeviceConfig device_config = {}

SPI device configuration.

gpio_num_t data_command_io = GPIO_NUM_NC

D/C GPIO pin.

uint32_t data_command_bit_mask = 1u << static_cast<uint32_t>(display_drivers::Flags::DC_LEVEL_BIT)

User bit that selects data mode.

uint32_t post_transaction_callback_bit_mask = 0

User bit mask that triggers the callback.

post_transaction_callback_t post_transaction_callback = nullptr

Optional IRQ-safe callback.

uint32_t pixel_data_flags = SPI_TRANS_DMA_BUFFER_ALIGN_MANUAL

Flags used for pixel payload transfers.

uint32_t timeout_ms = 10

Queue/result timeout in milliseconds.

Logger::Verbosity log_level = Logger::Verbosity::WARN

Logger verbosity.

Header File

Classes

class Ssd1351 : public espp::display_drivers::MipiDbiDisplayDriver

Display driver for the SSD1351 128x128 RGB OLED display controller.

Byte90 Ssd1351 Config

  static constexpr std::string_view dev_kit = "ALXV Labs Byte90";
  int clock_speed = 20 * 1000 * 1000;
  constexpr gpio_num_t mosi = GPIO_NUM_9;
  constexpr gpio_num_t miso = GPIO_NUM_NC;
  constexpr gpio_num_t sclk = GPIO_NUM_7;
  constexpr gpio_num_t spics = GPIO_NUM_44;
  constexpr gpio_num_t reset = GPIO_NUM_1;
  constexpr gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM;
  constexpr size_t width = 128;
  constexpr size_t height = 128;
  constexpr size_t pixel_buffer_size = width * height * sizeof(uint16_t);

  bool reset_value = false;
  bool invert_colors = false;
  int offset_x = 0;
  int offset_y = 0;
  bool mirror_x = false;
  bool mirror_y = true;
  auto rotation = espp::DisplayRotation::LANDSCAPE;

ssd1351 Example

    spi_bus = std::make_unique<espp::Spi>(espp::Spi::Config{
        .host = spi_num,
        .sclk_io_num = sclk,
        .mosi_io_num = mosi,
#ifdef CONFIG_DISPLAY_QUAD_SPI
        .miso_io_num = miso,
        .quadwp_io_num = data2,
        .quadhd_io_num = data3,
#else
        .miso_io_num = GPIO_NUM_NC,
#endif
        .max_transfer_sz = SPI_MAX_TRANSFER_BYTES,
    });
    if (!spi_bus->initialized()) {
      fmt::print("Failed to initialize SPI bus\n");
      return;
    }

#ifdef CONFIG_DISPLAY_QUAD_SPI
    std::error_code ec;
    spi_device = spi_bus->add_device(
        espp::Spi::DeviceConfig{
            .command_bits = 8,
            .address_bits = 24,
            .mode = 0,
            .clock_speed_hz = clock_speed,
            .input_delay_ns = 0,
            .cs_io_num = spics,
            .queue_size = spi_queue_size,
            .flags = SPI_DEVICE_HALFDUPLEX,
#ifndef CONFIG_T_ENCODER_PRO
            .pre_cb = lcd_spi_pre_transfer_callback,
#endif
            .post_cb = lcd_spi_post_transfer_callback,
        },
        ec);
    if (ec || !spi_device) {
      fmt::print("Failed to initialize SPI device: {}\n", ec.message());
      return;
    }
#else
    panel_io = std::make_unique<espp::SpiPanelIo>(espp::SpiPanelIo::Config{
        .spi = spi_bus.get(),
        .device_config =
            {
                .mode = 0,
                .clock_speed_hz = clock_speed,
                .input_delay_ns = 0,
                .cs_io_num = spics,
                .queue_size = spi_queue_size,
#ifdef CONFIG_HARDWARE_BYTE90
                .flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_3WIRE,
#endif
            },
        .data_command_io = dc_pin,
        .data_command_bit_mask = DC_LEVEL_BIT,
        .post_transaction_callback_bit_mask = FLUSH_BIT,
        .post_transaction_callback = lcd_spi_flush_ready,
    });
    if (!panel_io->initialized()) {
      fmt::print("Failed to initialize SPI panel I/O\n");
      return;
    }
#endif

    auto display_driver = std::make_shared<DisplayDriver>(espp::display_drivers::Config{
        .panel_io =
#ifdef CONFIG_DISPLAY_QUAD_SPI
            nullptr,
        .write_command = write_command,
#else
            panel_io.get(),
        .write_command = nullptr,
#endif
        .read_command = nullptr,
#ifdef CONFIG_DISPLAY_QUAD_SPI
        .lcd_send_lines = lcd_send_lines,
#else
        .lcd_send_lines = nullptr,
#endif
        .reset_pin = reset,
#ifndef CONFIG_T_ENCODER_PRO
        .data_command_pin = dc_pin,
#endif
        .reset_value = reset_value,
        .invert_colors = invert_colors,
        .offset_x = offset_x,
        .offset_y = offset_y,
        .mirror_x = mirror_x,
        .mirror_y = mirror_y,
    });
    display_driver->initialize();
    // initialize the display / lvgl
    auto display = std::make_shared<Display>(
        Display::LvglConfig{
            .width = width,
            .height = height,
            .flush_callback =
                [display_driver](lv_display_t *disp, const lv_area_t *area, uint8_t *color_map) {
                  display_driver->flush(disp, area, color_map);
                },
            .rotation_callback =
                [display_driver](const espp::DisplayRotation &rotation) {
                  display_driver->set_rotation(rotation);
                },
            .rotation = rotation},
#if DISPLAY_IS_OLED
        Display::OledConfig{
            .set_brightness_callback =
                [display_driver](float brightness) { display_driver->set_brightness(brightness); },
            .get_brightness_callback =
                [display_driver]() { return display_driver->get_brightness(); }},
#else
        Display::LcdConfig{.backlight_pin = backlight, .backlight_on_value = backlight_on_value},
#endif
        Display::DynamicMemoryConfig{.pixel_buffer_size = pixel_buffer_size,
                                     .double_buffered = true});

    display->set_brightness(1.0f);

    // initialize the gui
    Gui gui({});
    size_t iterations = 0;
    while (true) {
      auto label = fmt::format("Iterations: {}", iterations);
      gui.set_label(label);
      gui.set_meter(iterations % 100);
      iterations++;
      std::this_thread::sleep_for(100ms);
    }

Public Functions

inline virtual bool initialize() override

Initialize the concrete display controller.

Returns:

True on success.

inline virtual void set_rotation(const DisplayRotation &rotation) override

Update the controller rotation state.

Parameters:

rotation – New display rotation.

inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override

Clear a rectangular region to a solid color.

Parameters:
  • x – Starting X coordinate.

  • y – Starting Y coordinate.

  • width – Width in pixels.

  • height – Height in pixels.

  • color – RGB565 color value.

inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)

Write an area of pixel data without implicitly notifying LVGL.

Parameters:
  • disp – LVGL display pointer, used when synchronous flush completion is needed.

  • area – Area to update.

  • color_map – Pixel buffer for the area.

  • flags – Transport/user flags passed through to the write path.

inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)

Flush an area of pixel data and notify LVGL when appropriate.

Parameters:
  • disp – LVGL display pointer.

  • area – Area to flush.

  • color_map – Pixel buffer for the area.

inline virtual void set_offset(int x, int y)

Update the controller’s logical top-left pixel offset.

Parameters:
  • x – X offset in pixels.

  • y – Y offset in pixels.

inline virtual void get_offset(int &x, int &y) const

Read the controller’s logical top-left pixel offset.

Parameters:
  • x – Filled with the current X offset.

  • y – Filled with the current Y offset.

Header File

Classes

class St7123 : public espp::display_drivers::MipiDbiDisplayDriver

Public Functions

inline virtual bool initialize() override

Initialize the concrete display controller.

Returns:

True on success.

inline virtual void set_rotation(const DisplayRotation &rotation) override

Update the controller rotation state.

Parameters:

rotation – New display rotation.

inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override

Clear a rectangular region to a solid color.

Parameters:
  • x – Starting X coordinate.

  • y – Starting Y coordinate.

  • width – Width in pixels.

  • height – Height in pixels.

  • color – RGB565 color value.

inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)

Write an area of pixel data without implicitly notifying LVGL.

Parameters:
  • disp – LVGL display pointer, used when synchronous flush completion is needed.

  • area – Area to update.

  • color_map – Pixel buffer for the area.

  • flags – Transport/user flags passed through to the write path.

inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)

Flush an area of pixel data and notify LVGL when appropriate.

Parameters:
  • disp – LVGL display pointer.

  • area – Area to flush.

  • color_map – Pixel buffer for the area.

inline virtual void set_offset(int x, int y)

Update the controller’s logical top-left pixel offset.

Parameters:
  • x – X offset in pixels.

  • y – Y offset in pixels.

inline virtual void get_offset(int &x, int &y) const

Read the controller’s logical top-left pixel offset.

Parameters:
  • x – Filled with the current X offset.

  • y – Filled with the current Y offset.

Header File

Classes

class St7789 : public espp::display_drivers::MipiDbiDisplayDriver

Display driver for the ST7789 display controller.

This code is modified from https://github.com/lvgl/lvgl_esp32_drivers/blob/master/lvgl_tft/st7789.c and https://github.com/Bodmer/TFT_eSPI/blob/master/TFT_Drivers/ST7789_Defines.h

TTGO St7789 Config

  static constexpr std::string_view dev_kit = "TTGO T-Display";
  int clock_speed = 60 * 1000 * 1000;
  gpio_num_t mosi = GPIO_NUM_19;
  gpio_num_t sclk = GPIO_NUM_18;
  gpio_num_t spics = GPIO_NUM_5;
  gpio_num_t reset = GPIO_NUM_23;
  gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM;
  gpio_num_t backlight = GPIO_NUM_4;
  size_t width = 240;
  size_t height = 135;
  size_t pixel_buffer_size = 12800;
  bool backlight_on_value = false;
  bool reset_value = false;
  bool invert_colors = false;
  int offset_x = 40;
  int offset_y = 53;
  bool mirror_x = false;
  bool mirror_y = false;
  auto rotation = espp::DisplayRotation::PORTRAIT;

ESP32-S3-BOX St7789 Config

  static constexpr std::string_view dev_kit = "ESP32-S3-BOX";
  int clock_speed = 60 * 1000 * 1000;
  gpio_num_t mosi = GPIO_NUM_6;
  gpio_num_t sclk = GPIO_NUM_7;
  gpio_num_t spics = GPIO_NUM_5;
  gpio_num_t reset = GPIO_NUM_48;
  gpio_num_t dc_pin = (gpio_num_t)DC_PIN_NUM;
  gpio_num_t backlight = GPIO_NUM_45;
  size_t width = 320;
  size_t height = 240;
  size_t pixel_buffer_size = width * 50;
  bool backlight_on_value = true;
  bool reset_value = false;
  bool invert_colors = true;
  int offset_x = 0;
  int offset_y = 0;
  bool mirror_x = true;
  bool mirror_y = true;
  auto rotation = espp::DisplayRotation::LANDSCAPE;

st7789 Example

    spi_bus = std::make_unique<espp::Spi>(espp::Spi::Config{
        .host = spi_num,
        .sclk_io_num = sclk,
        .mosi_io_num = mosi,
#ifdef CONFIG_DISPLAY_QUAD_SPI
        .miso_io_num = miso,
        .quadwp_io_num = data2,
        .quadhd_io_num = data3,
#else
        .miso_io_num = GPIO_NUM_NC,
#endif
        .max_transfer_sz = SPI_MAX_TRANSFER_BYTES,
    });
    if (!spi_bus->initialized()) {
      fmt::print("Failed to initialize SPI bus\n");
      return;
    }

#ifdef CONFIG_DISPLAY_QUAD_SPI
    std::error_code ec;
    spi_device = spi_bus->add_device(
        espp::Spi::DeviceConfig{
            .command_bits = 8,
            .address_bits = 24,
            .mode = 0,
            .clock_speed_hz = clock_speed,
            .input_delay_ns = 0,
            .cs_io_num = spics,
            .queue_size = spi_queue_size,
            .flags = SPI_DEVICE_HALFDUPLEX,
#ifndef CONFIG_T_ENCODER_PRO
            .pre_cb = lcd_spi_pre_transfer_callback,
#endif
            .post_cb = lcd_spi_post_transfer_callback,
        },
        ec);
    if (ec || !spi_device) {
      fmt::print("Failed to initialize SPI device: {}\n", ec.message());
      return;
    }
#else
    panel_io = std::make_unique<espp::SpiPanelIo>(espp::SpiPanelIo::Config{
        .spi = spi_bus.get(),
        .device_config =
            {
                .mode = 0,
                .clock_speed_hz = clock_speed,
                .input_delay_ns = 0,
                .cs_io_num = spics,
                .queue_size = spi_queue_size,
#ifdef CONFIG_HARDWARE_BYTE90
                .flags = SPI_DEVICE_NO_DUMMY | SPI_DEVICE_3WIRE,
#endif
            },
        .data_command_io = dc_pin,
        .data_command_bit_mask = DC_LEVEL_BIT,
        .post_transaction_callback_bit_mask = FLUSH_BIT,
        .post_transaction_callback = lcd_spi_flush_ready,
    });
    if (!panel_io->initialized()) {
      fmt::print("Failed to initialize SPI panel I/O\n");
      return;
    }
#endif

    auto display_driver = std::make_shared<DisplayDriver>(espp::display_drivers::Config{
        .panel_io =
#ifdef CONFIG_DISPLAY_QUAD_SPI
            nullptr,
        .write_command = write_command,
#else
            panel_io.get(),
        .write_command = nullptr,
#endif
        .read_command = nullptr,
#ifdef CONFIG_DISPLAY_QUAD_SPI
        .lcd_send_lines = lcd_send_lines,
#else
        .lcd_send_lines = nullptr,
#endif
        .reset_pin = reset,
#ifndef CONFIG_T_ENCODER_PRO
        .data_command_pin = dc_pin,
#endif
        .reset_value = reset_value,
        .invert_colors = invert_colors,
        .offset_x = offset_x,
        .offset_y = offset_y,
        .mirror_x = mirror_x,
        .mirror_y = mirror_y,
    });
    display_driver->initialize();
    // initialize the display / lvgl
    auto display = std::make_shared<Display>(
        Display::LvglConfig{
            .width = width,
            .height = height,
            .flush_callback =
                [display_driver](lv_display_t *disp, const lv_area_t *area, uint8_t *color_map) {
                  display_driver->flush(disp, area, color_map);
                },
            .rotation_callback =
                [display_driver](const espp::DisplayRotation &rotation) {
                  display_driver->set_rotation(rotation);
                },
            .rotation = rotation},
#if DISPLAY_IS_OLED
        Display::OledConfig{
            .set_brightness_callback =
                [display_driver](float brightness) { display_driver->set_brightness(brightness); },
            .get_brightness_callback =
                [display_driver]() { return display_driver->get_brightness(); }},
#else
        Display::LcdConfig{.backlight_pin = backlight, .backlight_on_value = backlight_on_value},
#endif
        Display::DynamicMemoryConfig{.pixel_buffer_size = pixel_buffer_size,
                                     .double_buffered = true});

    display->set_brightness(1.0f);

    // initialize the gui
    Gui gui({});
    size_t iterations = 0;
    while (true) {
      auto label = fmt::format("Iterations: {}", iterations);
      gui.set_label(label);
      gui.set_meter(iterations % 100);
      iterations++;
      std::this_thread::sleep_for(100ms);
    }

Public Functions

inline virtual bool initialize() override

Initialize the concrete display controller.

Returns:

True on success.

inline virtual void set_rotation(const DisplayRotation &rotation) override

Update the controller rotation state.

Parameters:

rotation – New display rotation.

inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override

Clear a rectangular region to a solid color.

Parameters:
  • x – Starting X coordinate.

  • y – Starting Y coordinate.

  • width – Width in pixels.

  • height – Height in pixels.

  • color – RGB565 color value.

inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)

Write an area of pixel data without implicitly notifying LVGL.

Parameters:
  • disp – LVGL display pointer, used when synchronous flush completion is needed.

  • area – Area to update.

  • color_map – Pixel buffer for the area.

  • flags – Transport/user flags passed through to the write path.

inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)

Flush an area of pixel data and notify LVGL when appropriate.

Parameters:
  • disp – LVGL display pointer.

  • area – Area to flush.

  • color_map – Pixel buffer for the area.

inline virtual void set_offset(int x, int y)

Update the controller’s logical top-left pixel offset.

Parameters:
  • x – X offset in pixels.

  • y – Y offset in pixels.

inline virtual void get_offset(int &x, int &y) const

Read the controller’s logical top-left pixel offset.

Parameters:
  • x – Filled with the current X offset.

  • y – Filled with the current Y offset.

Header File

Classes

class St7796 : public espp::display_drivers::MipiDbiDisplayDriver

Display driver for the ST7796 display controller.

Public Types

enum class Command : uint8_t

Supported command values used by this driver wrapper.

Values:

enumerator slpout

Exit sleep mode.

enumerator invoff

Disable display inversion.

enumerator invon

Enable display inversion.

enumerator dispon

Turn the display on.

enumerator caset

Set the column address window.

enumerator raset

Set the row address window.

enumerator ramwr

Write pixel data to RAM.

enumerator madctl

Configure memory addressing and rotation.

enumerator colmod

Configure color depth / pixel format.

Public Functions

inline virtual bool initialize() override

Initialize the concrete display controller.

Returns:

True on success.

inline virtual void set_rotation(const DisplayRotation &rotation) override

Update the controller rotation state.

Parameters:

rotation – New display rotation.

inline virtual void clear(size_t x, size_t y, size_t width, size_t height, uint16_t color = 0x0000) override

Clear a rectangular region to a solid color.

Parameters:
  • x – Starting X coordinate.

  • y – Starting Y coordinate.

  • width – Width in pixels.

  • height – Height in pixels.

  • color – RGB565 color value.

inline virtual void fill(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map, uint32_t flags = 0)

Write an area of pixel data without implicitly notifying LVGL.

Parameters:
  • disp – LVGL display pointer, used when synchronous flush completion is needed.

  • area – Area to update.

  • color_map – Pixel buffer for the area.

  • flags – Transport/user flags passed through to the write path.

inline virtual void flush(lv_display_t *disp, const lv_area_t *area, uint8_t *color_map)

Flush an area of pixel data and notify LVGL when appropriate.

Parameters:
  • disp – LVGL display pointer.

  • area – Area to flush.

  • color_map – Pixel buffer for the area.

inline virtual void set_offset(int x, int y)

Update the controller’s logical top-left pixel offset.

Parameters:
  • x – X offset in pixels.

  • y – Y offset in pixels.

inline virtual void get_offset(int &x, int &y) const

Read the controller’s logical top-left pixel offset.

Parameters:
  • x – Filled with the current X offset.

  • y – Filled with the current Y offset.