1. 引言
在嵌入式开发中,触摸屏作为人机交互的重要接口,广泛应用于工控、医疗、消费电子等领域。本文基于 SPI 接口的多点触摸屏,从硬件原理、驱动框架到实际调试,系统梳理学习过程中的关键知识点与踩坑记录,帮助初学者快速建立整体认知。
2. 硬件基础
2.1 SPI 接口简介
SPI(Serial Peripheral Interface)是一种高速全双工同步串行总线,通常由四根线组成:
- SCLK:时钟信号,由主机产生
- MOSI:主机输出,从机输入
- MISO:主机输入,从机输出
- CS/SS:片选信号,低电平有效
SPI 支持多种工作模式(CPOL/CPHA 组合),触摸屏控制器通常工作在模式 0 或模式 3,具体需查阅芯片数据手册。
2.2 多点触摸屏工作原理
多点触摸屏(如电容式触摸屏)通过检测电容变化来定位触摸点。触摸控制器(如 GT911、FT5x06 等)负责扫描触摸面板,将触摸坐标通过 SPI 或 I2C 接口上报给主控。
典型架构如下:
#mermaid-svg-iu1s4mYnvPRHfjU4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-iu1s4mYnvPRHfjU4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-iu1s4mYnvPRHfjU4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-iu1s4mYnvPRHfjU4 .error-icon{fill:#552222;}#mermaid-svg-iu1s4mYnvPRHfjU4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-iu1s4mYnvPRHfjU4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-iu1s4mYnvPRHfjU4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-iu1s4mYnvPRHfjU4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-iu1s4mYnvPRHfjU4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-iu1s4mYnvPRHfjU4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-iu1s4mYnvPRHfjU4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-iu1s4mYnvPRHfjU4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-iu1s4mYnvPRHfjU4 .marker.cross{stroke:#333333;}#mermaid-svg-iu1s4mYnvPRHfjU4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-iu1s4mYnvPRHfjU4 p{margin:0;}#mermaid-svg-iu1s4mYnvPRHfjU4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-iu1s4mYnvPRHfjU4 .cluster-label text{fill:#333;}#mermaid-svg-iu1s4mYnvPRHfjU4 .cluster-label span{color:#333;}#mermaid-svg-iu1s4mYnvPRHfjU4 .cluster-label span p{background-color:transparent;}#mermaid-svg-iu1s4mYnvPRHfjU4 .label text,#mermaid-svg-iu1s4mYnvPRHfjU4 span{fill:#333;color:#333;}#mermaid-svg-iu1s4mYnvPRHfjU4 .node rect,#mermaid-svg-iu1s4mYnvPRHfjU4 .node circle,#mermaid-svg-iu1s4mYnvPRHfjU4 .node ellipse,#mermaid-svg-iu1s4mYnvPRHfjU4 .node polygon,#mermaid-svg-iu1s4mYnvPRHfjU4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-iu1s4mYnvPRHfjU4 .rough-node .label text,#mermaid-svg-iu1s4mYnvPRHfjU4 .node .label text,#mermaid-svg-iu1s4mYnvPRHfjU4 .image-shape .label,#mermaid-svg-iu1s4mYnvPRHfjU4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-iu1s4mYnvPRHfjU4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-iu1s4mYnvPRHfjU4 .rough-node .label,#mermaid-svg-iu1s4mYnvPRHfjU4 .node .label,#mermaid-svg-iu1s4mYnvPRHfjU4 .image-shape .label,#mermaid-svg-iu1s4mYnvPRHfjU4 .icon-shape .label{text-align:center;}#mermaid-svg-iu1s4mYnvPRHfjU4 .node.clickable{cursor:pointer;}#mermaid-svg-iu1s4mYnvPRHfjU4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-iu1s4mYnvPRHfjU4 .arrowheadPath{fill:#333333;}#mermaid-svg-iu1s4mYnvPRHfjU4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-iu1s4mYnvPRHfjU4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-iu1s4mYnvPRHfjU4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iu1s4mYnvPRHfjU4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-iu1s4mYnvPRHfjU4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iu1s4mYnvPRHfjU4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-iu1s4mYnvPRHfjU4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-iu1s4mYnvPRHfjU4 .cluster text{fill:#333;}#mermaid-svg-iu1s4mYnvPRHfjU4 .cluster span{color:#333;}#mermaid-svg-iu1s4mYnvPRHfjU4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-iu1s4mYnvPRHfjU4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-iu1s4mYnvPRHfjU4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-iu1s4mYnvPRHfjU4 .icon-shape,#mermaid-svg-iu1s4mYnvPRHfjU4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-iu1s4mYnvPRHfjU4 .icon-shape p,#mermaid-svg-iu1s4mYnvPRHfjU4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-iu1s4mYnvPRHfjU4 .icon-shape .label rect,#mermaid-svg-iu1s4mYnvPRHfjU4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-iu1s4mYnvPRHfjU4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-iu1s4mYnvPRHfjU4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-iu1s4mYnvPRHfjU4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 触摸面板
触摸控制器
SPI 总线
主控 MCU
应用层处理
3. 驱动开发流程
3.1 设备树配置
在 Linux 内核中,SPI 触摸屏通常通过设备树描述硬件连接:
dts
&spi1 {
status = "okay";
touch: touch@0 {
compatible = "vendor,touch-controller";
reg = <0>;
spi-max-frequency = <1000000>;
interrupt-parent = <&gpio>;
interrupts = <17 IRQ_TYPE_EDGE_FALLING>;
};
};
3.2 驱动框架
SPI 触摸屏驱动主要包含以下部分:
- probe 函数:初始化 SPI 设备、注册输入设备
- 中断处理:触摸事件到来时读取坐标数据
- 输入子系统上报 :通过
input_report_abs上报触摸坐标
c
static int touch_probe(struct spi_device *spi)
{
struct input_dev *input;
/* 分配并注册输入设备 */
input = devm_input_allocate_device(&spi->dev);
input_set_abs_params(input, ABS_MT_POSITION_X, 0, 1024, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 600, 0, 0);
/* 注册中断 */
return request_irq(gpio_to_irq(17), touch_irq_handler,
IRQF_TRIGGER_FALLING, "touch", spi);
}
3.3 多点触摸上报协议
Linux 内核使用 Type B 协议上报多点触摸:
c
input_mt_slot(input, slot_id);
input_mt_report_slot_state(input, ABS_MT_TRACKING_ID, true);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
input_mt_sync(input);
4. 调试与踩坑记录
4.1 SPI 时钟频率过高导致数据错乱
触摸控制器对 SPI 时钟有上限要求,超过后会出现坐标跳变。解决方法是降低 spi-max-frequency,并确认主控 SPI 模式与控制器匹配。
4.2 中断触发方式不匹配
部分控制器中断为低电平触发,若配置为边沿触发,可能丢失触摸事件。需结合数据手册确认 IRQ_TYPE_LEVEL_LOW 或 IRQ_TYPE_EDGE_FALLING。
4.3 坐标校准
多点触摸屏首次使用需进行校准,可通过 tslib 或内核 input_calibrate 完成,将原始坐标映射到屏幕分辨率。
5. 学习心得
通过本次 SPI 多点触摸屏的学习,我深刻体会到嵌入式开发中「硬件手册 + 内核框架 + 实际调试」三者结合的重要性。遇到问题时,先确认硬件连接与 SPI 时序,再检查驱动上报逻辑,往往能快速定位问题。
6. 总结
SPI 多点触摸屏的开发涉及硬件接口、内核驱动、输入子系统等多个层面。掌握 SPI 协议与触摸控制器工作原理,熟悉设备树配置与输入上报机制,是完成此类外设驱动的关键。希望本文的总结能为同样在学习嵌入式的朋友提供参考。