屏亮了还要点得准。今天配电容触摸。坐标必须按你这块屏的分辨率来,配成另一套尺寸会比完全没触摸更耗时间。

第四篇前面几章把屏点亮了。logo 能出、桌面能出,手往上一划——图标跑到别处去,或者上半屏完全点不中。这种「有触摸、但触摸是骗子」的状态,比完全没触摸更耗时间,因为你以为是显示方向的问题,会先去改横竖屏。

这章把骗子拆开。芯片是 GT911,地址 0x5d,挂在 I2C2。它不是电阻屏,也不是另一颗常见的 FT5406。开源鸿蒙标准系统上,这条通路走 HDF Input,不走内核主线 goodix 驱动。设备树里那颗 goodix,gt911 节点要保持 disabled,否则两边抢同一条总线,HDF 读寄存器全是 NACK。

我坐在板子前面时,最先做的不是改驱动,是先问三个问题:总线上到底是谁在应答?INT 脚有没有被别人拉着?报上来的 raw 坐标,是按 1024×600 报的,还是按某份公版竖屏 720×1280 报的?三个问题都有铁证,坐标那一问还出过 DisplayY = -377。负数被上层夹到 0,你就看见「上半屏失灵」。 

官方这张图请盯两分钟。上面是多模输入(MMI),中间是 Input 管理器和设备抽象,下面才是芯片驱动和 I2C/GPIO 适配。GT911 的 .c 只负责「认出芯片、把点读出来」。分辨率、复位脚、中断脚、I2C 几号总线,全在 HCS 里。你改错层,编译再勤也摸不到那颗芯片。


1. 先认芯片,再谈驱动

电容屏控制器藏在屏的柔性电路上,丝印经常被排线挡住。文档写 FT5406、板上焊 GT911,这种事发生过,而且会让你在错误的 I2C 地址上排一周。

认芯片只认总线应答,不认说明书封面。

hdc shell "i2cdetect -y -r 2"

在 I2C2 上,你希望看到类似:

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- 5d -- --
60: UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

说明:

地址常见身份备注
`0x5d`**GT911**本章主角
`0x38`FT5406 / 某些温湿度下一章;和 GT911 **不要同时 okay**
`0x36`MIPI 相机相机篇
`0x60`Type-C 口芯片板载常驻,扫到很正常
`UU`已被内核驱动占不是故障

0x5d 没有、0x38 也没有:先查排线、供电、I2C2 有没有 okay,别先改驱动。

GT911 的产品 ID 在寄存器 0x8140,四个字节,正常是 ASCII '9','1','1',0。16 位寄存器地址,i2cget 一次搞不定,用 i2ctransfer 或下面那份 C。

hdc shell "i2ctransfer -y 2 w2@0x5d 0x81 0x40 r4"

期望类似:

0x39 0x31 0x31 0x00

0x39 0x31 0x31 就是 '9''1''1'。这是芯片身份的铁证。读失败但 i2cdetect 能扫到:多半是复位脚没释放,芯片停在下载模式,只 ACK 地址不认寄存器。

电阻屏是另一条世界:ADC 采样、XPT2046 一类,走 SPI。GT911 是电容、I2C、多点。别把电阻屏的校准程序套过来。


2. 为什么走 HDF,不走主线 goodix

内核里本来就有 drivers/input/touchscreen/goodix.ccompatible = "goodix,gt911",Linux 发行版上用得很熟。开源鸿蒙标准系统的桌面、MMI、窗口,认的是 HDF Input 报上来的点。两条栈同时 bind 同一颗芯片,结果是:

  1. 主线 goodix 先 i2c_request,HDF 再访问 → NACK / busy
  2. 或者反过来,主线 probe 失败,你在 dmesg 里骂 goodix,其实 HDF 已经在干活
  3. 两套坐标映射叠在一起,点「又像对又像不对」

所以板级设备树里,内核节点只作备查,status 保持 disabled

