From 23316833f502a19907e871934e490aee82b23090 Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Mon, 20 Jul 2020 15:52:49 +0200 Subject: [PATCH 1/7] tests/touch_dev: adapt test application with new stmpe811 behavior --- tests/touch_dev/main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/touch_dev/main.c b/tests/touch_dev/main.c index aa7587f7a6..175a3ac7dd 100644 --- a/tests/touch_dev/main.c +++ b/tests/touch_dev/main.c @@ -37,7 +37,7 @@ static stmpe811_t stmpe811; static void _touch_event_cb(void *arg) { (void)arg; - puts("Pressed!"); + printf("Event: "); } int main(void) @@ -61,7 +61,10 @@ int main(void) if (current_touches != last_touches) { if (current_touches == 0) { - puts("Released!"); + puts("released!"); + } + if (current_touches > 0) { + puts("pressed!"); } last_touches = current_touches; } From 388bbfa008812cc3dc74a986b664e4f5fe5fcd99 Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Sun, 31 May 2020 17:57:36 +0200 Subject: [PATCH 2/7] drivers: add generic screen wrapper around display and touch devices --- drivers/include/screen_dev.h | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 drivers/include/screen_dev.h diff --git a/drivers/include/screen_dev.h b/drivers/include/screen_dev.h new file mode 100644 index 0000000000..775c6cb7ea --- /dev/null +++ b/drivers/include/screen_dev.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2020 Inria + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup drivers_screen_dev Screen device generic API + * @ingroup drivers_display + * @brief Define the generic API of a screen device + * + * @see drivers_disp_dev @see drivers_touch_dev + * + * @experimental This API is experimental and in an early state - expect + * changes! + * @{ + * + * @author Alexandre Abadie + */ + +#ifndef SCREEN_DEV_H +#define SCREEN_DEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "disp_dev.h" + +#ifdef MODULE_TOUCH_DEV +#include "touch_dev.h" +#endif + +/** + * @brief Screen device descriptor + */ +typedef struct { + disp_dev_t *display; /**< Pointer to the display device */ +#if MODULE_TOUCH_DEV || DOXYGEN + touch_dev_t *touch; /**< Pointer to the touch device */ +#endif +} screen_dev_t; + +#ifdef __cplusplus +} +#endif + +#endif /* SCREEN_DEV_H */ +/** @} */ From 4842da272c9158ffcb0a00a98248db31f2bf3f83 Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Sun, 31 May 2020 17:59:17 +0200 Subject: [PATCH 3/7] pkg/lvgl: add optional touch capability via screen generic API --- pkg/lvgl/Makefile.dep | 4 +++ pkg/lvgl/Makefile.include | 3 ++ pkg/lvgl/contrib/lvgl.c | 64 +++++++++++++++++++++++++++++++----- pkg/lvgl/include/lvgl_riot.h | 6 ++-- 4 files changed, 65 insertions(+), 12 deletions(-) diff --git a/pkg/lvgl/Makefile.dep b/pkg/lvgl/Makefile.dep index 57c09af27b..ef93f432d4 100644 --- a/pkg/lvgl/Makefile.dep +++ b/pkg/lvgl/Makefile.dep @@ -12,6 +12,10 @@ ifneq (,$(filter lvgl_contrib,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter lvgl_contrib_touch,$(USEMODULE))) + USEMODULE += touch_dev +endif + # lvgl is not compatible with non 32bit platforms # Building lv_misc triggers the error: # "left shift count >= width of type [-Werror=shift-count-overflow]" diff --git a/pkg/lvgl/Makefile.include b/pkg/lvgl/Makefile.include index de90f66a1f..a1ca9d971d 100644 --- a/pkg/lvgl/Makefile.include +++ b/pkg/lvgl/Makefile.include @@ -31,3 +31,6 @@ CFLAGS += -DLVGL_TASK_THREAD_PRIO=$(LVGL_TASK_THREAD_PRIO) # lvgl module is not a concrete module, so declare it as a pseudomodule PSEUDOMODULES += lvgl + +# touch capabilities are available via a pseudomodule +PSEUDOMODULES += lvgl_contrib_touch diff --git a/pkg/lvgl/contrib/lvgl.c b/pkg/lvgl/contrib/lvgl.c index cf0a3b130c..6f1f8eb0e3 100644 --- a/pkg/lvgl/contrib/lvgl.c +++ b/pkg/lvgl/contrib/lvgl.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Inria + * Copyright (C) 2019-2020 Inria * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -17,6 +17,8 @@ * @} */ +#include + #include "thread.h" #include "xtimer.h" @@ -25,7 +27,8 @@ #include "lvgl/lvgl.h" #include "lv_conf.h" #include "lvgl_riot.h" -#include "disp_dev.h" + +#include "screen_dev.h" #ifndef LVGL_TASK_THREAD_PRIO #define LVGL_TASK_THREAD_PRIO (THREAD_PRIORITY_MAIN + 1) @@ -52,7 +55,9 @@ static kernel_pid_t _task_thread_pid; static lv_disp_buf_t disp_buf; static lv_color_t buf[LVGL_COLOR_BUF_SIZE]; -static disp_dev_t *_dev = NULL; + +static screen_dev_t *_screen_dev = NULL; + static void *_task_thread(void *arg) { @@ -80,11 +85,11 @@ static void *_task_thread(void *arg) static void _disp_map(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) { - if (!_dev) { + if (!_screen_dev->display) { return; } - disp_dev_map(_dev, area->x1, area->x2, area->y1, area->y2, + disp_dev_map(_screen_dev->display, area->x1, area->x2, area->y1, area->y2, (const uint16_t *)color_p); LOG_DEBUG("[lvgl] flush display\n"); @@ -92,22 +97,63 @@ static void _disp_map(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *col lv_disp_flush_ready(drv); } -void lvgl_init(disp_dev_t *dev) +#ifdef MODULE_TOUCH_DEV +/* adapted from https://github.com/lvgl/lvgl/tree/v6.1.2#add-littlevgl-to-your-project */ +static bool _touch_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) +{ + if (!_screen_dev->touch) { + return false; + } + + (void)indev_driver; + static lv_coord_t last_x = 0; + static lv_coord_t last_y = 0; + + touch_t positions[1]; + uint8_t touches = touch_dev_touches(_screen_dev->touch, positions, 1); + + /* Save the state and save the pressed coordinates */ + data->state = (touches > 0) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + if (data->state == LV_INDEV_STATE_PR) { + last_x = positions[0].x; + last_y = positions[0].y; + } + + /* Set the coordinates (if released use the last pressed coordinates) */ + data->point.x = last_x; + data->point.y = last_y; + + return false; +} +#endif + +void lvgl_init(screen_dev_t *screen_dev) { - _dev = dev; lv_init(); + _screen_dev = screen_dev; + assert(screen_dev->display); + lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); /* Configure horizontal and vertical resolutions based on the underlying display device parameters */ - disp_drv.hor_res = disp_dev_width(dev); - disp_drv.ver_res = disp_dev_height(dev); + disp_drv.hor_res = disp_dev_width(screen_dev->display); + disp_drv.ver_res = disp_dev_height(screen_dev->display); disp_drv.flush_cb = _disp_map; disp_drv.buffer = &disp_buf; lv_disp_drv_register(&disp_drv); lv_disp_buf_init(&disp_buf, buf, NULL, LVGL_COLOR_BUF_SIZE); +#ifdef MODULE_TOUCH_DEV + assert(screen_dev->touch); + lv_indev_drv_t indev_drv; + lv_indev_drv_init(&indev_drv); + indev_drv.type = LV_INDEV_TYPE_POINTER; + indev_drv.read_cb = _touch_read; + lv_indev_drv_register(&indev_drv); +#endif + lv_task_handler(); _task_thread_pid = thread_create(_task_thread_stack, sizeof(_task_thread_stack), LVGL_TASK_THREAD_PRIO, THREAD_CREATE_STACKTEST, diff --git a/pkg/lvgl/include/lvgl_riot.h b/pkg/lvgl/include/lvgl_riot.h index 631156ae19..c65a7116ee 100644 --- a/pkg/lvgl/include/lvgl_riot.h +++ b/pkg/lvgl/include/lvgl_riot.h @@ -19,7 +19,7 @@ #ifndef LVGL_RIOT_H #define LVGL_RIOT_H -#include "disp_dev.h" +#include "screen_dev.h" #ifdef __cplusplus extern "C" { @@ -28,9 +28,9 @@ extern "C" { /** * @brief Initialize the lvgl display engine * - * @param[in] dev Pointer to the generic display device + * @param[in] screen_dev Pointer to the generic screen device */ -void lvgl_init(disp_dev_t *dev); +void lvgl_init(screen_dev_t *screen_dev); /** * @brief Wakeup lvgl when inactive From 1f6c51602aca05c4865fa5bf397f7ad0aee064b4 Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Sun, 31 May 2020 17:59:39 +0200 Subject: [PATCH 4/7] tests/pkg_lvgl: adapt to new lvgl API --- tests/pkg_lvgl/main.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/pkg_lvgl/main.c b/tests/pkg_lvgl/main.c index c70a124256..11ebd84558 100644 --- a/tests/pkg_lvgl/main.c +++ b/tests/pkg_lvgl/main.c @@ -25,12 +25,15 @@ #include "lvgl/lvgl.h" #include "lvgl_riot.h" +#include "screen_dev.h" + #include "ili9341.h" #include "ili9341_params.h" #include "disp_dev.h" #include "ili9341_disp_dev.h" -static ili9341_t dev; +static ili9341_t s_disp_dev; +static screen_dev_t s_screen; #define CPU_LABEL_COLOR "FF0000" #define MEM_LABEL_COLOR "0000FF" @@ -128,17 +131,17 @@ void sysmon_create(void) int main(void) { /* Configure the generic display driver interface */ - disp_dev_t *disp_dev = (disp_dev_t *)&dev; - disp_dev->driver = &ili9341_disp_dev_driver; + s_screen.display = (disp_dev_t *)&s_disp_dev; + s_screen.display->driver = &ili9341_disp_dev_driver; /* Enable backlight */ disp_dev_backlight_on(); /* Initialize the concrete display driver */ - ili9341_init(&dev, &ili9341_params[0]); + ili9341_init(&s_disp_dev, &ili9341_params[0]); - /* Initialize lvgl with the generic display driver interface */ - lvgl_init(disp_dev); + /* Initialize lvgl with the generic display and touch drivers */ + lvgl_init(&s_screen); /* Create the system monitor widget */ sysmon_create(); From 4b4e9830b02db6eaa6deee52a9bea0dedee509f7 Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Sun, 31 May 2020 18:04:03 +0200 Subject: [PATCH 5/7] drivers/touch_dev: clarify touch position coordinates origin --- drivers/include/touch_dev.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/include/touch_dev.h b/drivers/include/touch_dev.h index eb7df40d2a..bb4121ca9c 100644 --- a/drivers/include/touch_dev.h +++ b/drivers/include/touch_dev.h @@ -107,6 +107,8 @@ uint16_t touch_dev_width(const touch_dev_t *dev); * * If @p touches is NULL, this function only returns the number of touches. * + * Touch position coordinates use the top left corner as origin. + * * @param[in] dev Pointer to the touch device * @param[out] touches The array of touches * @param[in] len The touches array len From f7882f4f2a34482769b058c21db43fa54e9508b2 Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Sun, 31 May 2020 18:00:58 +0200 Subject: [PATCH 6/7] drivers/stmpe811: return touch_dev position relative to top left corner --- drivers/stmpe811/stmpe811_touch_dev.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/stmpe811/stmpe811_touch_dev.c b/drivers/stmpe811/stmpe811_touch_dev.c index f4da762213..a14731d35d 100644 --- a/drivers/stmpe811/stmpe811_touch_dev.c +++ b/drivers/stmpe811/stmpe811_touch_dev.c @@ -27,6 +27,9 @@ #include "stmpe811.h" #include "stmpe811_touch_dev.h" +#define ENABLE_DEBUG (0) +#include "debug.h" + uint16_t _stmpe811_height(const touch_dev_t *touch_dev) { const stmpe811_t *dev = (const stmpe811_t *)touch_dev; @@ -57,8 +60,13 @@ uint8_t _stmpe811_touches(const touch_dev_t *touch_dev, touch_t *touches, size_t if (ret && touches != NULL) { stmpe811_touch_position_t pos; stmpe811_read_touch_position(dev, &pos); - touches[0].x = pos.x; - touches[0].y = pos.y; + /* STMPE811 driver returns the position with origin at the bottom left + corner and portrait orientation, so convert them to use top left corner + as origin and landscape orientation. */ + touches[0].x = pos.y; + touches[0].y = dev->params.xmax - pos.x; + + DEBUG("X: %i, Y: %i\n", touches[0].x, touches[0].y) } return ret; From 712dbe9c95be5b71a08204074e43328f4111306c Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Sun, 31 May 2020 18:02:11 +0200 Subject: [PATCH 7/7] tests/pkg_lvgl_touch: add lvgl sample with touch capabilities --- tests/pkg_lvgl_touch/Makefile | 15 +++++ tests/pkg_lvgl_touch/Makefile.ci | 17 ++++++ tests/pkg_lvgl_touch/README.md | 18 ++++++ tests/pkg_lvgl_touch/main.c | 94 ++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 tests/pkg_lvgl_touch/Makefile create mode 100644 tests/pkg_lvgl_touch/Makefile.ci create mode 100644 tests/pkg_lvgl_touch/README.md create mode 100644 tests/pkg_lvgl_touch/main.c diff --git a/tests/pkg_lvgl_touch/Makefile b/tests/pkg_lvgl_touch/Makefile new file mode 100644 index 0000000000..ee21be62f4 --- /dev/null +++ b/tests/pkg_lvgl_touch/Makefile @@ -0,0 +1,15 @@ +BOARD ?= stm32f429i-disc1 +include ../Makefile.tests_common + +# No interactive_sync +DISABLE_MODULE += test_utils_interactive_sync + +USEPKG += lvgl +USEMODULE += lvgl_contrib +USEMODULE += ili9341 + +# Add touch capabilities +USEMODULE += lvgl_contrib_touch +USEMODULE += stmpe811 + +include $(RIOTBASE)/Makefile.include diff --git a/tests/pkg_lvgl_touch/Makefile.ci b/tests/pkg_lvgl_touch/Makefile.ci new file mode 100644 index 0000000000..7c661f9211 --- /dev/null +++ b/tests/pkg_lvgl_touch/Makefile.ci @@ -0,0 +1,17 @@ +BOARD_INSUFFICIENT_MEMORY := \ + blackpill \ + bluepill \ + i-nucleo-lrwan1 \ + nucleo-f031k6 \ + nucleo-f042k6 \ + nucleo-f302r8 \ + nucleo-f303k8 \ + nucleo-f334r8 \ + nucleo-l031k6 \ + nucleo-l053r8 \ + saml10-xpro \ + saml11-xpro \ + stm32f030f4-demo \ + stm32f0discovery \ + stm32l0538-disco \ + # diff --git a/tests/pkg_lvgl_touch/README.md b/tests/pkg_lvgl_touch/README.md new file mode 100644 index 0000000000..43f6c0441e --- /dev/null +++ b/tests/pkg_lvgl_touch/README.md @@ -0,0 +1,18 @@ +LittlevGL sample application +============================ + +This application shows a usage of LittlevGL with touch capabilities. + +### Flashing the application + +The application works without modification on the stm32f429i-disc1 board. To +build, flash and run the application for this board, just use: + +``` +make BOARD=stm32f429i-disc1 -C tests/pkg_lvgl_touch flash +``` + +### Expected result + +The application simply displays a button that can be clicked. Each time the +button is clicked, the message "Button clicked!" is displayed in the terminal. diff --git a/tests/pkg_lvgl_touch/main.c b/tests/pkg_lvgl_touch/main.c new file mode 100644 index 0000000000..47c68bb1d2 --- /dev/null +++ b/tests/pkg_lvgl_touch/main.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 Inria + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief LittlevGL example application with clickable button + * + * @author Alexandre Abadie + * + * @} + */ + +#include + +#include "lvgl/lvgl.h" +#include "lvgl_riot.h" + +#include "ili9341.h" +#include "ili9341_params.h" +#include "disp_dev.h" +#include "ili9341_disp_dev.h" + +#include "stmpe811.h" +#include "stmpe811_params.h" +#include "touch_dev.h" +#include "stmpe811_touch_dev.h" + +#include "screen_dev.h" + +static screen_dev_t s_screen; +static ili9341_t s_disp_dev; +static stmpe811_t s_touch_dev; + +static void _stmpe811_event_cb(void *arg) +{ + (void)arg; + lvgl_wakeup(); +} + +static void btn_event_cb(lv_obj_t * btn, lv_event_t event) +{ + (void)btn; + if (event == LV_EVENT_CLICKED) { + puts("Button clicked!"); + } +} + +int main(void) +{ + /* Configure the generic display driver interface */ + s_screen.display = (disp_dev_t *)&s_disp_dev; + s_screen.display->driver = &ili9341_disp_dev_driver; + + /* Initialize the concrete display driver */ + ili9341_init(&s_disp_dev, &ili9341_params[0]); + + /* Configure the generic touch driver interface */ + s_screen.touch = (touch_dev_t *)&s_touch_dev; + s_screen.touch->driver = &stmpe811_touch_dev_driver; + + /* Initialize the concrete touch driver */ + stmpe811_init(&s_touch_dev, &stmpe811_params[0], _stmpe811_event_cb, NULL); + + /* Initialize lvgl with the generic screen */ + lvgl_init(&s_screen); + + /* Add a button to the current screen */ + lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL); + + /* Set the button position and size */ + lv_coord_t x_size = 100; + lv_coord_t y_size = 50; + lv_coord_t x_pos = (disp_dev_width(s_screen.display) - x_size) / 2; + lv_coord_t y_pos = (disp_dev_height(s_screen.display) - y_size) / 2; + lv_obj_set_pos(btn, x_pos, y_pos); + lv_obj_set_size(btn, 100, 50); + + /*Assign a callback to the button*/ + lv_obj_set_event_cb(btn, btn_event_cb); + + /* Add a label to the button */ + lv_obj_t * label = lv_label_create(btn, NULL); + lv_label_set_text(label, "Click me"); + + return 0; +}