STM32MP157驱动开发——多点电容触摸屏驱动

news2024/11/20 2:40:44

STM32MP157驱动开发——多点电容触摸屏驱动

  • 一、简介
  • 二、电容触摸屏驱动框架简介
    • 多点触摸(MT)协议详解
  • 三、驱动开发
    • 1.添加 FT5426 设备节点
    • 2.FT5426 节点配置
    • 3.驱动编写
    • 4.运行测试
    • 5.将驱动添加到内核中
      • 1)将驱动文件放到合适的位置
      • 2)修改Makefile
    • 6.tslib 移植与使用
  • 四、使用内核自带的驱动
    • 1.使能内核自带的 FT5X06 驱动
    • 2.修改设备树
  • 五、4.3寸屏驱动
    • 1.修改设备树
    • 2.添加屏幕参数


参考文章:【正点原子】I.MX6U嵌入式Linux驱动开发——多点电容触摸屏

一、简介

  一开始出现的触摸屏是电阻触摸屏,只能单点触摸,在以前的学习机、功能机时代被广泛使用。2007年苹果的一代 iPhone,也就是 iPhone 2G上使用了多点电容触摸屏。和电阻触摸屏相比,电容触摸屏最大的优点是支持多点触摸(现在的电阻屏也支持多点触控了)。此外,电容屏只需要手指轻触即可,而电阻屏是需要手指给予一定的压力才有反应,而且电容屏不需要校准。
  正点原子的触摸屏采用的是 LCD + 触摸屏结合的方式。底下是 LCD 面板,上面是触摸面板,将两个封装到一起就成了带有触摸屏的 LCD 屏幕。电容触摸屏需要一个驱动 IC 来实现,一般使用的是 IIC 接口。主控制器可以通过 I2C 接口来读取驱动 IC里面的触摸坐标数据。原子的 ATK-7016、ATK-7084 触控 IC 为 FT5426,ATK-4342 使用的触控 IC 为 GT9147。
  本节就对 FT5426 进行开发。FT5426 的 I2C 设备地址为 0X38,ATK-7016 的电容触摸屏部分有 4 个 IO 用于连接主控制器:SCL、SDA、RST 和 INT,SCL 和 SDA 是 I2C 引脚,RST 是复位引脚,INT 是中断引脚。一般通过 INT 引脚来通知主控制器有触摸点按下,然后在 INT 中断服务函数中读取触摸数据。

二、电容触摸屏驱动框架简介

多点触摸(MT)协议详解

电容触摸屏驱动其实就是以下几种 linux 驱动框架的组合:

  • IIC 设备驱动,因为电容触摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 设备驱动
  • 通过中断引脚(INT)向 linux 内核上报触摸信息,因此需要用到 linux 中断驱动框架。坐标的上报在中断服务函数中完成。
  • 触摸屏的坐标信息、屏幕按下和抬起信息都属于 linux 的 input 子系统,因此向 linux 内核上报触摸屏坐标信息就得使用 input 子系统。
  • 在中断处理程序中按照 linux 的 MT 协议上报坐标信息。

linux内核中有一份文档详细的讲解了多点电容触摸屏协议,文档路径为:Documentation/input/multitouch-protocol.txt。且老版本中不支持此协议。
MT 协议被分为两种类型,TypeA 和 TypeB:
Type A:适用于触摸点不能被区分或者追踪,此类型的设备通常上报原始数据(此类型在实际使用中非常少!)
Type B:适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot 更新某一个触摸点的信息,FT5426 就属于此类型,一般的多点电容触摸屏 IC 都有此能力。
Type A时序:x1–>y1–>mt-sync–>x2–>y2–>mt-sync–>input-sync。
Type B时序:mt-slot–>mt-id–>x1–>y1–…–>sync

