Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

demo: lvgl: Add lvgl sample to draw touch events on the screen #67508

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions samples/modules/lvgl/touch_draw/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(lvgl_touch_draw)

FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
48 changes: 48 additions & 0 deletions samples/modules/lvgl/touch_draw/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.. zephyr:code-sample:: lvgl-touch-draw
:name: LVGL touch draw demo
:relevant-api: display_interface input_interface

Allow "drawing" on the screen with use of a touch input

Overview
********

This sample application features drawing functionality based on touch input.
Received touch input will be drawn onto the surface of the screen.
This feature can be generally helpful for testing proper functionality of the
touch interface.

When the board features a user-button (``sw0``) pushing this button will clear
the screen again.

Requirements
************

This demo requires a board or a shield with a display and touch-input device,
for example:

- :ref:`m5stack_core2`

Please make sure (:dtcompatible:`zephyr,lvgl-pointer-input`) is defined in
device tree.

Memory requirements
===================
The sample application requires an LVGL memory pool of at least 32 kBytes.

Building and Running
********************

Example building for :ref:`m5stack_core2`:

.. zephyr-app-commands::
:zephyr-app: samples/modules/lvgl/touch_draw
:board: m5stack_core2
:goals: build flash

References
**********

.. target-notes::

.. _LVGL Web Page: https://lvgl.io/
3 changes: 3 additions & 0 deletions samples/modules/lvgl/touch_draw/boards/m5stack_core2.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: Apache-2.0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


CONFIG_MAIN_STACK_SIZE=4096
3 changes: 3 additions & 0 deletions samples/modules/lvgl/touch_draw/boards/m5stack_stamps3.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: Apache-2.0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto with esp32s2 overlay


CONFIG_MAIN_STACK_SIZE=4096
17 changes: 17 additions & 0 deletions samples/modules/lvgl/touch_draw/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CONFIG_MAIN_STACK_SIZE=2048

CONFIG_COMMON_LIBC_MALLOC=y
CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=-1

CONFIG_DISPLAY=y
CONFIG_DISPLAY_LOG_LEVEL_ERR=y

faxe1008 marked this conversation as resolved.
Show resolved Hide resolved
CONFIG_LOG=y
CONFIG_SHELL=y

CONFIG_INPUT=y

CONFIG_LVGL=y
CONFIG_LV_Z_MEM_POOL_HEAP_LIB_C=y
CONFIG_LV_USE_LOG=y
CONFIG_LV_FONT_MONTSERRAT_14=y
18 changes: 18 additions & 0 deletions samples/modules/lvgl/touch_draw/sample.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
sample:
description: LVGL touch draw demo
name: LVGL touch draw
common:
modules:
- lvgl
harness: none
tags:
- samples
- display
- touch
- gui
- lvgl
tests:
sample.display.lvgl.touch_draw:
filter: dt_chosen_enabled("zephyr,display") and dt_chosen_enabled("zephyr,lvgl-pointer-input")
min_flash: 250
min_ram: 32
147 changes: 147 additions & 0 deletions samples/modules/lvgl/touch_draw/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright (c) 2024 Martin Kiepfer <mrmarteng@teleschirm.org>
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/display.h>
#include <zephyr/drivers/gpio.h>
#include <stdlib.h>
#include <lvgl.h>
#include <stdio.h>
#include <string.h>
#include <zephyr/kernel.h>
faxe1008 marked this conversation as resolved.
Show resolved Hide resolved
#include <lvgl_input_device.h>

#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(app);

struct pressing_callback_context {
lv_obj_t *canvas;
lv_indev_t *indev;
};

#ifdef CONFIG_GPIO
struct button_callback_context {
struct gpio_callback callback;
lv_obj_t *canvas;
};
static struct gpio_dt_spec button_gpio = GPIO_DT_SPEC_GET_OR(DT_ALIAS(sw0), gpios, {0});

static void button_isr_callback(const struct device *port, struct gpio_callback *cb, uint32_t pins)
{
ARG_UNUSED(port);
ARG_UNUSED(pins);

struct button_callback_context *ctx =
CONTAINER_OF(cb, struct button_callback_context, callback);

lv_canvas_fill_bg(ctx->canvas, lv_color_black(), LV_OPA_TRANSP);
}
#endif /* CONFIG_GPIO */

