2、TSP硬件接口:I2C接口详解、SPI接口详解、GPIO与中断引脚
好,咱们接着聊。上一章我们把TSP的基本概念和整体架构捋了一遍,这一章要深入到底层硬件接口了。说白了,触摸屏芯片和主处理器之间怎么“说话”,全靠这些接口。我刚开始做驱动的时候,觉得接口协议就是照着数据手册配寄存器,后来踩了不少坑才明白——接口选型和设计,直接决定了触摸屏的响应速度和稳定性。
咱们今天重点讲三个东西:I2C、SPI,还有GPIO和中断。前两个是数据传输通道,后一个是“敲门砖”。
2.1 I2C接口详解
I2C,全称Inter-Integrated Circuit,中文叫“集成电路间总线”。这玩意儿在手机里太常见了,几乎所有中低端触摸屏都用它。为什么?因为它只需要两根线:SCL(时钟线)和SDA(数据线)。
我个人的习惯是,只要触摸屏的报点率要求不超过200Hz,优先考虑I2C。原因很简单——引脚少,布线容易,而且大多数主控都自带I2C控制器,省事。
2.1.1 I2C的物理层
两根线,都是开漏输出,需要上拉电阻。标准模式下速率100kHz,快速模式400kHz,高速模式能到3.4MHz。触摸屏一般用400kHz就够了。
嗯,这里要注意:上拉电阻的取值很关键。电阻太小,功耗大;电阻太大,信号上升沿变缓,容易出错。我一般取4.7kΩ,对于400kHz的速率,这个值比较稳妥。
2.1.2 I2C的通信流程
I2C通信分三步:起始信号、数据传输、停止信号。每次传输,主设备先发一个7位或10位的从机地址,然后跟一个读写位。从机收到地址后,拉低SDA表示应答(ACK)。
触摸屏芯片作为从机,地址一般是固定的。比如汇顶的GT911,I2C地址是0x5D或0x14,取决于INT引脚的电平。你想想看,如果硬件设计时没注意这个细节,焊上去的芯片地址和驱动里写的不一致,那可就抓瞎了。
// I2C读取触摸屏数据的典型流程
// 1. 发送起始信号
// 2. 发送从机地址 + 写位 (0xBA)
// 3. 等待ACK
// 4. 发送寄存器地址 (比如0x814E)
// 5. 等待ACK
// 6. 发送重复起始信号
// 7. 发送从机地址 + 读位 (0xBB)
// 8. 等待ACK
// 9. 读取N个字节数据
// 10. 发送停止信号
static int tsp_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len)
{
struct i2c_msg msg[2];
u8 reg_buf[2];
reg_buf[0] = (reg >> 8) & 0xFF;
reg_buf[1] = reg & 0xFF;
msg[0].addr = client->addr;
msg[0].flags = 0; // 写
msg[0].len = 2;
msg[0].buf = reg_buf;
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD; // 读
msg[1].len = len;
msg[1].buf = buf;
return i2c_transfer(client->adapter, msg, 2);
}
2.1.3 I2C的优缺点
| 优点 | 缺点 |
|---|---|
| 引脚少(2根线) | 速率相对较低 |
| 支持多从机 | 传输距离短 |
| 硬件实现简单 | 无硬件流控 |
| 大多数MCU原生支持 | 每传输一字节都要应答,开销大 |
2.2 SPI接口详解
SPI,Serial Peripheral Interface,串行外设接口。这玩意儿比I2C快得多。如果你做的是游戏手机,或者需要240Hz以上报点率的高端屏,SPI几乎是唯一选择。
SPI用四根线:SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。全双工通信,速率轻松上几十MHz。我见过有些触摸屏用50MHz的SPI时钟,报点率能做到1000Hz以上。
2.2.1 SPI的四种模式
SPI有四种工作模式,由时钟极性(CPOL)和时钟相位(CPHA)决定。触摸屏芯片通常支持模式0或模式3。
| 模式 | CPOL | CPHA | 说明 |
|---|---|---|---|
| 模式0 | 0 | 0 | 空闲时时钟为低,第一个边沿采样 |
| 模式1 | 0 | 1 | 空闲时时钟为低,第二个边沿采样 |
| 模式2 | 1 | 0 | 空闲时时钟为高,第一个边沿采样 |
| 模式3 | 1 | 1 | 空闲时时钟为高,第二个边沿采样 |
我建议你在初始化SPI时,一定要确认触摸屏数据手册里写的是哪种模式。搞错了的话,读出来的数据全是0xFF或者0x00,根本没法用。
2.2.2 SPI的DMA传输
SPI配合DMA(直接内存访问)使用,性能才能完全释放。触摸屏每次上报的数据量不大,但频率高。如果用CPU逐字节读取,中断频繁,CPU占用率会很高。
// SPI + DMA 读取触摸数据的伪代码
void tsp_spi_dma_read(struct spi_device *spi, u8 *rx_buf, int len)
{
struct spi_transfer t = {
.tx_buf = NULL, // 只读,不需要发送
.rx_buf = rx_buf,
.len = len,
.speed_hz = 20 * 1000 * 1000, // 20MHz
.bits_per_word = 8,
.cs_change = 0,
};
// 使用DMA传输
spi->controller->dma_rx = true;
spi_sync_transfer(spi, &t, 1);
}
2.2.3 I2C vs SPI,怎么选?
说白了,看需求。普通手机、平板,I2C完全够用。游戏手机、工业平板、高刷新率设备,上SPI。还有一个因素:主控资源。有些低端主控只有I2C没有SPI,那就没得选了。
2.3 GPIO与中断引脚
GPIO,通用输入输出。在触摸屏里,GPIO主要干两件事:复位和中断。其中中断引脚最重要,它是触摸屏通知主控“我有数据了”的信号。
2.3.1 中断引脚的工作机制
触摸屏芯片检测到触摸事件后,会拉高或拉低INT引脚。主控收到这个边沿信号后,进入中断服务程序,通过I2C或SPI读取触摸数据。
这里有个细节:中断触发方式。一般用下降沿触发或低电平触发。我个人的习惯是用下降沿触发,因为电平触发容易在中断服务程序里产生多次中断,处理不好会死循环。
2.3.2 中断引脚在驱动中的注册
// 在Linux驱动中注册触摸屏中断
static irqreturn_t tsp_irq_handler(int irq, void *dev_id)
{
struct tsp_data *ts = dev_id;
u8 buf[64];
int ret;
// 读取触摸数据
ret = tsp_i2c_read(ts->client, ts->reg_status, buf, sizeof(buf));
if (ret < 0) {
dev_err(&ts->client->dev, "I2C read failed\n");
return IRQ_NONE;
}
// 解析触摸点并上报
tsp_process_data(ts, buf);
return IRQ_HANDLED;
}
static int tsp_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct tsp_data *ts;
int ret;
// ... 分配数据结构、初始化硬件 ...
// 注册中断,下降沿触发
ret = request_threaded_irq(client->irq, NULL, tsp_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"tsp_irq", ts);
if (ret) {
dev_err(&client->dev, "Failed to request irq\n");
return ret;
}
return 0;
}
2.3.3 GPIO的复位功能
触摸屏芯片上电后,需要主控通过一个GPIO给它一个复位脉冲。这个时序很关键:拉低复位引脚,保持至少10ms,再拉高,然后等待芯片初始化完成(通常需要50-200ms)。
你想想看,如果复位时序不对,芯片可能处于异常状态,I2C通信都建立不起来。我见过有人把复位时间写成了1ms,结果芯片没完全复位,读出来的校准数据全是乱的。
2.4 知识体系总览
下面这张图,把TSP硬件接口的核心逻辑串起来了。你看一遍,应该能对整个数据流向有个直观认识。
从图上你能看到,主控通过I2C或SPI与触摸屏芯片交换数据,同时通过GPIO控制复位和接收中断。这三者配合好了,触摸屏才能正常工作。
好了,这一章的内容就到这儿。接口协议这东西,光看文档不行,得动手调。下次你拿到一块触摸屏模组,先看数据手册确认接口类型,然后用示波器量一下波形,再写驱动。一步一步来,不会出大问题。
公众号:蓝海资料掘金营,微信deep3321