在电容触摸屏驱动框架中,会通过中断来向系统上报触摸点坐标信息的。但是此中断的申请,使用的是 devm_request_threaded_irq 函数,而不是之前学习的 request_threaded_irq,此函数的作用是中断线程化。
硬件中断具有最高优先级,不论什么时候只要硬件中断发生,内核都会终止当前正在执行的操作,转而去执行中断处理程序(不考虑关闭中断和中断优先级的情况),如果中断非常频繁,那么内核将会频繁的执行中断处理程序,导致任务得不到及时的处理。中断线程化以后中断将作为内核线程运行,而且也可以被赋予不同的优先级,任务的优先级可能比中断线程的优先级高,这样做的目的就是保证高优先级的任务能被优先处理。
对于触摸屏而言,只要手指放到屏幕上,它可能就会一直产生中断(视具体芯片而定,FT5426 是这样的),中断处理程序里面需要通过 I2C 读取触摸信息并上报给内核,I2C 的速度最大只有 400KHz,算是低速外设。不断的产生中断、读取触摸信息、上报信息会导致处理器在触摸中断上花费大量的时间,但是触摸相对来说不是那么重要的事件,因此可以将触摸中断线程化。
使用“devm_”前缀的函数申请到的资源可以由系统自动释放,不需要手动处理。例:之前的驱动里面申请了很多资源,比如:gpio、irq、input_dev,那么就需要添加很多 goto 语句对其做处理,当这样的标签多了以后代码看起来就不整洁了。使用 devm_request_threaded_irq 函数来申请中断,那么就不需要再调用 free_irq 函数对其进行释放。
中断处理函数中上报信息示例:

1 static irqreturn_t xxx_handler(int irq, void *dev_id)
2 {
3 
4 		int num; /* 触摸点数量 */
5 		int x[n], y[n]; /* 保存坐标值 */
6 
7		/* 1、从触摸芯片获取各个触摸点坐标值 */
8 ......
9
10 		/* 2、上报每一个触摸点坐标 */
11 		for (i = 0; i < num; i++) {
12 			input_mt_slot(input, id);
13 			input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
14 			input_report_abs(input, ABS_MT_POSITION_X, x[i]);
15 			input_report_abs(input, ABS_MT_POSITION_Y, y[i]);
16 		}
17 ......
18
19 		input_sync(input);
20 ......
21
22 		return IRQ_HANDLED;
23 }

三、驱动开发

原理图:
在这里插入图片描述
I2C2_SCL 和 I2C2_SDA 对应的引脚为 PH4 和 PH5。CT_INT 对应的引脚为 PI1,CT_RST 对应的引脚为 PH15。
对于中断触发模式,当 FT5426 检测到有触摸事件发生时,会将中断信号拉低,所以对主机控制器来说,是一个下降沿中断触发方式;当一直按着触摸屏不松开,则会一直触发中断,现在大部分的触摸 IC 都是这样设计的。

1.添加 FT5426 设备节点

在 stm32mp15-pinctrl.dtsi 中,添加引脚配置信息:

ft5426int_reset_pins_a: ft5426int_reset_pins-0 {
	pins1 {
		pinmux = <STM32_PINMUX('I', 1, GPIO)>, /* ft5426 INT */
				 <STM32_PINMUX('H', 15, GPIO)>; /* ft5426 RESET */
		bias-pull-up;
		slew-rate = <0>;
	};
};

2.FT5426 节点配置

FT5426这个触控 IC 挂载在I2C2 总线接口上,因此需要向 I2C2 节点下添加一个子节点(省略了之前的hdmi节点):

&i2c2 {
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&i2c2_pins_a>;
	pinctrl-1 = <&i2c2_pins_sleep_a>;
	status = "okay";
	
	ft5426: ft5426@38 {
		compatible = "edt,edt-ft5426";
		pinctrl-0 = <&ft5426int_reset_pins_a>;
		reg = <0x38>;
		irq-gpios = <&gpioi 1 GPIO_ACTIVE_LOW>;
		reset-gpios = <&gpioh 15 GPIO_ACTIVE_LOW>;
		status = "okay";
	};
};

FT5426 的器件地址为0X38,irq-gpios 属性描述中断 IO 对应的 GPIO 为 PI1,reset-gpios 属性描述复位 IO 对应的 GPIO 为 PH15。

3.驱动编写

ft5x06.c:

#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/input/mt.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/interrupt.h>

/* FT5426寄存器相关宏定义 */
#define FT5426_DEVIDE_MODE_REG	    0x00	// 模式寄存器
#define FT5426_TD_STATUS_REG    	0x02  	// 状态寄存器
#define FT5426_TOUCH_DATA_REG   	0x03   	// 触摸数据读取的起始寄存器
#define FT5426_ID_G_MODE_REG    	0xA4  	// 中断模式寄存器

#define MAX_SUPPORT_POINTS		5    	// ft5426最大支持5点触摸

