-
Notifications
You must be signed in to change notification settings - Fork 6.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
demo: lvgl: Add lvgl sample to draw touch events on the screen
This is a small lvgl touch demo application featuring functionality to "draw" on the the screen. This can be useful to test touch input functionality during board setup. Signed-off-by: Martin Kiepfer <mrmarteng@teleschirm.org>
- Loading branch information
Martin Kiepfer
committed
Feb 9, 2024
1 parent
24a4623
commit 7665fd7
Showing
7 changed files
with
247 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
CONFIG_MAIN_STACK_SIZE=4096 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
CONFIG_MAIN_STACK_SIZE=4096 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
/* | ||
* 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> | ||
#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; | ||
struct pressing_callback_context pressing_cb_ctx; | ||
#ifdef CONFIG_GPIO | ||
struct button_callback_context btn_cb_ctx; | ||
#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 = 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."); | ||
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); | ||
|
||
#ifdef CONFIG_GPIO | ||
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 /* CONFIG_GPIO */ | ||
|
||
lv_task_handler(); | ||
display_blanking_off(display_dev); | ||
|
||
while (true) { | ||
lv_task_handler(); | ||
k_sleep(K_MSEC(10)); | ||
} | ||
} |