&i2c2 {
    status = "okay";
    clock-frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&i2c2m1_xfer &gt911_int_pin &gt911_rst_pin>;

    /* 内核主线 goodix:禁用,把总线让给 HDF */
    gt911_lvds: gt911@5d {
        compatible = "goodix,gt911";
        pinctrl-names = "default";
        pinctrl-0 = <&gt911_int_pin &gt911_rst_pin>;
        reg = <0x5d>;
        interrupt-parent = <&gpio0>;
        interrupts = <RK_PC7 IRQ_TYPE_LEVEL_LOW>;
        reset-gpios = <&gpio2 RK_PD0 GPIO_ACTIVE_HIGH>;
        status = "disabled";
    };
};

status = "disabled" 不是「这块板没有 GT911」。是「内核别 bind,HDF 来 bind」。这和 AHT20 那颗温湿度同一套路:DTS 声明地址方便对照,真正干活的人在 HCS。

内核配置里:

CONFIG_DRIVERS_HDF_TP_5P5_GT911=y

板级 build_kernel.sh 注入段要兜住它。公版碎片有时会把它关掉、把 FT5406 打开。你只改 HCS 不改这段,编出来的内核可能根本没链 GT911 芯片驱动。

对应的 pinctrl,INT 和 RST 必须是 GPIO 功能,不能停在别的复用:

mipi_panel_tp {
    gt911_int_pin: gt911-int-pin {
        rockchip,pins = <0 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>;
    };
    gt911_rst_pin: gt911-rst-pin {
        rockchip,pins = <2 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
    };
};

脚位(本板 LVDS / 常见 10 寸电容):

信号引脚内核编号算法
SDA/SCLI2C2总线号 2HCS `busNum = 2`
INTGPIO0_C7**23**`0*32 + 2*8 + 7`
RSTGPIO2_D0**88**`2*32 + 3*8 + 0`

编号算错,HCS 里写了 36、82,那是另一块屏的脚。驱动会「复位成功」(GPIO 控制器返回 0),芯片却没被碰到。


3. HCS 才是 HDF 的设备树

路径:

vendor/rk/rk3568_evb/hdf_config/khdf/input/input_config.hcs
vendor/rk/rk3568_evb/hdf_config/khdf/device_info/device_info.hcs

input_config.hcs 里和坐标、总线、脚相关的核心段如下。这是 GT911 + 1024×600 横屏 该有的样子:

root {
    input_config {
        touchConfig {
            touch0 {
                boardConfig {
                    match_attr = "touch_device1";
                    inputAttr {
                        inputType = 0;       /* 0 = touch */
                        solutionX = 1024;    /* 必须等于屏宽 */
                        solutionY = 600;     /* 必须等于屏高 */
                        devName = "main_touch";
                    }
                    busConfig {
                        busType = 0;         /* 0 = i2c */
                        busNum = 2;
                    }
                    pinConfig {
                        rstGpio = 88;        /* GPIO2_D0 */
                        intGpio = 23;        /* GPIO0_C7 */
                        rstRegCfg = [0x0, 0x0];
                        intRegCfg = [0x0, 0x0];
                    }
                    powerConfig {
                        vccType = 0;         /* 硬件常供电,不用 HDF 推 LDO */
                        vccNum = 0;
                        vccValue = 1800;
                        vciType = 0;
                        vciNum = 0;
                        vciValue = 3300;
                    }
                }
                chipConfig {
                    template touchChip {
                        match_attr = "";
                        chipName = "gt911";
                        vendorName = "zsj";
                        busType = 0;
                        deviceAddr = 0x5D;
                        irqFlag = 2;         /* 下降沿 */
                        maxSpeed = 400;
                        chipVersion = 0;
                        powerSequence {
                            /* [type, status, dir, delay_ms]
                             * type: 3=reset 4=int
                             * status: 0=low 1=high 2=nop
                             * dir: 0=in 1=out 2=nop
                             */
                            powerOnSeq = [4, 0, 1, 5,
                                         3, 0, 1, 10,
                                         3, 1, 1, 60,
                                         4, 2, 0, 50];
                            suspendSeq = [3, 0, 2, 10];
                            resumeSeq  = [3, 1, 2, 10];
                            powerOffSeq = [3, 0, 2, 10,
                                           1, 0, 2, 20];
                        }
                    }
                    chip0 :: touchChip {
                        match_attr = "gt911_1024x600";
                        chipInfo = "ZIDN45100";
                        chipVersion = 0;
                    }
                }
            }
        }
    }
}