#define TOUCH_EVENT_DOWN      	0x00    // 按下
#define TOUCH_EVENT_UP          0x01    // 抬起
#define TOUCH_EVENT_ON         	0x02    // 接触
#define TOUCH_EVENT_RESERVED  	0x03    // 保留

struct edt_ft5426_dev {
    struct i2c_client *client;
    struct input_dev *input;
    int reset_gpio;
    int irq_gpio;
};

static int edt_ft5426_ts_write(struct edt_ft5426_dev *ft5426, u8 addr, u8 *buf, u16 len)
{
    struct i2c_client *client = ft5426->client;
    struct i2c_msg msg;
    u8 send_buf[6] = {0};
    int ret;

    send_buf[0] = addr;
    memcpy(&send_buf[1], buf, len);

    msg.flags = 0;                  //i2c写
    msg.addr = client->addr;
    msg.buf = send_buf;
    msg.len = len + 1;

    ret = i2c_transfer(client->adapter, &msg, 1);
    if (1 == ret)
        return 0;
    else {
        dev_err(&client->dev, "%s: write error, addr=0x%x len=%d.\n", __func__, addr, len);
        return -1;
    }
}

static int edt_ft5426_ts_read(struct edt_ft5426_dev *ft5426, u8 addr, u8 *buf, u16 len)
{
    struct i2c_client *client = ft5426->client;
    struct i2c_msg msg[2];
    int ret;

    msg[0].flags = 0;             	// i2c写
    msg[0].addr = client->addr;
    msg[0].buf = &addr;
    msg[0].len = 1;              	// 1个字节

    msg[1].flags = I2C_M_RD;    	//i2c读
    msg[1].addr = client->addr;
    msg[1].buf = buf;
    msg[1].len = len;

    ret = i2c_transfer(client->adapter, msg, 2);
    if (2 == ret)
        return 0;
    else {
        dev_err(&client->dev, "%s: read error, addr=0x%x len=%d.\n", __func__, addr, len);
        return -1;
    }
}

static int edt_ft5426_ts_reset(struct edt_ft5426_dev *ft5426)
{
    struct i2c_client *client = ft5426->client;
    int ret;

    /* 从设备树中获取复位管脚 */
    ft5426->reset_gpio = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);
    if (!gpio_is_valid(ft5426->reset_gpio)) {
        dev_err(&client->dev, "Failed to get ts reset gpio\n");
        return ft5426->reset_gpio;
    }

    /* 申请使用管脚 */
    ret = devm_gpio_request_one(&client->dev, ft5426->reset_gpio, GPIOF_OUT_INIT_HIGH, "ft5426 reset");
    if (ret < 0)
        return ret;

    msleep(20);
    gpio_set_value_cansleep(ft5426->reset_gpio, 0);    	// 拉低复位引脚
    msleep(5);
    gpio_set_value_cansleep(ft5426->reset_gpio, 1);   	// 拉高复位引脚,结束复位

    return 0;
}

static irqreturn_t edt_ft5426_ts_isr(int irq, void *dev_id)
{
    struct edt_ft5426_dev *ft5426 = dev_id;
    u8 rdbuf[30] = {0};
    int i, type, x, y, id;
    bool down;
    int ret;

    /* 读取FT5426触摸点坐标从0x02寄存器开始,连续读取29个寄存器 */
    ret = edt_ft5426_ts_read(ft5426, FT5426_TD_STATUS_REG, rdbuf, 29);
    if (ret)
        goto out;

    for (i = 0; i < MAX_SUPPORT_POINTS; i++) {

        u8 *buf = &rdbuf[i * 6 + 1];

        /* 以第一个触摸点为例,寄存器TOUCH1_XH(地址0x03),各bit位描述如下:
         * bit7:6  Event flag  0:按下 1:释放 2:接触 3:没有事件
         * bit5:4  保留
         * bit3:0  X轴触摸点的11~8位
         */
        type = buf[0] >> 6;                     // 获取触摸点的Event Flag
        if (type == TOUCH_EVENT_RESERVED)
            continue;

        /* 我们所使用的触摸屏和FT5426是反过来的 */
        x = ((buf[2] << 8) | buf[3]) & 0x0fff;
        y = ((buf[0] << 8) | buf[1]) & 0x0fff;

        /* 以第一个触摸点为例,寄存器TOUCH1_YH(地址0x05),各bit位描述如下:
         * bit7:4  Touch ID  触摸ID,表示是哪个触摸点
         * bit3:0  Y轴触摸点的11~8位。
         */
        id = (buf[2] >> 4) & 0x0f;
        down = type != TOUCH_EVENT_UP;

        input_mt_slot(ft5426->input, id);
        input_mt_report_slot_state(ft5426->input, MT_TOOL_FINGER, down);

        if (!down)
            continue;

        input_report_abs(ft5426->input, ABS_MT_POSITION_X, x);
        input_report_abs(ft5426->input, ABS_MT_POSITION_Y, y);
    }

    input_mt_report_pointer_emulation(ft5426->input, true);
    input_sync(ft5426->input);

out:
    return IRQ_HANDLED;
}

