diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index ea07a13a68..82833da0b3 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -576,6 +576,12 @@ ifneq (,$(filter si70%,$(USEMODULE))) USEMODULE += si70xx endif +ifneq (,$(filter stmpe811,$(USEMODULE))) + FEATURES_REQUIRED += periph_gpio_irq + FEATURES_REQUIRED += periph_i2c + USEMODULE += xtimer +endif + ifneq (,$(filter slipdev,$(USEMODULE))) USEMODULE += tsrb FEATURES_REQUIRED += periph_uart diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 39f276a5b8..685078b89b 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -308,6 +308,10 @@ ifneq (,$(filter srf04,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/srf04/include endif +ifneq (,$(filter stmpe811,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/stmpe811/include +endif + ifneq (,$(filter sx127x,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sx127x/include endif diff --git a/drivers/include/stmpe811.h b/drivers/include/stmpe811.h new file mode 100644 index 0000000000..5464f28c40 --- /dev/null +++ b/drivers/include/stmpe811.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2019 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_stmpe811 STMPE811 Touchscreen Controller + * @ingroup drivers_sensors + * @brief Device driver interface for the STMPE811 touchscreen controller + * + * @{ + * + * @file + * + * @author Alexandre Abadie + */ + +#ifndef STMPE811_H +#define STMPE811_H + +#include "saul.h" +#include "periph/gpio.h" +#include "periph/i2c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Return codes + */ +enum { + STMPE811_OK = 0, /**< Everything was fine */ + STMPE811_ERR_I2C, /**< Error on the I2C bus */ + STMPE811_ERR_NODEV, /**< No valid device on I2C bus */ + STMPE811_ERR_RESET, /**< Software reset failed */ +}; + +/** + * @brief Touch state enum + */ +typedef enum { + STMPE811_TOUCH_STATE_PRESSED, /**< Touchscreen is pressed */ + STMPE811_TOUCH_STATE_RELEASED, /**< Touchscreen is released */ +} stmpe811_touch_state_t; + +/** + * @brief Touch position structure + */ +typedef struct { + uint16_t x; /**< X position */ + uint16_t y; /**< Y position */ +} stmpe811_touch_position_t; + +/** + * @brief Signature of touch event callback triggered from interrupt + * + * @param[in] arg optional context for the callback + */ +typedef void (*touch_event_cb_t)(void *arg); + +/** + * @brief Device initialization parameters + */ +typedef struct { + i2c_t i2c; /**< I2C device which is used */ + uint8_t addr; /**< Device I2C address */ + gpio_t int_pin; /**< Touch screen interrupt pin */ + uint16_t xmax; /**< Touch screen max X position */ + uint16_t ymax; /**< Touch screen max Y position */ +} stmpe811_params_t; + +/** + * @brief Device descriptor for the STMPE811 sensor + */ +typedef struct { + stmpe811_params_t params; /**< Device parameters */ + uint16_t prev_x; /**< Previous X coordinate */ + uint16_t prev_y; /**< Previous Y coordinate */ +} stmpe811_t; + +/** + * @brief Initialize the given STMPE811 device + * + * @param[inout] dev Device descriptor of the STMPE811 + * @param[in] params Initialization parameters of the STMPE811 device + * @param[in] cb Callback function called on touch interrupts + * @param[in] arg Context argument used in callback function + * + * @return STMPE811_OK on success + * @return -STMPE811_ERR_NODEV when no valid device + * @return -STMPE811_ERR_RESET when software reset failed + * @return -STMPE811_ERR_I2C on any I2C error + */ +int stmpe811_init(stmpe811_t *dev, const stmpe811_params_t * params, + touch_event_cb_t cb, void *arg); + +/** + * @brief Read the touch position + * + * @param[in] dev Device descriptor of the STMPE811 + * @param[out] position Touch position + * + * @return STMPE811_OK on success + * @return -STMPE811_ERR_I2C on any I2C error + */ +int stmpe811_read_touch_position(stmpe811_t *dev, stmpe811_touch_position_t *position); + +/** + * @brief Read the touch state (pressed or released) + * + * @param[in] dev Device descriptor of the STMPE811 + * @param[out] state Touch state + * + * @return STMPE811_OK on success + * @return -STMPE811_ERR_I2C on any I2C error + */ +int stmpe811_read_touch_state(const stmpe811_t *dev, stmpe811_touch_state_t *state); + +#ifdef __cplusplus +} +#endif + +#endif /* STMPE811_H */ +/** @} */ diff --git a/drivers/stmpe811/Makefile b/drivers/stmpe811/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/stmpe811/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/stmpe811/include/stmpe811_constants.h b/drivers/stmpe811/include/stmpe811_constants.h new file mode 100644 index 0000000000..954b0e2b90 --- /dev/null +++ b/drivers/stmpe811/include/stmpe811_constants.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2019 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 drivers_stmpe811 + * + * @{ + * @file + * @brief Constants for STMPE811 + * + * @author Alexandre Abadie + */ + +#ifndef STMPE811_CONSTANTS_H +#define STMPE811_CONSTANTS_H + +#include "stmpe811.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define STMPE811_I2C_ADDR_DEFAULT (0x41) /**< Default I2C address */ + +#define STMPE811_CHIP_ID_VALUE (0x0811) /**< Chip ID */ + +/* @name Registers + * @{ + */ +#define STMPE811_CHIP_ID (0x00) /**< STMPE811 Device identification */ +#define STMPE811_ID_VER (0x02) /**< STMPE811 Revision number */ +#define STMPE811_SYS_CTRL1 (0x03) /**< Reset control */ +#define STMPE811_SYS_CTRL2 (0x04) /**< Clock control */ +#define STMPE811_SPI_CFG (0x08) /**< SPI interface configuration */ +#define STMPE811_INT_CTRL (0x09) /**< Interrupt control register */ +#define STMPE811_INT_EN (0x0A) /**< Interrupt enable register */ +#define STMPE811_INT_STA (0x0B) /**< Interrupt status register */ +#define STMPE811_GPIO_EN (0x0C) /**< GPIO interrupt enable register */ +#define STMPE811_GPIO_INT_STA (0x0D) /**< GPIO interrupt status register */ +#define STMPE811_ADC_INT_EN (0x0E) /**< ADC interrupt enable register */ +#define STMPE811_ADC_INT_STA (0x0F) /**< ADC interface status register */ +#define STMPE811_GPIO_SET_PIN (0x10) /**< GPIO set pin register */ +#define STMPE811_GPIO_CLR_PIN (0x11) /**< GPIO clear pin register */ +#define STMPE811_MP_STA (0x12) /**< GPIO monitor pin state register */ +#define STMPE811_GPIO_DIR (0x13) /**< GPIO direction register */ +#define STMPE811_GPIO_ED (0x14) /**< GPIO edge detect register */ +#define STMPE811_GPIO_RE (0x15) /**< GPIO rising edge register */ +#define STMPE811_GPIO_FE (0x16) /**< GPIO falling edge register */ +#define STMPE811_GPIO_ALT_FUNCTION (0x17) /**< Alternate function register */ +#define STMPE811_ADC_CTRL1 (0x20) /**< ADC control */ +#define STMPE811_ADC_CTRL2 (0x21) /**< ADC control */ +#define STMPE811_ADC_CAPT (0x22) /**< To initiate ADC data acquisition */ +#define STMPE811_ADC_DATA_CHO (0x30) /**< ADC channel 0 */ +#define STMPE811_ADC_DATA_CH1 (0x32) /**< ADC channel 1 */ +#define STMPE811_ADC_DATA_CH2 (0x34) /**< ADC channel 2 */ +#define STMPE811_ADC_DATA_CH3 (0x36) /**< ADC channel 3 */ +#define STMPE811_ADC_DATA_CH4 (0x38) /**< ADC channel 4 */ +#define STMPE811_ADC_DATA_CH5 (0x3A) /**< ADC channel 5 */ +#define STMPE811_ADC_DATA_CH6 (0x3C) /**< ADC channel 6 */ +#define STMPE811_ADC_DATA_CH7 (0x3E) /**< ADC channel 7 */ +#define STMPE811_TSC_CTRL (0x40) /**< 4-wire tsc setup */ +#define STMPE811_TSC_CFG (0x41) /**< Tsc configuration */ +#define STMPE811_WDW_TR_X (0x42) /**< Window setup for top right X */ +#define STMPE811_WDW_TR_Y (0x44) /**< Window setup for top right Y */ +#define STMPE811_WDW_BL_X (0x46) /**< Window setup for bottom left X */ +#define STMPE811_WDW_BL_Y (0x48) /**< Window setup for bottom left Y */ +#define STMPE811_FIFO_TH (0x4A) /**< FIFO level to generate interrupt */ +#define STMPE811_FIFO_CTRL_STA (0x4B) /**< Current status of FIFO */ +#define STMPE811_FIFO_SIZE (0x4C) /**< Current filled level of FIFO */ +#define STMPE811_TSC_DATA_X (0x4D) /**< Data port for tsc data access */ +#define STMPE811_TSC_DATA_Y (0x4F) /**< Data port for tsc data access */ +#define STMPE811_TSC_DATA_Z (0x51) /**< Data port for tsc data access */ +#define STMPE811_TSC_DATA_XYZ (0x52) /**< Data port for tsc data access */ +#define STMPE811_TSC_DATA_INC (0x57) /**< Data port for tsc auto-increment data access */ +#define STMPE811_TSC_DATA_NON_INC (0xD7) /**< Data port for tsc non auto-increment data access */ +#define STMPE811_TSC_FRACTION_Z (0x56) /**< Touchscreen controller FRACTION_Z */ +#define STMPE811_TSC_DATA (0x57) /**< Data port for tsc data access */ +#define STMPE811_TSC_I_DRIVE (0x58) /**< Touchscreen controller drivel */ +#define STMPE811_TSC_SHIELD (0x59) /**< Touchscreen controller shield */ +#define STMPE811_TEMP_CTRL (0x60) /**< Temperature sensor setup */ +#define STMPE811_TEMP_DATA (0x61) /**< Temperature data access port */ +#define STMPE811_TEMP_TH (0x62) /**< Threshold for temp controlled int */ +/** @} */ + +/* @name SYS_CTRL1 register bitfields + * @{ + */ +#define STMPE811_SYS_CTRL1_HIBERNATE (1 << 0) /**< Hibernate the device*/ +#define STMPE811_SYS_CTRL1_SOFT_RESET (1 << 1) /**< Trigger software reset */ +/** @} */ + +/* @name SYS_CTRL2 register bitfields + * @{ + */ +#define STMPE811_SYS_CTRL2_ADC_OFF (1 << 0) /**< Disable ADC */ +#define STMPE811_SYS_CTRL2_TSC_OFF (1 << 1) /**< Disable Touchscreen*/ +#define STMPE811_SYS_CTRL2_GPIO_OFF (1 << 2) /**< Disable GPIO */ +#define STMPE811_SYS_CTRL2_TS_OFF (1 << 3) /**< Disable Temperature sensor */ +/** @} */ + +/* @name INT_CTRL register bitfields + * @{ + */ +#define STMPE811_INT_CTRL_INT_POLARITY (1 << 2) /**< Configure interrupt polarity (falling or raising) */ +#define STMPE811_INT_CTRL_INT_TYPE (1 << 1) /**< Configure interrupt type (edge or level) */ +#define STMPE811_INT_CTRL_GLOBAL_INT (1 << 0) /**< Enable global interrupt */ +/** @} */ + +/* @name INT_EN register bitfields + * @{ + */ +#define STMPE811_INT_EN_TOUCH_DET (1 << 0) /**< Enable touch detection interrupt */ +#define STMPE811_INT_EN_FIFO_TH (1 << 1) /**< Enable FIFO threshold interrupt */ +#define STMPE811_INT_EN_FIFO_OFLOW (1 << 2) /**< Enable FIFO overflow interrupt */ +#define STMPE811_INT_EN_FIFO_FULL (1 << 3) /**< Enable FIFO full interrupt */ +#define STMPE811_INT_EN_FIFO_EMPTY (1 << 4) /**< Enable FIFO empty interrupt */ +#define STMPE811_INT_EN_TEMP_SENS (1 << 5) /**< Enable temperature sensor interrupt */ +#define STMPE811_INT_EN_ADC (1 << 6) /**< Enable ADC interrupt */ +#define STMPE811_INT_EN_GPIO (1 << 7) /**< Enable GPIO interrupt */ +/** @} */ + +/* @name ADC_CTRL1 register bitfields + * @{ + */ +#define STMPE811_ADC_CTRL1_SAMPLE_TIME_POS (4) /**< Sample time bits shift position */ +#define STMPE811_ADC_CTRL1_SAMPLE_TIME_36 (0b000) /**< Conversion time: 36 cycles */ +#define STMPE811_ADC_CTRL1_SAMPLE_TIME_44 (0b001) /**< Conversion time: 44 cycles */ +#define STMPE811_ADC_CTRL1_SAMPLE_TIME_56 (0b010) /**< Conversion time: 56 cycles */ +#define STMPE811_ADC_CTRL1_SAMPLE_TIME_64 (0b011) /**< Conversion time: 64 cycles */ +#define STMPE811_ADC_CTRL1_SAMPLE_TIME_80 (0b100) /**< Conversion time: 80 cycles */ +#define STMPE811_ADC_CTRL1_SAMPLE_TIME_96 (0b101) /**< Conversion time: 96 cycles */ +#define STMPE811_ADC_CTRL1_SAMPLE_TIME_124 (0b110) /**< Conversion time: 124 cycles */ +#define STMPE811_ADC_CTRL1_MOD_12B (1 << 3) /**< Enable 12 bit ADC (10bit if 0) */ +/** @} */ + +/* @name ADC_CTRL2 register bitfields + * @{ + */ +#define STMPE811_ADC_CTRL2_FREQ_1_625MHZ (0b00) /**< ADC clock frequency 1.625MHz */ +#define STMPE811_ADC_CTRL2_FREQ_3_25MHZ (0b01) /**< ADC clock frequency 3.25MHz */ +#define STMPE811_ADC_CTRL2_FREQ_6_5MHZ (0b10) /**< ADC clock frequency 6.5MHz */ +#define STMPE811_ADC_CTRL2_FREQ_6_5_2MHZ (0b11) /**< ADC clock frequency 6.5MHz */ +/** @} */ + +/* @name TSC_CTRL register bitfields + * @{ + */ +#define STMPE811_TSC_CTRL_EN (1 << 0) /**< Enable touchscreen */ +#define STMPE811_TSC_CTRL_OPMOD_POS (1) /**< Operating mode bit shift position */ +#define STMPE811_TSC_CTRL_OPMOD_XYZ (0b000) /**< X,Y,Z acquisition */ +#define STMPE811_TSC_CTRL_OPMOD_XY_ONLY (0b001) /**< X,Y only acquisition */ +#define STMPE811_TSC_CTRL_OPMOD_X_ONLY (0b010) /**< X only acquisition */ +#define STMPE811_TSC_CTRL_OPMOD_Y_ONLY (0b011) /**< Y only acquisition */ +#define STMPE811_TSC_CTRL_OPMOD_Z_ONLY (0b100) /**< Z only acquisition */ +#define STMPE811_TSC_CTRL_TRACK_POS (4) /**< Movement tracking index bit shift position */ +#define STMPE811_TSC_CTRL_TRACK_NO (0b000) /**< No window tracking */ +#define STMPE811_TSC_CTRL_TRACK_4 (0b001) /**< Tracking index 4 */ +#define STMPE811_TSC_CTRL_TRACK_8 (0b010) /**< Tracking index 8 */ +#define STMPE811_TSC_CTRL_TRACK_16 (0b011) /**< Tracking index 16 */ +#define STMPE811_TSC_CTRL_TRACK_32 (0b100) /**< Tracking index 32 */ +#define STMPE811_TSC_CTRL_TRACK_64 (0b101) /**< Tracking index 64 */ +#define STMPE811_TSC_CTRL_TRACK_92 (0b110) /**< Tracking index 92 */ +#define STMPE811_TSC_CTRL_TRACK_127 (0b111) /**< Tracking index 127 */ +#define STMPE811_TSC_CTRL_STA (1 << 7) /**< Touchscreen status (1: touch detected, 0: no touch detected), read-only */ +/** @} */ + +/* @name TSC_CFG register bitfields + * @{ + */ +#define STMPE811_TSC_CFG_AVE_CTRL_POS (6) /**< Average control bit shift position */ +#define STMPE811_TSC_CFG_AVE_CTRL_1 (0b00) /**< Average control, 1 sample */ +#define STMPE811_TSC_CFG_AVE_CTRL_2 (0b01) /**< Average control, 2 sample */ +#define STMPE811_TSC_CFG_AVE_CTRL_4 (0b10) /**< Average control, 4 sample */ +#define STMPE811_TSC_CFG_AVE_CTRL_8 (0b11) /**< Average control, 8 sample */ +#define STMPE811_TSC_CFG_TOUCH_DET_DELAY_POS (3) /**< Touch detection delay bit shift position */ +#define STMPE811_TSC_CFG_TOUCH_DET_DELAY_10US (0b000) /**< Touch detection 10us delay */ +#define STMPE811_TSC_CFG_TOUCH_DET_DELAY_50US (0b001) /**< Touch detection 50us delay */ +#define STMPE811_TSC_CFG_TOUCH_DET_DELAY_100US (0b010) /**< Touch detection 100us delay */ +#define STMPE811_TSC_CFG_TOUCH_DET_DELAY_500US (0b011) /**< Touch detection 500us delay */ +#define STMPE811_TSC_CFG_TOUCH_DET_DELAY_1MS (0b100) /**< Touch detection 1ms delay */ +#define STMPE811_TSC_CFG_TOUCH_DET_DELAY_5MS (0b101) /**< Touch detection 5ms delay */ +#define STMPE811_TSC_CFG_TOUCH_DET_DELAY_10MS (0b110) /**< Touch detection 10ms delay */ +#define STMPE811_TSC_CFG_TOUCH_DET_DELAY_50MS (0b111) /**< Touch detection 50ms delay */ +#define STMPE811_TSC_CFG_SETTLING_10US (0b000) /**< Settling time 10us */ +#define STMPE811_TSC_CFG_SETTLING_100US (0b001) /**< Settling time 100us */ +#define STMPE811_TSC_CFG_SETTLING_500US (0b010) /**< Settling time 500us */ +#define STMPE811_TSC_CFG_SETTLING_1MS (0b011) /**< Settling time 1ms */ +#define STMPE811_TSC_CFG_SETTLING_5MS (0b100) /**< Settling time 5ms */ +#define STMPE811_TSC_CFG_SETTLING_10MS (0b101) /**< Settling time 10ms */ +#define STMPE811_TSC_CFG_SETTLING_50MS (0b110) /**< Settling time 50ms */ +#define STMPE811_TSC_CFG_SETTLING_100MS (0b111) /**< Settling time 100ms */ +/** @} */ + +/* @name FIFO_CTRL_STA register bitfields + * @{ + */ +#define STMPE811_FIFO_CTRL_STA_RESET (1 << 0) /**< Reset FIFO */ +/** @} */ + +/* @name TSC_FRACTION_Z register bitfields + * @{ + */ +#define STMPE811_TSC_FRACTION_Z_0_8 (0b000) /**< Fractional part is 0, whole part is 8 */ +#define STMPE811_TSC_FRACTION_Z_1_7 (0b001) /**< Fractional part is 1, whole part is 7 */ +#define STMPE811_TSC_FRACTION_Z_2_6 (0b010) /**< Fractional part is 2, whole part is 6 */ +#define STMPE811_TSC_FRACTION_Z_3_5 (0b011) /**< Fractional part is 3, whole part is 5 */ +#define STMPE811_TSC_FRACTION_Z_4_4 (0b100) /**< Fractional part is 4, whole part is 4 */ +#define STMPE811_TSC_FRACTION_Z_5_3 (0b101) /**< Fractional part is 5, whole part is 3 */ +#define STMPE811_TSC_FRACTION_Z_6_2 (0b110) /**< Fractional part is 6, whole part is 2 */ +#define STMPE811_TSC_FRACTION_Z_7_1 (0b111) /**< Fractional part is 7, whole part is 1 */ +/** @} */ + +/* @name TSC_I_DRIVE register bitfields + * @{ + */ +#define STMPE811_TSC_I_DRIVE_50MA (1 << 0) /**< Enable 50mA drive current, 20mA if 0 */ +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* STMPE811_CONSTANTS_H */ +/** @} */ diff --git a/drivers/stmpe811/include/stmpe811_params.h b/drivers/stmpe811/include/stmpe811_params.h new file mode 100644 index 0000000000..2fa2dcb8f9 --- /dev/null +++ b/drivers/stmpe811/include/stmpe811_params.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 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 drivers_stmpe811 + * + * @{ + * @file + * @brief Default configuration for STMPE811 + * + * @author Alexandre Abadie + */ + +#ifndef STMPE811_PARAMS_H +#define STMPE811_PARAMS_H + +#include "board.h" +#include "stmpe811.h" +#include "stmpe811_constants.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Set default configuration parameters for the STMPE811 + * @{ + * + * These default values are adapted for the @ref boards_stm32f429i-disc1 board + */ +#ifndef STMPE811_PARAM_I2C_DEV +#define STMPE811_PARAM_I2C_DEV I2C_DEV(0) +#endif +#ifndef STMPE811_PARAM_ADDR +#define STMPE811_PARAM_ADDR (STMPE811_I2C_ADDR_DEFAULT) +#endif +#ifndef STMPE811_PARAM_INT_PIN +#define STMPE811_PARAM_INT_PIN GPIO_PIN(0, 15) +#endif +#ifndef STMPE811_PARAM_XMAX +#define STMPE811_PARAM_XMAX (240U) +#endif +#ifndef STMPE811_PARAM_YMAX +#define STMPE811_PARAM_YMAX (320U) +#endif + +#ifndef STMPE811_PARAMS +#define STMPE811_PARAMS { .i2c = STMPE811_PARAM_I2C_DEV, \ + .addr = STMPE811_PARAM_ADDR, \ + .int_pin = STMPE811_PARAM_INT_PIN, \ + .xmax = STMPE811_PARAM_XMAX, \ + .ymax = STMPE811_PARAM_YMAX, \ + } +#endif +/**@}*/ + +/** + * @brief Configure STMPE811 + */ +static const stmpe811_params_t stmpe811_params[] = +{ + STMPE811_PARAMS +}; + +#ifdef __cplusplus +} +#endif + +#endif /* STMPE811_PARAMS_H */ +/** @} */ diff --git a/drivers/stmpe811/stmpe811.c b/drivers/stmpe811/stmpe811.c new file mode 100644 index 0000000000..a04a2b0810 --- /dev/null +++ b/drivers/stmpe811/stmpe811.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2019 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 drivers_stmpe811 + * @{ + * + * @file + * @brief Device driver implementation for the STMPE811 touchscreen controller. + * + * @author Alexandre Abadie + * + * @} + */ + +#include + +#include "xtimer.h" +#include "periph/i2c.h" +#include "periph/gpio.h" + +#include "stmpe811.h" +#include "stmpe811_constants.h" +#include "stmpe811_params.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define STMPE811_DEV_I2C (dev->params.i2c) +#define STMPE811_DEV_ADDR (dev->params.addr) + +static int _soft_reset(const stmpe811_t *dev) +{ + if (i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_SYS_CTRL1, STMPE811_SYS_CTRL1_SOFT_RESET, 0) < 0) { + DEBUG("[stmpe811] soft reset: cannot write soft reset bit to SYS_CTRL1 register\n"); + return -STMPE811_ERR_I2C; + } + xtimer_usleep(10 * US_PER_MS); + + if (i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_SYS_CTRL1, 0, 0) < 0) { + DEBUG("[stmpe811] soft reset: cannot clear SYS_CTRL1 register\n"); + return -STMPE811_ERR_I2C; + } + xtimer_usleep(2 * US_PER_MS); + + return STMPE811_OK; +} + +static void _reset_fifo(const stmpe811_t *dev) +{ + i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_FIFO_CTRL_STA, STMPE811_FIFO_CTRL_STA_RESET, 0); + i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_FIFO_CTRL_STA, 0, 0); +} + +static void _clear_interrupt_status(const stmpe811_t *dev) +{ + i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, STMPE811_INT_STA, 0xff, 0); +} + +int stmpe811_init(stmpe811_t *dev, const stmpe811_params_t * params, touch_event_cb_t cb, void *arg) +{ + dev->params = *params; + int ret = STMPE811_OK; + + /* Acquire I2C device */ + i2c_acquire(STMPE811_DEV_I2C); + + uint16_t device_id; + if (i2c_read_regs(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_CHIP_ID, &device_id, 2, 0) < 0) { + DEBUG("[stmpe811] init: cannot read CHIP_ID register\n"); + i2c_release(STMPE811_DEV_I2C); + return -STMPE811_ERR_I2C; + } + + device_id = (device_id << 8) | (device_id >> 8); + if (device_id != STMPE811_CHIP_ID_VALUE) { + DEBUG("[stmpe811] init: invalid device id (actual: 0x%04X, expected: 0x%04X)\n", + device_id, STMPE811_CHIP_ID_VALUE); + i2c_release(STMPE811_DEV_I2C); + return -STMPE811_ERR_NODEV; + } + + DEBUG("[stmpe811] init: valid device\n"); + + ret = _soft_reset(dev); + if (ret != STMPE811_OK) { + DEBUG("[stmpe811] init: reset failed\n"); + i2c_release(STMPE811_DEV_I2C); + return -STMPE811_ERR_RESET; + } + + DEBUG("[stmpe811] init: soft reset done\n"); + + /* Initialization sequence */ + + /* disable temperature sensor and GPIO */ + ret = i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_SYS_CTRL2, + (STMPE811_SYS_CTRL2_TS_OFF | STMPE811_SYS_CTRL2_GPIO_OFF), 0); + + /* set to 80 cycles and adc resolution to 12 bit*/ + uint8_t reg = ((uint8_t)(STMPE811_ADC_CTRL1_SAMPLE_TIME_80 << STMPE811_ADC_CTRL1_SAMPLE_TIME_POS) | + STMPE811_ADC_CTRL1_MOD_12B); + ret += i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_ADC_CTRL1, reg, 0); + + /* set adc clock speed to 3.25 MHz */ + ret += i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_ADC_CTRL2, STMPE811_ADC_CTRL2_FREQ_3_25MHZ, 0); + + /* set GPIO AF to function as ts/adc */ + ret += i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_GPIO_ALT_FUNCTION, 0x00, 0); + + /* set touchscreen configuration */ + reg = ((uint8_t)(STMPE811_TSC_CFG_AVE_CTRL_4 << STMPE811_TSC_CFG_AVE_CTRL_POS) | + (uint8_t)(STMPE811_TSC_CFG_TOUCH_DET_DELAY_500US << STMPE811_TSC_CFG_TOUCH_DET_DELAY_POS) | + (STMPE811_TSC_CFG_SETTLING_500US)); + ret += i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_TSC_CFG, reg, 0); + + /* set fifo threshold */ + ret += i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_FIFO_TH, 0x01, 0); + + /* reset fifo */ + _reset_fifo(dev); + + /* set fractional part to 7, whole part to 1 */ + ret += i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_TSC_FRACTION_Z, STMPE811_TSC_FRACTION_Z_7_1, 0); + + /* set current limit value to 50 mA */ + ret += i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_TSC_I_DRIVE, STMPE811_TSC_I_DRIVE_50MA, 0); + + /* enable touchscreen clock */ + ret += i2c_read_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_SYS_CTRL2, ®, 0); + reg &= ~STMPE811_SYS_CTRL2_TSC_OFF; + ret += i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_SYS_CTRL2, reg, 0); + + ret += i2c_read_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_TSC_CTRL, ®, 0); + reg |= STMPE811_TSC_CTRL_EN; + ret += i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_TSC_CTRL, reg, 0); + + /* clear interrupt status */ + _clear_interrupt_status(dev); + + if ((dev->params.int_pin != GPIO_UNDEF) && cb) { + DEBUG("[stmpe811] init: configuring touchscreen interrupt\n"); + gpio_init_int(dev->params.int_pin, GPIO_IN, GPIO_RISING, cb, arg); + + /* Enable touchscreen interrupt */ + ret += i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_INT_EN, STMPE811_INT_EN_TOUCH_DET, 0); + + /* Enable global interrupt */ + ret += i2c_write_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_INT_CTRL, STMPE811_INT_CTRL_GLOBAL_INT, 0); + } + + if (ret < 0) { + i2c_release(STMPE811_DEV_I2C); + DEBUG("[stmpe811] init: initialization sequence failed\n"); + return -STMPE811_ERR_I2C; + } + + /* Release I2C device */ + i2c_release(STMPE811_DEV_I2C); + + DEBUG("[stmpe811] initialization successful\n"); + + return ret; +} + +int stmpe811_read_touch_position(stmpe811_t *dev, stmpe811_touch_position_t *position) +{ + uint16_t tmp_x, tmp_y; + + /* Acquire I2C device */ + i2c_acquire(STMPE811_DEV_I2C); + + uint8_t xyz[4]; + uint32_t xyz_ul; + + if (i2c_read_regs(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, + STMPE811_TSC_DATA_NON_INC, &xyz, sizeof(xyz), 0) < 0) { + DEBUG("[stmpe811] position: cannot read position\n"); + i2c_release(STMPE811_DEV_I2C); + return -STMPE811_ERR_I2C; + } + _reset_fifo(dev); + + /* Release I2C device */ + i2c_release(STMPE811_DEV_I2C); + + xyz_ul = ((uint32_t)xyz[0] << 24) | ((uint32_t)xyz[1] << 16) | \ + ((uint32_t)xyz[2] << 8) | (xyz[3] << 0); + + tmp_x = (xyz_ul >> 20) & 0xfff; + tmp_y = (xyz_ul >> 8) & 0xfff; + + /* Y value first correction */ + tmp_y -= 360; + + /* Y value second correction */ + tmp_y /= 11; + + /* clamp y position */ + if (tmp_y > dev->params.ymax) { + tmp_y = dev->prev_y; + } + + /* X value first correction */ + if (tmp_x <= 3000) { + tmp_x = 3870 - tmp_x; + } + else { + tmp_x = 3800 - tmp_x; + } + + /* X value second correction */ + tmp_x /= 15; + + /* clamp x position */ + if (tmp_x > dev->params.xmax) { + tmp_x = dev->prev_x; + } + + dev->prev_x = tmp_x; + dev->prev_y = tmp_y; + position->x = tmp_x; + position->y = tmp_y; + + return STMPE811_OK; +} + +int stmpe811_read_touch_state(const stmpe811_t *dev, stmpe811_touch_state_t *state) +{ + uint8_t val; + + /* Acquire I2C device */ + i2c_acquire(STMPE811_DEV_I2C); + + if (i2c_read_reg(STMPE811_DEV_I2C, STMPE811_DEV_ADDR, STMPE811_TSC_CTRL, &val, 0) < 0) { + DEBUG("[stmpe811] position: cannot read touch state\n"); + i2c_release(STMPE811_DEV_I2C); + return -STMPE811_ERR_I2C; + } + + if ((val & STMPE811_TSC_CTRL_STA)) { + _clear_interrupt_status(dev); + *state = STMPE811_TOUCH_STATE_PRESSED; + } + else { + _reset_fifo(dev); + *state = STMPE811_TOUCH_STATE_RELEASED; + } + + /* Release I2C device */ + i2c_release(STMPE811_DEV_I2C); + + return STMPE811_OK; +} diff --git a/tests/driver_stmpe811/Makefile b/tests/driver_stmpe811/Makefile new file mode 100644 index 0000000000..ae5eeb40eb --- /dev/null +++ b/tests/driver_stmpe811/Makefile @@ -0,0 +1,8 @@ +BOARD ?= stm32f429i-disc1 + +include ../Makefile.tests_common + +USEMODULE += xtimer +USEMODULE += stmpe811 + +include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_stmpe811/README.md b/tests/driver_stmpe811/README.md new file mode 100644 index 0000000000..96d2bfbf77 --- /dev/null +++ b/tests/driver_stmpe811/README.md @@ -0,0 +1,33 @@ +## About + +This is the test application for the STMPE811 touchscreen controller. + +## Usage + +The application works out of the box on a STM32F429I-DISC1 board: + +``` +make -C tests/driver_stmpe811 flash term +``` + +## Expected output + +The application initializes the STMPE811 and displays "Pressed!" when a touch +event is detected. +Current touch positions are printed in terminal while holding the screen +pressed. +"Released" is displayed when the screen is released. + +``` +2020-02-10 10:20:17,647 # Pressed! +2020-02-10 10:20:17,653 # X: 167, Y:81 +2020-02-10 10:20:17,659 # X: 165, Y:75 +2020-02-10 10:20:17,671 # X: 165, Y:69 +2020-02-10 10:20:17,689 # X: 166, Y:68 +2020-02-10 10:20:17,701 # X: 167, Y:68 +2020-02-10 10:20:17,713 # X: 169, Y:69 +2020-02-10 10:20:17,725 # X: 170, Y:69 +2020-02-10 10:20:17,737 # X: 170, Y:70 +2020-02-10 10:20:17,755 # X: 173, Y:69 +2020-02-10 10:20:17,761 # Released! +``` diff --git a/tests/driver_stmpe811/main.c b/tests/driver_stmpe811/main.c new file mode 100644 index 0000000000..e29361558a --- /dev/null +++ b/tests/driver_stmpe811/main.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2019 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 Test application for the STMPE811 touchscreen controller + * + * @author Alexandre Abadie + * + * @} + */ + +#include + +#include "xtimer.h" + +#include "stmpe811.h" +#include "stmpe811_params.h" + +static void _touch_event_cb(void *arg) +{ + (void)arg; + puts("Pressed!"); +} + +int main(void) +{ + stmpe811_t dev; + + puts("STMPE811 test application\n"); + + printf("+------------Initializing------------+\n"); + int ret = stmpe811_init(&dev, &stmpe811_params[0], _touch_event_cb, NULL); + if (ret != STMPE811_OK) { + puts("[Error] Initialization failed"); + return 1; + } + + puts("Initialization successful"); + + stmpe811_touch_state_t current_touch_state; + stmpe811_read_touch_state(&dev, ¤t_touch_state); + stmpe811_touch_state_t last_touch_state = current_touch_state; + + while (1) { + stmpe811_read_touch_state(&dev, ¤t_touch_state); + if (current_touch_state != last_touch_state) { + if (current_touch_state == STMPE811_TOUCH_STATE_RELEASED) { + puts("Released!"); + } + last_touch_state = current_touch_state; + } + + /* Display touch position if pressed */ + if (current_touch_state == STMPE811_TOUCH_STATE_PRESSED) { + stmpe811_touch_position_t position; + stmpe811_read_touch_position(&dev, &position); + printf("X: %i, Y:%i\n", position.x, position.y); + } + + xtimer_usleep(10 * US_PER_MS); + } + + return 0; +}