Files
edgetx-gx12/radio/src/targets/pl18/tp_cst340.cpp
T
cc17046e7a feat: Flysky PL18 Support (#4105)
Co-authored-by: raphaelcoeffic <raphael.coeffic@frafos.com>
Co-authored-by: rotorman <risto.koiva@web.de>
Co-authored-by: Xy201207 <yaoxu@flysky.com>
Co-authored-by: Peter Feerick <peter.feerick@gmail.com>
2023-12-06 09:00:44 +10:00

561 lines
16 KiB
C++

/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "stm32_hal_ll.h"
#include "stm32_hal.h"
#include "stm32_i2c_driver.h"
#include "stm32_gpio_driver.h"
#include "stm32_exti_driver.h"
#include "hal.h"
#include "timers_driver.h"
#include "delays_driver.h"
#include "tp_cst340.h"
#include "debug.h"
#define TOUCH_FT6236_I2C_ADDRESS (0x70>>1)
#define TOUCH_CST340_I2C_ADDRESS 0x1A
extern uint8_t TouchControllerType;
volatile static bool touchEventOccured;
enum TouchControllers {TC_NONE, TC_FT6236, TC_CST340};
TouchControllers touchController = TC_NONE;
static tc_handle_TypeDef tc_handle = {0, 0};
tmr10ms_t downTime = 0;
tmr10ms_t tapTime = 0;
short tapCount = 0;
#define TAP_TIME 25
struct TouchControllerDescriptor
{
void (*read)(uint16_t * X, uint16_t * Y, uint32_t * event);
uint8_t (*detectTouch)();
void (*printDebugInfo)();
uint32_t contactEvent;
};
static const TouchControllerDescriptor *tc = nullptr;
static TouchState internalTouchState = {};
static void _cst340_exti_isr(void)
{
touchEventOccured = true;
}
static void TOUCH_AF_ExtiStop(void)
{
stm32_exti_disable(TOUCH_INT_EXTI_Line);
}
static void TOUCH_AF_ExtiConfig(void)
{
__HAL_RCC_SYSCFG_CLK_ENABLE();
LL_SYSCFG_SetEXTISource(TOUCH_INT_EXTI_Port, TOUCH_INT_EXTI_SysCfgLine);
stm32_exti_enable(TOUCH_INT_EXTI_Line,
LL_EXTI_TRIGGER_FALLING,
_cst340_exti_isr);
}
static void TOUCH_AF_GPIOConfig(void)
{
LL_GPIO_InitTypeDef gpioInit;
LL_GPIO_StructInit(&gpioInit);
stm32_gpio_enable_clock(TOUCH_RST_GPIO);
stm32_gpio_enable_clock(TOUCH_INT_GPIO);
gpioInit.Mode = LL_GPIO_MODE_OUTPUT;
gpioInit.Speed = LL_GPIO_SPEED_FREQ_LOW;
gpioInit.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
gpioInit.Pull = LL_GPIO_PULL_NO;
gpioInit.Pin = TOUCH_RST_GPIO_PIN;
LL_GPIO_Init(TOUCH_RST_GPIO, &gpioInit);
LL_GPIO_SetOutputPin(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN);
gpioInit.Pin = TOUCH_INT_GPIO_PIN;
gpioInit.Mode = LL_GPIO_MODE_INPUT;
gpioInit.Pull = LL_GPIO_PULL_UP;
gpioInit.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
LL_GPIO_Init(TOUCH_INT_GPIO, &gpioInit);
LL_GPIO_SetOutputPin(TOUCH_INT_GPIO, TOUCH_INT_GPIO_PIN);
}
void I2C_Init_Radio(void)
{
TRACE("CST340 I2C Init");
if (stm32_i2c_init(TOUCH_I2C_BUS, TOUCH_I2C_CLK_RATE) < 0) {
TRACE("CST340 ERROR: stm32_i2c_init failed");
return;
}
}
// void Touch_DeInit()
// {
// I2C_DeInit(I2C_B1);
// __HAL_RCC_I2C1_FORCE_RESET();
// delay_ms(150);
// __HAL_RCC_I2C1_RELEASE_RESET();
// }
#define I2C_TIMEOUT_MAX 5 // 5 ms
bool touch_i2c_read(uint8_t addr, uint8_t reg, uint8_t * data, uint8_t len)
{
// if(touchController == TC_CST836U)
// {
// if(stm32_i2c_master_tx(TOUCH_I2C_BUS, addr, &reg, 1, 3) < 0)
// return false;
// delay_us(5);
// if(stm32_i2c_master_rx(TOUCH_I2C_BUS, addr, data, len, I2C_TIMEOUT_MAX) < 0)
// return false;
// } else {
if (stm32_i2c_read(TOUCH_I2C_BUS, addr, reg, 1, data, len, I2C_TIMEOUT_MAX) < 0)
return false;
// }
return true;
}
#if 0
static bool touch_i2c_write(uint8_t addr, uint8_t reg, uint8_t * data, uint8_t len)
{
if (stm32_i2c_write(TOUCH_I2C_BUS, addr, reg, 1, data, len, I2C_TIMEOUT_MAX) < 0)
return false;
return true;
}
static void TS_IO_Write(uint8_t addr, uint8_t reg, uint8_t data)
{
uint8_t tryCount = 3;
while (!touch_i2c_write(addr, reg, &data, 1)) {
if (--tryCount == 0) break;
I2C_Init();
}
}
#endif
static uint8_t TS_IO_Read(uint8_t addr, uint8_t reg)
{
uint8_t result;
uint8_t tryCount = 3;
while (!touch_i2c_read(addr, reg, &result, 1)) {
if (--tryCount == 0) break;
I2C_Init_Radio();
// I2C_Init();
}
return result;
}
static uint16_t TS_IO_ReadMultiple(uint8_t addr, uint8_t reg, uint8_t * buffer, uint16_t length)
{
uint8_t tryCount = 3;
while (!touch_i2c_read(addr, reg, buffer, length)) {
if (--tryCount == 0) break;
I2C_Init_Radio();
// I2C_Init();
}
return 1;
}
static void touch_ft6236_debug_info(void)
{
#if defined(DEBUG)
TRACE("ft6x36: thrhld = %d", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_TH_GROUP) * 4);
TRACE("ft6x36: rep rate=", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_PERIODACTIVE) * 10);
TRACE("ft6x36: fw lib 0x%02X %02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_LIB_VER_H), TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_LIB_VER_L));
TRACE("ft6x36: fw v 0x%02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_FIRMID));
TRACE("ft6x36: CHIP ID 0x%02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_CIPHER));
TRACE("ft6x36: CTPM ID 0x%02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_FOCALTECH_ID));
TRACE("ft6x36: rel code 0x%02X", TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, TOUCH_FT6236_REG_RELEASE_CODE_ID));
#endif
}
/**
* @brief Return if there is touches detected or not.
* Try to detect new touches and forget the old ones (reset internal global
* variables).
* @param DeviceAddr: Device address on communication Bus.
* @retval : Number of active touches detected (can be 0, 1 or 2).
*/
static uint8_t ft6x06_TS_DetectTouch()
{
volatile uint8_t nbTouch = 0;
/* Read register FT6206_TD_STAT_REG to check number of touches detection */
nbTouch = TS_IO_Read(TOUCH_FT6236_I2C_ADDRESS, FT6206_TD_STAT_REG);
nbTouch &= FT6206_TD_STAT_MASK;
if (nbTouch > FT6206_MAX_DETECTABLE_TOUCH) {
/* If invalid number of touch detected, set it to zero */
nbTouch = 0;
}
/* Update ft6x06 driver internal global : current number of active touches */
tc_handle.currActiveTouchNb = nbTouch;
/* Reset current active touch index on which to work on */
tc_handle.currActiveTouchIdx = 0;
return (nbTouch);
}
#if 0
/**
* @brief Get the touch detailed informations on touch number 'touchIdx' (0..1)
* This touch detailed information contains :
* - weight that was applied to this touch
* - sub-area of the touch in the touch panel
* - event of linked to the touch (press down, lift up, ...)
* @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6x06).
* @param touchIdx : Passed index of the touch (0..1) on which we want to get the
* detailed information.
* @param pWeight : Pointer to to get the weight information of 'touchIdx'.
* @param pArea : Pointer to to get the sub-area information of 'touchIdx'.
* @param pEvent : Pointer to to get the event information of 'touchIdx'.
* @retval None.
*/
static void ft6x06_TS_GetTouchInfo(uint16_t DeviceAddr,
uint32_t touchIdx,
uint32_t * pWeight,
uint32_t * pArea,
uint32_t * pEvent)
{
uint8_t regAddress = 0;
uint8_t dataxy[3];
if (touchIdx < ft6x06_handle.currActiveTouchNb) {
switch (touchIdx) {
case 0 :
regAddress = FT6206_P1_WEIGHT_REG;
break;
case 1 :
regAddress = FT6206_P2_WEIGHT_REG;
break;
default :
break;
} /* end switch(touchIdx) */
/* Read weight, area and Event Id of touch index */
TS_IO_ReadMultiple(DeviceAddr, regAddress, dataxy, sizeof(dataxy));
/* Return weight of touch index */
*pWeight = (dataxy[0] & FT6206_TOUCH_WEIGHT_MASK) >> FT6206_TOUCH_WEIGHT_SHIFT;
/* Return area of touch index */
*pArea = (dataxy[1] & FT6206_TOUCH_AREA_MASK) >> FT6206_TOUCH_AREA_SHIFT;
/* Return Event Id of touch index */
*pEvent = (dataxy[2] & FT6206_TOUCH_EVT_FLAG_MASK) >> FT6206_TOUCH_EVT_FLAG_SHIFT;
} /* of if(touchIdx < ft6x06_handle.currActiveTouchNb) */
}
#endif
/**
* @brief Get the touch screen X and Y positions values
* Manage multi touch thanks to touch Index global
* variable 'tc_handle.currActiveTouchIdx'.
* @param DeviceAddr: Device address on communication Bus.
* @param X: Pointer to X position value
* @param Y: Pointer to Y position value
* @retval None.
*/
static void ft6x06_TS_GetXY(uint16_t * X, uint16_t * Y, uint32_t * event)
{
uint8_t regAddress = 0;
uint8_t dataxy[4];
if (tc_handle.currActiveTouchIdx < tc_handle.currActiveTouchNb) {
switch (tc_handle.currActiveTouchIdx) {
case 0 :
regAddress = FT6206_P1_XH_REG;
break;
case 1 :
regAddress = FT6206_P2_XH_REG;
break;
default :
break;
}
/* Read X and Y positions */
TS_IO_ReadMultiple(TOUCH_FT6236_I2C_ADDRESS, regAddress, dataxy, sizeof(dataxy));
/* Send back ready X position to caller */
*X = ((dataxy[0] & FT6206_MSB_MASK) << 8) | (dataxy[1] & FT6206_LSB_MASK);
/* Send back ready Y position to caller */
*Y = ((dataxy[2] & FT6206_MSB_MASK) << 8) | (dataxy[3] & FT6206_LSB_MASK);
*event = (dataxy[0] & FT6206_TOUCH_EVT_FLAG_MASK) >> FT6206_TOUCH_EVT_FLAG_SHIFT;
/*
uint32_t weight;
uint32_t area;
ft6x06_TS_GetTouchInfo(DeviceAddr, ft6x06_handle.currActiveTouchIdx, &weight, &area, event);
*/
tc_handle.currActiveTouchIdx++;
}
}
static void touch_cst340_debug_info(void)
{
#if 0 // Disabled because cannot compile, will fix when necessary
#if defined(DEBUG)
uint8_t tmp[4];
if (!TS_IO_Write(CST340_MODE_DEBUG_INFO, tmp, 0))
TRACE("CST340 chip NOT FOUND");
// Check the value, expected ChipID
uint32_t chipId = tmp[0] << 8) + tmp[1];
if (!I2C_CST340_ReadRegister(CST340_FWVER_REG, tmp, 4))
TRACE("Error reading CST340 firmware version!");
uint32_t fwVersion = tmp[0] << 24 | tmp[1]<<16 | tmp[2]<<8 | tmp[0];
// Enter normal mode
if (!I2C_CST340_WriteRegister(CST340_MODE_NORMAL, tmp, 0))
TRACE("ERROR chaning CST340 mode back to normal!");
TRACE("cst340: fw ver 0x%08X", fwVersion);
TRACE("cst836u: chip id 0x%04X", chipId);
#endif
#endif
}
/**
* @brief Get the touch screen X and Y positions values
* @param DeviceAddr: Device address on communication Bus.
* @param X: Pointer to X position value
* @param Y: Pointer to Y position value
* @retval None.
*/
static void cst340_TS_GetXY(uint16_t * X, uint16_t * Y, uint32_t * event)
{
uint8_t dataxy[4];
/* Read X and Y positions */
TS_IO_ReadMultiple(TOUCH_CST340_I2C_ADDRESS, CST340_FINGER1_REG, dataxy, sizeof(dataxy));
/* Send back ready X position to caller */
*X = ((dataxy[1]<<4) + ((dataxy[3]>>4)&0x0f));
*Y = ((dataxy[2]<<4) + ((dataxy[3])&0x0f));
/* Send back ready Y position to caller */
*event = dataxy[0];
}
/**
* @brief Return if there is touches detected or not.
* Try to detect new touches and forget the old ones (reset internal global
* variables).
* @param DeviceAddr: Device address on communication Bus.
* @retval : Number of active touches detected
*/
static uint8_t cst340_TS_DetectTouch()
{
uint8_t nbTouch;
uint8_t reg = TS_IO_Read(TOUCH_CST340_I2C_ADDRESS, CST340_FINGER1_REG);
if( reg == 0x06 )
nbTouch = 1;
else
nbTouch = 0;
tc_handle.currActiveTouchNb = nbTouch;
tc_handle.currActiveTouchIdx = 0;
return (nbTouch);
}
void TouchReset()
{
LL_GPIO_ResetOutputPin(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN);
delay_ms(10);
LL_GPIO_SetOutputPin(TOUCH_RST_GPIO, TOUCH_RST_GPIO_PIN);
delay_ms(300);
}
static const TouchControllerDescriptor FT6236 =
{
.read = ft6x06_TS_GetXY,
.detectTouch = ft6x06_TS_DetectTouch,
.printDebugInfo = touch_ft6236_debug_info,
.contactEvent = FT6206_TOUCH_EVT_FLAG_CONTACT
};
static const TouchControllerDescriptor CST340 =
{
.read = cst340_TS_GetXY,
.detectTouch = cst340_TS_DetectTouch,
.printDebugInfo = touch_cst340_debug_info,
.contactEvent = CST340_TOUCH_EVT_FLAG_CONTACT
};
void detectTouchController()
{
if( stm32_i2c_is_dev_ready(TOUCH_I2C_BUS, TOUCH_CST340_I2C_ADDRESS, 3, 5) == 0)
{
TouchControllerType = 0;
touchController = TC_CST340;
tc = &CST340;
} else {
TouchControllerType = 1;
touchController = TC_FT6236;
tc = &FT6236;
}
}
void TouchInit()
{
TOUCH_AF_GPIOConfig(); // SET RST=OUT INT=IN INT=HIGH
I2C_Init_Radio();
TouchReset();
detectTouchController();
TOUCH_AF_ExtiConfig();
tc->printDebugInfo();
}
void handleTouch()
{
unsigned short touchX;
unsigned short touchY;
uint32_t tEvent = 0;
tc->read(&touchX, &touchY, &tEvent);
#if defined(DEBUG)
TRACE("handleTouch: touchX=%d, touchY=%d, tEvent=%d", touchX, touchY, tEvent);
#endif
// touch sensor is rotated by 90 deg
unsigned short tmp = touchY;
touchY = 319 - touchX;
touchX = tmp;
if (tEvent == tc->contactEvent) {
int dx = touchX - internalTouchState.x;
int dy = touchY - internalTouchState.y;
internalTouchState.x = touchX;
internalTouchState.y = touchY;
if (internalTouchState.event == TE_NONE || internalTouchState.event == TE_UP || internalTouchState.event == TE_SLIDE_END) {
internalTouchState.startX = internalTouchState.x;
internalTouchState.startY = internalTouchState.y;
internalTouchState.event = TE_DOWN;
}
else if (internalTouchState.event == TE_DOWN) {
if (dx >= SLIDE_RANGE || dx <= -SLIDE_RANGE || dy >= SLIDE_RANGE || dy <= -SLIDE_RANGE) {
internalTouchState.event = TE_SLIDE;
internalTouchState.deltaX = (short) dx;
internalTouchState.deltaY = (short) dy;
}
else {
internalTouchState.event = TE_DOWN;
internalTouchState.deltaX = 0;
internalTouchState.deltaY = 0;
}
}
else if (internalTouchState.event == TE_SLIDE) {
internalTouchState.event = TE_SLIDE; //no change
internalTouchState.deltaX = (short) dx;
internalTouchState.deltaY = (short) dy;
}
}
}
static bool lastHasTouch = false;
bool touchPanelEventOccured()
{
bool result = touchEventOccured;
uint8_t hasTouch = false;
if (touchEventOccured) {
hasTouch = tc->detectTouch();
if (!hasTouch && !lastHasTouch) {
touchEventOccured = false;
result = false;
}
lastHasTouch = hasTouch;
}
#if defined(DEBUG)
TRACE("TouchEvent: %d, %d, %d, %d", touchEventOccured, lastHasTouch, hasTouch, result);
#endif
return result;
}
TouchState touchPanelRead()
{
if (!touchEventOccured) return internalTouchState;
touchEventOccured = false;
tmr10ms_t now = get_tmr10ms();
internalTouchState.tapCount = 0;
if (tc->detectTouch()) {
handleTouch();
if (internalTouchState.event == TE_DOWN && downTime == 0) {
downTime = now;
}
} else {
if (internalTouchState.event == TE_DOWN) {
internalTouchState.event = TE_UP;
if (now - downTime <= TAP_TIME) {
if (now - tapTime > TAP_TIME) {
tapCount = 1;
} else {
tapCount++;
}
internalTouchState.tapCount = tapCount;
tapTime = now;
} else {
internalTouchState.tapCount = 0; // not a tap
}
downTime = 0;
} else {
tapCount = 0;
internalTouchState.tapCount = 0;
internalTouchState.event = TE_SLIDE_END;
}
}
TouchState ret = internalTouchState;
internalTouchState.deltaX = 0;
internalTouchState.deltaY = 0;
if(internalTouchState.event == TE_UP || internalTouchState.event == TE_SLIDE_END)
internalTouchState.event = TE_NONE;
#if defined(DEBUG)
TRACE("%s: Event = %d", touchController == TC_CST340 ? "CST340" : "FT6236", ret.event);
#endif
return ret;
}
TouchState getInternalTouchState()
{
return internalTouchState;
}