static int edt_ft5426_ts_irq(struct edt_ft5426_dev *ft5426)
{
    struct i2c_client *client = ft5426->client;
    int ret;

    /* 从设备树中获取中断管脚 */
    ft5426->irq_gpio = of_get_named_gpio(client->dev.of_node, "irq-gpios", 0);
    if (!gpio_is_valid(ft5426->irq_gpio)) {
        dev_err(&client->dev, "Failed to get ts interrupt gpio\n");
        return ft5426->irq_gpio;
    }

    /* 申请使用管脚 */
    ret = devm_gpio_request_one(&client->dev, ft5426->irq_gpio, GPIOF_IN, "ft5426 interrupt");
    if (ret < 0)
        return ret;

    /* 注册中断服务函数 */
    ret = devm_request_threaded_irq(&client->dev, gpio_to_irq(ft5426->irq_gpio),
                NULL, edt_ft5426_ts_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                client->name, ft5426);
    if (ret) {
        dev_err(&client->dev, "Failed to request touchscreen IRQ.\n");
        return ret;
    }

    return 0;
}

static int edt_ft5426_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    struct edt_ft5426_dev *ft5426;
    struct input_dev *input;
    u8 data;
    int ret;

    /* 实例化一个struct edt_ft5426_dev对象 */
    ft5426 = devm_kzalloc(&client->dev, sizeof(struct edt_ft5426_dev), GFP_KERNEL);
    if (!ft5426) {
        dev_err(&client->dev, "Failed to allocate ft5426 driver data.\n");
        return -ENOMEM;
    }

    ft5426->client = client;

    /* 复位FT5426触摸芯片 */
    ret = edt_ft5426_ts_reset(ft5426);
    if (ret)
        return ret;

    msleep(5);

    /* 初始化FT5426 */
    data = 0;
    edt_ft5426_ts_write(ft5426, FT5426_DEVIDE_MODE_REG, &data, 1);
    data = 1;
    edt_ft5426_ts_write(ft5426, FT5426_ID_G_MODE_REG, &data, 1);

    /* 申请、注册中断服务函数 */
    ret = edt_ft5426_ts_irq(ft5426);
    if (ret)
        return ret;

    /* 注册input设备 */
    input = devm_input_allocate_device(&client->dev);
    if (!input) {
        dev_err(&client->dev, "Failed to allocate input device.\n");
        return -ENOMEM;
    }

    ft5426->input = input;
    input->name = "FocalTech FT5426 TouchScreen";
    input->id.bustype = BUS_I2C;

    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);

    ret = input_mt_init_slots(input, MAX_SUPPORT_POINTS, INPUT_MT_DIRECT);
    if (ret) {
        dev_err(&client->dev, "Failed to init MT slots.\n");
        return ret;
    }

    ret = input_register_device(input);
    if (ret)
        return ret;

    i2c_set_clientdata(client, ft5426);
    return 0;
}

static int edt_ft5426_ts_remove(struct i2c_client *client)
{
    struct edt_ft5426_dev *ft5426 = i2c_get_clientdata(client);
    input_unregister_device(ft5426->input);
    return 0;
}

static const struct of_device_id edt_ft5426_of_match[] = {
    { .compatible = "edt,edt-ft5426", },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, edt_ft5426_of_match);

static struct i2c_driver edt_ft5426_ts_driver = {
    .driver = {
        .owner     		= THIS_MODULE,
        .name          	= "edt_ft5426",
        .of_match_table	= of_match_ptr(edt_ft5426_of_match),
    },
    .probe    = edt_ft5426_ts_probe,
    .remove   = edt_ft5426_ts_remove,
};

