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 的寄存器空间布局:

GT911 寄存器空间布局 产品信息 0x8040 - 0x8046 芯片ID / 版本号 配置表 0x8047 - 0x80FF 分辨率 / 灵敏度 坐标数据 0x8140 - 0x814E 触摸点坐标 状态寄存器 0x814F 触摸 / 缓冲区状态 扩展数据 0x8150 - 0x81FF 手势 / 自定义

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 占用低的优点。

中断模式的工作流程如下:

  1. 初始化: 配置 INT 引脚为下降沿触发中断,设置 I2C 通信参数。
  2. 触摸事件: 用户触摸屏幕时,GT911 检测到触摸,将 INT 引脚拉低。
  3. 中断处理: CPU 响应中断,在中断服务程序中读取状态寄存器 0x814E。
  4. 数据读取: 根据状态寄存器指示的触摸点数,读取 0x8140 开始的坐标数据。
  5. 清除标志: 读取完毕后,向 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 中断与轮询模式选择决策

下图展示了中断模式与轮询模式的选择决策流程:

中断与轮询模式选择决策 开始选择 INT 引脚是否可用? 中断模式 实时性好,CPU占用低 轮询模式 无需额外引脚,实现简单 配置 threaded IRQ 配置定时器周期 是 否
实践建议: 在驱动开发初期,建议先实现轮询模式进行功能验证。确认触摸坐标读取正确后,再切换到中断模式以提升性能。两种模式的数据读取逻辑可以复用,只需在初始化阶段选择不同的触发方式。

4.6 本章小结