318 lines
9.4 KiB
C
318 lines
9.4 KiB
C
/*
|
|
* Copyright 2019-2020 NXP
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "fsl_gt911.h"
|
|
|
|
/*******************************************************************************
|
|
* Definitions
|
|
******************************************************************************/
|
|
/*! @brief GT911 I2C address. */
|
|
#define GT911_I2C_ADDRESS0 (0x5D)
|
|
#define GT911_I2C_ADDRESS1 (0x14)
|
|
|
|
#define GT911_REG_ADDR_SIZE 2
|
|
|
|
/*! @brief GT911 registers. */
|
|
#define GT911_REG_ID 0x8140U
|
|
#define GT911_CONFIG_ADDR 0x8047U
|
|
#define GT911_REG_XL 0x8048U
|
|
#define GT911_REG_XH 0x8049U
|
|
#define GT911_REG_YL 0x804AU
|
|
#define GT911_REG_YH 0x804BU
|
|
#define GT911_REG_TOUCH_NUM 0x804CU
|
|
#define GT911_REG_CONFIG_VERSION 0x8047U
|
|
#define GT911_REG_MODULE_SWITCH1 0x804DU
|
|
#define GT911_REG_STAT 0x814EU
|
|
#define GT911_REG_FIRST_POINT 0x814FU
|
|
|
|
#define GT911_STAT_BUF_MASK (1U << 7U)
|
|
#define GT911_STAT_POINT_NUMBER_MASK (0xFU << 0U)
|
|
#define GT911_MODULE_SWITCH_X2Y_MASK (1U << 3U)
|
|
#define GT911_MODULE_SWITCH_INT_MASK (3U << 0U)
|
|
|
|
#define GT911_CONFIG_SIZE (186U)
|
|
|
|
/*******************************************************************************
|
|
* Prototypes
|
|
******************************************************************************/
|
|
/* Verify firmware, return true if pass. */
|
|
static bool GT911_VerifyFirmware(const uint8_t *firmware);
|
|
static uint8_t GT911_GetFirmwareCheckSum(const uint8_t *firmware);
|
|
|
|
/*******************************************************************************
|
|
* Variables
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
static uint8_t GT911_GetFirmwareCheckSum(const uint8_t *firmware)
|
|
{
|
|
uint8_t sum = 0;
|
|
uint16_t i = 0;
|
|
|
|
for (i = 0; i < GT911_CONFIG_SIZE - 2U; i++)
|
|
{
|
|
sum += (*firmware);
|
|
firmware++;
|
|
}
|
|
|
|
return (~sum + 1U);
|
|
}
|
|
|
|
static bool GT911_VerifyFirmware(const uint8_t *firmware)
|
|
{
|
|
return ((firmware[GT911_REG_CONFIG_VERSION - GT911_CONFIG_ADDR] != 0U) &&
|
|
(GT911_GetFirmwareCheckSum(firmware) == firmware[GT911_CONFIG_SIZE - 2U]));
|
|
}
|
|
|
|
status_t GT911_Init(gt911_handle_t *handle, const gt911_config_t *config)
|
|
{
|
|
status_t status;
|
|
uint32_t deviceID;
|
|
uint8_t gt911Config[GT911_CONFIG_SIZE];
|
|
|
|
assert(NULL != handle);
|
|
|
|
(void)memset(handle, 0, sizeof(*handle));
|
|
|
|
handle->I2C_SendFunc = config->I2C_SendFunc;
|
|
handle->I2C_ReceiveFunc = config->I2C_ReceiveFunc;
|
|
handle->timeDelayMsFunc = config->timeDelayMsFunc;
|
|
handle->pullResetPinFunc = config->pullResetPinFunc;
|
|
|
|
/* Reset the panel and set the I2C address mode. */
|
|
config->intPinFunc(kGT911_IntPinPullDown);
|
|
config->pullResetPinFunc(false);
|
|
|
|
/* >= 10ms. */
|
|
handle->timeDelayMsFunc(20);
|
|
|
|
if (kGT911_I2cAddrAny == config->i2cAddrMode)
|
|
{
|
|
config->pullResetPinFunc(true);
|
|
|
|
/* >= 55ms */
|
|
handle->timeDelayMsFunc(55);
|
|
|
|
config->intPinFunc(kGT911_IntPinInput);
|
|
|
|
/* Try address 0 */
|
|
handle->i2cAddr = GT911_I2C_ADDRESS0;
|
|
status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_ID, GT911_REG_ADDR_SIZE, (uint8_t *)&deviceID, 4);
|
|
|
|
if (kStatus_Success != status)
|
|
{
|
|
/* Try address 1 */
|
|
handle->i2cAddr = GT911_I2C_ADDRESS1;
|
|
status =
|
|
handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_ID, GT911_REG_ADDR_SIZE, (uint8_t *)&deviceID, 4);
|
|
|
|
if (kStatus_Success != status)
|
|
{
|
|
return status;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (kGT911_I2cAddrMode1 == config->i2cAddrMode)
|
|
{
|
|
config->intPinFunc(kGT911_IntPinPullUp);
|
|
handle->i2cAddr = GT911_I2C_ADDRESS1;
|
|
}
|
|
else
|
|
{
|
|
handle->i2cAddr = GT911_I2C_ADDRESS0;
|
|
}
|
|
|
|
/* >= 100us */
|
|
handle->timeDelayMsFunc(1);
|
|
|
|
config->pullResetPinFunc(true);
|
|
|
|
/* >= 5ms */
|
|
handle->timeDelayMsFunc(5);
|
|
|
|
config->intPinFunc(kGT911_IntPinPullDown);
|
|
|
|
/* >= 50ms */
|
|
handle->timeDelayMsFunc(50);
|
|
|
|
config->intPinFunc(kGT911_IntPinInput);
|
|
|
|
status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_ID, GT911_REG_ADDR_SIZE, (uint8_t *)&deviceID, 4);
|
|
if (kStatus_Success != status)
|
|
{
|
|
return status;
|
|
}
|
|
}
|
|
|
|
/* Verify the device. */
|
|
if (deviceID != 0x00313139U)
|
|
{
|
|
return kStatus_Fail;
|
|
}
|
|
|
|
/* Initialize the IC. */
|
|
status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_CONFIG_ADDR, GT911_REG_ADDR_SIZE, gt911Config,
|
|
GT911_CONFIG_SIZE);
|
|
if (kStatus_Success != status)
|
|
{
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* GT911 driver gets the original firmware from touch panel control IC, modify
|
|
* the configuration, then set it to the IC again. The original firmware
|
|
* read from the touch IC must be correct, otherwise setting wrong firmware
|
|
* to the touch IC will break it.
|
|
*/
|
|
if (true != GT911_VerifyFirmware(gt911Config))
|
|
{
|
|
return kStatus_Fail;
|
|
}
|
|
|
|
handle->resolutionX = ((uint16_t)gt911Config[GT911_REG_XH - GT911_CONFIG_ADDR]) << 8U;
|
|
handle->resolutionX += gt911Config[GT911_REG_XL - GT911_CONFIG_ADDR];
|
|
handle->resolutionY = ((uint16_t)gt911Config[GT911_REG_YH - GT911_CONFIG_ADDR]) << 8U;
|
|
handle->resolutionY += gt911Config[GT911_REG_YL - GT911_CONFIG_ADDR];
|
|
|
|
gt911Config[GT911_REG_TOUCH_NUM - GT911_CONFIG_ADDR] = (config->touchPointNum) & 0x0FU;
|
|
|
|
gt911Config[GT911_REG_MODULE_SWITCH1 - GT911_CONFIG_ADDR] &= (uint8_t)(~GT911_MODULE_SWITCH_INT_MASK);
|
|
gt911Config[GT911_REG_MODULE_SWITCH1 - GT911_CONFIG_ADDR] |= (uint8_t)(config->intTrigMode);
|
|
|
|
gt911Config[GT911_CONFIG_SIZE - 2U] = GT911_GetFirmwareCheckSum(gt911Config);
|
|
gt911Config[GT911_CONFIG_SIZE - 1U] = 1U; /* Mark the firmware as valid. */
|
|
|
|
return handle->I2C_SendFunc(handle->i2cAddr, GT911_CONFIG_ADDR, GT911_REG_ADDR_SIZE, gt911Config,
|
|
GT911_CONFIG_SIZE);
|
|
}
|
|
|
|
status_t GT911_Deinit(gt911_handle_t *handle)
|
|
{
|
|
handle->pullResetPinFunc(false);
|
|
return kStatus_Success;
|
|
}
|
|
|
|
static status_t GT911_ReadRawTouchData(gt911_handle_t *handle, uint8_t *touchPointNum)
|
|
{
|
|
status_t status;
|
|
uint8_t gt911Stat;
|
|
|
|
status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_STAT, GT911_REG_ADDR_SIZE, >911Stat, 1);
|
|
if (kStatus_Success != status)
|
|
{
|
|
*touchPointNum = 0;
|
|
return status;
|
|
}
|
|
|
|
*touchPointNum = gt911Stat & GT911_STAT_POINT_NUMBER_MASK;
|
|
|
|
if (0U != (gt911Stat & GT911_STAT_BUF_MASK))
|
|
{
|
|
if (*touchPointNum > 0U)
|
|
{
|
|
status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_FIRST_POINT, GT911_REG_ADDR_SIZE,
|
|
(void *)handle->pointReg, (*touchPointNum) * sizeof(gt911_point_reg_t));
|
|
}
|
|
|
|
/* Must set the status register to 0 after read. */
|
|
gt911Stat = 0;
|
|
status = handle->I2C_SendFunc(handle->i2cAddr, GT911_REG_STAT, GT911_REG_ADDR_SIZE, >911Stat, 1);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
status_t GT911_GetSingleTouch(gt911_handle_t *handle, int *touch_x, int *touch_y)
|
|
{
|
|
status_t status;
|
|
uint8_t touchPointNum;
|
|
|
|
status = GT911_ReadRawTouchData(handle, &touchPointNum);
|
|
|
|
if (kStatus_Success == status)
|
|
{
|
|
if (touchPointNum > 0U)
|
|
{
|
|
*touch_x =
|
|
(int)(uint16_t)((uint16_t)handle->pointReg[0].lowX + (((uint16_t)handle->pointReg[0].highX) << 8U));
|
|
*touch_y =
|
|
(int)(uint16_t)((uint16_t)handle->pointReg[0].lowY + (((uint16_t)handle->pointReg[0].highY) << 8U));
|
|
}
|
|
else
|
|
{
|
|
status = (status_t)kStatus_TOUCHPANEL_NotTouched;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = kStatus_Fail;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
status_t GT911_GetMultiTouch(gt911_handle_t *handle, uint8_t *touch_count, touch_point_t touch_array[])
|
|
{
|
|
status_t status;
|
|
uint32_t i;
|
|
uint8_t desiredTouchPointNum;
|
|
uint8_t actualTouchPointNum;
|
|
|
|
status = GT911_ReadRawTouchData(handle, &actualTouchPointNum);
|
|
|
|
if (kStatus_Success == status)
|
|
{
|
|
desiredTouchPointNum = *touch_count;
|
|
|
|
if (0U == actualTouchPointNum)
|
|
{
|
|
status = (status_t)kStatus_TOUCHPANEL_NotTouched;
|
|
}
|
|
else if (actualTouchPointNum > desiredTouchPointNum)
|
|
{
|
|
actualTouchPointNum = desiredTouchPointNum;
|
|
}
|
|
else
|
|
{
|
|
/* MISRA compatible. */
|
|
}
|
|
|
|
for (i = 0; i < actualTouchPointNum; i++)
|
|
{
|
|
touch_array[i].valid = true;
|
|
touch_array[i].touchID = handle->pointReg[i].id;
|
|
touch_array[i].x = handle->pointReg[i].lowX + (((uint16_t)handle->pointReg[i].highX) << 8U);
|
|
touch_array[i].y = handle->pointReg[i].lowY + (((uint16_t)handle->pointReg[i].highY) << 8U);
|
|
}
|
|
|
|
for (; i < desiredTouchPointNum; i++)
|
|
{
|
|
touch_array[i].valid = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = kStatus_Fail;
|
|
}
|
|
|
|
*touch_count = actualTouchPointNum;
|
|
|
|
return status;
|
|
}
|
|
|
|
status_t GT911_GetResolution(gt911_handle_t *handle, int *resolutionX, int *resolutionY)
|
|
{
|
|
*resolutionX = (int)handle->resolutionX;
|
|
*resolutionY = (int)handle->resolutionY;
|
|
|
|
return kStatus_Success;
|
|
}
|