module_i2c_driver(edt_ft5426_ts_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("amonter");
MODULE_INFO(intree, "Y");

①自定义结构体 edt_ft5426_dev,用于描述 FT5426 设备,其中包括 I2C 从机设备指针 client、input 输入设备指针 input、一个复位引脚 reset_gpio 以及一个中断引脚 irq_gpio。
②自定义函数 edt_ft5426_ts_write,用于向 FT5426 内部寄存器连续写入数据,可指定写入数据字节长度。
③自定义函数 edt_ft5426_ts_read,用于连续读取 FT5426 内部寄存器中的数据,可指定读取数据字节长度。
④自定义函数 edt_ft5426_ts_reset,用于复位 FT5426 触摸芯片,FT5426 的复位 IO 为低电平有效。FT5426 的复位过程没有什么特殊要求,直接将复位 IO 拉低,延时 5ms 然后再将其拉高即可。复位结束之后先延时一段时间再进行读写寄存器操作。
⑤edt_ft5426_ts_isr 函数,触摸屏中断服务函数,触摸点坐标的上报就是在此函数中完成的。从 0x02 这个地址开始,一共 29 个寄存器,是存储的所有触摸点信息。使用for循环一个一个上报,使用 Type B 时序,最后通过 input_sync 函数上报 SYN_REPORT 事件。
⑥自定义函数 edt_ft5426_ts_irq,用于初始化 FT5426 中断 IO,使用函数 devm_request_threaded_irq 申请并注册中断,为下降沿触发。
⑦I2C 总线的 probe 函数 edt_ft5426_ts_probe,当 I2C 从机设备与驱动匹配成功之后就会执行这个函数,一般在此函数中完成一些初始化工作。
⑧input_mt_init_slots 函数是用来初始化 slots,第二个参数表示触摸屏设置支持的最大触摸点数量,FT5426 是个 5 点电容触摸芯片,因此一共 5 个 slot;最后一个参数是一个标志位,表示设备类型,INPUT_MT_DIRECT 表示为触摸屏设备类型。
⑨edt_ft5426_ts_remove 函数用来卸载驱动模块,因为前面很多资源都是用“ devm_”前缀函数来申请的,因此不需要手动释放。此函数只需要调用 input_unregister_device 来释放掉前面添加到内核中的 input_dev。

4.运行测试

将驱动文件编译,放入nfs指定目录然后启动开发板。加载驱动模块后就会生成/dev/input/eventX(X=1,2,3…)。
在这里插入图片描述
数据解析:
使用hexdump /dev/input/event1命令,然后手动操作电容屏,终端就可以接受到数据。上报的信息是按照 input_event 类型呈现的。
请添加图片描述
在这里插入图片描述

5.将驱动添加到内核中

将驱动添加到内核,系统启动时就会自动挂载,不需要再手动挂载了。

1)将驱动文件放到合适的位置

ft5x06.c 是个触摸屏驱动,linux 内核里将触摸屏驱动放到了 drivers/input/touchscreen 目录下,因此将 ft5x06.c 也拷贝到此目录下。

2)修改Makefile

修改 drivers/input/touchscreen 目录下的 Makefile,在最下面添加一行:

obj-y += ft5x06.o

这样就将驱动文件添加进了内核编译。修改完成以后重新编译 linux 内核,然后用新的 uImage 启动开发板。如果驱动添加成功,系统启动的时候就会输出下图信息:
在这里插入图片描述

6.tslib 移植与使用

  tslib 是一个开源的第三方库,用于触摸屏性能调试,使用电阻屏的时候一般使用 tslib 进行校准。虽然电容屏不需要校准,但是由于电容屏加工的原因,有的时候其不一定精准,因此有时候也需要进行校准。
  在 buildroot 的 menuconfig 中使能 tslib 库:
