This is an automated email from the ASF dual-hosted git repository. rymek pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit fd0c300b2fccb6f6c2a58575f0193aa46fed1e0e Author: Jerzy Kasenberg <jerzy.kasenb...@codecoup.pl> AuthorDate: Fri May 12 11:32:28 2023 +0200 lvgl: Add support for ADC touch screen This add support for resistive 4 wire touch screen, where X+/X-/Y+/Y- electrodes are connected to GPIO pins and MCU's ADC. Signed-off-by: Jerzy Kasenberg <jerzy.kasenb...@codecoup.pl> --- .../lvgl/indev/adc_touch/include/adc_touch.h | 56 +++++ hw/drivers/display/lvgl/indev/adc_touch/pkg.yml | 43 ++++ .../display/lvgl/indev/adc_touch/src/adc_touch.c | 227 +++++++++++++++++++++ hw/drivers/display/lvgl/indev/adc_touch/syscfg.yml | 83 ++++++++ hw/drivers/display/lvgl/pkg.yml | 2 + hw/drivers/display/lvgl/syscfg.yml | 3 + 6 files changed, 414 insertions(+) diff --git a/hw/drivers/display/lvgl/indev/adc_touch/include/adc_touch.h b/hw/drivers/display/lvgl/indev/adc_touch/include/adc_touch.h new file mode 100644 index 000000000..337770651 --- /dev/null +++ b/hw/drivers/display/lvgl/indev/adc_touch/include/adc_touch.h @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef ADC_TOUCH_H +#define ADC_TOUCH_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void * adc_dev_t; + +/** + * Open ADC device for touch screen access + * + * Function should be implemented by user to setup ADC that will be used + * to measure values connected to X and Y electrodes. + * + * @param x_pin - pin to use for X coordinate measurement. + * @param y_pin - pit to use for Y coordinate measurement. + * @return value to be used in subsequent adc_touch_adc_read function + */ +adc_dev_t adc_touch_adc_open(int x_pin, int y_pin); + +/** + * Read ADC value for given pin + * + * @param adc - value returned form adc_touch_adc_open() + * @param pin - one of the pins to measure + * @return value measured on selected pin + */ +uint16_t adc_touch_adc_read(adc_dev_t adc, int pin); + +#ifdef __cplusplus +} +#endif + +#endif /* ADC_TOUCH_H */ diff --git a/hw/drivers/display/lvgl/indev/adc_touch/pkg.yml b/hw/drivers/display/lvgl/indev/adc_touch/pkg.yml new file mode 100644 index 000000000..f7eca8c20 --- /dev/null +++ b/hw/drivers/display/lvgl/indev/adc_touch/pkg.yml @@ -0,0 +1,43 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: hw/drivers/display/lvgl/indev/adc_touch +pkg.description: ADC touch driver +pkg.keywords: + - display + - touch + + +pkg.cflags: + - -DLV_CONF_INCLUDE_SIMPLE + +pkg.req_apis: + - adc_touch_adc + +pkg.deps.(ADC_TOUCH_DEFAULT_ADC && NORDIC_NRFX): + - hw/drivers/display/lvgl/indev/adc_touch/adc_nrfx + +pkg.deps.(ADC_TOUCH_DEFAULT_ADC && MCU_STM32F4): + - hw/drivers/display/lvgl/indev/adc_touch/adc_stm32f4 + +pkg.deps.(ADC_TOUCH_DEFAULT_ADC && MCU_STM32F7): + - hw/drivers/display/lvgl/indev/adc_touch/adc_stm32f7 + +pkg.init: + adc_touch_init: 1100 diff --git a/hw/drivers/display/lvgl/indev/adc_touch/src/adc_touch.c b/hw/drivers/display/lvgl/indev/adc_touch/src/adc_touch.c new file mode 100644 index 000000000..453591b45 --- /dev/null +++ b/hw/drivers/display/lvgl/indev/adc_touch/src/adc_touch.c @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <stdio.h> +#include <os/mynewt.h> +#include <os/os_time.h> +#include <os/os_dev.h> +#include <hal/hal_gpio.h> +#include <bsp/bsp.h> + +#include <hal/lv_hal_indev.h> +#include <core/lv_disp.h> +#include <lv_api_map.h> +#include <adc_touch.h> + +static adc_dev_t touch_dev; + +struct touch_electrodes { + int xp_pin; + int yp_pin; + int xm_pin; + int ym_pin; +}; + +struct touch_electrodes electrodes = { + .xp_pin = MYNEWT_VAL(ADC_TOUCH_XP_PIN), + .yp_pin = MYNEWT_VAL(ADC_TOUCH_YP_PIN), + .xm_pin = MYNEWT_VAL(ADC_TOUCH_XM_PIN), + .ym_pin = MYNEWT_VAL(ADC_TOUCH_YM_PIN), +}; + +static lv_indev_drv_t adc_drv; +static lv_indev_t *adc_dev; + +struct touch_screen_data { + /* ADC value for left edge */ + uint16_t adc_left; + /* ADC value for right edge */ + uint16_t adc_right; + /* ADC value for top edge */ + uint16_t adc_top; + /* ADC value for bottom edge */ + uint16_t adc_bottom; + /* Current value for X, Y detected */ + int x; + int y; + /* Values that were last reported */ + int last_x; + int last_y; +}; + +#define INVERTED_X (MYNEWT_VAL(ADC_TOUCH_ADC_LEFT) > MYNEWT_VAL(ADC_TOUCH_ADC_RIGHT)) +#define INVERTED_Y (MYNEWT_VAL(ADC_TOUCH_ADC_TOP) > MYNEWT_VAL(ADC_TOUCH_ADC_BOTTOM)) + +static struct touch_screen_data touch_screen_data = { + .adc_left = MYNEWT_VAL(ADC_TOUCH_ADC_LEFT), + .adc_right = MYNEWT_VAL(ADC_TOUCH_ADC_RIGHT), + .adc_top = MYNEWT_VAL(ADC_TOUCH_ADC_TOP), + .adc_bottom = MYNEWT_VAL(ADC_TOUCH_ADC_BOTTOM), +}; + +void +adc_touch_handler(void) +{ + bool touched; + int x; + int y; + int last_val; + int nx, ny; + touch_screen_data.x = -1; + touch_screen_data.y = -1; + + /* Check if there is short between plates using GPIO + */ + hal_gpio_init_in(electrodes.yp_pin, HAL_GPIO_PULL_UP); + hal_gpio_init_in(electrodes.ym_pin, HAL_GPIO_PULL_NONE); + hal_gpio_init_out(electrodes.xp_pin, 0); + hal_gpio_init_out(electrodes.xm_pin, 0); + + os_cputime_delay_usecs(MYNEWT_VAL(ADC_TOUCH_ADC_DELAY_US)); + + touched = hal_gpio_read(electrodes.ym_pin) == 0; + + if (touched) { + /* Short detected */ + + /* X+ = VCC + * X- = GND, + * Y+/Y- as input without pull-up + */ + hal_gpio_init_out(electrodes.xp_pin, 1); + hal_gpio_init_in(electrodes.yp_pin, HAL_GPIO_PULL_NONE); + os_cputime_delay_usecs(MYNEWT_VAL(ADC_TOUCH_ADC_DELAY_US)); + + last_val = -1; + for (nx = 0; nx < 10; nx++) { + /* Take measurement on Y pin that is routed to ADC channel */ + x = adc_touch_adc_read(touch_dev, electrodes.yp_pin); + if (abs((x - last_val)) > (x / 16)) { + last_val = x; + } else { + x = (x + last_val) / 2; + ++nx; + break; + } + } + + /* Sanity check for ADC reading */ + if (x < MYNEWT_VAL_ADC_TOUCH_ADC_X_MIN || x > MYNEWT_VAL_ADC_TOUCH_ADC_X_MAX) { + goto done; + } + + /* Y+ = VCC + * Y- = GND, + * X+/X- as input without pull-up + */ + hal_gpio_init_out(electrodes.yp_pin, 1); + hal_gpio_init_out(electrodes.ym_pin, 0); + hal_gpio_init_in(electrodes.xp_pin, HAL_GPIO_PULL_NONE); + hal_gpio_init_in(electrodes.xm_pin, HAL_GPIO_PULL_NONE); + + os_cputime_delay_usecs(MYNEWT_VAL(ADC_TOUCH_ADC_DELAY_US)); + + last_val = -1; + for (ny = 0; ny < 10; ++ny) { + /* Take measurement on X pin that is routed to ADC channel */ + y = adc_touch_adc_read(touch_dev, electrodes.xp_pin); + if (abs((y - last_val)) > (y / 16)) { + last_val = y; + } else { + ++ny; + break; + } + } + + /* Sanity check for ADC reading */ + if (y < MYNEWT_VAL_ADC_TOUCH_ADC_Y_MIN || x > MYNEWT_VAL_ADC_TOUCH_ADC_Y_MAX) { + goto done; + } + + /* If x is outside what is considered left-right range, adjust range */ + if (INVERTED_X) { + if (x > touch_screen_data.adc_left) { + touch_screen_data.adc_left = x; + } else if (x < touch_screen_data.adc_right) { + touch_screen_data.adc_right = x; + } + } else { + if (x < touch_screen_data.adc_left) { + touch_screen_data.adc_left = x; + } else if (x > touch_screen_data.adc_right) { + touch_screen_data.adc_right = x; + } + } + /* If y is outside what is considered top-bottom range, adjust range */ + if (INVERTED_Y) { + if (y > touch_screen_data.adc_top) { + touch_screen_data.adc_top = y; + } else if (y < touch_screen_data.adc_bottom) { + touch_screen_data.adc_bottom = y; + } + } else { + if (y < touch_screen_data.adc_top) { + touch_screen_data.adc_top = y; + } else if (y > touch_screen_data.adc_bottom) { + touch_screen_data.adc_bottom = y; + } + } + + /* Convert to display coordinates */ + touch_screen_data.x = (x - touch_screen_data.adc_left) * LV_HOR_RES / + (touch_screen_data.adc_right - touch_screen_data.adc_left); + touch_screen_data.y = (y - touch_screen_data.adc_top) * LV_VER_RES / + (touch_screen_data.adc_bottom - touch_screen_data.adc_top); + } +done: + hal_gpio_init_out(electrodes.xp_pin, 0); + hal_gpio_init_out(electrodes.xm_pin, 0); + hal_gpio_init_out(electrodes.yp_pin, 0); + hal_gpio_init_out(electrodes.ym_pin, 0); +} + +static void +adc_touch_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) +{ + adc_touch_handler(); + + if (touch_screen_data.x < 0 || touch_screen_data.y < 0) { + data->point.x = touch_screen_data.last_x; + data->point.y = touch_screen_data.last_y; + data->state = LV_INDEV_STATE_REL; + } else { + touch_screen_data.last_x = touch_screen_data.x; + touch_screen_data.last_y = touch_screen_data.y; + data->point.x = touch_screen_data.last_x; + data->point.y = touch_screen_data.last_y; + data->state = LV_INDEV_STATE_PR; + } +} + +void +adc_touch_init(void) +{ + touch_dev = adc_touch_adc_open(electrodes.xp_pin, electrodes.yp_pin); + + /* Register a keypad input device */ + lv_indev_drv_init(&adc_drv); + adc_drv.type = LV_INDEV_TYPE_POINTER; + adc_drv.read_cb = adc_touch_read; + adc_dev = lv_indev_drv_register(&adc_drv); +} diff --git a/hw/drivers/display/lvgl/indev/adc_touch/syscfg.yml b/hw/drivers/display/lvgl/indev/adc_touch/syscfg.yml new file mode 100644 index 000000000..c6e7cc553 --- /dev/null +++ b/hw/drivers/display/lvgl/indev/adc_touch/syscfg.yml @@ -0,0 +1,83 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + ADC_TOUCH_XP_PIN: + description: > + Pin connected to touch screen X+ electrode. + value: + ADC_TOUCH_XM_PIN: + description: > + Pin connected to touch screen X- electrode. + value: + ADC_TOUCH_YP_PIN: + description: > + Pin connected to touch screen Y+ electrode. + value: + ADC_TOUCH_YM_PIN: + description: > + Pin connected to touch screen Y- electrode. + value: + ADC_TOUCH_ADC_X_MIN: + description: > + Minimum value of ADC for x reading. + Readings lower then this value will be considered invalid. + value: 4300 + ADC_TOUCH_ADC_X_MAX: + description: > + Maximum value of ADC for x reading. + Readings higher then this value will be considered invalid. + value: 11500 + ADC_TOUCH_ADC_Y_MIN: + description: > + Minimum value of ADC for y reading. + Readings lower then this value will be considered invalid. + value: 3400 + ADC_TOUCH_ADC_Y_MAX: + description: > + Maximum value of ADC for y reading. + Readings higher then this value will be considered invalid. + value: 12500 + ADC_TOUCH_ADC_LEFT: + description: + ADC value for X coordinate 0. + This value will be adjusted in runtime. + It can be set to value between ADC_TOUCH_ADC_X_MIN or ADC_TOUCH_ADC_X_MAX. + value: + ADC_TOUCH_ADC_RIGHT: + description: + ADC value for X coordinate at the right edge of the screen. + This value will be adjusted in runtime. + It can be set to value between ADC_TOUCH_ADC_X_MIN or ADC_TOUCH_ADC_X_MAX. + value: + ADC_TOUCH_ADC_TOP: + description: + ADC value for Y coordinate 0. + This value will be adjusted in runtime. + It can be set to value between ADC_TOUCH_ADC_Y_MIN or ADC_TOUCH_ADC_Y_MAX. + value: + ADC_TOUCH_ADC_BOTTOM: + description: + ADC value for Y coordinate at the bottom edge of the screen. + This value will be adjusted in runtime. + It can be set to value between ADC_TOUCH_ADC_Y_MIN or ADC_TOUCH_ADC_Y_MAX. + value: + ADC_TOUCH_ADC_DELAY_US: + description: + Delay after GPIO is set high and measurement + value: 30 diff --git a/hw/drivers/display/lvgl/pkg.yml b/hw/drivers/display/lvgl/pkg.yml index faec417cb..b40e34aa6 100644 --- a/hw/drivers/display/lvgl/pkg.yml +++ b/hw/drivers/display/lvgl/pkg.yml @@ -73,6 +73,8 @@ pkg.deps.LVGL_XPT2046: - "@apache-mynewt-core/hw/drivers/display/lvgl/indev/xpt2046" pkg.deps.LVGL_STMPE610: - "@apache-mynewt-core/hw/drivers/display/lvgl/indev/stmpe610" +pkg.deps.LVGL_ADC_TOUCH: + - "@apache-mynewt-core/hw/drivers/display/lvgl/indev/adc_touch" pkg.cflags: - -DLV_CONF_INCLUDE_SIMPLE=1 diff --git a/hw/drivers/display/lvgl/syscfg.yml b/hw/drivers/display/lvgl/syscfg.yml index 504f2a1ac..7da15004b 100644 --- a/hw/drivers/display/lvgl/syscfg.yml +++ b/hw/drivers/display/lvgl/syscfg.yml @@ -43,6 +43,9 @@ syscfg.defs: LVGL_STMPE610: description: Enable STMPE610 touchscreen driver. value: + LVGL_ADC_TOUCH: + description: Enable ADC touchscreen driver. + value: LVGL_TIMER_PERIOD_MS: description: LV timer interval for periodical refresh and touch read value: 10