野火STM32F103驱动GT911触摸芯片
GT911触摸芯片
芯片介绍
GT911 是专为 7”~8”设计的新一代 5 点电容触控方案,拥有 26 个驱动通道和 14 个感 应通道,以满足更高的 touch 精度要求。 GT911 可同时识别 5 个触摸点位的实时准确位置,移动轨迹及触摸面积。并可根据主控需要,读取相应点数的触摸信息。
芯片原理图
![](https://img-blog.csdnimg.cn/img_convert/c18ccbfdec274de6ae943a28d749925c.png)
管脚定义
![](https://img-blog.csdnimg.cn/img_convert/6ffa017aadcc4c439835d75f0f7f682f.png)
管脚号 | 名称 | 功能描述 | 备注 |
1~11 | SEN3~SEN13 | 触摸模拟信号输入 | |
12 | AVDD28 | 模拟电源正 | 接 2.2uF 滤波电容 |
13 | AVDD18 | 接 2.2uF 滤波电容 | |
14 | DVDD12 | 接 2.2uF 滤波电容 | |
15 | DGND | 数字信号地 | |
16 | INT | 中断信号 | |
17 | Sensor_OPT1 | 模组识别口 | |
18 | Sensor_OPT2 | 模组识别口(备选) | 需外部下拉 |
19 | I2C_SDA | I2C 数据信号 | |
20 | I2C_SCL | I2C 时钟信号 | |
21 | VDDIO | GPIO 电平控制 | 接 2.2uF 滤波电容 悬空:1.8V 接 AVDD:AVDD |
22 | /RSTB | 系统复位脚 | 需外部 10K 上拉,拉低复位 |
23~48 | DRV25~DRV0 | 驱动信号输出 | |
49 | AGND | 模拟电源地 | |
50~52 | SEN0~SEN2 | 触摸模拟信号输入 |
I2C通信
GT911 提供标准的 I 2 C 通讯接口,由 SCL 和 SDA 与主 CPU 进行通讯。 在系统中 GT911 始终作为从设备,所有通讯都是由主 CPU 发起,建议通讯速度为 400Kbps 或 以下。其支持的 I 2 C 硬件电路支持时序如下:
![](https://img-blog.csdnimg.cn/img_convert/34630b9c9e684721b438118c15050931.png)
GT911 的 I 2 C 从设备地址有两组,分别为 0xBA/0xBB 和 0x28/0x29。主控在上电初始 化时控制 Reset 和 INT 口状态进行设定,设定方法及时序图如下:
上电时序图:
![](https://img-blog.csdnimg.cn/img_convert/8f9f0986289b4700b863faf322dce4d1.png)
设定地址为0x28/0x29的时序:
![](https://img-blog.csdnimg.cn/img_convert/cdb9c09d6c37438ebc96e2130e6326cd.png)
设定地址为 0xBA/0xBB 的时序:
![](https://img-blog.csdnimg.cn/img_convert/70cc80ba4cc545c99d2b11c102c741f5.png)
IIC通信实例(以设备地址为 0xBA/0xBB 为例)
数据传输
通讯总是由主 CPU 发起,有效的起始信号为:在 SCL 保持为“1”时,SDA 上发生由“1” 到“0”的跳变。地址信息或数据流均在起始信号之后传输。
所有连接在I 2 C总线上的从设备,都要检测总线上起始信号之后所发送的8位地址信息, 并做出正确反应。在收到与自己相匹配的地址信息时,GT911 在第 9 个时钟周期,将 SDA 改为输出口,并置“0”作为应答信号。若收到不与自己匹配的地址信息,即非 0XBA 或 0XBB,GT911 将保持闲置状态。
SDA 口上的数据按 9 个时钟周期串行发送 9 位数据:8 位有效数据+1 位接收方发送的 应答信号 ACK 或非应答信号 NACK。数据传输在 SCL 为“1”时有效。 当通讯完成时,由主 CPU 发送停止信号。停止信号是当 SCL 为“1”时,SDA 状态由“0” 到“1”的跳变。
对 GT911 写操作
![](https://img-blog.csdnimg.cn/img_convert/903b1498494445769b15272405b1d395.png)
上图为主 CPU 对 GT911 进行的写操作流程图。
首先主 CPU 产生一个起始信号,然后 发送地址信息及读写位信息“0”表示写操作:0XBA。 在收到应答后,主 CPU 发送寄存器的 16 位地址,随后是 8 位要写入到寄存器的数据 内容。 GT911 寄存器的地址指针会在写操作后自动加 1,所以当主 CPU 需要对连续地址的寄 存器进行写操作时,可以在一次写操作中连续写入。写操作完成,主 CPU 发送停止信 号结束当前写操作。
对 GT911 读操作
![](https://img-blog.csdnimg.cn/img_convert/7eae1e00f53840068803d092207d5083.png)
上图为主 CPU 对 GT911 进行的读操作流程图。
首先主 CPU 产生一个起始信号,然后 发送设备地址信息及读写位信息“0”表示写操作:0XBA。 在收到应答后,主 CPU 发送首寄存器的 16 位地址信息,设置要读取的寄存器地址。 在收到应答后,主 CPU 重新发送一次起始信号,发送读操作:0XBB。收到应答后, 主 CPU 开始读取数据
GT911 同样支持连续的读操作,默认为连续读取数据。主 CPU 在每收到一个 Byte 数 据后需发送一个应答信号表示成功接收。在接收到所需的最后一个Byte数据后,主CPU 发送“非应答信号 NACK”,然后再发送停止信号结束通讯。
详细代码
主函数
/**
******************************************************************************
* @file main.c
* @author GYLJ
* @version V1.0
* @date 2022-10-xx
* @brief 电容触摸屏-GT911触摸芯片测试
******************************************************************************
* @attention
*
* 实验平台:野火 STM32 F103 霸道开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :https://fire-stm32.taobao.com
*
******************************************************************************
*/
#include "stm32f10x.h" // 相当于51单片机中的 #include <reg51.h>
#include "gt9xx.h"
#include "bsp_usart.h"
#include "core_delay.h"
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main ( void )
{
USART_Config();
/* 初始化内核定时器 */
CPU_TS_TmrInit();
/* 触摸芯片初始化 */
GTP_Init_Panel();
printf("\r\n ********** 触摸面板程序 *********** \r\n");
while ( 1 )
{
}
}
GT9xx.C
/**
******************************************************************************
* @file gtxx.c
* @author fire
* @version V1.0
* @date 2015-xx-xx
* @brief i2c电容屏驱动函数gt9157/GT917S/gt5688芯片
******************************************************************************
* @attention
*
* 实验平台:野火 STM32 F429 开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :https://fire-stm32.taobao.com
*
******************************************************************************
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "gt9xx.h"
#include "bsp_i2c_touch.h"
// 7寸屏GT917S驱动配置
const uint8_t CTP_CFG_GT917S[] = {
0x84,0x20,0x03,0xE0,0x01,0x05,0x05,0x00,0x00,0x40,
0x00,0x0F,0x78,0x64,0x53,0x11,0x00,0x00,0x00,0x00,
0x23,0x17,0x19,0x1D,0x0F,0x04,0x00,0x00,0x00,0x00,
0x00,0x00,0x04,0x51,0x14,0x00,0x00,0x00,0x00,0x00,
0x32,0x00,0x00,0x50,0x38,0x28,0x8A,0x20,0x11,0x37,
0x39,0xA2,0x07,0x38,0x6D,0x28,0x11,0x03,0x24,0x00,
0x01,0x28,0x50,0xC0,0x94,0x02,0x00,0x00,0x53,0xB8,
0x2E,0xA2,0x35,0x8F,0x3B,0x80,0x42,0x75,0x49,0x6B,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x4C,0x3C,
0xFF,0xFF,0x07,0x14,0x14,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x73,
0x50,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x1F,0x1D,0x1B,0x1A,0x19,0x18,0x17,0x16,0x15,0x09,
0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0x1C,0x1B,0x1A,0x19,0x18,0x17,0x15,0x14,
0x13,0x12,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x05,0x00,0x00,0x0F,
0x00,0x00,0x00,0x80,0x46,0x08,0x96,0x50,0x32,0x0A,
0x0A,0x64,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x32,0x03,0x0C,0x08,0x23,0x00,0x14,0x23,0x00,0x28,
0x46,0x30,0x3C,0xD0,0x07,0x50,0x70,0xB0,0x01
};
//uint8_t config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH]
// = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
/* 触摸IC类型默认为5寸屏的ic */
TOUCH_IC touchIC = GT917S;
const TOUCH_PARAM_TypeDef touch_param[1] =
{
/* GT917S,4.3寸屏 */
{
.max_width = 800,
.max_height = 480,
.config_reg_addr = 0x8050,
}
};
static int8_t GTP_I2C_Test(void);
//static void GT91xx_Config_Read_Proc(void);
static void Delay(__IO uint32_t nCount) //简单的延时函数
{
for(; nCount != 0; nCount--);
}
/**
* @brief 使用IIC进行数据传输
* @param
* @arg i2c_msg:数据传输结构体
* @arg num:数据传输结构体的个数
* @retval 正常完成的传输结构个数,若不正常,返回0xff
*/
static int I2C_Transfer( struct i2c_msg *msgs,int num)
{
int im = 0;
int ret = 0;
GTP_DEBUG_FUNC();
for (im = 0; ret == 0 && im != num; im++)
{
if ((msgs[im].flags&I2C_M_RD)) //根据flag判断是读数据还是写数据
{
ret = I2C_ReadBytes(msgs[im].addr, msgs[im].buf, msgs[im].len); //IIC读取数据
} else
{
ret = I2C_WriteBytes(msgs[im].addr, msgs[im].buf, msgs[im].len); //IIC写入数据
}
}
if(ret)
return ret;
return im; //正常完成的传输结构个数
}
/**
* @brief 从IIC设备中读取数据
* @param
* @arg client_addr:设备地址
* @arg buf[0~1]: 读取数据寄存器的起始地址
* @arg buf[2~len-1]: 存储读出来数据的缓冲buffer
* @arg len: GTP_ADDR_LENGTH + read bytes count(寄存器地址长度+读取的数据字节数)
* @retval i2c_msgs传输结构体的个数,2为成功,其它为失败
*/
static int32_t GTP_I2C_Read(uint8_t client_addr, uint8_t *buf, int32_t len)
{
struct i2c_msg msgs[2];
int32_t ret=-1;
int32_t retries = 0;
GTP_DEBUG_FUNC();
/*一个读数据的过程可以分为两个传输过程:
* 1. IIC 写入 要读取的寄存器地址
* 2. IIC 读取 数据
* */
msgs[0].flags = !I2C_M_RD; //写入
msgs[0].addr = client_addr; //IIC设备地址
msgs[0].len = GTP_ADDR_LENGTH; //寄存器地址为2字节(即写入两字节的数据)
msgs[0].buf = &buf[0]; //buf[0~1]存储的是要读取的寄存器地址
msgs[1].flags = I2C_M_RD; //读取
msgs[1].addr = client_addr; //IIC设备地址
msgs[1].len = len - GTP_ADDR_LENGTH; //要读取的数据长度
msgs[1].buf = &buf[GTP_ADDR_LENGTH]; //buf[GTP_ADDR_LENGTH]之后的缓冲区存储读出的数据
while(retries < 5)
{
ret = I2C_Transfer( msgs, 2); //调用IIC数据传输过程函数,有2个传输过程
if(ret == 2)break;
retries++;
}
if((retries >= 5))
{
GTP_ERROR("I2C Read: 0x%04X, %d bytes failed, errcode: %d! Process reset.", (((uint16_t)(buf[0] << 8)) | buf[1]), len-2, ret);
}
return ret;
}
/**
* @brief 向IIC设备写入数据
* @param
* @arg client_addr:设备地址
* @arg buf[0~1]: 要写入的数据寄存器的起始地址
* @arg buf[2~len-1]: 要写入的数据
* @arg len: GTP_ADDR_LENGTH + write bytes count(寄存器地址长度+写入的数据字节数)
* @retval i2c_msgs传输结构体的个数,1为成功,其它为失败
*/
static int32_t GTP_I2C_Write(uint8_t client_addr,uint8_t *buf,int32_t len)
{
struct i2c_msg msg;
int32_t ret = -1;
int32_t retries = 0;
GTP_DEBUG_FUNC();
/*一个写数据的过程只需要一个传输过程:
* 1. IIC连续 写入 数据寄存器地址及数据
* */
msg.flags = !I2C_M_RD; //写入
msg.addr = client_addr; //从设备地址
msg.len = len; //长度直接等于(寄存器地址长度+写入的数据字节数)
msg.buf = buf; //直接连续写入缓冲区中的数据(包括了寄存器地址)
while(retries < 5)
{
ret = I2C_Transfer(&msg, 1); //调用IIC数据传输过程函数,1个传输过程
if (ret == 1)break;
retries++;
}
if((retries >= 5))
{
GTP_ERROR("I2C Write: 0x%04X, %d bytes failed, errcode: %d! Process reset.", (((uint16_t)(buf[0] << 8)) | buf[1]), len-2, ret);
}
return ret;
}
/**
* @brief 使用IIC读取再次数据,检验是否正常
* @param
* @arg client:设备地址
* @arg addr: 寄存器地址
* @arg rxbuf: 存储读出的数据
* @arg len: 读取的字节数
* @retval
* @arg FAIL
* @arg SUCCESS
*/
int32_t GTP_I2C_Read_dbl_check(uint8_t client_addr, uint16_t addr, uint8_t *rxbuf, int len)
{
uint8_t buf[16] = {0};
uint8_t confirm_buf[16] = {0};
uint8_t retry = 0;
GTP_DEBUG_FUNC();
while (retry++ < 3)
{
memset(buf, 0xAA, 16);
buf[0] = (uint8_t)(addr >> 8);
buf[1] = (uint8_t)(addr & 0xFF);
GTP_I2C_Read(client_addr, buf, len + 2);
memset(confirm_buf, 0xAB, 16);
confirm_buf[0] = (uint8_t)(addr >> 8);
confirm_buf[1] = (uint8_t)(addr & 0xFF);
GTP_I2C_Read(client_addr, confirm_buf, len + 2);
if (!memcmp(buf, confirm_buf, len+2))
{
memcpy(rxbuf, confirm_buf+2, len);
return SUCCESS;
}
}
GTP_ERROR("I2C read 0x%04X, %d bytes, double check failed!", addr, len);
return FAIL;
}
/**
* @brief 关闭GT91xx中断
* @param 无
* @retval 无
*/
void GTP_IRQ_Disable(void)
{
GTP_DEBUG_FUNC();
}
/**
* @brief 使能GT91xx中断
* @param 无
* @retval 无
*/
void GTP_IRQ_Enable(void)
{
GTP_DEBUG_FUNC();
I2C_GTP_IRQEnable();
}
/**
* @brief 用于处理或报告触屏检测到按下
* @param
* @arg id: 触摸顺序trackID
* @arg x: 触摸的 x 坐标
* @arg y: 触摸的 y 坐标
* @arg w: 触摸的 大小
* @retval 无
*/
/*用于记录连续触摸时(长按)的上一次触摸位置,负数值表示上一次无触摸按下*/
volatile static int16_t pre_x[GTP_MAX_TOUCH] ={-1,-1,-1,-1,-1};
volatile static int16_t pre_y[GTP_MAX_TOUCH] ={-1,-1,-1,-1,-1};
static void GTP_Touch_Down(int32_t id,int32_t x,int32_t y,int32_t w)
{
GTP_DEBUG_FUNC();
/*取x、y初始值大于屏幕像素值*/
GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, x, y, w);
/************************************/
/*在此处添加自己的触摸点按下时处理过程即可*/
/* (x,y) 即为最新的触摸点 *************/
/************************************/
/*prex,prey数组存储上一次触摸的位置,id为轨迹编号(多点触控时有多轨迹)*/
pre_x[id] = x; pre_y[id] =y;
}
/**
* @brief 用于处理或报告触屏释放
* @param 释放点的id号
* @retval 无
*/
static void GTP_Touch_Up( int32_t id)
{
/*****************************************/
/*在此处添加自己的触摸点释放时的处理过程即可*/
/* pre_x[id],pre_y[id] 即为最新的释放点 ****/
/*******************************************/
/***id为轨迹编号(多点触控时有多轨迹)********/
/*触笔释放,把pre xy 重置为负*/
pre_x[id] = -1;
pre_y[id] = -1;
GTP_DEBUG("Touch id[%2d] release!", id);
}
/**
* @brief 触屏处理函数,轮询或者在触摸中断调用
* @param 无
* @retval 无
*/
static void Goodix_TS_Work_Func(void)
{
uint8_t end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0};
uint8_t point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1]={GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF};
uint8_t touch_num = 0;
uint8_t finger = 0;
static uint16_t pre_touch = 0;
static uint8_t pre_id[GTP_MAX_TOUCH] = {0};
uint8_t client_addr=GTP_ADDRESS;
uint8_t* coor_data = NULL;
int32_t input_x = 0;
int32_t input_y = 0;
int32_t input_w = 0;
uint8_t id = 0;
int32_t i = 0;
int32_t ret = -1;
GTP_DEBUG_FUNC();
ret = GTP_I2C_Read(client_addr, point_data, 12);//10字节寄存器加2字节地址
if (ret < 0)
{
GTP_ERROR("I2C transfer error. errno:%d\n ", ret);
return;
}
finger = point_data[GTP_ADDR_LENGTH];//状态寄存器数据
if (finger == 0x00) //没有数据,退出
{
return;
}
if((finger & 0x80) == 0)//判断buffer status位
{
goto exit_work_func;//坐标未就绪,数据无效
}
touch_num = finger & 0x0f;//坐标点数
if (touch_num > GTP_MAX_TOUCH)
{
goto exit_work_func;//大于最大支持点数,错误退出
}
if (touch_num > 1)//不止一个点
{
uint8_t buf[8 * GTP_MAX_TOUCH] = {(GTP_READ_COOR_ADDR + 10) >> 8, (GTP_READ_COOR_ADDR + 10) & 0xff};
ret = GTP_I2C_Read(client_addr, buf, 2 + 8 * (touch_num - 1));
memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1)); //复制其余点数的数据到point_data
}
if (pre_touch>touch_num) //pre_touch>touch_num,表示有的点释放了
{
for (i = 0; i < pre_touch; i++) //一个点一个点处理
{
uint8_t j;
for(j=0; j<touch_num; j++)
{
coor_data = &point_data[j * 8 + 3];
id = coor_data[0] & 0x0F; //track id
if(pre_id[i] == id)
break;
if(j >= touch_num-1) //遍历当前所有id都找不到pre_id[i],表示已释放
{
GTP_Touch_Up( pre_id[i]);
}
}
}
}
if (touch_num)
{
for (i = 0; i < touch_num; i++) //一个点一个点处理
{
coor_data = &point_data[i * 8 + 3];
id = coor_data[0] & 0x0F; //track id
pre_id[i] = id;
input_x = coor_data[1] | (coor_data[2] << 8); //x坐标
input_y = coor_data[3] | (coor_data[4] << 8); //y坐标
input_w = coor_data[5] | (coor_data[6] << 8); //size
{
GTP_Touch_Down( id, input_x, input_y, input_w);//数据处理其中 480-input_y 是为了换一下y的方向
}
}
}
else if (pre_touch) //touch_ num=0 且pre_touch!=0
{
for(i=0;i<pre_touch;i++)
{
GTP_Touch_Up(pre_id[i]);
}
}
pre_touch = touch_num;
exit_work_func:
{
ret = GTP_I2C_Write(client_addr, end_cmd, 3);
if (ret < 0)
{
GTP_INFO("I2C write end_cmd error!");
}
}
}
/**
* @brief 给触屏芯片重新复位
* @param 无
* @retval 无
*/
int8_t GTP_Reset_Guitar(void)
{
GTP_DEBUG_FUNC();
#if 1
I2C_ResetChip();
return 0;
#else //软件复位
int8_t ret = -1;
int8_t retry = 0;
uint8_t reset_command[3]={(uint8_t)GTP_REG_COMMAND>>8,(uint8_t)GTP_REG_COMMAND&0xFF,2};
//写入复位命令
while(retry++ < 5)
{
ret = GTP_I2C_Write(GTP_ADDRESS, reset_command, 3);
if (ret > 0)
{
GTP_INFO("GTP enter sleep!");
return ret;
}
}
GTP_ERROR("GTP send sleep cmd failed.");
return ret;
#endif
}
/**
* @brief 进入睡眠模式
* @param 无
* @retval 1为成功,其它为失败
*/
//int8_t GTP_Enter_Sleep(void)
//{
// int8_t ret = -1;
// int8_t retry = 0;
// uint8_t reset_comment[3] = {(uint8_t)(GTP_REG_COMMENT >> 8), (uint8_t)GTP_REG_COMMENT&0xFF, 5};//5
//
// GTP_DEBUG_FUNC();
//
// while(retry++ < 5)
// {
// ret = GTP_I2C_Write(GTP_ADDRESS, reset_comment, 3);
// if (ret > 0)
// {
// GTP_INFO("GTP enter sleep!");
//
// return ret;
// }
//
// }
// GTP_ERROR("GTP send sleep cmd failed.");
// return ret;
//}
int8_t GTP_Send_Command(uint8_t command)
{
int8_t ret = -1;
int8_t retry = 0;
uint8_t command_buf[3] = {(uint8_t)(GTP_REG_COMMAND >> 8), (uint8_t)GTP_REG_COMMAND&0xFF, GTP_COMMAND_READSTATUS};
GTP_DEBUG_FUNC();
while(retry++ < 5)
{
ret = GTP_I2C_Write(GTP_ADDRESS, command_buf, 3);
if (ret > 0)
{
GTP_INFO("send command success!");
return ret;
}
}
GTP_ERROR("send command fail!");
return ret;
}
/**
* @brief 唤醒触摸屏
* @param 无
* @retval 0为成功,其它为失败
*/
int8_t GTP_WakeUp_Sleep(void)
{
uint8_t retry = 0;
int8_t ret = -1;
GTP_DEBUG_FUNC();
while(retry++ < 10)
{
ret = GTP_I2C_Test();
if (ret > 0)
{
GTP_INFO("GTP wakeup sleep.");
return ret;
}
GTP_Reset_Guitar();
}
GTP_ERROR("GTP wakeup sleep failed.");
return ret;
}
static int32_t GTP_Get_Info(void)
{
uint8_t opr_buf[10] = {0};
int32_t ret = 0;
uint16_t abs_x_max = GTP_MAX_WIDTH;
uint16_t abs_y_max = GTP_MAX_HEIGHT;
uint8_t int_trigger_type = GTP_INT_TRIGGER;
opr_buf[0] = (uint8_t)((GTP_REG_CONFIG_DATA+1) >> 8);
opr_buf[1] = (uint8_t)((GTP_REG_CONFIG_DATA+1) & 0xFF);
ret = GTP_I2C_Read(GTP_ADDRESS, opr_buf, 10);
if (ret < 0)
{
return FAIL;
}
abs_x_max = (opr_buf[3] << 8) + opr_buf[2];
abs_y_max = (opr_buf[5] << 8) + opr_buf[4];
GTP_DEBUG("RES");
// GTP_DEBUG("opr_buf:");
// for (int i = 0; i < 10; i++) {printf(" %d\n", opr_buf[i]);}
GTP_DEBUG_ARRAY(&opr_buf[0],10);
opr_buf[0] = (uint8_t)((GTP_REG_CONFIG_DATA+6) >> 8);
opr_buf[1] = (uint8_t)((GTP_REG_CONFIG_DATA+6) & 0xFF);
ret = GTP_I2C_Read(GTP_ADDRESS, opr_buf, 3);
if (ret < 0)
{
return FAIL;
}
int_trigger_type = opr_buf[7] & 0x03;
GTP_INFO("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
abs_x_max,abs_y_max,int_trigger_type);
return SUCCESS;
}
/*******************************************************
Function:
Initialize gtp.
Input:
ts: goodix private data
Output:
Executive outcomes.
0: succeed, otherwise: failed
*******************************************************/
int32_t GTP_Init_Panel(void)
{
int32_t ret = -1;
int32_t i = 0;
uint16_t check_sum = 0;
int32_t retry = 0;
const uint8_t* cfg_info;
uint8_t cfg_info_len ;
uint8_t* config;
uint8_t cfg_num =0 ; //需要配置的寄存器个数
GTP_DEBUG_FUNC();
I2C_Touch_Init();
ret = GTP_I2C_Test();
if (ret < 0)
{
GTP_ERROR("I2C communication ERROR!");
return ret;
}
//获取触摸IC的型号
GTP_Read_Version();
#if UPDATE_CONFIG
config = (uint8_t *)malloc (GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
if (config == NULL)
{
GTP_ERROR("malloc fail ! ");
return -1;
}
config[0] = GTP_REG_CONFIG_DATA >> 8;
config[1] = GTP_REG_CONFIG_DATA & 0xff;
//根据IC的型号指向不同的配置
if(touchIC == GT917S)
{
cfg_info = CTP_CFG_GT917S;//指向寄存器配置
cfg_info_len = CFG_GROUP_LEN(CTP_CFG_GT917S) ;//计算配置表的大小
}
memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
memcpy(&config[GTP_ADDR_LENGTH], cfg_info, cfg_info_len);
cfg_num = cfg_info_len;
GTP_DEBUG("cfg_info_len = %d ",cfg_info_len);
GTP_DEBUG("cfg_num = %d ",cfg_num);
GTP_DEBUG_ARRAY(config,6);
/*根据LCD的扫描方向设置分辨率*/
config[GTP_ADDR_LENGTH+1] = LCD_PIXEL_WIDTH & 0xFF;
config[GTP_ADDR_LENGTH+2] = LCD_PIXEL_WIDTH >> 8;
config[GTP_ADDR_LENGTH+3] = LCD_PIXEL_HEIGHT & 0xFF;
config[GTP_ADDR_LENGTH+4] = LCD_PIXEL_HEIGHT >> 8;
/*根据模式设置X2Y交换*/
//不交换
config[GTP_ADDR_LENGTH+6] &= ~(X2Y_LOC);
//交换
// config[GTP_ADDR_LENGTH+6] |= (X2Y_LOC);
//计算要写入checksum寄存器的值
check_sum = 0;
/* 计算check sum校验值 */
if(touchIC == GT917S)
{
for (i = GTP_ADDR_LENGTH; i < (cfg_num+GTP_ADDR_LENGTH-3); i += 2)
{
check_sum += (config[i] << 8) + config[i + 1];
}
check_sum = 0 - check_sum;
GTP_DEBUG("Config checksum: 0x%04X", check_sum);
//更新checksum
config[(cfg_num+GTP_ADDR_LENGTH -3)] = (check_sum >> 8) & 0xFF;
config[(cfg_num+GTP_ADDR_LENGTH -2)] = check_sum & 0xFF;
config[(cfg_num+GTP_ADDR_LENGTH -1)] = 0x01;
}
// 写入配置信息
for (retry = 0; retry < 5; retry++)
{
ret = GTP_I2C_Write(GTP_ADDRESS, config , cfg_num + GTP_ADDR_LENGTH+2);
if (ret > 0)
{
break;
}
}
Delay(0xfffff); //延迟等待芯片更新
#if 1 //读出写入的数据,检查是否正常写入
//检验读出的数据与写入的是否相同
{
uint16_t i;
uint8_t buf[300];
buf[0] = config[0];
buf[1] =config[1]; //寄存器地址
GTP_DEBUG_FUNC();
ret = GTP_I2C_Read(GTP_ADDRESS, buf, sizeof(buf));
GTP_DEBUG("read ");
GTP_DEBUG_ARRAY(buf,cfg_num);
GTP_DEBUG("write ");
GTP_DEBUG_ARRAY(config,cfg_num);
//不对比版本号
for(i=3;i<cfg_num+GTP_ADDR_LENGTH-3;i++)
{
if(config[i] != buf[i])
{
GTP_ERROR("Config fail ! i = %d ",i);
// free(config);
// return -1;
}
}
if(i==cfg_num+GTP_ADDR_LENGTH-3)
GTP_DEBUG("Config success ! i = %d ",i);
}
#endif
free(config);
#endif
/* emXGUI示例中不使能中断 */
GTP_IRQ_Enable();
GTP_Get_Info();
return 0;
}
/*******************************************************
Function:
Read chip version.
Input:
client: i2c device
version: buffer to keep ic firmware version
Output:
read operation return.
2: succeed, otherwise: failed
*******************************************************/
int32_t GTP_Read_Version(void)
{
int32_t ret = -1;
uint8_t buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff}; //寄存器地址
GTP_DEBUG_FUNC();
ret = GTP_I2C_Read(GTP_ADDRESS, buf, sizeof(buf));
if (ret < 0)
{
GTP_ERROR("GTP read version failed");
return ret;
}
if(buf[4] == '7')
{
//GT917S芯片
GTP_INFO("IC2 Version: %c%c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
if(buf[2] == '9' && buf[3] == '1' && buf[4] == '7' && buf[5] == 'S')
{
touchIC = GT917S;
/* 设置当前的液晶屏类型 */
//cur_lcd = INCH_5;
}
}
else
GTP_INFO("Unknown IC Version: %c%c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
return ret;
}
/*******************************************************
Function:
I2c test Function.
Input:
client:i2c client.
Output:
Executive outcomes.
2: succeed, otherwise failed.
*******************************************************/
static int8_t GTP_I2C_Test( void)
{
uint8_t test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
uint8_t retry = 0;
int8_t ret = -1;
GTP_DEBUG_FUNC();
while(retry++ < 5)
{
ret = GTP_I2C_Read(GTP_ADDRESS, test, 3);
if (ret > 0)
{
return ret;
}
GTP_ERROR("GTP i2c test failed time %d.",retry);
}
return ret;
}
//检测到触摸中断时调用,
void GTP_TouchProcess(void)
{
GTP_DEBUG_FUNC();
Goodix_TS_Work_Func();
}
#if 0//没有到的测试函数
/*******************************************************
Function:
Request gpio(INT & RST) ports.
Input:
ts: private data.
Output:
Executive outcomes.
>= 0: succeed, < 0: failed
*******************************************************/
static int8_t GTP_Request_IO_Port(struct goodix_ts_data *ts)
{
}
/*******************************************************
Function:
Request interrupt.
Input:
ts: private data.
Output:
Executive outcomes.
0: succeed, -1: failed.
*******************************************************/
static int8_t GTP_Request_IRQ(struct goodix_ts_data *ts)
{
}
//输出要初始化的数据及芯片中的真实数据
static void GT91xx_Config_Read_Proc(void)
{
char temp_data[GTP_CONFIG_MAX_LENGTH + 2] = {0x80, 0x47};
int i;
GTP_INFO("==== GT9XX config init value====\n");
for (i = 0 ; i < GTP_CONFIG_MAX_LENGTH ; i++)
{
printf("reg0x%x = 0x%02X ", i+0x8047, config[i + 2]);
if (i % 10 == 9)
printf("\n");
}
GTP_INFO("==== GT9XX config real value====\n");
GTP_I2C_Read(GTP_ADDRESS, (uint8_t *)temp_data, GTP_CONFIG_MAX_LENGTH + 2);
for (i = 0 ; i < GTP_CONFIG_MAX_LENGTH ; i++)
{
printf("reg0x%x = 0x%02X ", i+0x8047,temp_data[i+2]);
if (i % 10 == 9)
printf("\n");
}
}
//向芯片写入配置数据
static int32_t GT91xx_Config_Write_Proc(void)
{
int32_t ret = -1;
int32_t i = 0;
uint8_t check_sum = 0;
int32_t retry = 0;
uint8_t cfg_num =0x80FE-0x8047+1 ; //需要配置的寄存器个数
uint8_t cfg_info[] = CTP_CFG_GROUP1;
uint8_t cfg_info_len =CFG_GROUP_LEN(cfg_info) ;
GTP_INFO("==== GT9XX send config====\n");
memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
memcpy(&config[GTP_ADDR_LENGTH], cfg_info,cfg_info_len);
//计算要写入checksum寄存器的值
check_sum = 0;
for (i = GTP_ADDR_LENGTH; i < cfg_num+GTP_ADDR_LENGTH; i++)
{
check_sum += config[i];
}
config[ cfg_num+GTP_ADDR_LENGTH] = (~check_sum) + 1; //checksum
config[ cfg_num+GTP_ADDR_LENGTH+1] = 1; //refresh 配置更新标志
//写入配置信息
for (retry = 0; retry < 5; retry++)
{
ret = GTP_I2C_Write(GTP_ADDRESS, config , cfg_num + GTP_ADDR_LENGTH+2);
if (ret > 0)
{
break;
}
}
return ret;
}
#endif
/**
* @brief 触屏中断服务函数,emXGUI示例中没有使用中断
* @param 无
* @retval 无
*/
void GTP_IRQHandler(void)
{
if(EXTI_GetITStatus(GTP_INT_EXTI_LINE) != RESET) //确保是否产生了EXTI Line中断
{
GTP_TouchProcess();
EXTI_ClearITPendingBit(GTP_INT_EXTI_LINE); //清除中断标志位
}
}
/**
* @brief 触屏检测函数,本函数作为emXGUI的定制检测函数,
* 参考Goodix_TS_Work_Func修改而来, 只读取单个触摸点坐标
* @param x[out] y[out] 读取到的坐标
* @retval 坐标有效返回1,否则返回0
*/
int GTP_Execu( int *x,int *y)
{
uint8_t end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0};
//2-寄存器地址 1-状态寄存器 8*1-每个触摸点使用8个寄存器
uint8_t point_data[2 + 1 + 8 * 1 + 1]={GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF};
uint8_t touch_num = 0;
uint8_t finger = 0;
uint8_t client_addr=GTP_ADDRESS;
int32_t input_x = 0;
int32_t input_y = 0;
int32_t ret = -1;
GTP_DEBUG_FUNC();
ret = GTP_I2C_Read(client_addr, point_data, 12);//10字节寄存器加2字节地址
if (ret < 0)
{
GTP_ERROR("I2C transfer error. errno:%d\n ", ret);
return 0;
}
finger = point_data[GTP_ADDR_LENGTH];//状态寄存器数据
if (finger == 0x00) //没有数据,退出
{
return 0;
}
if((finger & 0x80) == 0)//判断buffer status位
{
goto exit_work_func;//坐标未就绪,数据无效
}
touch_num = finger & 0x0f;//坐标点数
if (touch_num > GTP_MAX_TOUCH)
{
goto exit_work_func;//大于最大支持点数,错误退出
}
if (touch_num)
{
// id = point_data[0] & 0x0F; //track id
input_x = point_data[3+1] | (point_data[3+2] << 8); //x坐标
input_y = point_data[3+3] | (point_data[3+4] << 8); //y坐标
// input_w = coor_data[5] | (coor_data[6] << 8); //size
if(input_x < GTP_MAX_WIDTH && input_y < GTP_MAX_HEIGHT)
{
*x = input_x;
*y = 480 - input_y; // 交换一下y
}
else
{
//超出范围,错误退出
goto exit_work_func;
}
}
exit_work_func:
{
//清空标志
ret = GTP_I2C_Write(client_addr, end_cmd, 3);
if (ret < 0)
{
GTP_INFO("I2C write end_cmd error!");
return 0;
}
}
return touch_num;
}
//MODULE_DESCRIPTION("GTP Series Driver");
//MODULE_LICENSE("GPL");
GT9XX.h
/* drivers/input/touchscreen/gt9xx.h
*
* 2010 - 2013 Goodix Technology.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be a reference
* to you, when you are integrating the GOODiX's CTP IC into your system,
* 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.
*
*/
#ifndef _GOODIX_GTXX_H
#define _GOODIX_GTXX_H
#include "stm32f10x.h"
#ifndef NULL
#define NULL 0
#endif
#define LCD_PIXEL_HEIGHT 480
#define LCD_PIXEL_WIDTH 800
#define UPDATE_CONFIG 1 // 1 :更新配置 0 :不更新配置
/*flags的可取值,注释掉的在本工程没有用到*/
//#define I2C_M_TEN 0x0010 /* 表示这是个10位地址 */
//#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */
//#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
//#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
//#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
//#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
/* 表示读数据 */
#define I2C_M_RD 0x0001
/*
* 存储I2C通讯的信息
* @addr: 从设备的I2C设备地址
* @flags: 控制标志
* @len: 读写数据的长度
* @buf: 存储读写数据的指针
**/
struct i2c_msg {
uint8_t addr; /*从设备的I2C设备地址 */
uint16_t flags; /*控制标志*/
uint16_t len; /*读写数据的长度 */
uint8_t *buf; /*存储读写数据的指针 */
};
/**
* @brief 触摸屏参数
*/
typedef struct
{
/*根据触摸屏类型配置*/
uint16_t max_width; //触点最大值,高
uint16_t max_height; //触点最大值,宽
uint16_t config_reg_addr; //不同类型的触摸ic配置寄存器地址不同
}TOUCH_PARAM_TypeDef;
/**
* @brief 触摸屏类型
*/
typedef enum
{
GT917S=0,
}TOUCH_IC;
extern TOUCH_IC touchIC;
extern const TOUCH_PARAM_TypeDef touch_param[];
// STEP_3(optional): Specify your special config info if needed
#define GTP_MAX_HEIGHT touch_param[touchIC].max_height
#define GTP_MAX_WIDTH touch_param[touchIC].max_width
#define GTP_INT_TRIGGER 0
#define GTP_MAX_TOUCH 5
//***************************PART3:OTHER define*********************************
#define GTP_DRIVER_VERSION "V2.2<2014/01/14>"
#define GTP_I2C_NAME "Goodix-TS"
#define GT91XX_CONFIG_PROC_FILE "gt9xx_config"
#define GTP_POLL_TIME 10
#define GTP_ADDR_LENGTH 2
#define GTP_CONFIG_MIN_LENGTH 186
#define GTP_CONFIG_MAX_LENGTH 256
#define FAIL 0
#define SUCCESS 1
#define SWITCH_OFF 0
#define SWITCH_ON 1
//******************** For GT9XXF Start **********************//
#define GTP_REG_BAK_REF 0x99D0
#define GTP_REG_MAIN_CLK 0x8020
#define GTP_REG_CHIP_TYPE 0x8000
#define GTP_REG_HAVE_KEY 0x804E
#define GTP_REG_MATRIX_DRVNUM 0x8069
#define GTP_REG_MATRIX_SENNUM 0x806A
#define GTP_REG_COMMAND 0x8040
#define GTP_COMMAND_READSTATUS 0
#define GTP_COMMAND_DIFFERENCE 1
#define GTP_COMMAND_SOFTRESET 2
#define GTP_COMMAND_UPDATE 3
#define GTP_COMMAND_CALCULATE 4
#define GTP_COMMAND_TURNOFF 5
#define GTP_FL_FW_BURN 0x00
#define GTP_FL_ESD_RECOVERY 0x01
#define GTP_FL_READ_REPAIR 0x02
#define GTP_BAK_REF_SEND 0
#define GTP_BAK_REF_STORE 1
#define CFG_LOC_DRVA_NUM 29
#define CFG_LOC_DRVB_NUM 30
#define CFG_LOC_SENS_NUM 31
#define GTP_CHK_FW_MAX 40
#define GTP_CHK_FS_MNT_MAX 300
#define GTP_BAK_REF_PATH "/data/gtp_ref.bin"
#define GTP_MAIN_CLK_PATH "/data/gtp_clk.bin"
#define GTP_RQST_CONFIG 0x01
#define GTP_RQST_BAK_REF 0x02
#define GTP_RQST_RESET 0x03
#define GTP_RQST_MAIN_CLOCK 0x04
#define GTP_RQST_RESPONDED 0x00
#define GTP_RQST_IDLE 0xFF
//******************** For GT9XXF End **********************//
// Registers define
#define GTP_READ_COOR_ADDR 0x814E
#define GTP_REG_SLEEP 0x8040
#define GTP_REG_SENSOR_ID 0x814A
#define GTP_REG_CONFIG_DATA touch_param[touchIC].config_reg_addr
#define GTP_REG_VERSION 0x8140
#define RESOLUTION_LOC 3
#define TRIGGER_LOC 8
#define X2Y_LOC (1<<3)
#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
//***************************PART1:ON/OFF define*******************************
#define GTP_DEBUG_ON 1
#define GTP_DEBUG_ARRAY_ON 1
#define GTP_DEBUG_FUNC_ON 0
// Log define
#define GTP_INFO(fmt,arg...) printf("<<-GTP-INFO->> "fmt"\n",##arg)
#define GTP_ERROR(fmt,arg...) printf("<<-GTP-ERROR->> "fmt"\n",##arg)
#define GTP_DEBUG(fmt,arg...) do{\
if(GTP_DEBUG_ON)\
printf("<<-GTP-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
}while(0)
#define GTP_DEBUG_ARRAY(array, num) do{\
int32_t i;\
uint8_t* a = array;\
if(GTP_DEBUG_ARRAY_ON)\
{\
printf("<<-GTP-DEBUG-ARRAY->>\n");\
for (i = 0; i < (num); i++)\
{\
printf("%02x ", (a)[i]);\
if ((i + 1 ) %10 == 0)\
{\
printf("\n");\
}\
}\
printf("\n");\
}\
}while(0)
#define GTP_DEBUG_FUNC() do{\
if(GTP_DEBUG_FUNC_ON)\
printf("<<-GTP-FUNC->> Func:%s@Line:%d\n",__func__,__LINE__);\
}while(0)
#define GTP_SWAP(x, y) do{\
typeof(x) z = x;\
x = y;\
y = z;\
}while (0)
//*****************************End of Part III********************************
int8_t GTP_Reset_Guitar(void);
int32_t GTP_Read_Version(void);
void GTP_IRQ_Disable(void);
void GTP_IRQ_Enable(void);
int32_t GTP_Init_Panel(void);
int8_t GTP_Send_Command(uint8_t command);
int GTP_Execu( int *x,int *y);
#endif /* _GOODIX_GT9XX_H_ */
bsp_i2c_touch.c
/**
******************************************************************************
* @file bsp_i2c_ee.c
* @author STMicroelectronics
* @version V1.0
* @date 2015-xx-xx
* @brief 电容触摸屏的专用iic驱动
******************************************************************************
* @attention
*
* 实验平台:野火 STM32 F407 开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :https://fire-stm32.taobao.com
*
******************************************************************************
*/
#include "bsp_i2c_touch.h"
#include "core_delay.h"
#include "bsp_usart.h"
/* STM32 I2C 快速模式 */
#define I2C_Speed 400000
/* 这个地址只要与STM32外挂的I2C器件地址不一样即可 */
#define I2C_OWN_ADDRESS7 0x0A
//static void Delay(__IO uint32_t nCount) //简单的延时函数
//{
// for(; nCount != 0; nCount--);
//}
/**
* @brief 使能触摸屏中断
* @param 无
* @retval 无
*/
void I2C_GTP_IRQEnable(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/*配置 INT 为浮空输入 */
GPIO_InitStructure.GPIO_Pin = GTP_INT_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GTP_INT_GPIO_PORT, &GPIO_InitStructure);
/* 连接 EXTI 中断源 到INT 引脚 */
GPIO_EXTILineConfig(GTP_INT_EXTI_PORTSOURCE, GTP_INT_EXTI_PINSOURCE);
/* 选择 EXTI 中断源 */
EXTI_InitStructure.EXTI_Line = GTP_INT_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* 配置中断优先级 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/*使能中断*/
NVIC_InitStructure.NVIC_IRQChannel = GTP_INT_EXTI_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief 关闭触摸屏中断
* @param 无
* @retval 无
*/
void I2C_GTP_IRQDisable(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/*配置 INT 为浮空输入 */
GPIO_InitStructure.GPIO_Pin = GTP_INT_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GTP_INT_GPIO_PORT, &GPIO_InitStructure);
/* 连接 EXTI 中断源 到INT 引脚 */
GPIO_EXTILineConfig(GTP_INT_EXTI_PORTSOURCE, GTP_INT_EXTI_PINSOURCE);
/* 选择 EXTI 中断源 */
EXTI_InitStructure.EXTI_Line = GTP_INT_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = DISABLE;
EXTI_Init(&EXTI_InitStructure);
/* 配置中断优先级 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* 关闭中断 */
NVIC_InitStructure.NVIC_IRQChannel = GTP_INT_EXTI_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief 触摸屏 I/O配置
* @param 无
* @retval 无
*/
static void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*使能触摸屏使用的引脚的时钟*/
RCC_APB2PeriphClockCmd(GTP_I2C_SCL_GPIO_CLK|
GTP_I2C_SDA_GPIO_CLK|
GTP_RST_GPIO_CLK|GTP_INT_GPIO_CLK,
ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/*配置SCL引脚 */
GPIO_InitStructure.GPIO_Pin = GTP_I2C_SCL_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GTP_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
/*配置SDA引脚 */
GPIO_InitStructure.GPIO_Pin = GTP_I2C_SDA_PIN;
GPIO_Init(GTP_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
/*配置RST引脚,推挽输出 */
GPIO_InitStructure.GPIO_Pin = GTP_RST_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GTP_RST_GPIO_PORT, &GPIO_InitStructure);
/*配置 INT引脚,推挽输出,方便初始化 */
GPIO_InitStructure.GPIO_Pin = GTP_INT_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//设置为下拉,方便初始化
GPIO_Init(GTP_INT_GPIO_PORT, &GPIO_InitStructure);
}
/**
* @brief 对GT91xx芯片进行复位
* @param 无
* @retval 无
*/
void I2C_ResetChip(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*配置 INT引脚,下拉推挽输出,方便初始化 */
GPIO_InitStructure.GPIO_Pin = GTP_INT_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置为下拉,方便初始化
GPIO_Init(GTP_INT_GPIO_PORT, &GPIO_InitStructure);
/*初始化GT5688,rst为高电平,int为低电平,则gt5688的设备地址被配置为0xBA*/
GPIO_ResetBits (GTP_INT_GPIO_PORT,GTP_INT_GPIO_PIN);
/*复位为低电平,为初始化做准备*/
GPIO_ResetBits (GTP_RST_GPIO_PORT,GTP_RST_GPIO_PIN);
// Delay_us(200);
// Delay(1);
Delay_ms(1);
/*拉高一段时间,进行初始化*/
GPIO_SetBits (GTP_RST_GPIO_PORT,GTP_RST_GPIO_PIN);
Delay_ms(55);
/*把INT引脚设置为浮空输入模式,以便接收触摸中断信号*/
GPIO_InitStructure.GPIO_Pin = GTP_INT_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GTP_INT_GPIO_PORT, &GPIO_InitStructure);
}
/**
* @brief I2C 外设(GT5xx)初始化
* @param 无
* @retval 无
*/
void I2C_Touch_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
I2C_GPIO_Config();
I2C_ResetChip();
I2C_GTP_IRQDisable();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Delay
* 功能说明: I2C总线位延迟,最快400KHz
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void i2c_Delay(void)
{
uint8_t i;
/*
下面的时间是通过逻辑分析仪测试得到的。
工作条件:CPU主频180MHz ,MDK编译环境,1级优化
循环次数为50时,SCL频率 = 333KHz
循环次数为30时,SCL频率 = 533KHz,
循环次数为20时,SCL频率 = 727KHz,
*/
for (i = 0; i < 50; i++);
// Delay_us(40);
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Start
* 功能说明: CPU发起I2C总线启动信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Start(void)
{
/* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */
I2C_SDA_1();
I2C_SCL_1();
i2c_Delay();
I2C_SDA_0();
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Start
* 功能说明: CPU发起I2C总线停止信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Stop(void)
{
/* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */
I2C_SDA_0();
I2C_SCL_1();
i2c_Delay();
I2C_SDA_1();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_SendByte
* 功能说明: CPU向I2C总线设备发送8bit数据
* 形 参:_ucByte : 等待发送的字节
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_SendByte(uint8_t _ucByte)
{
uint8_t i;
/* 先发送字节的高位bit7 */
for (i = 0; i < 8; i++)
{
if (_ucByte & 0x80)
{
I2C_SDA_1();
}
else
{
I2C_SDA_0();
}
i2c_Delay();
I2C_SCL_1();
i2c_Delay();
I2C_SCL_0();
if (i == 7)
{
I2C_SDA_1(); // 释放总线
}
_ucByte <<= 1; /* 左移一个bit */
i2c_Delay();
}
}
/*
*********************************************************************************************************
* 函 数 名: i2c_ReadByte
* 功能说明: CPU从I2C总线设备读取8bit数据
* 形 参:无
* 返 回 值: 读到的数据
*********************************************************************************************************
*/
uint8_t i2c_ReadByte(void)
{
uint8_t i;
uint8_t value;
/* 读到第1个bit为数据的bit7 */
value = 0;
for (i = 0; i < 8; i++)
{
value <<= 1;
I2C_SCL_1();
i2c_Delay();
if (I2C_SDA_READ())
{
value++;
}
I2C_SCL_0();
i2c_Delay();
}
return value;
}
/*
*********************************************************************************************************
* 函 数 名: i2c_WaitAck
* 功能说明: CPU产生一个时钟,并读取器件的ACK应答信号
* 形 参:无
* 返 回 值: 返回0表示正确应答,1表示无器件响应
*********************************************************************************************************
*/
uint8_t i2c_WaitAck(void)
{
uint8_t re;
I2C_SDA_1(); /* CPU释放SDA总线 */
i2c_Delay();
I2C_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
i2c_Delay();
if (I2C_SDA_READ()) /* CPU读取SDA口线状态 */
{
re = 1;
}
else
{
re = 0;
}
I2C_SCL_0();
i2c_Delay();
return re;
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Ack
* 功能说明: CPU产生一个ACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Ack(void)
{
I2C_SDA_0(); /* CPU驱动SDA = 0 */
i2c_Delay();
I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
I2C_SDA_1(); /* CPU释放SDA总线 */
}
/*
*********************************************************************************************************
* 函 数 名: i2c_NAck
* 功能说明: CPU产生1个NACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_NAck(void)
{
I2C_SDA_1(); /* CPU驱动SDA = 1 */
i2c_Delay();
I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
#define I2C_DIR_WR 0 /* 写控制bit */
#define I2C_DIR_RD 1 /* 读控制bit */
/**
* @brief 使用IIC读取数据
* @param
* @arg ClientAddr:从设备地址
* @arg pBuffer:存放由从机读取的数据的缓冲区指针
* @arg NumByteToRead:读取的数据长度
* @retval 无
*/
uint32_t I2C_ReadBytes(uint8_t ClientAddr,uint8_t* pBuffer, uint16_t NumByteToRead)
{
/* 第1步:发起I2C总线启动信号 */
i2c_Start();
/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
i2c_SendByte(ClientAddr | I2C_DIR_RD); /* 此处是读指令 */
/* 第3步:等待ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* 器件无应答 */
}
while(NumByteToRead)
{
*pBuffer = i2c_ReadByte();
if(NumByteToRead == 1)
{
i2c_NAck(); /* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */
/* 发送I2C总线停止信号 */
i2c_Stop();
}
/* 读指针自增 */
pBuffer++;
/*计数器自减 */
NumByteToRead--;
i2c_Ack(); /* 中间字节读完后,CPU产生ACK信号(驱动SDA = 0) */
}
/* 发送I2C总线停止信号 */
i2c_Stop();
return 0; /* 执行成功 */
cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
/* 发送I2C总线停止信号 */
i2c_Stop();
return 1;
}
/**
* @brief 使用IIC写入数据
* @param
* @arg ClientAddr:从设备地址
* @arg pBuffer:缓冲区指针
* @arg NumByteToWrite:写的字节数
* @retval 无
*/
uint32_t I2C_WriteBytes(uint8_t ClientAddr,uint8_t* pBuffer, uint8_t NumByteToWrite)
{
uint16_t m;
/* 第0步:发停止信号,启动内部写操作 */
i2c_Stop();
/* 通过检查器件应答的方式,判断内部写操作是否完成, 一般小于 10ms
CLK频率为200KHz时,查询次数为30次左右
*/
for (m = 0; m < 1000; m++)
{
/* 第1步:发起I2C总线启动信号 */
i2c_Start();
/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
i2c_SendByte(ClientAddr | I2C_DIR_WR); /* 此处是写指令 */
/* 第3步:发送一个时钟,判断器件是否正确应答 */
if (i2c_WaitAck() == 0)
{
break;
}
}
if (m == 1000)
{
goto cmd_fail; /* EEPROM器件写超时 */
}
while(NumByteToWrite--)
{
/* 第4步:开始写入数据 */
i2c_SendByte(*pBuffer);
//printf(" 0x%x\r\n", *pBuffer);
/* 第5步:检查ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* 器件无应答 */
}
pBuffer++; /* 地址增1 */
}
/* 命令执行成功,发送I2C总线停止信号 */
i2c_Stop();
return 0;
cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
/* 发送I2C总线停止信号 */
i2c_Stop();
return 1;
}
/*********************************************END OF FILE**********************/
bsp_i2c_touch.h
#ifndef __I2C_TOUCH_H
#define __I2C_TOUCH_H
#include "stm32f10x.h"
/*设定使用的电容屏IIC设备地址*/
#define GTP_ADDRESS 0xBA
#define I2CT_FLAG_TIMEOUT ((uint32_t)0x1000)
#define I2CT_LONG_TIMEOUT ((uint32_t)(10 * I2CT_FLAG_TIMEOUT))
/*I2C引脚*/
#define GTP_I2C_SCL_PIN GPIO_Pin_10
#define GTP_I2C_SCL_GPIO_PORT GPIOF
#define GTP_I2C_SCL_GPIO_CLK RCC_APB2Periph_GPIOF
#define GTP_I2C_SCL_SOURCE GPIO_PinSource10
#define GTP_I2C_SDA_PIN GPIO_Pin_6
#define GTP_I2C_SDA_GPIO_PORT GPIOF
#define GTP_I2C_SDA_GPIO_CLK RCC_APB2Periph_GPIOF
#define GTP_I2C_SDA_SOURCE GPIO_PinSource6
/*复位引脚*/
#define GTP_RST_GPIO_PORT GPIOF
#define GTP_RST_GPIO_CLK RCC_APB2Periph_GPIOF
#define GTP_RST_GPIO_PIN GPIO_Pin_11
/*中断引脚*/
#define GTP_INT_GPIO_PORT GPIOF
#define GTP_INT_GPIO_CLK RCC_APB2Periph_GPIOF
#define GTP_INT_GPIO_PIN GPIO_Pin_9
#define GTP_INT_EXTI_PORTSOURCE GPIO_PortSourceGPIOF
#define GTP_INT_EXTI_PINSOURCE GPIO_PinSource9
#define GTP_INT_EXTI_LINE EXTI_Line9
#define GTP_INT_EXTI_IRQ EXTI9_5_IRQn
/*中断服务函数*/
#define GTP_IRQHandler EXTI9_5_IRQHandler
//软件IIC使用的宏
#define I2C_SCL_1() GPIO_SetBits(GTP_I2C_SCL_GPIO_PORT, GTP_I2C_SCL_PIN) /* SCL = 1 */
#define I2C_SCL_0() GPIO_ResetBits(GTP_I2C_SCL_GPIO_PORT, GTP_I2C_SCL_PIN) /* SCL = 0 */
#define I2C_SDA_1() GPIO_SetBits(GTP_I2C_SDA_GPIO_PORT, GTP_I2C_SDA_PIN) /* SDA = 1 */
#define I2C_SDA_0() GPIO_ResetBits(GTP_I2C_SDA_GPIO_PORT, GTP_I2C_SDA_PIN) /* SDA = 0 */
#define I2C_SDA_READ() GPIO_ReadInputDataBit(GTP_I2C_SDA_GPIO_PORT, GTP_I2C_SDA_PIN) /* 读SDA口线状态 */
//函数接口
void I2C_Touch_Init(void);
uint32_t I2C_WriteBytes(uint8_t ClientAddr,uint8_t* pBuffer, uint8_t NumByteToWrite);
uint32_t I2C_ReadBytes(uint8_t ClientAddr,uint8_t* pBuffer, uint16_t NumByteToRead);
void I2C_ResetChip(void);
void I2C_GTP_IRQDisable(void);
void I2C_GTP_IRQEnable(void);
#endif /* __I2C_TOUCH_H */
主要部分就这些,实测能用(野火霸道开发板测试)。
测试结果:
![](https://img-blog.csdnimg.cn/img_convert/02c89fec5cd84976a9aa45c5066d8ab6.png)