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

Reply via email to