device_info.hcs 要把芯片驱动真正挂上:

device_hdf_touch :: device {
    device0 :: deviceNode {
        policy = 2;
        priority = 120;
        preload = 0;
        permission = 0660;
        moduleName = "HDF_TOUCH";
        serviceName = "hdf_input_event1";
        deviceMatchAttr = "touch_device1";
    }
}
device_touch_chip :: device {
    device0 :: deviceNode {
        policy = 0;
        priority = 130;
        preload = 0;
        permission = 0660;
        moduleName = "HDF_TOUCH_GT911";
        serviceName = "hdf_touch_gt911_service";
        deviceMatchAttr = "gt911_1024x600";
    }
}

三处必须对上:

  1. boardConfig.match_attr = device_hdf_touch 的 deviceMatchAttr
  2. chip0.match_attr = device_touch_chip 的 deviceMatchAttr
  3. moduleName 必须是 HDF_TOUCH_GT911,不要留成 FT5406 那份

切过 RGB 屏的人,这里经常还停在 HDF_TOUCH_FT5406。HCS 和屏是一对,不是「一份配置打天下」。

powerOnSeq 的编码别看注释想当然。[3, 1, 0, 20] 的意思是 RST、HIGH、输入、等 20 ms——方向是输入时,写 HIGH 只进锁存器,脚根本没被驱动。GT911 上电序列要先把 INT 拉成输出、RST 拉低再拉高,最后 INT 改回输入给芯片用。


4. INT 脚被 regulator 占:probe 成功、永远没中断

公版 rk3568-evb1 一类 dtsi 里,常有:

vcc3v3_lcd0_n: vcc3v3-lcd0-n {
    compatible = "regulator-fixed";
    gpio = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>;
    enable-active-high;
    regulator-boot-on;
};

GPIO0_C7 在公版 Evb 上也许真是 LCD 电源使能。在这块底板上,它是 GT911 的 INT。开机 regulator 把它拉高,大约几十秒后框架做 late cleanup,没消费者的 boot-on 电源会被关掉,脚再被拉低锁死。中断永远进不来。

你看到的现象是:ChipDetect 成功、产品 ID 是 911、main_touch 注册了,手指滑过去 dmesg 没有 IRQ。因为电平被电源框架按「使能脚」管理,不按「中断脚」管理。

修法:在板级 dts 删掉这两个属性,不要去改芯片驱动。

&vcc3v3_lcd0_n {
    /delete-property/ enable-active-high;
    /delete-property/ gpio;
};

同组的 vcc3v3_lcd1_n 若占了别的脚,一并删。这不是「关掉液晶供电」,电源该 always-on 的继续 always-on,只是别再用 GPIO0_C7 当使能。

验证:

hdc shell "mount -t debugfs none /sys/kernel/debug"
hdc shell "cat /sys/kernel/debug/gpio | grep -E 'gpio-23|gpio-88'"

期望 INT(23)被 HDF 申请成输入,RST(88)被申请成输出。若 23 的 label 还是某 regulator,HCS 里的 intGpio = 23 只是个数字,物理脚不听它的。


5. 坐标:720×1280 写进芯片,1024×600 拿来减

屏是横的 1024×600,桌面也修成横的了,点图标仍然不准:左半屏到不了 0,上半屏 DisplayY 是负数。方向其实对(左小于右、上小于下),坏在缩放。