在这里插入图片描述
然后使用sudo make编译出文件系统,并解压到 nfs 的对应目录即可。
测试
校准命令:ts_calibrate,如果对校准结果不满意,直接删除掉 /etc/pointercal 文件。
使用ts_test_mt命令测试触摸屏工作是否正常,以及多点触摸是否有效。此时会打开一个测试界面,有三个按钮“Drag”、“Draw”和“Quit”,这三个按钮的功能如下:
Drag:拖拽按钮,默认就是此功能,可以看到屏幕中间有一个十字光标,可以通过触摸屏幕来拖拽此光标。一个触摸点一个十字光标,对于 5 点电容触摸屏,如果 5 个手指都放到屏幕上,那么就有 5 个光标,一个手指一个。
Draw:绘制按钮,按下此按钮就可以在屏幕上进行简单的绘制,可以通过此功能检测多点触摸工作是否正常。
Quit:退出按钮,退出 ts_test_mt 测试软件。
点击“Draw”按钮,使用绘制功能,5 个手指一起划过屏幕,如果多点电容屏工作正常的话就会在屏幕上留下 5 条线。

四、使用内核自带的驱动

内核自带的 FT5426 的驱动文件为 drivers/input/touchscreen/edt-ft5x06.c,此驱动文件不仅能够驱动 FT5426,FT5206、FT5406 这些都可以驱动。
先将之前添加进内核编译的自己的驱动去除,将Makefile中添加的命令去掉即可。

1.使能内核自带的 FT5X06 驱动

在 Linux 内核的 menuconfig 进行使能:
在这里插入图片描述

2.修改设备树

修改之前编写的 ft5426 设备节点,添加 compatible 属性。edt-ft5x06.c 所支持的 compatible 属性列表如下:
在这里插入图片描述
将 compatible 属性修改为某一个兼容值即可。

ft5426: ft5426@38 {
		compatible = "edt,edt-ft5406";
		pinctrl-0 = <&ft5426int_reset_pins_a>;
		reg = <0x38>;
		irq-gpios = <&gpioi 1 GPIO_ACTIVE_LOW>;
		reset-gpios = <&gpioh 15 GPIO_ACTIVE_LOW>;
		status = "okay";
};

修改完成后重新编译出 uImage 和设备树,然后启动开发板即可。

五、4.3寸屏驱动

  4.3寸屏幕的驱动 IC 都是 GT9147,因此本质上就是编写 GT9147 驱动。

1.修改设备树

在 i2c2 节点下添加一个子节点:

gt9147: gt9147@14 {
	compatible = "atk-gt9147";
	reg = <0x14>;
	interrupt-parent = <&gpioi>;
	interrupts = <1 IRQ_TYPE_EDGE_RISING>;
	interrupt-gpios = <&gpioi 1 GPIO_ACTIVE_LOW>;
	reset-gpios = <&gpioh 15 GPIO_ACTIVE_LOW>;
	status = "okay";
};

在 ST 官方的内核配置中,已经把 gt9147 这个驱动编译进内核了,所以这里的 compatible 的属性值为“atk-gt9147”,免得使用内核的 gt9147 驱动代码。

2.添加屏幕参数

在 drivers/gpu/drm/panel/panel-simple.c 文件下,添加对应屏幕的参数,4.3 寸 800480 和 480272 这两款屏幕参数如下:

static const struct drm_display_mode ATK4384_mode = {
	.clock = 33300,
	.hdisplay = 800,
	.hsync_start = 800 + 88,
	.hsync_end = 800 + 88 + 48,
	.htotal = 800 + 88 + 48 + 40,
	.vdisplay = 480,
	.vsync_start = 480 + 32,
	.vsync_end = 480 + 32 + 3,
	.vtotal = 480 + 32 + 3 + 13,
	.vrefresh = 60,
};
static const struct drm_display_mode ATK4342_mode = {
	.clock = 9000,
	.hdisplay = 480,
	.hsync_start = 480 + 40,
	.hsync_end = 480 + 40 + 1,
	.htotal = 480 + 40 + 1 + 5,
	.vdisplay = 272,
	.vsync_start = 272 + 8,
	.vsync_end = 272 + 8 + 1,
	.vtotal = 272 + 8 + 1 + 8,
	.vrefresh = 60,
};
static const struct panel_desc alientek_desc = {
	.modes = &ATK7016_mode,
	.num_modes = 1,
	.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
};

前两个为 800480 和 480272 两个屏的参数,第三个中,modes 属性为“ATK7016_mode”,如果屏为 480*272 就把 modes 属性修改为 ATK4342_mode。
将原子的驱动文件拷贝进来然后编译,编译完成后手动挂载即可。如果在使用 tslib 的时候提示找不到设备,使用export TSLIB_TSDEVICE=/dev/input/event1命令手动声明设备即可。

