diff --git a/boards/native/native_sim/native_sim.dts b/boards/native/native_sim/native_sim.dts index 1f1b11ad9e727cb..162fcf074577ab0 100644 --- a/boards/native/native_sim/native_sim.dts +++ b/boards/native/native_sim/native_sim.dts @@ -25,6 +25,7 @@ zephyr,canbus = &can_loopback0; zephyr,code-partition = &slot0_partition; zephyr,bt-hci = &bt_hci_userchan; + zephyr,touch = &input_sdl_touch; }; aliases { diff --git a/boards/st/stm32f429i_disc1/stm32f429i_disc1.dts b/boards/st/stm32f429i_disc1/stm32f429i_disc1.dts index cbcc551a71635de..ff16f6648e4ad55 100644 --- a/boards/st/stm32f429i_disc1/stm32f429i_disc1.dts +++ b/boards/st/stm32f429i_disc1/stm32f429i_disc1.dts @@ -22,6 +22,7 @@ zephyr,flash = &flash0; zephyr,ccm = &ccm0; zephyr,display = <dc; + zephyr,touch = &stmpe811; }; sdram2: sdram@d0000000 { diff --git a/boards/st/stm32f746g_disco/stm32f746g_disco.dts b/boards/st/stm32f746g_disco/stm32f746g_disco.dts index 2c31fef1c92c42f..e224d24beaa05ad 100644 --- a/boards/st/stm32f746g_disco/stm32f746g_disco.dts +++ b/boards/st/stm32f746g_disco/stm32f746g_disco.dts @@ -24,6 +24,7 @@ zephyr,dtcm = &dtcm; zephyr,flash-controller = &n25q128a1; zephyr,display = <dc; + zephyr,touch = &ft5336; }; leds { diff --git a/samples/drivers/touch/CMakeLists.txt b/samples/drivers/touch/CMakeLists.txt new file mode 100644 index 000000000000000..e3531c4a6129f55 --- /dev/null +++ b/samples/drivers/touch/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(touch) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/touch/Kconfig b/samples/drivers/touch/Kconfig new file mode 100644 index 000000000000000..0f4d717e2d06e1f --- /dev/null +++ b/samples/drivers/touch/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +config CROSS_WIDTH + int "Horizontal length of the cross to be drawn" + default 20 + +config CROSS_HEIGHT + int "Vertical length of the cross to be drawn" + default 20 + +source "Kconfig.zephyr" diff --git a/samples/drivers/touch/README.rst b/samples/drivers/touch/README.rst new file mode 100644 index 000000000000000..3a748f51880bcd3 --- /dev/null +++ b/samples/drivers/touch/README.rst @@ -0,0 +1,31 @@ +.. zephyr:code-sample:: touch + :name: touch + + Basic touchscreen sample. + +Overview +******** +This sample will draw a small plus in the last touched coordinates, that way you can check +if the touch screen works for a board, examine its parameters such as inverted/swapped axes. + +Building and Running +******************** +While this is a generic sample and it should work with any boards with both display controllers +and touch controllers supported by Zephyr (provided the corresponding /chosen node properties +are set i.e. `zephyr,touch` and `zephyr,display`). +Below is an example on how to build the sample for :ref:`stm32f746g_disco_board`; + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/touch + :board: stm32f746g_disco + :goals: build + :compact: + +For testing purpose without the need of any hardware, the :ref:`native_sim ` +board is also supported and can be built as follows; + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/touch + :board: native_sim + :goals: build + :compact: diff --git a/samples/drivers/touch/prj.conf b/samples/drivers/touch/prj.conf new file mode 100644 index 000000000000000..7e808b98aead3f3 --- /dev/null +++ b/samples/drivers/touch/prj.conf @@ -0,0 +1,4 @@ +CONFIG_HEAP_MEM_POOL_SIZE=16384 +CONFIG_LOG=y +CONFIG_INPUT=y +CONFIG_DISPLAY=y diff --git a/samples/drivers/touch/sample.yaml b/samples/drivers/touch/sample.yaml new file mode 100644 index 000000000000000..301e62d22d4734d --- /dev/null +++ b/samples/drivers/touch/sample.yaml @@ -0,0 +1,16 @@ +sample: + description: Sample application for touch controllers + name: touch_sample +tests: + sample.touch.native: + build_only: true + platform_allow: native_sim/native/64 + tags: + - touch + sample.touch.ft5336: + platform_allow: + - stm32f429i_disc1 + - stm32f746g_disco + tags: + - touch + harness: none diff --git a/samples/drivers/touch/src/main.c b/samples/drivers/touch/src/main.c new file mode 100644 index 000000000000000..9e176cbdd72de2e --- /dev/null +++ b/samples/drivers/touch/src/main.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2024 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(sample, LOG_LEVEL_INF); + +#define BUFFER_SIZE (CONFIG_CROSS_WIDTH * CONFIG_CROSS_HEIGHT * 4) +#define REFRESH_RATE 100 + +#if !DT_NODE_EXISTS(DT_CHOSEN(zephyr_touch)) +#error "Unsupported board: zephyr,touch is not assigned" +#endif + +#if !DT_NODE_EXISTS(DT_CHOSEN(zephyr_display)) +#error "Unsupported board: zephyr,display is not assigned" +#endif + +static const struct device *const display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display)); +static const struct device *const touch_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_touch)); +static struct display_capabilities capabilities; +static struct display_buffer_descriptor buf_desc = {.buf_size = BUFFER_SIZE, + .pitch = CONFIG_CROSS_WIDTH, + .width = CONFIG_CROSS_WIDTH, + .height = CONFIG_CROSS_HEIGHT}; + +static uint8_t buffer_cross[BUFFER_SIZE]; +static const uint8_t buffer_cross_empty[BUFFER_SIZE]; +static struct k_sem sync; + +static struct { + size_t x; + size_t y; +} touch_point, touch_point_drawn; + +static void touch_event_callback(struct input_event *evt, void *user_data) +{ + if (evt->code == INPUT_ABS_X) { + touch_point.x = evt->value; + } + if (evt->code == INPUT_ABS_Y) { + touch_point.y = evt->value; + } + if (evt->sync) { + k_sem_give(&sync); + } +} +INPUT_CALLBACK_DEFINE(touch_dev, touch_event_callback, NULL); + +static void clear_screen(void) +{ + int x; + int y; + + for (x = 0; x < capabilities.x_resolution; x += CONFIG_CROSS_WIDTH) { + for (y = 0; y < capabilities.y_resolution; y += CONFIG_CROSS_HEIGHT) { + display_write(display_dev, x, y, &buf_desc, buffer_cross_empty); + } + } +} + +static void fill_cross_buffer(int bpp) +{ + int i; + int x; + int y; + int index; + + for (i = 0; i < bpp; i++) { + for (x = 0; x < CONFIG_CROSS_WIDTH; x++) { + index = bpp * (CONFIG_CROSS_HEIGHT / 2 * CONFIG_CROSS_WIDTH + x); + buffer_cross[index + i] = -1; + } + for (y = 0; y < CONFIG_CROSS_HEIGHT; y++) { + index = bpp * (y * CONFIG_CROSS_WIDTH + CONFIG_CROSS_WIDTH / 2); + buffer_cross[index + i] = -1; + } + } +} + +int main(void) +{ + int bpp; + + LOG_INF("Touch sample for touchscreen: %s, dc: %s", touch_dev->name, display_dev->name); + + if (!device_is_ready(touch_dev)) { + LOG_ERR("Device %s not found. Aborting sample.", display_dev->name); + return 0; + } + + if (!device_is_ready(display_dev)) { + LOG_ERR("Device %s not found. Aborting sample.", display_dev->name); + return 0; + } + + display_get_capabilities(display_dev, &capabilities); + bpp = DISPLAY_BITS_PER_PIXEL(capabilities.current_pixel_format) / 8u; + + if (bpp == 0 || bpp > 4) { + LOG_ERR("Unsupported BPP=%d", bpp); + return 0; + } + fill_cross_buffer(bpp); + display_blanking_off(display_dev); + + clear_screen(); + touch_point_drawn.x = CONFIG_CROSS_WIDTH / 2; + touch_point_drawn.y = CONFIG_CROSS_HEIGHT / 2; + touch_point.x = -1; + touch_point.y = -1; + + k_sem_init(&sync, 0, 1); + + while (1) { + k_msleep(REFRESH_RATE); + k_sem_take(&sync, K_FOREVER); + LOG_INF("TOUCH X, Y: (%d, %d)", touch_point.x, touch_point.y); + + display_write(display_dev, touch_point_drawn.x - CONFIG_CROSS_WIDTH / 2, + touch_point_drawn.y - CONFIG_CROSS_HEIGHT / 2, &buf_desc, + buffer_cross_empty); + display_write(display_dev, touch_point.x - CONFIG_CROSS_WIDTH / 2, + touch_point.y - CONFIG_CROSS_HEIGHT / 2, &buf_desc, buffer_cross); + + touch_point_drawn.x = touch_point.x; + touch_point_drawn.y = touch_point.y; + } + return 0; +}