4、GT911芯片手册解读:寄存器映射、配置表、中断与轮询模式
GT911 是汇顶科技推出的电容式触摸屏控制芯片,支持最多 5 点触控,广泛应用于工控、车载和消费电子领域。本章将深入解读 GT911 芯片手册的核心内容,包括寄存器映射、配置表结构、中断机制与轮询模式,为后续驱动移植打下基础。
关键提示: GT911 的 I2C 地址可通过外部电阻配置,常见地址为 0x5D 或 0x14。驱动初始化时需先读取芯片版本信息,确认通信正常后再加载配置表。
4.1 寄存器映射结构
GT911 的寄存器空间采用 16 位地址寻址,分为多个功能区域。下表列出了核心寄存器区域及其偏移地址:
| 地址范围 | 区域名称 | 说明 |
|---|---|---|
| 0x8040 - 0x8046 | 产品信息 | 包含芯片 ID、版本号、传感器 ID |
| 0x8047 - 0x80FF | 配置表 | 触摸屏参数配置,如分辨率、灵敏度 |
| 0x8140 - 0x814E | 坐标数据 | 当前触摸点的坐标、压力、面积 |
| 0x814F | 状态寄存器 | 触摸状态、缓冲区状态、按键状态 |
| 0x8150 - 0x81FF | 扩展数据 | 手势识别、自定义数据 |
寄存器访问采用 I2C 连续读写方式,每次操作需先发送 16 位地址(高字节在前)。下图展示了 GT911 的寄存器空间布局:
4.2 配置表详解
配置表是 GT911 驱动的核心,决定了触摸屏的物理行为。配置表存储在芯片的 Flash 中,上电时自动加载。驱动可通过 I2C 写入新配置并触发软复位使配置生效。
配置表的关键字段如下:
| 偏移地址 | 字段名 | 字节数 | 说明 |
|---|---|---|---|
| 0x8047 | 配置版本号 | 2 | 用于校验配置表是否匹配 |
| 0x8049 | X 方向分辨率 | 2 | 触摸屏 X 轴最大坐标值 |
| 0x804B | Y 方向分辨率 | 2 | 触摸屏 Y 轴最大坐标值 |
| 0x804D | 触摸点数 | 1 | 最大支持触摸点数(1-5) |
| 0x804E | 模块切换时间 | 1 | 扫描周期,单位 10us |
| 0x804F | 刷新频率 | 1 | 触摸扫描频率 |
| 0x8050 | 触摸阈值 | 1 | 触摸检测灵敏度阈值 |
配置表加载流程: 驱动初始化时,先读取配置版本号与驱动内置版本对比。若不一致,则写入新配置表,然后向 0x8040 寄存器写入 0x01 触发软复位,等待 100ms 后重新读取版本号确认生效。
配置表写入示例代码:
/* GT911 配置表写入函数 */
static int gt911_write_config(struct i2c_client *client, u8 *config, int len)
{
int ret;
u8 buf[256];
struct i2c_msg msg;
/* 构造写入数据:16位地址 + 配置数据 */
buf[0] = (GT911_CONFIG_ADDR >> 8) & 0xFF; /* 地址高字节 */
buf[1] = GT911_CONFIG_ADDR & 0xFF; /* 地址低字节 */
memcpy(&buf[2], config, len);
msg.addr = client->addr;
msg.flags = 0; /* 写操作 */
msg.len = len + 2;
msg.buf = buf;
ret = i2c_transfer(client->adapter, &msg, 1);
if (ret != 1) {
dev_err(&client->dev, "write config failed\n");
return -EIO;
}
/* 触发软复位 */
gt911_soft_reset(client);
msleep(100);
return 0;
}
4.3 中断模式
GT911 支持硬件中断模式,通过 INT 引脚向主机报告触摸事件。中断模式是驱动开发的首选方式,具有实时性好、CPU 占用低的优点。
中断模式的工作流程如下:
- 初始化: 配置 INT 引脚为下降沿触发中断,设置 I2C 通信参数。
- 触摸事件: 用户触摸屏幕时,GT911 检测到触摸,将 INT 引脚拉低。
- 中断处理: CPU 响应中断,在中断服务程序中读取状态寄存器 0x814E。
- 数据读取: 根据状态寄存器指示的触摸点数,读取 0x8140 开始的坐标数据。
- 清除标志: 读取完毕后,向 0x814E 写入 0x00 清除中断标志,INT 引脚恢复高电平。
中断模式的状态寄存器 0x814E 位定义:
| 位 | 名称 | 说明 |
|---|---|---|
| Bit 7 | 缓冲区状态 | 0:缓冲区空;1:缓冲区有数据 |
| Bit 6 | 触摸状态 | 0:无触摸;1:有触摸 |
| Bit 5:4 | 保留 | 固定为 0 |
| Bit 3:0 | 触摸点数 | 当前有效的触摸点数量(0-5) |
中断处理函数示例:
/* GT911 中断处理函数 */
static irqreturn_t gt911_irq_handler(int irq, void *dev_id)
{
struct gt911_data *ts = dev_id;
struct i2c_client *client = ts->client;
u8 status;
int touch_count;
int i;
/* 读取状态寄存器 */
gt911_read_reg(client, 0x814E, &status, 1);
/* 检查是否有触摸数据 */
if (!(status & 0x80)) {
/* 缓冲区为空,清除中断 */
gt911_write_reg(client, 0x814E, 0x00);
return IRQ_HANDLED;
}
touch_count = status & 0x0F;
if (touch_count > MAX_TOUCH_POINTS)
touch_count = MAX_TOUCH_POINTS;
/* 读取每个触摸点的坐标数据 */
for (i = 0; i < touch_count; i++) {
u8 buf[6];
u16 addr = 0x8140 + i * 6;
gt911_read_reg(client, addr, buf, 6);
ts->points[i].x = (buf[0] << 8) | buf[1];
ts->points[i].y = (buf[2] << 8) | buf[3];
ts->points[i].pressure = buf[4];
ts->points[i].area = buf[5];
}
/* 上报触摸事件到输入子系统 */
input_report_key(ts->input, BTN_TOUCH, touch_count > 0);
for (i = 0; i < touch_count; i++) {
input_report_abs(ts->input, ABS_MT_POSITION_X, ts->points[i].x);
input_report_abs(ts->input, ABS_MT_POSITION_Y, ts->points[i].y);
input_mt_sync(ts->input);
}
input_sync(ts->input);
/* 清除中断标志 */
gt911_write_reg(client, 0x814E, 0x00);
return IRQ_HANDLED;
}
中断模式注意事项: 中断服务程序中应避免长时间阻塞操作。I2C 通信在中断上下文中可能因总线忙而延迟,建议使用 threaded IRQ 或将数据读取放到工作队列中处理。
4.4 轮询模式
轮询模式适用于硬件不支持中断或 GPIO 资源受限的场景。驱动通过定时器周期性读取状态寄存器,判断是否有触摸事件。
轮询模式与中断模式的核心区别:
| 对比项 | 中断模式 | 轮询模式 |
|---|---|---|
| 实时性 | 高,事件触发立即响应 | 低,取决于轮询周期 |
| CPU 占用 | 低,仅事件发生时占用 | 高,周期性占用 CPU |
| 硬件要求 | 需要 INT 引脚连接 | 无需额外引脚 |
| 驱动复杂度 | 中等,需处理中断上下文 | 简单,定时器回调即可 |
| 适用场景 | 对响应速度要求高的场景 | 资源受限或调试阶段 |
轮询模式的实现通常使用内核定时器:
/* GT911 轮询定时器回调 */
static void gt911_poll_timer(struct timer_list *t)
{
struct gt911_data *ts = from_timer(ts, t, poll_timer);
u8 status;
/* 读取状态寄存器 */
gt911_read_reg(ts->client, 0x814E, &status, 1);
if (status & 0x80) {
/* 有触摸数据,执行数据读取 */
gt911_read_touch_data(ts);
}
/* 重新启动定时器,轮询周期 20ms */
mod_timer(&ts->poll_timer, jiffies + msecs_to_jiffies(20));
}
/* 启动轮询 */
static void gt911_start_poll(struct gt911_data *ts)
{
timer_setup(&ts->poll_timer, gt911_poll_timer, 0);
mod_timer(&ts->poll_timer, jiffies + msecs_to_jiffies(20));
}
轮询周期的选择需要权衡响应速度和 CPU 占用。一般建议:
- 10ms - 20ms: 响应较快,适合交互式应用,CPU 占用中等。
- 30ms - 50ms: 响应可接受,适合非实时场景,CPU 占用较低。
- 大于 50ms: 响应延迟明显,仅用于调试或低功耗场景。
4.5 中断与轮询模式选择决策
下图展示了中断模式与轮询模式的选择决策流程:
实践建议: 在驱动开发初期,建议先实现轮询模式进行功能验证。确认触摸坐标读取正确后,再切换到中断模式以提升性能。两种模式的数据读取逻辑可以复用,只需在初始化阶段选择不同的触发方式。