ESP32-WROVER-KIT

Wrover-Kit

The ESP32-WROVER-KIT is a development board for the ESP32-WROVER module. It features a nice display and a lot of expansion headers.

The espp::WroverKit component provides a singleton hardware abstraction for initializing the display subsystems.

API Reference

Header File

Classes

class WroverKit : public espp::BaseComponent

The WroverKit class provides an interface to the ESP32-WROVER-KIT ESP32 development board.

The class provides access to the following features:

The class is a singleton and can be accessed using the get() method.

Example

  espp::WroverKit &wrover = espp::WroverKit::get();
  wrover.set_log_level(espp::Logger::Verbosity::INFO);

  // initialize the LCD
  if (!wrover.initialize_lcd()) {
    logger.error("Failed to initialize LCD!");
    return;
  }
  // set the pixel buffer to be 50 lines high
  static constexpr size_t pixel_buffer_size = wrover.lcd_width() * 50;
  // initialize the LVGL display for the wrover-kit
  if (!wrover.initialize_display(pixel_buffer_size)) {
    logger.error("Failed to initialize display!");
    return;
  }

  logger.info("Adding LVGL objects to the screen.");
  lv_obj_t *bg = nullptr;
  lv_obj_t *label = nullptr;
  static auto update_layout = [&]() {
    int width = wrover.rotated_display_width();
    int height = wrover.rotated_display_height();
    lv_obj_set_size(bg, width, height);
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
    if (circle_layer) {
      lv_obj_set_size(circle_layer, width, height);
      lv_obj_align(circle_layer, LV_ALIGN_CENTER, 0, 0);
      lv_obj_move_foreground(circle_layer);
      lv_obj_invalidate(circle_layer);
    }
  };

  // initialize the button, which we'll use to cycle the rotation of the display
  espp::Button button(espp::Button::Config{
      .name = "Boot Button",
      .interrupt_config =
          espp::Interrupt::PinConfig{.gpio_num = GPIO_NUM_0,
                                     .callback =
                                         [](const auto &event) {
                                           if (event.active) {
                                             // lock the display mutex
                                             std::lock_guard<std::mutex> lock(lvgl_mutex);
                                             static auto rotation = LV_DISPLAY_ROTATION_0;
                                             rotation = static_cast<lv_display_rotation_t>(
                                                 (static_cast<int>(rotation) + 1) % 4);
                                             fmt::print("Setting rotation to {}\n", (int)rotation);
                                             lv_display_t *disp = lv_display_get_default();
                                             lv_disp_set_rotation(disp, rotation);
                                             update_layout();
                                           }
                                         },
                                     .active_level = espp::Interrupt::ActiveLevel::LOW,
                                     .interrupt_type = espp::Interrupt::Type::ANY_EDGE,
                                     .pullup_enabled = false,
                                     .pulldown_enabled = false},
  });

  // set the background color to black
  bg = lv_obj_create(lv_screen_active());
  lv_obj_set_size(bg, wrover.rotated_display_width(), wrover.rotated_display_height());
  lv_obj_set_style_bg_color(bg, lv_color_make(0, 0, 0), 0);
  if (!initialize_circle_layer(wrover.rotated_display_width(), wrover.rotated_display_height())) {
    logger.error("Failed to initialize circle layer!");
    return;
  }

  // add text in the center of the screen
  label = lv_label_create(lv_screen_active());
  lv_label_set_text(label, "Drawing circles to the screen.");
  lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
  lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
  update_layout();

  lv_obj_move_foreground(circle_layer);

  // start a simple thread to do the lv_task_handler every 16ms
  espp::Task lv_task({.callback = [](std::mutex &m, std::condition_variable &cv) -> bool {
                        {
                          std::lock_guard<std::mutex> lock(lvgl_mutex);
                          lv_task_handler();
                        }
                        std::unique_lock<std::mutex> lock(m);
                        cv.wait_for(lock, 16ms);
                        return false;
                      },
                      .task_config = {
                          .name = "lv_task",
                      }});
  lv_task.start();

  // set the display brightness to be 75%
  wrover.brightness(75.0f);

  while (true) {
    auto start = esp_timer_get_time();
    // if there are 10 circles on the screen, clear them
    if (visible_circle_count >= MAX_CIRCLES) {
      std::lock_guard<std::mutex> lock(lvgl_mutex);
      clear_circles();
    } else {
      // draw a circle of circles on the screen (just draw the next circle)
      int middle_x = wrover.rotated_display_width() / 2;
      int middle_y = wrover.rotated_display_height() / 2;
      static constexpr int radius = 50;
      float angle = visible_circle_count * 2.0f * M_PI / MAX_CIRCLES;
      int x = middle_x + radius * cos(angle);
      int y = middle_y + radius * sin(angle);
      std::lock_guard<std::mutex> lock(lvgl_mutex);
      draw_circle(x, y, 10);
    }
    auto end = esp_timer_get_time();
    auto elapsed = end - start;
    std::this_thread::sleep_for(100ms - std::chrono::microseconds(elapsed));
  }

