一、GT9147 触摸屏
GT9147 是什么
GT9147 是一款电容触摸屏控制器。它负责检测触摸屏上的触摸点,通过 I2C 把坐标告诉主控。
主要特性
| 参数 | 值 |
|---|---|
| 通信接口 | I2C |
| 设备地址 | 0x14(GT1151)或 0x5D(GT9147) |
| 支持触摸点 | 最多 5 点 |
| 中断输出 | 有,触摸时产生中断 |
| 复位 | 有,通过 RST 引脚复位 |
和主控的连接
-
I2C2:SDA、SCL,用来读坐标和写配置
-
GPIO1_IO09:中断引脚(CT_INT),触摸时产生中断
-
GPIO5_IO09:复位引脚(CT_RST),控制复位
工作原理
-
上电后,主控通过 RST 引脚复位 GT9147
-
主控通过 I2C 读设备 ID,确认芯片型号
-
配置 GT9147 进入"读坐标"模式
-
触摸发生时,GT9147 拉低中断引脚,产生中断
-
主控在中断服务函数里通过 I2C 读触摸点数量、坐标
-
处理完后,通过 I2C 清中断标志
二、GT9147 的寄存器
| 寄存器 | 作用 |
|---|---|
| 0x8140 | 设备 ID(4 字节) |
| 0x814E | 触摸状态寄存器 |
| 0x8150 | 触摸点 0 坐标 |
| 0x8158 | 触摸点 1 坐标 |
| 0x8160 | 触摸点 2 坐标 |
| 0x8168 | 触摸点 3 坐标 |
| 0x8170 | 触摸点 4 坐标 |
| 0x8040 | 控制寄存器,进入读坐标模式 |
触摸状态寄存器(0x814E)
-
低 4 位:触摸点数量(0~5)
-
bit7:坐标就绪标志
坐标寄存器
每个触摸点的坐标占 4 字节:
-
字节 0~1:X 坐标(低字节在前)
-
字节 2~3:Y 坐标(低字节在前)
三、gt9147初始化
1. I2C 初始化
c
i2c_init(I2C2);
GT9147 接在 I2C2 上。
2. 引脚复用
c
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO09_GPIO1_IO09, 0); // CT_INT
IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09, 0); // CT_RST
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO09_GPIO1_IO09, 0x10B0);
IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09, 0x10B0);
-
GPIO1_IO09:中断引脚
-
GPIO5_IO09:复位引脚
3. 设置方向
c
GPIO1->GDIR |= (1 << 9); // 中断引脚先设为输出
GPIO5->GDIR |= (1 << 9); // 复位引脚设为输出
4. 复位 GT9147
c
GPIO1->DR &= ~(1 << 9); // 中断引脚拉低
GPIO5->DR &= ~(1 << 9); // 复位引脚拉低
delay_ms(50);
GPIO5->DR |= (1 << 9); // 复位引脚拉高,释放复位
delay_ms(100);
复位序列:拉低复位引脚,延时,拉高,延时。GT9147 复位后进入工作状态。
5. 读设备 ID
c
unsigned char buffer[128] = {0};
gt9147_read(0x8140, buffer, 4);
printf("Gesture ID = %s\n", buffer);
读 0x8140 寄存器的 4 个字节,就是芯片型号字符串。根据读到的型号,选择对应的设备地址和坐标寄存器地址。
6. 配置中断
c
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO09_GPIO1_IO09, 0x0800); // 开漏
GPIO1->GDIR &= ~(1 << 9); // 设为输入
GPIO1->ICR1 |= (3 << 18); // 触发方式:上升沿
GPIO1->IMR |= (1 << 9); // 中断屏蔽解除
-
电气特性改成开漏(0x0800)
-
中断引脚设为输入
-
ICR1 设置触发方式
-
IMR 使能中断
7. 配置 GIC
c
GIC_SetPriority(GPIO1_Combined_0_15_IRQn, 0);
system_interrupt_register(GPIO1_Combined_0_15_IRQn, touch_irq_hangdler);
GIC_EnableIRQ(GPIO1_Combined_0_15_IRQn);
和之前中断一样,设置优先级、注册处理函数、使能。
8. 进入读坐标模式
c
buffer[0] = 0;
gt9147_write(0x8040, buffer, 1);
写 0x8040 寄存器,告诉 GT9147 进入读坐标模式。
四、中断处理
c
void touch_irq_hangdler(void)
{
if ((GPIO1->ISR & (1 << 9)) != 0)
{
unsigned char buffer[64] = {0};
gt9147_read(0x814E, buffer, 1);
unsigned char num = buffer[0] & 0x0F;
if (_gt9147.num != num)
{
_gt9147.num = num;
int i = 0;
for (i = 0; i < num; i++)
{
gt9147_read(pointer_add[i], buffer, 4);
_gt9147.x[i] = (buffer[1] << 8) | (buffer[0] << 0);
_gt9147.y[i] = (buffer[3] << 8) | (buffer[2] << 0);
}
_gt9147.vail = 1;
show_pointer();
}
buffer[0] = 0;
gt9147_write(0x814E, buffer, 1);
GPIO1->ISR |= (1 << 9);
}
}
1. 检查中断状态
c
if ((GPIO1->ISR & (1 << 9)) != 0)
检查 GPIO1_IO09 的中断状态,确认是触摸中断。
2. 读触摸点数量
c
gt9147_read(0x814E, buffer, 1);
unsigned char num = buffer[0] & 0x0F;
读 0x814E 寄存器,低 4 位是触摸点数量。
3. 读坐标
c
for (i = 0; i < num; i++)
{
gt9147_read(pointer_add[i], buffer, 4);
_gt9147.x[i] = (buffer[1] << 8) | (buffer[0] << 0);
_gt9147.y[i] = (buffer[3] << 8) | (buffer[2] << 0);
}
每个触摸点读 4 字节:X 低字节、X 高字节、Y 低字节、Y 高字节。合成 16 位坐标。
4. 显示坐标
c
show_pointer();
打印触摸点数量和坐标。
5. 清中断标志
c
buffer[0] = 0;
gt9147_write(0x814E, buffer, 1);
GPIO1->ISR |= (1 << 9);
-
写 0x814E 寄存器,告诉 GT9147 处理完毕
-
写 1 清 GPIO1 的中断标志位
清标志是必须的,不清的话中断会一直触发。
五、SPI 通信
SPI 是什么
SPI(Serial Peripheral Interface,串行外设接口)是一种同步串行通信协议,比 I2C 快。
四根线
| 线 | 名称 | 作用 |
|---|---|---|
| SCLK | 时钟 | 主机产生 |
| MOSI | Master Out Slave In | 主机发,从机收 |
| MISO | Master In Slave Out | 从机发,主机收 |
| SS | Slave Select | 片选,选择从机 |
和 I2C 的区别
| 部分 | I2C | SPI |
|---|---|---|
| 线数 | 2(SCL、SDA) | 4(SCLK、MOSI、MISO、SS) |
| 速度 | 较慢 | 较快 |
| 拓扑 | 一主多从,有地址 | 一主多从,有片选 |
| 应答 | 有 ACK/NACK | 无 |
| 全双工 | 半双工 | 全双工 |
SPI 的优点
-
速度快:可以到几十 MHz
-
全双工:收发可以同时进行
-
协议简单:没有地址、应答,只有片选
SPI 的缺点
-
线多:每个从机需要一根片选线
-
没有应答:不知道对方收没收到
六、SPI 初始化
1. 引脚复用
c
IOMUXC_SetPinMux(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0);
IOMUXC_SetPinMux(IOMUXC_UART2_RTS_B_ECSPI3_MISO, 0);
IOMUXC_SetPinMux(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK, 0);
IOMUXC_SetPinMux(IOMUXC_UART2_TX_DATA_ECSPI3_SS0, 0);
把 UART2 的四个引脚复用成 ECSPI3 的 MOSI、MISO、SCLK、SS0。
2. 电气特性
c
IOMUXC_SetPinConfig(IOMUXC_UART2_CTS_B_ECSPI3_MOSI, 0x10B1);
// ...
0x10B1 配置电气特性,比之前用的 0x10B0 多一点,可能开了上拉或其他特性。
3. 片选引脚
c
GPIO1->GDIR |= (1 << 20);
GPIO1->DR |= (1 << 20);
GPIO1_IO20 用作片选,设为输出,默认拉高(不选中)。
4. 配置 CONREG
c
ECSPI3->CONREG = 0;
ECSPI3->CONREG |= (7 << 20) | (14 << 12) | (2 << 8) | (1 << 4) | (1 << 3);
-
bits 20-23:
PRE_DIV,预分频 -
bits 12-15:
POST_DIV,后分频 -
bits 8-11:
CHANNEL_MODE,通道模式 -
bit 4:
SMC,开始模式控制 -
bit 3:
SCLK_POL,时钟极性
5. 配置 CONFIGREG
c
ECSPI3->CONFIGREG = 0;
ECSPI3->CONFIGREG |= (1 << 20) | (1 << 4) | (1 << 0);
-
bit 20:
SCLK_CTL,时钟控制 -
bit 4:
DATA_CTL,数据控制 -
bit 0:
SS_CTL,片选控制
6. 使能 SPI
c
ECSPI3->CONREG |= (1 << 0);
CONREG 的 bit0 是 EN,SPI 使能位。
七、收发数据
c
unsigned int ecspi3_write_and_read(unsigned int data)
{
unsigned int ret = 0;
while((ECSPI3->STATREG & (1 << 0)) == 0); // 等 TX FIFO 就绪
ECSPI3->TXDATA = data; // 写数据
while((ECSPI3->STATREG & (1 << 3)) == 0); // 等 RX FIFO 有数据
ret = ECSPI3->RXDATA; // 读数据
return ret;
}
SPI 是全双工的:发一个字节的同时,也收一个字节。
流程:
-
等
STATREG的 bit0(TE,TX FIFO Empty),表示可以写数据 -
写
TXDATA -
等
STATREG的 bit3(RR,RX FIFO Ready),表示收到数据 -
读
RXDATA
注意:SPI 没有"只发"或"只收",每次收发都是同时进行的。要读数据,必须发一个"哑字节"(dummy byte,通常是 0xFF)来产生时钟。
八、今日总结
今天学了 GT9147 触摸屏和 SPI 通信,核心要点:
GT9147
-
电容触摸屏控制器,通过 I2C 通信
-
引脚:I2C2(SDA、SCL)、GPIO1_IO09(中断)、GPIO5_IO09(复位)
-
初始化:复位 → 读设备 ID → 配中断 → 进入读坐标模式
-
中断处理:读触摸点数量 → 读坐标 → 清中断标志
-
坐标格式:每点 4 字节,X 低、X 高、Y 低、Y 高
SPI
-
同步串行通信,四根线(SCLK、MOSI、MISO、SS)
-
全双工:收发同时进行
-
寄存器:CONREG(控制)、CONFIGREG(配置)、STATREG(状态)、TXDATA/RXDATA(数据)
-
收发流程:等 TX 就绪 → 写数据 → 等 RX 就绪 → 读数据
-
特点:速度快,无应答,用片选选择从机