树莓派3移植GT811触摸屏驱动

news/2024/11/17 20:28:36/

原料:

1.树莓派3b+
2.微雪7寸电容触摸屏(1024*600)
3.usb转TTL模块

准备:

树莓派的中断资源没找到,用内核线程定时查询的方式来获取GT811的触摸数据。

下图是树莓派的GPIO引脚图:
这里写图片描述

下图是微雪7寸屏触摸i2c信号的引线方式(线色对应I2C的信号:橙->5V 蓝->GND 黄->SCL 绿->SDA):
这里写图片描述

将微雪自带的GD32F103芯片去掉(这个芯片通过i2c接口读取触摸屏数据,再转换成usb接口)。GD32F103的I2C信号会干扰我们的通信。

与树莓派的接线如下图,需要显示的话可以连接hdmi线,其他的就不用连了:

这里写图片描述

环境准备:
1.串口调试:
a. 修改/boot/config.txt,增加如下2行
dtoverlay=pi3-miniuart-bt
enable_uart=1
b. 修改/boot/cmdline
console=ttyAMA0,115200

2.微雪7寸hdmi触摸屏配置:
微雪7寸HDMI触摸屏工作与树莓派时,必须手动设置分辨率。
a.将系统镜像写到TF卡中。
b.编辑TF卡根目录下/boot/confi.txt文件。
在文件结尾添加:
max_usb_current=1
hdmi_group=2
hdmi_mode=1
hdmi_mode=87
hdmi_cvt 1024 600 60 0 0 0
c.插接hdmi线盒usb线连接到树莓派的usb口上,启动即可。

3.启动I2C平台
a.执行如下命令进行树莓派配置
sudo raspi-config
b.选择Advanced Options -> I2C ->yes
c.启动i2C内核驱动

4.测试连接
a.安装i2c-tool工具
sudo apt-get install i2c-tools
b.i2c-tool查询i2c设备
i2cdetect -y 1
-y 代表取消用户交互过程,直接执行指令;
1 代表I2C总线编号;
执行结果如下:
这里写图片描述
0x5d就是GT811的id了,如果显示的是UU表明该设备已经被用了。

驱动移植:

下表是gt811主要用读取触摸点的寄存器
这里写图片描述
0x0721地址是触控点和key的状态,gt811最多支持5点触控,这里只用一点,所以寄存器0x721的tp0位和0x723~0x727对我们有用。在驱动里定时读取,然后在上报input位置就行了。

开始正题贴代码。
gt811_ts.c