Public Types

using Pixel = lv_color16_t

Alias for the pixel type used by the wrover-kit display.

Public Functions

bool initialize_lcd()

Initialize the LCD (low level display driver)

Returns:

true if the LCD was successfully initialized, false otherwise

bool initialize_display(size_t pixel_buffer_size)

Initialize the display (lvgl display driver)

Note

This will also allocate two full frame buffers in the SPIRAM

Parameters:

pixel_buffer_size – The size of the pixel buffer

Returns:

true if the display was successfully initialized, false otherwise

size_t rotated_display_width() const

Get the display width in pixels, according to the current orientation

Returns:

The display width in pixels, according to the current orientation

size_t rotated_display_height() const

Get the display height in pixels, according to the current orientation

Returns:

The display height in pixels, according to the current orientation

std::shared_ptr<Display<Pixel>> display() const

Get a shared pointer to the display

Returns:

A shared pointer to the display

void brightness(float brightness)

Set the brightness of the backlight

Note

This function will only work after initialize_lcd() has been called

Parameters:

brightness – The brightness of the backlight as a percentage (0 - 100)

float brightness() const

Get the brightness of the backlight

Note

This function will only work after initialize_lcd() has been called

Returns:

The brightness of the backlight as a percentage (0 - 100)

Pixel *vram0() const

Get the VRAM 0 pointer (DMA memory used by LVGL)

Note

This is the memory used by LVGL for rendering

Note

This is null unless initialize_display() has been called

Returns:

The VRAM 0 pointer

Pixel *vram1() const

Get the VRAM 1 pointer (DMA memory used by LVGL)

Note

This is the memory used by LVGL for rendering

Note

This is null unless initialize_display() has been called

Returns:

The VRAM 1 pointer

uint8_t *frame_buffer0() const

Get the frame buffer 0 pointer

Note

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

Note

This is null unless initialize_display() has been called

Returns:

The frame buffer 0 pointer

uint8_t *frame_buffer1() const

Get the frame buffer 1 pointer

Note

This memory is designed to be used by the application developer and is provided as a convenience. It is not used by the display driver.

Note

This is null unless initialize_display() has been called

Returns:

The frame buffer 1 pointer

void write_lcd_frame(const uint16_t x, const uint16_t y, const uint16_t width, const uint16_t height, uint8_t *data)

Write a frame to the LCD

Note

This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction

Parameters:
  • x – The x coordinate

  • y – The y coordinate

  • width – The width of the frame, in pixels

  • height – The height of the frame, in pixels

  • data – The data to write

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

Public Static Functions

static inline WroverKit &get()

Access the singleton instance of the WroverKit class.

Returns:

Reference to the singleton instance of the WroverKit class

static inline constexpr size_t lcd_width()

Get the width of the LCD in pixels

Returns:

The width of the LCD in pixels

static inline constexpr size_t lcd_height()

Get the height of the LCD in pixels

Returns:

The height of the LCD in pixels

static inline constexpr auto get_lcd_dc_gpio()

Get the GPIO pin for the LCD data/command signal

Returns:

The GPIO pin for the LCD data/command signal

Public Static Attributes

static constexpr size_t SPI_MAX_TRANSFER_BYTES = SPI_LL_DMA_MAX_BIT_LEN / 8

Maximum number of bytes that can be transferred in a single SPI transaction to the Display. 2MB on ESP32.

struct TouchpadData

The data structure for the touchpad.

Public Functions

bool operator==(const TouchpadData &rhs) const = default

Compare two TouchpadData objects for equality.

Parameters:

rhs – The right hand side of the comparison

Returns:

true if the two TouchpadData objects are equal, false otherwise

Public Members

uint8_t num_touch_points = 0

The number of touch points.

uint16_t x = 0

The x coordinate.

uint16_t y = 0

The y coordinate.

uint8_t btn_state = 0

The button state (0 = button released, 1 = button pressed)