HDF 通用 GT911 驱动在 CONFIG_ARCH_ROCKCHIP 分支有一份 firmWareParm[],开机写进芯片。寄存器从 0x8050 起,紧跟着的分辨率是:

/* drivers/hdf_core/framework/model/input/driver/touchscreen/touch_gt911.h */
uint8_t firmWareParm[FIRMWARE_LEN] = {
    0x80, 0x50,          /* 寄存器 0x8050 */
    0x64,                /* 配置版本 */
    0xD0, 0x02,          /* X = 0x02D0 = 720 */
    0x00, 0x05,          /* Y = 0x0500 = 1280 */
    /* ... 后面一长串阈值、通道表 */
};

这是某份 720×1280 竖屏公版 的配置被照搬过来。芯片老老实实按 720×1280 报 raw。驱动 ChipVersionDefault 的 ROCKCHIP 分支若再写:

x = resX - rawX;   /* resX 来自 HCS,是 1024 */
y = resY - rawY;   /* resY 是 600,rawY 却能到 ~1280 */

600 - 1280 = -680,再带点边沿偏移,串口里就出现过 DisplayY: -377。上层把负数夹到 0,上半屏全部变成「点了等于点在 y=0」。左半屏 rawX 到不了 0(芯片按 720 报,还带原点偏移),减完也到不了屏幕左边。

所以:

  • HCS 的 solutionX/Y 必须等于屏,这是映射的目标矩形
  • 芯片实际报点范围 是另一回事,由 firmware 和模组决定
  • 两者不一致时,用减法当映射,一定会穿出屏幕

实测慢划满屏(贴边缘)得到的 raw 边界,本板这一块是:

raw
14
597
15
1015

raw 随右、下增大,和屏同向,不能再做 res - raw 反转。线性标定:

#define GT_RAW_X_MIN    14
#define GT_RAW_X_MAX    597
#define GT_RAW_Y_MIN    15
#define GT_RAW_Y_MAX    1015

static void ChipVersionDefault(ChipDevice *device, FrameData *frame,
                               const uint8_t *buf, uint8_t pointNum)
{
    for (uint8_t i = 0; i < pointNum; i++) {
        int32_t resX = device->driver->boardCfg->attr.resolutionX;
        int32_t resY = device->driver->boardCfg->attr.resolutionY;
        int32_t rawX = (buf[GT_POINT_SIZE * i + GT_X_LOW] & 0xFF) |
                       ((buf[GT_POINT_SIZE * i + GT_X_HIGH] & 0xFF) << 8);
        int32_t rawY = (buf[GT_POINT_SIZE * i + GT_Y_LOW] & 0xFF) |
                       ((buf[GT_POINT_SIZE * i + GT_Y_HIGH] & 0xFF) << 8);

        frame->fingers[i].x = (rawX - GT_RAW_X_MIN) * resX
                            / (GT_RAW_X_MAX - GT_RAW_X_MIN);
        frame->fingers[i].y = (rawY - GT_RAW_Y_MIN) * resY
                            / (GT_RAW_Y_MAX - GT_RAW_Y_MIN);

        if (frame->fingers[i].x < 0) {
            frame->fingers[i].x = 0;
        } else if (frame->fingers[i].x > resX - 1) {
            frame->fingers[i].x = resX - 1;
        }
        if (frame->fingers[i].y < 0) {
            frame->fingers[i].y = 0;
        } else if (frame->fingers[i].y > resY - 1) {
            frame->fingers[i].y = resY - 1;
        }
        frame->fingers[i].valid = true;
    }
}

文件:

drivers/hdf_core/framework/model/input/driver/touchscreen/touch_gt911.c

换一块模组,边界会变。标定方法:在驱动里临时打 raw 日志,手指贴四边慢划,记下最小最大,填进四个宏。轴若整体反了,对那一轴改 res - mapped,不要两轴一起翻着试。