注:如果想直接使用 Linux 自带的 gt9147 驱动,直接修改设备树的 compatible 属性值为“goodix,gt9147”即可。另外,原子哥的驱动中,因为 GT9147 没有硬件检测每个触摸点的按下和抬起,因此只能单点触摸。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/124624.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Xillinx的设计约束阅读整理

《适用于FPGA和SOC的UlteraFast设计方法指南》&#xff08;UG949&#xff09; 《Vivado Design Suite 用户指南&#xff1a;设计分析与收敛技巧》(UG906) 《Vivado Design Suite 用户指南&#xff1a;使用约束》(UG903) 《Vivado Design Suite Tcl 命令参考指南》(UG835) 约束文…

【java基础】关于线程的一些基础知识点

1.线程的概念&#xff1a; 在java的应用中&#xff0c;线程更多情况下指的是Thread&#xff0c;更精细一点&#xff0c;执行线程就是执行Thread实体下面的run方法&#xff0c;java通过cpu调试&#xff0c;交替进行这些thread&#xff0c;就达到了共同进行这种效果&#xff1b;…

【尚硅谷】SpringBoot2核心技术-1-基础入门

【尚硅谷】SpringBoot2核心技术-1-基础入门一、Spring与SpringBoot1、Spring能做什么1.1、Spring的能力1.2、Spring的生态【没写完】二、SpringBoot2入门1、系统要求1.1、maven设置2、HelloWorld2.1、创建maven工程2.2、引入依赖2.3、创建主程序2.4、编写业务2.5、测试2.6、简化…

DM8开发技能

DM8开发技能 基础学习笔记005 文章目录DM8开发技能1、DMSQL程序设计1.1 概念1.2 数据类型1.3 程序定义1.3.1 存储过程1.3.2 存储函数1.3.3 客户端DMSQL程序1.3.4 参数1.3.5 控制结构&#xff08;1&#xff09;顺序结构&#xff08;2&#xff09;分支结构&#xff08;3&#xf…

Doo Prime 德璞资本:道琼斯期货投资前必看的入门知识

美国道琼工业指数是全球最受关注的股指之一&#xff0c;而道琼斯期货则是典型的衍生性金融商品&#xff0c;交易的标的是道琼指数本身&#xff0c;属于期货投资的范畴&#xff0c;适合短线进出、波段交易。想要参与美国的期货投资市场&#xff0c;却不知道期货该如何开始吗&…

C# XPath的概念

一 XPath的概念 1 XPath是对XML进行查询的表达式 ① Axes(路径) / 及 //; ② 第几个子节点[1] 等&#xff1b; ③ 属性 ④ 条件 [] ⑤ 例如 /books/book/title //price para[type“warning”][5] 2 使用XPath ① XmlDocument docnew XmlDocument(); ② doc.LoadXml(strXml)…

通过idea打包java Maven项目 架包与全包

1 仅架包 架包定义&#xff1a;指仅将代码打包到jar中&#xff0c;在运行的平台必须保证依赖。 方法&#xff1a;maven —> Lifecyle —> Clean —> Package 2 架包与全包(推荐) 全包定义&#xff1a;将maven项目中的依赖于代码都打为一个包。 方法&#xff1a;mave…

RK3568平台开发系列讲解(Linux系统篇)Linux 管道的使用

🚀返回专栏总目录 文章目录 一、 管道1.1、单向管道1.2、双向管道沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍管道的使用。 一、 管道 在 fork() 成功创建子进程之后,已经打开的文件描述符在父子进程间是共享的,管道就是利用这一特性来工作的。 创建…

C++:设计一个文本行编辑程序,先从输入文件中读取数据,然后根据行编辑命令处理,将结果写到输出文件中。

3.1题目&#xff1a; 设计一个文本行编辑程序 对文本文件按行进行编辑&#xff1a;先从输入文件中读取数据&#xff0c;然后根据行编辑命令处理&#xff0c;将结果写到输出文件中。行编辑命令包括&#xff1a;序号 行编辑命令格式 功能 &#xff11; *L m&#xff0c;n …

ts概述、ts环境准备和编译、ts类型声明