#include <linux/delay.h>#include <linux/property.h>#include <linux/init.h>  
#include <linux/module.h>  
#include <linux/moduleparam.h>  #include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/mutex.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/kthread.h>const static unsigned short normal_address[] = {0x5d, I2C_CLIENT_END};  static struct input_dev *ts_input;   static struct i2c_client * this_client = NULL;  MODULE_LICENSE("Dual BSD/GPL");  struct sensor_gt811 {struct mutex lock;struct i2c_client *client;struct completion wait;bool is_self_test;u16 x_axis;u16 y_axis;u16 z_axis;u8 sample;u8 out_rate;u8 mesura;u8 mode;u8 gain;struct task_struct     * thread;
};
static struct sensor_gt811 *gt811;static int i2c_read_bytes(struct i2c_client *client, uint8_t *buf, int len)  
{  struct i2c_msg msgs[2];  int ret=-1;  msgs[0].flags=!I2C_M_RD;  msgs[0].addr=client->addr;  msgs[0].len=2;  msgs[0].buf=&buf[0];  msgs[1].flags=I2C_M_RD;  msgs[1].addr=client->addr;  msgs[1].len=len-2;  msgs[1].buf=&buf[2];  ret=i2c_transfer(client->adapter,msgs, 2);  return ret;  
}  static int i2c_write_bytes(struct i2c_client *client,uint8_t *data,int len)  
{  struct i2c_msg msg;  int ret=-1;  msg.flags=!I2C_M_RD;  msg.addr=client->addr;  msg.len=len;  msg.buf=data;     ret=i2c_transfer(client->adapter,&msg, 1);  return ret;  
}  static int gt811_thread(void *arg)
{unsigned char point_data[25] = {0x07, 0x21, 0};  unsigned  short input_x = 0;  unsigned  short input_y = 0;  unsigned  short input_p = 0; static unsigned int status = 0;  int ret;while(!kthread_should_stop()){// 50ms查询一次msleep_interruptible(50);//读取gt811寄存器信息ret=i2c_read_bytes(this_client, point_data, sizeof(point_data)/sizeof(point_data[0]));  if(ret <= 0){  printk("Failed\n");  return 0;  } //point_data数组的前两位是要读取寄存器的起始地址,point_data[2]对应gt811芯片寄存器的0x0721寄存器内容if(point_data[2]&0x1f){  status=1;       //标记有触点触发input_y = ((point_data[4]<<8)|point_data[5]);  input_x = ((point_data[6]<<8)|point_data[7]);  input_p = point_data[8];  }  //如果没有触摸动作 并且上次有触摸 表明触摸松开   else if(status){  status = 0; //触摸点被释放input_mt_report_slot_state(ts_input, MT_TOOL_FINGER, false);input_mt_sync_frame(ts_input);input_sync(ts_input);  } if(status){  if(input_x >=0 &&input_x<1024 &&input_y>=0&&input_y<600){//printk("x=%d,y=%d,w=%d\n",input_x,input_y,input_p); //触摸点被按下input_mt_report_slot_state(ts_input, MT_TOOL_FINGER, true);input_report_abs(ts_input, ABS_MT_POSITION_X, input_x);input_report_abs(ts_input, ABS_MT_POSITION_Y, 600-input_y);         input_report_abs(ts_input, ABS_MT_TOUCH_MAJOR, input_p);input_mt_sync_frame(ts_input);input_sync(ts_input);}}   } return 1;
}//初始化GT811
static int ts_init_panel(struct i2c_client *client){  short ret=-1;  uint8_t config_info[] = {  0x06,0xA2,  0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,0x02,0x00,0x02,0x22,0x12,0x22,0x22,0x22,0x32,0x22,0x42,0x22,0x52,0x22,0x62,0x22,0x72,0x22,0x83,0x22,0x92,0x22,0xA2,0x22,0xB2,0x22,0xC2,0x22,0xD2,0x22,0xE2,0x22,0xF2,0x22,0x1B,0x03,0x28,0x28,0x28,0x20,0x20,0x20,0x0F,0x0F,0x0A,0x45,0x30,0x04,0x03,0x00,0x05,0xE0,0x01,0x20,0x03,0x00,0x00,0x38,0x33,0x35,0x30,0x00,0x00,0x26,0x14,0x02,0x0A,0x00,0x00,0x00,0x00,0x00,0x14,0x10,0x30,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01    };  //配置gt811触摸点分辨率config_info[62] = 600 >> 8;  config_info[61] = 600 & 0xff;  config_info[64] = 1024 >> 8;  config_info[63] = 1024 & 0xff;  ret = i2c_write_bytes(client, config_info, sizeof(config_info)/sizeof(config_info[0]));  if(ret < 0)  {  printk(KERN_ERR "GT811 Send config failed!\n");   return ret;   }  
printk(KERN_ALERT"config gt811\n"); return 0;  
}  static int gt811_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
int retry, ret;  char test_data;  //i2c_set_clientdata(client, gt811);printk("ts_probe\n");  test_data = 0;  if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))   {  dev_err(&client->dev, "Must have I2C_FUNC_I2C.\n");  return -ENODEV;  }  gt811 = devm_kzalloc(&client->dev, sizeof(struct sensor_gt811),GFP_KERNEL);if (!gt811)return -ENOMEM;i2c_set_clientdata(client, gt811);gt811->client = client;for(retry=0;retry < 5; retry++)  {  msleep(100);  ret =i2c_write_bytes(client, &test_data, 1);  if (ret > 0)  break;  dev_info(&client->dev, "GT811 I2C TEST FAILED!Please check the HARDWARE connect\n");  }  if(ret <= 0)  {  dev_err(&client->dev, "Warnning: I2C communication might be ERROR!\n");  return -ENODEV;  }  //初始化gt811芯片for(retry = 0; retry != 5; ++ retry){  ret = ts_init_panel(client);  if(ret != 0){  continue;  }  else{  break;  }  }  if(ret != 0){  printk("GT811 Configue failed!\n");  return -ENODEV;  }  this_client = client;  //申请input设备空间  ts_input = input_allocate_device();  if(IS_ERR(ts_input)){  printk("GT811 allocate ts input device failed!\n");  return -ENOMEM;  }  ts_input->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;  ts_input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);  ts_input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);  /*input_set_abs_params(ts_input, ABS_Y, 0,  1024, 0, 0);  input_set_abs_params(ts_input, ABS_X, 0, 600, 0, 0);  input_set_abs_params(ts_input, ABS_PRESSURE, 0, 255, 0, 0);  */__set_bit(INPUT_PROP_DIRECT, ts_input->propbit);__set_bit(EV_ABS, ts_input->evbit);input_mt_init_slots(ts_input, 1,0);input_set_abs_params(ts_input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);input_set_abs_params(ts_input, ABS_MT_POSITION_X, 0, 1024, 0, 0);input_set_abs_params(ts_input, ABS_MT_POSITION_Y, 0, 600, 0, 0);    ts_input->name = "gt811-ts";  ts_input->phys = "input/ts";  ts_input->id.bustype = BUS_I2C;  ts_input->id.product = 0xBEEF;  ts_input->id.vendor  =0xDEAD;  //注册输入设备  ret = input_register_device(ts_input);  if(ret < 0){  printk("Unable register %s input device!\n", ts_input->name);  input_free_device(ts_input);  return -ENOMEM;  } 
//启动内核线程,主要的触摸轮寻工作就在这里做gt811->thread = kthread_run(gt811_thread, gt811, "gt811");if(gt811->thread == NULL){printk(KERN_ALERT"gt811_thread err\n");  } return 0;
}static int gt811_remove(struct i2c_client *client)
{kthread_stop(gt811->thread);i2c_set_clientdata(client, NULL);input_unregister_device(ts_input);//kfree(gt811);return 0;
}#ifdef CONFIG_OF
static const struct of_device_id gt811_of_match[] = {{ .compatible = "goodix,gt811", },{ }
};
MODULE_DEVICE_TABLE(of, gt811_of_match);
#endifstatic const struct i2c_device_id gt811_id[] = {{"gt811", 0},{ }
};
MODULE_DEVICE_TABLE(i2c, gt811_id);static struct i2c_driver gt811_driver = {.driver = {.name = "gt811",.of_match_table = of_match_ptr(gt811_of_match),},.probe = gt811_probe,.remove = gt811_remove,.id_table = gt811_id,
};module_i2c_driver(gt811_driver);