有人问:为什么不改 firmWareParm 把 720/1280 改成 1024/600?GT911 的配置表带 checksum,写错会让芯片拒收整表,退回出厂参数,更难查。本板没有厂商提供的正确 config,所以 不改 firmware、只改主机侧映射。这是保守、可逆、上板验证过的路。


6. 改 khdf 之后,编译为什么像没改

HDF 触摸编进内核 Image(khdf),不是一个用户态 so。你改了 .c 或 .hcs,GN 的内核 action 经常 不把它们当依赖

两口井:

口 1:源码没重编。

rm -f out/kernel/checkpoint/compile_check
rm -rf out/kernel/src_tmp/linux-5.10/boot_linux
./build.sh --product-name rk3568_evb --ccache

只跑 ninja boot_linux 有时会命中旧 Image。清 checkpoint 强迫 build_kernel.sh 再走一遍。

口 2:HCS 改了,hcb 没重生。

hc-gen 的 make 依赖常常只有顶层 hdf.hcs。你改的是被 #include 的 input_config.hcs,顶层 mtime 不变,旧的 hdf_hcs_hex.o 继续链进内核。刷完「solution 明明写了 1024,芯片还按 720 报」。

touch vendor/rk/rk3568_evb/hdf_config/khdf/hdf.hcs
# 或者删掉生成的 hdf_hcs_hex.c / .o 再编

验证新内核在跑,不要只看文件日期。驱动里留一行独特日志,刷完:

hdc shell "dmesg | grep -E 'GT911|main_touch|ChipDetect|HDF_INPUT'"

没有这些字,你刷的可能是另一块闪存上的旧 boot_linux。U-Boot 经常去 eMMC 找内核,即便你自以为在从 SD 起。刷之前:

hdc shell "cat /proc/partitions"
hdc shell "ls -l /dev/block/mmcblk*p5"

dd 必须写 /dev/block/mmcblkXp5,禁止 /dev/mmcblkXp5(不存在时会建成普通文件,md5 还对)。改了 DTS 还要刷 resource 分区 p4 里的 rk-kernel.dtb,那才是开机真正用的设备树。触摸这章如果只动了 khdf 的 .c,刷 p5 即可;动了 dts 的 pinctrl / regulator,p4 和 p5 一起刷。


7. 上板:从 dmesg 到 evtest

期望的内核日志形状(关键字,不是逐字对照):

LinuxI2cProbe: i2c adapter 2 add success
ChipDetect: TOUCH IC is GT911
Product ID : 911_....
get dev ability/attr succ
input device main_touch registered

IRQ 能挂上,/proc/interrupts 里对应 gpio 编号在手指按下时会涨。

找事件节点:

hdc shell "cat /proc/bus/input/devices"

HDF 桥过来的名字不一定叫 Goodix Capacitive TouchScreen。见过叫 main_touch,也见过叫 VSoC touchscreen——别被 VSoC 三个字母吓回去,那是桥的名字,不是「纯虚拟、没硬件」。

hdc shell "cat /proc/bus/input/devices"
# 记下 Handlers=eventN

hdc shell "evtest /dev/input/event11"

没有 evtest 就用 od

hdc shell "od -An -tx1 /dev/input/event11"

按下应看到 EV_ABS(type=0x03)的 ABS_MT_POSITION_X/Y,以及 EV_SYN。坐标应在 [0,1023]×[0,599]。出现负数、或 Y 经常是 0,回到第 5 节。

桌面验证:点左上角状态栏、右下角导航,四角都能点中,这一章才算过。只看 dmesg 有 ChipDetect,只能说明 I2C 通,不能说明映射对。


8. 完整 C:读产品 ID,确认不是「DTS 写了就算」

用户态 32 位 musl。不要用 aarch64 的 gcc。下面这份只依赖 /dev/i2c-2CONFIG_I2C_CHARDEV=y 时才有这个节点。

