Seeed Studio Round Display
SsRoundDisplay
The Seeed Studio Round Display is a development board containing a 240x240 round display with touchscreen, RTC, battery charger, and uSD card slot. It support connection to a QtyPy or a XIAO module.
The espp::SsRoundDisplay component provides a singleton hardware abstraction for initializing the display and touchscreen components for the Seeed Studio Round Display.
API Reference
Header File
Classes
-
class SsRoundDisplay : public espp::BaseComponent
The SsRoundDisplay class provides an interface to the Seeed Studio Round Display development board.
The class provides access to the following features:
Touchpad
The class is a singleton and can be accessed using the get() method.
Example
#if CONFIG_EXAMPLE_HARDWARE_XIAOS3 logger.info("Using XiaoS3 hardware configuration"); espp::SsRoundDisplay::set_pin_config(espp::SsRoundDisplay::XiaoS3Config); #elif CONFIG_EXAMPLE_HARDWARE_QTPYS3 logger.info("Using QtpyS3 hardware configuration"); espp::SsRoundDisplay::set_pin_config(espp::SsRoundDisplay::QtpyS3Config); #else #error "Please select a hardware configuration" #endif espp::SsRoundDisplay &round_display = espp::SsRoundDisplay::get(); auto touch_callback = [&](const auto &touch) { // NOTE: since we're directly using the touchpad data, and not using the // TouchpadInput + LVGL, we'll need to ensure the touchpad data is // converted into proper screen coordinates instead of simply using the // raw values. static auto previous_touchpad_data = round_display.touchpad_convert(touch); auto touchpad_data = round_display.touchpad_convert(touch); if (touchpad_data != previous_touchpad_data) { logger.info("Touch: {}", touchpad_data); previous_touchpad_data = touchpad_data; // if the button is pressed, clear the circles if (touchpad_data.btn_state) { clear_circles(); } // if there is a touch point, draw a circle if (touchpad_data.num_touch_points > 0) { draw_circle(touchpad_data.x, touchpad_data.y, 10); } } }; // initialize the LCD if (!round_display.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 = round_display.lcd_width() * 50; espp::Task::BaseConfig display_task_config = { .name = "Display", .stack_size_bytes = 6 * 1024, .priority = 10, .core_id = 0, }; // initialize the LVGL display for the seeed-studio-round-display if (!round_display.initialize_display(pixel_buffer_size, display_task_config)) { logger.error("Failed to initialize display!"); return; } // initialize the touchpad if (!round_display.initialize_touch(touch_callback)) { logger.error("Failed to initialize touchpad!"); return; } // set the background color to black lv_obj_t *bg = lv_obj_create(lv_screen_active()); lv_obj_set_size(bg, round_display.lcd_width(), round_display.lcd_height()); lv_obj_set_style_bg_color(bg, lv_color_make(0, 0, 0), 0); // add text in the center of the screen lv_obj_t *label = lv_label_create(lv_screen_active()); lv_label_set_text(label, "Touch the screen!"); lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0); // add a button in the top middel which (when pressed) will rotate the display // through 0, 90, 180, 270 degrees lv_obj_t *btn = lv_btn_create(lv_screen_active()); lv_obj_set_size(btn, 50, 50); lv_obj_align(btn, LV_ALIGN_TOP_MID, 0, 0); lv_obj_t *label_btn = lv_label_create(btn); lv_label_set_text(label_btn, LV_SYMBOL_REFRESH); lv_obj_align(label_btn, LV_ALIGN_CENTER, 0, 0); lv_obj_add_event_cb(btn, on_rotate_pressed, LV_EVENT_PRESSED, nullptr); // add a button in the bottom middle which (when pressed) will clear the // circles lv_obj_t *btn_clear = lv_btn_create(lv_screen_active()); lv_obj_set_size(btn_clear, 50, 50); lv_obj_align(btn_clear, LV_ALIGN_BOTTOM_MID, 0, 0); lv_obj_add_state(btn_clear, LV_STATE_CHECKED); // make the button red lv_obj_t *label_btn_clear = lv_label_create(btn_clear); lv_label_set_text(label_btn_clear, LV_SYMBOL_TRASH); lv_obj_align(label_btn_clear, LV_ALIGN_CENTER, 0, 0); lv_obj_add_event_cb(btn_clear, on_clear_pressed, LV_EVENT_PRESSED, nullptr); // disable scrolling on the screen (so that it doesn't behave weirdly when // rotated and drawing with your finger) lv_obj_set_scrollbar_mode(lv_screen_active(), LV_SCROLLBAR_MODE_OFF); lv_obj_clear_flag(lv_screen_active(), LV_OBJ_FLAG_SCROLLABLE); // 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::recursive_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% round_display.brightness(75.0f); // loop forever while (true) { std::this_thread::sleep_for(1s); }
Note
You must call set_pin_config() before calling get() for the first time, in order to provide the appropriate pin configuration for the controller board connected to the display. Some pin configuration structures are provided for convenience.
Public Types
-
using Pixel = lv_color16_t
Alias for the type of pixel the display uses.
-
using TouchpadData = espp::TouchpadData
Alias for the touchpad data.
-
using touch_callback_t = std::function<void(const TouchpadData&)>
The touch callback function type
- Param data
The touchpad data
Public Functions
-
espp::I2c &internal_i2c()
Get a reference to the internal I2C bus
- Returns
A reference to the internal I2C bus
-
espp::Interrupt &interrupts()
Get a reference to the interrupts
- Returns
A reference to the interrupts
-
bool initialize_touch(const touch_callback_t &callback = nullptr)
Initialize the touchpad
Note
This will configure the touchpad interrupt pin which will automatically call the touch callback function when the touchpad is touched
Warning
This method should be called after the display has been initialized if you want the touchpad to be recognized and used with LVGL and its objects.
- Parameters
callback – The touchpad callback
- Returns
true if the touchpad was successfully initialized, false otherwise
-
std::shared_ptr<TouchpadInput> touchpad_input() const
Get the touchpad input
- Returns
A shared pointer to the touchpad input
-
TouchpadData touchpad_data() const
Get the most recent touchpad data
- Returns
The touchpad data
-
void touchpad_read(uint8_t *num_touch_points, uint16_t *x, uint16_t *y, uint8_t *btn_state)
Get the most recent touchpad data
See also
Note
This method is a convenience method for integrating with LVGL, the data it returns is identical to the data returned by the touchpad_data() method
- Parameters
num_touch_points – The number of touch points
x – The x coordinate
y – The y coordinate
btn_state – The button state (0 = button released, 1 = button pressed)
-
TouchpadData touchpad_convert(const TouchpadData &data) const
Convert touchpad data from raw reading to display coordinates
Note
Uses the touch_invert_x and touch_invert_y settings to determine if the x and y coordinates should be inverted
- Parameters
data – The touchpad data to convert
- Returns
The converted touchpad data
-
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, const espp::Task::BaseConfig &task_config={.name="Display",.stack_size_bytes=4096,.priority=10,.core_id=0}, int update_period_ms=16)
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
task_config – The task configuration for the display task
update_period_ms – The update period of the display task
- Returns
true if the display was successfully initialized, false otherwise
-
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
- Parameters
brightness – The brightness of the backlight as a percentage (0 - 100)
-
float brightness() const
Get the brightness of the backlight
- 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(const uint8_t *data, size_t length, uint32_t user_data)
Write data to the LCD
Note
This method is designed to be used by the display driver
Note
This method queues the data to be written to the LCD, only blocking if there is an ongoing SPI transaction
- Parameters
data – The data to write
length – The length of the data
user_data – User data to pass to the spi transaction callback
-
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
-
void write_lcd_lines(int xs, int ys, int xe, int ye, const uint8_t *data, uint32_t user_data)
Write lines 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
xs – The x start coordinate
ys – The y start coordinate
xe – The x end coordinate
ye – The y end coordinate
data – The data to write
user_data – User data to pass to the spi transaction callback
-
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
See also
See also
- Returns
The verbosity level of the logger
-
inline void set_log_level(espp::Logger::Verbosity level)
Set the log level for the logger
See also
See also
- 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
See also
See also
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
See also
See also
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
See also
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 void set_pin_config(const PinConfig &pin_config)
Set the pin configuration for the controller board connected to the display.
- Parameters
pin_config – The pin configuration for the controller board
-
static inline SsRoundDisplay &get()
Access the singleton instance of the SsRoundDisplay class.
Note
This method must be called after set_pin_config() has been called
- Returns
Reference to the singleton instance of the SsRoundDisplay 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 PinConfig XiaoS3Config = {.sda = GPIO_NUM_5,.scl = GPIO_NUM_6,.usd_cs = GPIO_NUM_3,.lcd_cs = GPIO_NUM_2,.lcd_dc = GPIO_NUM_4,.lcd_backlight = GPIO_NUM_43,.miso = GPIO_NUM_8,.mosi = GPIO_NUM_9,.sck = GPIO_NUM_7,.touch_interrupt = GPIO_NUM_44,}
The default pin configuration for the Seeed Studio Round Display connected to the Xiao ESP32-S3.
- static constexpr PinConfig QtpyS3Config = {.sda = GPIO_NUM_7,.scl = GPIO_NUM_6,.usd_cs = GPIO_NUM_9,.lcd_cs = GPIO_NUM_17,.lcd_dc = GPIO_NUM_8,.lcd_backlight = GPIO_NUM_5,.miso = GPIO_NUM_37,.mosi = GPIO_NUM_35,.sck = GPIO_NUM_36,.touch_interrupt = GPIO_NUM_16,}
The default pin configuration for the Seeed Studio Round Display connected to the Qtpy Esp32S3.
-
struct PinConfig
The pin configuration structure.
Public Members
-
gpio_num_t sda = GPIO_NUM_NC
I2C data.
-
gpio_num_t scl = GPIO_NUM_NC
I2C clock.
-
gpio_num_t usd_cs = GPIO_NUM_NC
uSD card chip select
-
gpio_num_t lcd_cs = GPIO_NUM_NC
LCD chip select.
-
gpio_num_t lcd_dc = GPIO_NUM_NC
LCD data/command.
-
gpio_num_t lcd_backlight = GPIO_NUM_NC
LCD backlight.
-
gpio_num_t miso = GPIO_NUM_NC
SPI MISO.
-
gpio_num_t mosi = GPIO_NUM_NC
SPI MOSI.
-
gpio_num_t sck = GPIO_NUM_NC
SPI SCK.
-
gpio_num_t touch_interrupt = GPIO_NUM_NC
Touch interrupt.
-
gpio_num_t sda = GPIO_NUM_NC