将gt811_ts.c文件拷贝到内核目录drivers/input/touchscreen/下,并修改drivers/input/touchscreen/目录下的Kconfig和Makefile.
Makefile添加
obj-$(CONFIG_TOUCHSCREEN_GT811) += gt811_ts.o

Kconfig添加

config TOUCHSCREEN_GT811tristate "GT811 I2C touchscreen"depends on I2ChelpSay Y here if you have the Goodix touchscreen (such as oneinstalled in Onda v975w tablets) connected to yoursystem. It also supports 5-finger chip models, which can befound on ARM tablets, like Wexler TAB7200 and MSI Primo73.If unsure, say N.To compile this driver as a module, choose M here: themodule will be called goodix.

添加设备树节点:
修改arch/arm/boot/dts/bcm2708_common.dtsi文件。找到i2c节点添加gt811设备。

nano arch/arm/boot/dts/bcm2708_common.dtsi

添加以下代码:

gt811: gt811@5d {compatible = "goodix,gt811";reg = <0x5d>;
};

这里写图片描述

内核编译:

重新编译内核
内核下载及编译参考http://blog.csdn.net/xdw1985829/article/details/39077611?_t_t_t=0.15414440189488232

执行指令

KERNEL=kernel7
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
make menuconfig

这里写图片描述
选择GT811 I2c touchscreen 为“M”,选择“*”也可以。不过lsmod命令就看不到模块了。保存.config

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 zImage modules dtbs

将sd卡插入ubuntu 挂载到 /media/XX/ 下,升级sd卡的驱动模块、内核、和设备树。