文章目录1. ts概述2. ts环境准备和编译3. ts类型声明3.1 布尔值3.2 数字类型3.3 字符串类型3.4 any和unknown3.5 void、null、undefined3.6 never类型3.7 字面量类型3.8 枚举类型3.9 object对象类型3.10 数组3.11 元组3.12 自定义类型type3.13 联合类型3.14 交叉类型3.15 类型断…

《深入理解计算机系统》学习笔记 —— 虚拟内存详解

文章目录虚拟内存物理内存、物理地址、虚拟地址虚拟地址空间虚拟内存缓存页表分配页面页命中缺页虚拟内存的好处简化链接mmap虚拟内存的私有性地址翻译我们先看一下使用页表进行地址翻译有哪些东西&#xff1a;虚拟地址到物理地址处理过程页面大小和虚拟地址物理地址关系TLB翻译…

2022年,我45岁,一息尚存不落征帆,静稳前行未来可期

2022年&#xff0c;我45岁&#xff0c;一息尚存不落征帆&#xff0c;静稳前行未来可期&#xff0c; 关键词&#xff1a;模式固定&#xff0c;回顾与审视&#xff0c;不间断地阅读 模式固定 本年的52周&#xff0c;每逢周五我会把还在更新的15册讲书各讲一期。每期讲20分钟左…

nodejs mp2 姿势启动

以前运行 nodejs 代码都是 node xxx.js&#xff1b; 但是很容易就关掉了&#xff0c; 或者你想看跟详细的数据 是看不到的。 可以试试 pm2的方式 运行你的代码&#xff1b;学习新的姿势&#xff01; pm2的安装&#xff1a; 1&#xff1a; npm install pm2 -g C:\Users\Admini…

数据治理:数据治理框架和标准

参考《一本书讲透数据治理》、《数据治理》等 数据治理并不是新概念&#xff0c;在国内外都有实践&#xff0c;这里重点介绍下国内外对数据治理的主流框架和标准 国际数据治理框架 国际上&#xff0c;主流的数据治理框架主要有&#xff1a;ISO数据治理标准、GDI数据治理框架、…

深入浅出scala之函数(匿名函数)(P41-45)

文章目录1.函数的定义2.匿名函数3.递归函数4.无参函数5.方法和函数的区别联系1.函数的定义 package MethodDemoobject FunctionDefinition {// 实现加法的功能&#xff0c;省略写法&#xff0c;把函数体写在返回值的位置val f1 ((a: Int, b: Int) > { a b })val f2 (a: …

Charles - 配置抓Chrome、iOS、Android包环境

官网下载地址&#xff1a;https://www.charlesproxy.com/。 1、设置代理http端口 路径&#xff1a;Proxy > Proxy Settings > Proxies > HTTP proxy > Prot 2、设置代理https端口 路径&#xff1a;SSL Proxying Settings > SSL Proxyin 3、Mac证书配置 …

谷粒商城-基础篇-Day06-属性分组

属性分组 抽取出一个tree组件放到modules下的common下的category.vue <template><el-tree :data"menus" :props"defaultProps" node-key"catId"ref"menu"></el-tree> </template><script> //这里可以…

LVGL学习笔记6 - 输入设备

目录 1. 移植文件 2. 移除多余代码 3. 输入设备初始化 4. 输入设备读回调函数 4.1 LV_INDEV_TYPE_POINTER 4.2 LV_INDEV_TYPE_KEYPAD 4.3 LV_INDEV_TYPE_ENCODER 4.4 LV_INDEV_TYPE_BUTTON 5. 事件 6. 实例 7 Group 7.1 创建Group 7.2 与输入设备关联 7.3 添加对…

低频功率放大器参考电路图解大全

功率放大器一般也被我们称为电压放大器&#xff0c;主要是把微弱信号进行电压放大&#xff0c;其输入输出的电压电流一般很小&#xff0c;不能够直接驱动功率较大的仪器。为了满足使用需求&#xff0c;需要在放大器末级增加功率放大器。而功率放大器主要就是放大信号功率&#…

供应商绩效管理对企业采购组织的重要价值

供应商绩效管理是供应商管理中的重要组成部分&#xff0c;它在企业整个采购管理生命周期中起到重要的作用&#xff0c;作为管理好供应商的一个重要手段&#xff0c;现代企业几乎都会对供应商实施绩效考核。供应商绩效管理是对公司供应商的可靠性、质量和性能的监视和分析。它能…