From 18b36e1d743c1e75bb5c3712bb80c561be0fd2e1 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Sat, 18 Jan 2020 14:57:43 +0100 Subject: [PATCH] cst816s: Initial include of cst816s touch screen driver --- drivers/Makefile.dep | 7 + drivers/Makefile.include | 4 + drivers/cst816s/Makefile | 1 + drivers/cst816s/cst816s.c | 91 +++++++++++++ drivers/cst816s/include/cst816s_internal.h | 46 +++++++ drivers/cst816s/include/cst816s_params.h | 84 ++++++++++++ drivers/include/cst816s.h | 151 +++++++++++++++++++++ 7 files changed, 384 insertions(+) create mode 100644 drivers/cst816s/Makefile create mode 100644 drivers/cst816s/cst816s.c create mode 100644 drivers/cst816s/include/cst816s_internal.h create mode 100644 drivers/cst816s/include/cst816s_params.h create mode 100644 drivers/include/cst816s.h diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 4a7ef6978fbd..4ae323c23e73 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -139,6 +139,13 @@ ifneq (,$(filter ccs811,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter cst816s,$(USEMODULE))) + FEATURES_REQUIRED += periph_gpio_irq + FEATURES_REQUIRED += periph_gpio + FEATURES_REQUIRED += periph_i2c + USEMODULE += xtimer +endif + ifneq (,$(filter dcf77,$(USEMODULE))) FEATURES_REQUIRED += periph_gpio FEATURES_REQUIRED += periph_gpio_irq diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 58ef09489aed..07dffa832481 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -64,6 +64,10 @@ ifneq (,$(filter ccs811,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ccs811/include endif +ifneq (,$(filter cst816s,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/cst816s/include +endif + ifneq (,$(filter dcf77,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/dcf77/include endif diff --git a/drivers/cst816s/Makefile b/drivers/cst816s/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/drivers/cst816s/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/cst816s/cst816s.c b/drivers/cst816s/cst816s.c new file mode 100644 index 000000000000..5584cf4e0802 --- /dev/null +++ b/drivers/cst816s/cst816s.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2020 Koen Zandberg + * + * 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 drivers_cst816s + * @{ + * + * @file + * @brief Device driver implementation for cst816s touch screen + * + * @author koen Zandberg + * + * @} + */ + +#include "log.h" +#include "periph/gpio.h" +#include "periph/i2c.h" +#include "xtimer.h" + +#include "cst816s.h" +#include "cst816s_internal.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static void _gpio_irq(void *arg) +{ + cst816s_t *dev = arg; + + dev->cb(dev, dev->cb_arg); +} + +static void _cst816s_reset(cst816s_t *dev) +{ + /* Reset, sleep durations based on + * https://github.com/lupyuen/hynitron_i2c_cst0xxse/blob/master/cst0xx_core.c#L1078-L1085 */ + gpio_clear(dev->params->reset); + xtimer_usleep(CST816S_RESET_DURATION_LOW); + gpio_set(dev->params->reset); + xtimer_usleep(CST816S_RESET_DURATION_HIGH); +} + +int cst816s_read(cst816s_t *dev, cst816s_touch_data_t *data) +{ + uint8_t buf[9]; /* 3 bytes "header" and 6 bytes touch info */ + + i2c_acquire(dev->params->i2c_dev); + int res = i2c_read_regs(dev->params->i2c_dev, dev->params->i2c_addr, + 0, buf, sizeof(buf), 0); + i2c_release(dev->params->i2c_dev); + + if (res < 0) { + return res; + } + + data->gesture = buf[1]; + data->action = buf[3] >> 6; + data->x = (buf[3] & 0x0f) << 8 | buf[4]; + data->y = (buf[5] & 0x0f) << 8 | buf[6]; + + return 0; +} + +int cst816s_init(cst816s_t *dev, const cst816s_params_t *params, + cst816s_irq_cb_t cb, void *arg) +{ + assert(dev && params); + dev->params = params; + dev->cb = cb; + dev->cb_arg = arg; + + gpio_init(dev->params->reset, GPIO_OUT); + _cst816s_reset(dev); + + if (cb) { + int res = gpio_init_int(dev->params->irq, GPIO_IN, + dev->params->irq_flank, + _gpio_irq, dev); + if (res < 0) { + return CST816S_ERR_IRQ; + } + } + return CST816S_OK; + /* The device will not respond until the first touch event */ +} diff --git a/drivers/cst816s/include/cst816s_internal.h b/drivers/cst816s/include/cst816s_internal.h new file mode 100644 index 000000000000..aed6ec1bc2ed --- /dev/null +++ b/drivers/cst816s/include/cst816s_internal.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2020 Koen Zandberg + * + * 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. + */ + +#ifndef CST816S_INTERNAL_H +#define CST816S_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define CST816S_RESET_DURATION_LOW (20 * US_PER_MS) +#define CST816S_RESET_DURATION_HIGH (400 * US_PER_MS) + +#define CST816S_REG_INT_CNT 0x8F +#define CST816S_REG_FLOW_WORK_CNT 0x91 +#define CST816S_REG_WORKMODE 0x00 +#define CST816S_REG_WORKMODE_FACTORY_VALUE 0x40 +#define CST816S_REG_WORKMODE_WORK_VALUE 0x00 +#define CST816S_REG_CHIP_ID 0xA3 +#define CST816S_REG_CHIP_ID2 0x9F +#define CST816S_REG_POWER_MODE 0xA5 +#define CST816S_REG_FW_VER 0xA6 +#define CST816S_REG_VENDOR_ID 0xA8 +#define CST816S_REG_LCD_BUSY_NUM 0xAB +#define CST816S_REG_FACE_DEC_MODE_EN 0xB0 +#define CST816S_REG_GLOVE_MODE_EN 0xC0 +#define CST816S_REG_COVER_MODE_EN 0xC1 +#define CST816S_REG_CHARGER_MODE_EN 0x8B +#define CST816S_REG_GESTURE_EN 0xD0 +#define CST816S_REG_GESTURE_OUTPUT_ADDRESS 0xD3 +#define CST816S_REG_ESD_SATURATE 0xED + +#define CST816S_REG_POWER_MODE_SLEEP_VALUE 0x03 + + +#ifdef __cplusplus +} +#endif + +#endif /* CST816_INTERNAL_H */ +/** @} */ diff --git a/drivers/cst816s/include/cst816s_params.h b/drivers/cst816s/include/cst816s_params.h new file mode 100644 index 000000000000..3b20a4f75860 --- /dev/null +++ b/drivers/cst816s/include/cst816s_params.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020 Koen Zandberg + * + * 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 drivers_cst816s + * + * @brief Default configuration for the CST816S touch screen driver + * + * + * @author koen Zandberg + */ + +#ifndef CST816S_PARAMS_H +#define CST816S_PARAMS_H + +#include "board.h" +#include "cst816s.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Set default configuration parameters for the CST816S + * @{ + */ +/* I2C configuration */ +#ifndef CST816S_PARAM_I2C_DEV +#define CST816S_PARAM_I2C_DEV I2C_DEV(0) +#endif + +#ifndef CST816S_PARAM_I2C_ADDR +#define CST816S_PARAM_I2C_ADDR (0x15) +#endif + +#ifndef CST816S_PARAM_IRQ +#define CST816S_PARAM_IRQ GPIO_PIN(0, 28) +#endif + +#ifndef CST816S_PARAM_IRQ_FLANK +#define CST816S_PARAM_IRQ_FLANK GPIO_FALLING +#endif + +#ifndef CST816S_PARAM_RESET +#define CST816S_PARAM_RESET GPIO_PIN(0, 10) +#endif + + +#define CST816S_PARAMS \ + { \ + .i2c_dev = CST816S_PARAM_I2C_DEV, \ + .i2c_addr = CST816S_PARAM_I2C_ADDR, \ + .irq = CST816S_PARAM_IRQ, \ + .irq_flank = CST816S_PARAM_IRQ_FLANK, \ + .reset = CST816S_PARAM_RESET, \ + } +/**@}*/ + +/** + * @brief Configure BMX280 + */ +static const cst816s_params_t cst816s_params[] = +{ + CST816S_PARAMS +}; + +/** + * @brief The number of configured sensors + */ +#define CST816S_NUMOF ARRAY_SIZE(cst816s_params) + +#ifdef __cplusplus +} +#endif + +#endif /* BMX280_PARAMS_H */ +/** @} */ + diff --git a/drivers/include/cst816s.h b/drivers/include/cst816s.h new file mode 100644 index 000000000000..b6f446120376 --- /dev/null +++ b/drivers/include/cst816s.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2020 Koen Zandberg + * + * 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_cst816s Cst816S touch screen driver + * + * @ingroup drivers_sensors + * @brief Device driver interface for the Hynitron CST816S touch screen + * + * The CST816S is a touch sensor from Hynitron with integrated gesture + * detection. It is able to measure both the position of a single finger and a + * number of basic gestures. The PineTime board has one of these for the touch + * screen. + * + * Documentation about the specifics is very limited and most of this driver is + * based on experimenting with the chip and from community effort on the + * PineTime. + * + * Two things about the driver are noteworthy: + * 1. It only responds to I2C commands after an event, such as a touch + * detection. Do not expect it to respond on init. Instead after a touch + * event, it will assert the IRQ and respond to I2C reads for a short time. + * 2. While it should be able to detect multiple finger events, this version of + * the chip always returns only a single finger event and a gesture. + * + * Reading the display data multiple times during a single event will return the + * last sampled finger position. + * + * @{ + * @file + * @brief Device driver interface for the CST816S touch screen + * + * @author koen Zandberg + */ + +#ifndef CST816S_H +#define CST816S_H + +#include + +#include "periph/i2c.h" +#include "periph/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief cst816s_t forward declaration + */ +typedef struct _cst816s cst816s_t; + +/** + * @brief callback definition + */ +typedef void (*cst816s_irq_cb_t)(cst816s_t *dev, void *arg); + +/** + * @brief cst816s touch event touch state + */ +typedef enum { + CST816S_TOUCH_DOWN = 0, /**< Touch press */ + CST816S_TOUCH_UP = 1, /**< Touch release */ + CST816S_TOUCH_CONTACT = 2, /**< Touch contact */ +} cst816s_touch_t; + +/** + * @brief CST816S Gesture types + */ +typedef enum { + CST816S_GESTURE_NONE = 0x00, /**< no gesture detecte */ + CST816S_GESTURE_SLIDE_DOWN = 0x01, /**< downward slide detected */ + CST816S_GESTURE_SLIDE_UP = 0x02, /**< upward slide detected */ + CST816S_GESTURE_SLIDE_LEFT = 0x03, /**< left slide detected */ + CST816S_GESTURE_SLIDE_RIGHT = 0x04, /**< right slide detected */ + CST816S_GESTURE_SINGLE_CLICK = 0x05, /**< single click detected */ + CST816S_GESTURE_DOUBLE_CLICK = 0x0b, /**< double click detected */ + CST816S_GESTURE_LONG_PRESS = 0x0c, /**< long press detected */ +} cst816s_gesture_t; + +/** + * @brief cst816s touch event data + */ +typedef struct { + cst816s_gesture_t gesture; /**< Detected gesture */ + uint16_t x; /**< X coordinate */ + uint16_t y; /**< Y coordinate */ +} cst816s_touch_data_t; + +typedef struct { + /* I2C details */ + i2c_t i2c_dev; /**< I2C device which is used */ + uint8_t i2c_addr; /**< I2C address */ + gpio_t irq; /**< IRQ pin */ + gpio_flank_t irq_flank; /**< IRQ flank */ + gpio_t reset; /**< Device reset GPIO */ +} cst816s_params_t; + +/** + * @brief cst816s device descriptor + */ +struct _cst816s { + const cst816s_params_t *params; /**< Device parameters */ + cst816s_irq_cb_t cb; /**< Configured IRQ event callback */ + void *cb_arg; /**< Extra argument for the callback */ +}; + +/** + * @brief Status and error return codes + */ +enum { + CST816S_OK = 0, /**< everything was fine */ + CST816S_ERR_IRQ = -1, /**< IRQ initialization error */ +}; + +/** + * @brief Initialize the given cst816s device + * + * @param[out] dev device descriptor of the given cst816s device + * @param[in] params static configuration parameters + * @param[in] cb callback for the cst816s event interrupt, may be NULL + * @param[in] arg extra argument passed to the event interrupt. + * + * @returns CST816S_OK on success + * @returns CST816S_ERR_IRQ on IRQ initialization error + */ +int cst816s_init(cst816s_t *dev, const cst816s_params_t *params, + cst816s_irq_cb_t cb, void *arg); + +/** + * @brief Read touch data from the cst816s device + * + * @param[in] dev device descriptor + * @param[out] data Touch data + * + * @returns 0 on success + * @returns negative on I2C access error + */ +int cst816s_read(cst816s_t *dev, cst816s_touch_data_t *data); + +#ifdef __cplusplus +} +#endif + +#endif /* CST816_H */ +/** @} */