sudo make INSTALL_MOD_PATH=/media/XX/3598ef8e-09be-47ef-9d01-f24cf61dff1d/  modules_install
sudo mv /media/pmj/boot/KERNEL.img /media/XX/boot/KERNEL-backup.img
sudo scripts/mkknlimg arch/arm/boot/zImage /media/XX/boot/KERNEL.img
sudo cp arch/arm/boot/dts/*.dtb /media/pmj/boot/
sudo cp arch/arm/boot/dts/overlays/*.dtb* /media/XX/boot/overlays/
sudo cp arch/arm/boot/dts/overlays/README /media/XX/boot/overlays/

然后启动sd卡。

结束:

可以看到树莓派打印log里包括了反白的内容,说明设备和驱动都挂载成功了!
这里写图片描述
启动后点击触摸屏就会有打印位置信息,这里就不贴图了,因为。。。触摸屏的排线被我玩坏了 T^T
当然,打印的信息只是方便调试,用的时候要屏蔽掉。

这里写图片描述
执行lsmd能看到gt811_ts模块
执行i2cdetect -y 1 能看到之前是0x5d现在已经被占用的UU。
至此已经完成移植。
我用qt做了个测试程序,可以下载:http://download.csdn.net/download/xiaopanpanpanpan/10118464
树莓派qt环境搭建可参考http://blog.csdn.net/shenhuan1104/article/details/53486619


http://www.ppmy.cn/news/797679.html

相关文章

21款AMG GT50改GT63S暗夜版包围、黄色安全带,夜色组件

梅赛德斯-AMG GT四门跑车拥有 纯正赛道基因&#xff0c;兼具独特的跑车设计、强劲的动力表现和极高的日常驾驶舒适性&#xff0c;是AMG‘性能豪华’的完美代表。与生俱来的运动天赋&#xff0c;转瞬之间即可点燃畅快激情&#xff0c;无论城市公路还是人生赛道&#xff0c;对速度…

仙境传说RO:添加自定义道具

仙境传说RO&#xff1a;添加自定义道具 大家好&#xff0c;我是艾西今天和大家聊一下仙境传说RO怎么添加自定义道具。在我们开服时加入一些道具模组等往往会让我们的服务器更有特色以及消费点&#xff0c;那么让我们直接进入正题开始操作&#xff1a;&#xff08;此处我们讲的…

手把手教你云相册项目简易开发 day1 Kafka+IDEA+Springboot+Redis+MySQL+libvips 简单运行和使用

项目的创建 项目采用的是微服务的架构。先创建一个父项目cloud-photo&#xff0c;然后再在module下创建api、image、users的子项目 相关配置&#xff1a; application.yml。此处如果没有redis的话可以先注释掉&#xff0c;因为后面启动需要mysql连接成功和redis服务启动 spr…

装黑苹果接显示器后设置分辨率

装了个黑苹果&#xff0c;设置分辨率时只有两个选项分辨率选项&#xff0c;本来以为是要注入核显&#xff0c;折腾了一上午加下午两个小时&#xff0c;快放弃了&#xff0c;后来终于找到了&#xff0c;按住键盘a/t鼠标点击缩放就出来了&#xff0c;太难受了。记录一下这个坑

[1057]VMware安装的虚拟机窗口如何自适应屏幕大小

vmware是一款非常好用的虚拟机&#xff0c;大部分用户都会用vmware安装各种操作系统&#xff0c;安装后可能会出现一个问题&#xff0c;就是主机屏幕太小&#xff0c;无法完整显示VMware虚拟机界面&#xff0c;这时候就可以设置让VMware自动适应主机窗口&#xff0c;一起来了解…

VMware15 安装 mac OS 10.14 分辨率调整为1920*1080?

安装好黑苹果10.14系统后&#xff0c; 然后在Mac虚拟机里的终端执行下面的命令&#xff0c;执行完之后重启即可 1920*1080分辨率&#xff1a; sudo nvram AC20C489-DD86-4E99-992C-B7C742C1DDA9:width%80%07%00%00 sudo nvram AC20C489-DD86-4E99-992C-B7C742C1DDA9:height…

vmware虚拟机使用多显示器

起因&#xff1a; vmware虚拟机希望使用多显示器 解决&#xff1a; 点击此按钮&#xff0c;“循环使用多个监视器”