static void lv_draw_pressing_callback(lv_event_t *e)
{
lv_point_t point;
lv_draw_rect_dsc_t dsc;
struct pressing_callback_context *ctx = e->user_data;

lv_indev_get_point(ctx->indev, &point);

lv_draw_rect_dsc_init(&dsc);
dsc.bg_color = lv_palette_main(LV_PALETTE_GREY);
dsc.border_width = 0U;
dsc.outline_color = lv_palette_main(LV_PALETTE_GREY);
dsc.outline_width = 3U;
dsc.outline_pad = 0U;
dsc.outline_opa = LV_OPA_COVER;
dsc.radius = 5U;

lv_canvas_draw_rect(ctx->canvas, point.x, point.y, 10U, 10U, &dsc);
}

int main(void)
{
const struct device *display_dev;
const struct device *pointer_dev;
lv_obj_t *touch_label;
lv_opa_t *mask_map;
static struct pressing_callback_context pressing_cb_ctx;
#ifdef CONFIG_GPIO
static struct button_callback_context btn_cb_ctx;

if (gpio_is_ready_dt(&button_gpio)) {
int err;

err = gpio_pin_configure_dt(&button_gpio, GPIO_INPUT);
if (err) {
LOG_ERR("Failed to configure button gpio: %d", err);
return -EIO;
}

gpio_init_callback(&btn_cb_ctx.callback, button_isr_callback, BIT(button_gpio.pin));
btn_cb_ctx.canvas = pressing_cb_ctx.canvas;

err = gpio_add_callback(button_gpio.port, &btn_cb_ctx.callback);
if (err) {
LOG_ERR("Failed to add button callback: %d", err);
return -EIO;
}

err = gpio_pin_interrupt_configure_dt(&button_gpio, GPIO_INT_EDGE_TO_ACTIVE);
if (err) {
LOG_ERR("Failed to configure button callback: %d", err);
return -EIO;
}
}
#endif

display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
if (!device_is_ready(display_dev)) {
LOG_ERR("Device not ready, aborting test");
return -ENODEV;
}

pointer_dev = DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_lvgl_pointer_input));
if (!device_is_ready(pointer_dev)) {
LOG_ERR("Device not ready, aborting test");
return -ENODEV;
}
pressing_cb_ctx.indev = lvgl_input_get_indev(pointer_dev);

/**
* The required canvas buf size is calculated by
* (lv_img_color_format_get_px_size(cf) * width) / 8 * height)
* 2 bpp are used here to reduce overall memory requirements
**/
mask_map = (lv_opa_t *)malloc(LV_VER_RES * LV_HOR_RES * sizeof(lv_opa_t) / 4U);
if (mask_map == NULL) {
LOG_ERR("Allocating canvas layer failed. Please review LVGL mem pool size.");
faxe1008 marked this conversation as resolved.
Show resolved Hide resolved
return -ENOMEM;
}

/* Create canvas layer for "drawing" touch events */
pressing_cb_ctx.canvas = lv_canvas_create(lv_scr_act());
lv_canvas_set_buffer(pressing_cb_ctx.canvas, mask_map, LV_HOR_RES, LV_VER_RES,
LV_IMG_CF_ALPHA_2BIT);
lv_canvas_fill_bg(pressing_cb_ctx.canvas, lv_color_black(), LV_OPA_TRANSP);
lv_obj_center(pressing_cb_ctx.canvas);
lv_obj_add_event_cb(lv_scr_act(), lv_draw_pressing_callback, LV_EVENT_PRESSING,
&pressing_cb_ctx);

/* Create label with "touch me" text */
touch_label = lv_label_create(lv_scr_act());
lv_label_set_text(touch_label, "touch me!");
lv_obj_align(touch_label, LV_ALIGN_CENTER, 0, 0);

lv_task_handler();
display_blanking_off(display_dev);

while (true) {
lv_task_handler();
k_sleep(K_MSEC(10));
faxe1008 marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +144 to +145
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
lv_task_handler();
k_sleep(K_MSEC(10));
k_sleep(lv_task_handler());

}
}