/* gt911_id.c — 读 GT911 0x8140 产品 ID
 * 编译(在 OpenHarmony SDK native 目录下):
 *
 * armv7-unknown-linux-ohos-clang --target=arm-linux-ohos \
 *   --sysroot=${OHOS_NATIVE}/sysroot \
 *   -o gt911_id gt911_id.c \
 *   -Wl,--dynamic-linker=/system/lib/ld-musl-arm.so.1
 *
 * hdc file send gt911_id /data/gt911_id
 * hdc shell "chmod 755 /data/gt911_id; /data/gt911_id"
 */
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>

#define GT911_ADDR      0x5d
#define GT911_REG_ID    0x8140

static int gt911_read(int fd, uint16_t reg, uint8_t *buf, uint16_t len)
{
    uint8_t addr[2] = { (uint8_t)(reg >> 8), (uint8_t)(reg & 0xff) };
    struct i2c_msg msgs[2] = {
        { .addr = GT911_ADDR, .flags = 0,        .len = 2,   .buf = addr },
        { .addr = GT911_ADDR, .flags = I2C_M_RD, .len = len, .buf = buf  },
    };
    struct i2c_rdwr_ioctl_data xfer = { .msgs = msgs, .nmsgs = 2 };
    return ioctl(fd, I2C_RDWR, &xfer);
}

int main(void)
{
    int fd = open("/dev/i2c-2", O_RDWR);
    if (fd < 0) {
        perror("open /dev/i2c-2");
        return 1;
    }

    uint8_t id[4] = {0};
    if (gt911_read(fd, GT911_REG_ID, id, 4) < 0) {
        perror("read 0x8140");
        close(fd);
        return 1;
    }
    close(fd);

    printf("raw: %02x %02x %02x %02x\n", id[0], id[1], id[2], id[3]);
    printf("id : %c%c%c\n", id[0], id[1], id[2]);
    if (id[0] == '9' && id[1] == '1' && id[2] == '1') {
        printf("PASS: GT911\n");
        return 0;
    }
    printf("FAIL: not GT911. 若地址 0x38 有应答,去看 FT5406 那篇。\n");
    return 2;
}

HDF 已经占用 0x5d 时,这份程序会报 busy,那反而是好消息:说明驱动占着芯片。先 i2cdetect 看 UU。要强制用户态读,得停 HDF 触摸(重启前的诊断才用),日常不要和驱动抢。

读报点寄存器 0x814E(buffer status)可以确认手指按下时芯片有没有置位。status 的 bit7 为 1 表示有新点。这能区分「芯片没报点」和「报了但映射错」。

/* 轮询 0x814E,按一下屏应看到非零 */
uint8_t st = 0;
if (gt911_read(fd, 0x814E, &st, 1) == 0) {
    printf("status=0x%02x%s\n", st,
           (st & 0x80) ? "  (have touch)" : "");
}

9. 应用侧:触摸已经进 MMI,不必自己读 I2C

ArkTS 应用不要再去打开 /dev/i2c-2。点、滑、多指,走窗口的触摸事件。下面这份只用来在开发期把坐标打到屏幕上,确认「应用看到的点和手指一致」。量产界面没必要留。

// TouchProbe.ets — API 11,横屏 1024×600
import window from '@ohos.window';

@Entry
@Component
struct TouchProbe {
  @State info: string = '用手指点、滑,看坐标是否落在屏内';
  @State x: number = -1;
  @State y: number = -1;

  build() {
    Column() {
      Text('GT911 坐标探针').fontSize(22).fontWeight(FontWeight.Bold)
        .margin({ bottom: 12 })
      Text(this.info).fontSize(16).fontColor('#1565C0')
      Text(`x=${this.x}  y=${this.y}`).fontSize(28).margin({ top: 24 })
      Text('左上应接近 (0,0),右下应接近 (1023,599)。\n出现负数或超界,回到驱动映射。')
        .fontSize(14).margin({ top: 16 })
    }
    .width('100%').height('100%')
    .justifyContent(FlexAlign.Center)
    .onTouch((e: TouchEvent) => {
      if (e.touches.length > 0) {
        this.x = Math.round(e.touches[0].x);
        this.y = Math.round(e.touches[0].y);
        this.info = `pointers=${e.touches.length}`;
      }
    })
  }

