1. 硬件层
触摸屏硬件:触摸屏通常包括电容式或电阻式触摸屏,它们通过感应手指的触摸来产生信号。电容式触摸屏利用人体的电流感应工作,而电阻式触摸屏则通过压力改变电阻值来检测触摸。
传感器与接口:触摸屏包含多个触摸传感器,这些传感器通过总线接口(如I2C、SPI等)与主控芯片通信,将触摸数据(如位置、压力等)传输给软件层。
2. 软件层
输入子系统:Android内核中的输入子系统是一个关键组件,负责处理来自各种输入设备的数据,包括触摸屏。输入子系统从触摸屏驱动程序接收触摸数据,并将其转换为标准的输入事件,然后传递给上层应用程序。
触摸屏驱动程序:触摸屏驱动程序是Android内核中实现触摸屏功能的具体实现。它负责与硬件层通信,读取触摸传感器的数据,并通过输入子系统将其上报给系统。
3 . 触摸屏驱动流程
-
初始化与配置
设备树(DTS)配置:在设备树文件中配置触摸屏相关的硬件参数,如GPIO、I2C地址等。
驱动程序加载:在系统启动时,根据设备树配置加载触摸屏驱动程序。驱动程序会进行必要的初始化工作,如设置GPIO引脚、配置I2C接口等。
1.1 设置GPIO引脚:
打开 vendor\mediatek\proprietary\scripts\DrvGen.exe
选择 cendor\mediatek\proprietary\bootable\bootloader\lk\target\ $ (project) \dct\dct\codegen.dws 配置文件1.2 创建ft5x16,将供应商提供的驱动驱动资料拷贝到该目录下;
1.3 修改配置文件:CUSTOM_KERNEL_TOUCHPANEL其值由改为ft5x16,表明对应ft5x16子目录;
打开ft5x16.c文件,修改一下:
static struct i2c_board_info __initdata ft5x16_i2c_tpd={
I2C_BOARD_INFO("ft5x16", (0x70>>1))}; //"ft5x16"为设备名 ,设备地址为高7位
static struct tpd_driver_t tpd_device_driver = {
.tpd_device_name = "FT5x16",
.tpd_local_init = tpd_local_init,
.suspend = tpd_suspend,
.resume = tpd_resume,
#ifdef TPD_HAVE_BUTTON
.tpd_have_button = 1,
#else
.tpd_have_button = 0,
#endif
};
/* called when loaded into kernel */
static int __init tpd_driver_init(void) {
printk("MediaTek FT5x16 touch panel driver init\n");
/* 注册板级设备信息 */
i2c_register_board_info(IIC_PORT, &ft5x16_i2c_tpd, 1); //IIC_PORT表示i2c控制器号,由电路原理图可知TP设备连接到i2c控制器0,ft5x16_i2c_tpd为i2c设备结构,1表示该i2c_board_info个数
if(tpd_driver_add(&tpd_device_driver) < 0)
printk("add FT5x16 driver failed\n");
return 0;
}
1.4 I2C通信
新驱动编译进内核,启动内核后,我们怎样验证i2c接口能够正常通信呢?
系统启动后通过串口或adb shell进入系统命令行窗口,查询/sys/bus/i2c/devices目录下是否有0-0038信息,查询/sys/bus/i2c/drivers目录下是否存在‘ft5x16’设备名;先保证i2c能够正常通信;
1.5 中断触发
中断注册函数:
mt_eint_registration(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE, tpd_eint_interrupt_handler, 1);
//tpd_eint_interrupt_handler函数为中断回调函数
1.6 数据上报
当触摸屏产生中断的时候就会调用到该接口;然后在中断处理函数中唤醒运行在子线程中的等待队列,再通过子线程获取TP数据并上报到系统;
static DECLARE_WAIT_QUEUE_HEAD(waiter); //初始化等待队列
thread = kthread_run(touch_event_handler, 0, TPD_DEVICE); //新建线程
static int touch_event_handler(void *unused)
{
......
do
{
mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);
set_current_state(TASK_INTERRUPTIBLE);
wait_event_interruptible(waiter,tpd_flag!=0); //等待队列进入休眠,等待唤醒
tpd_flag = 0;
set_current_state(TASK_RUNNING);
......
if (tpd_touchinfo(&cinfo, &pinfo)) //获取TP数据
{
//TPD_DEBUG("point_num = %d\n",point_num);
TPD_DEBUG_SET_TIME;
if(point_num >0)
{
for(i =0; i<point_num; i++)//only support 3 point
{
cinfo.x[i] = cinfo.x[i];
cinfo.y[i] = cinfo.y[i];
tpd_down(cinfo.x[i], cinfo.y[i], cinfo.id[i]); //上报按下数据
printk(KERN_DEBUG"----calibration----- X:%4d, Y:%4d, P:%4d \n", cinfo.x[i], cinfo.y[i], cinfo.id[i]);