  async aboutToAppear() {
    try {
      let w = await window.getLastWindow(getContext(this));
      await w.setPreferredOrientation(window.Orientation.LANDSCAPE);
    } catch (err) {
      this.info = '横屏请求失败: ' + JSON.stringify(err);
    }
  }
}

若桌面能点中图标,这个页面只是复读。若桌面不准、这个页面准,问题在 Launcher 窗口尺寸;反过来,两边都不准,问题在 HDF 映射。分层,别两边一起改。


10. 和 FT5406、电阻屏、矩阵键盘的边界

东西怎么区分去哪一章
GT911 @0x5dI2C 产品 ID `911`本章
FT5406 @0x38常跟 RGB / 某款 MIPI 屏`23-电容触摸FT5406.md`
电阻屏SPI + ADC,不是这颗别套这篇 HCS
板载 KEY3/4/5adc-keys / gpio-keys`24-板载按键.md`
4×4 矩阵`gpio-matrix-keypad``25-矩阵键盘.md`

同一条 I2C2 上 GT911 和 FT5406 不要同时 okay。地址不同看似能共存,复位脚、中断脚、HCS 的 moduleName 只有一份。两套屏轮流接,就做两份 HCS / 两份镜像,切屏等于切触摸。


11. 排障表

现象先看原因处理
`i2cdetect` 无 0x5d排线、I2C2 status、供电没芯片或总线没起来先硬件
0x5d ACK,0x8140 NACKRST 时序、INT 占用芯片停在错误模式查 powerOnSeq、regulator
ChipDetect 成功,无报点`debugfs` 看 gpio-23INT 被 regulator 占删 `vcc3v3_lcd0_n` 的 gpio
有报点,上半屏失灵串口 DisplayY 是否为负720×1280 映射到 600改 `ChipVersionDefault`
点左右反了raw 是否随右增大多做了一次 `res-raw`去掉反转
改 HCS 不生效`hdf.hcs` mtimeinclude 没触发 hc-gen`touch hdf.hcs` 重编
改 .c 不生效`dmesg` 无新日志旧 Image / 刷错介质清 checkpoint,刷 `/dev/block/`
和 FT5406 谁也不稳两套 moduleName抢总线、抢脚只留一套 okay
flowchart TD
  A[触摸不准或无触摸] --> B{i2cdetect 0x5d?}
  B -->|无| C[查排线 I2C2 供电]
  B -->|有| D{0x8140 读到 911?}
  D -->|否| E[RST/INT/时序]
  D -->|是| F{dmesg ChipDetect?}
  F -->|否| G[HCS moduleName / GT911=y / goodix 是否抢]
  F -->|是| H{有中断计数?}
  H -->|否| I[GPIO0_C7 被 regulator 占]
  H -->|是| J{坐标在 0..1023 / 0..599?}
  J -->|否| K[firmWareParm 720x1280 映射]
  J -->|是| L[查窗口横竖屏]

芯片身份用 I2C 说话:GT911 @0x5d,产品 ID 911。说明书封面可以错,总线不会陪你错。开源鸿蒙标准系统走 HDF Input,内核 goodix 节点 disabled 是让路,不是拆掉触摸。HCS 的 solutionX/Y 是屏的像素;芯片 firmware 可能仍按 720×1280 报,用减法硬套会得到负的 DisplayY。INT = GPIO0_C7 时,公版 LCD 电源节点必须放开这根脚。改 khdf 要清 checkpoint,改 include 进去的 HCS 要碰顶层 hdf.hcs。刷 /dev/block/,动 DTS 记得 resource 分区。

同一条 I2C,另一个地址、另一套脚,是 FT5406。两套配置不要在同一份镜像里同时亮绿灯。


系列第 22 篇 · 芯片:瑞芯微 RK3568 · OpenHarmony 4.1(API 11) · Linux 5.10

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