海思35xx实现GT911触摸屏功能「建议收藏」

海思35xx实现GT911触摸屏功能「建议收藏」海思35xx通过gpio模拟i2c实现GT911触摸功能1.遇到的问题地址选配后一直不对,首先检测硬件问题,然后通过调试驱动部分,打印调试从设备给的ack(没有逻辑分析仪);发现寄存器地址一直为FF或00,检查发现GT911地址均为16bit,而读写i2c接口是8位的;成功后点击触摸板点击位置与实际不一致;可以进行坐标转换;2.网上下载GT91xx编程指南文件电容触摸芯片GT911Datasheet文件3.Datasheet分析(1)gpio模拟时,可能需要注意这个延时时间;

大家好,又见面了,我是你们的朋友全栈君。

海思35xx通过gpio模拟i2c实现GT911触摸功能

1.遇到的问题

  1. 地址选配后一直不对,首先检测硬件问题,然后通过调试驱动部分,打印调试从设备给的ack(没有逻辑分析仪);发现寄存器地址一直为FF或00,检查发现GT911地址均为16bit,而读写i2c接口是8位的;
  2. 成功后点击触摸板点击位置与实际不一致;可以进行坐标转换;

2.网上下载

GT91xx编程指南文件
电容触摸芯片GT911 Datasheet 文件

3.Datasheet 重点部分

(1) gpio模拟时,可能需要注意这个延时时间;
海思35xx实现GT911触摸屏功能「建议收藏」
(2) 选择地址为0x28/0x29或0xBA/0xBB时序
海思35xx实现GT911触摸屏功能「建议收藏」

4.部分代码

(1) 部分寄存器定义

#define GT_CMD_WR 0x28 //写地址
//#define GT_CMD_RD 0x29 //读命令 我的驱动内部逻辑已处理,仅需要写地址就可以了

//GT91xx 部分寄存器定义
#define GT_CTRL_REG 0X8040 //GT911控制寄存器
#define GT_CFGS_REG 0X8047 //GT911配置起始地址寄存器
#define GT_CHECK_REG 0X80FF //GT911校验和寄存器
#define GT_FRESH_REG 0X8100 //配置已更新标志
#define GT_PID_REG 0X8140 //GT911产品ID寄存器
#define GT_FIRMVERSION_REG 0x8144 //固件版本

#define GT_GSTID_REG 0X814E //GT911当前检测到的触摸情况
#define GT_TP1_REG 0X8150 //第一个触摸点数据地址
#define GT_TP2_REG 0X8158 //第二个触摸点数据地址
#define GT_TP3_REG 0X8160 //第三个触摸点数据地址
#define GT_TP4_REG 0X8168 //第四个触摸点数据地址
#define GT_TP5_REG 0X8170 //第五个触摸点数据地址

const u32 GT911_TPX_TBL[5]={ 
   GT_TP1_REG,GT_TP2_REG,GT_TP3_REG,GT_TP4_REG,GT_TP5_REG};

(2) 配置GT911从设备地址0x28/0x29或0xBB/0xBA

void TouchScreen::GT911_INT(u8 cmd)
{ 
   
    if(cmd){ 
   
        CGpio::Instance()->SetGpio(13,5,1,1);
    }else{ 
   
        CGpio::Instance()->SetGpio(13,5,1,0);
    }
}

void TouchScreen::GT911_RST(u8 cmd)
{ 
   
    if(cmd){ 
   
        CGpio::Instance()->SetGpio(6,3,1,1);
    }else{ 
   
        CGpio::Instance()->SetGpio(6,3,1,0);
    }
}

//我选的是0x28/0x29
void TouchScreen::goodix_init()
{ 
     
    GT911_RST(0);
    GT911_INT(0);
    msleep(50);

    GT911_INT(1);
    usleep(200);

    GT911_RST(1);
    msleep(10);

    GT911_INT(0);
    msleep(80);

    Hi_Gpio_SetDir(13,5,0);//GPIO13_5设为输入
    msleep(60);
    return;
}

(3) i2c写接口及驱动接口参考

	// gpio_i2c2_read 、 gpio_i2c2_write驱动部分参考如下:
	EXPORT_SYMBOL(gpio_i2c2_read);
	unsigned int gpio_i2c2_read(unsigned char devaddress, unsigned short address, int num_bytes)
	{ 
   
	    unsigned char rxdata;
		unsigned int  ret = 0x00;
	    int i;
	    
	    i2c_start_bit(); //gpio模拟i2c 略
	    i2c_send_byte((unsigned char)(devaddress));
	    i2c_receive_ack();
	   
	    i2c_send_byte((unsigned char)((address >> 8) & 0xff));
	    i2c_receive_ack();

	    i2c_send_byte((unsigned char)(address & 0xff));
	    i2c_receive_ack(); 
		
	    i2c_start_bit();
	    i2c_send_byte((unsigned char)(devaddress) | 1); //只需要写地址的原因在这里,完全可以其他处理;
	    i2c_receive_ack();
	    
		for (i=0; i<num_bytes-1; i++) { 
   
			rxdata = i2c_receive_byte();
			//i2c_send_ack();
			ret |= rxdata;
			ret <<= 8;
		}
	    rxdata = i2c_receive_byte();
		// i2c_send_ack();
	    i2c_stop_bit();
		ret |= rxdata;
			
		// printk("dev=%x, reg =%x, rxd=%x\n", devaddress, address, ret);
	    return ret;
	}

	EXPORT_SYMBOL(gpio_i2c2_write);
	void gpio_i2c2_write(unsigned char devaddress, unsigned short address, unsigned int data, int num_bytes)
	{ 
   
		int i;

	    i2c_start_bit();
	    i2c_send_byte((unsigned char)(devaddress));
	    i2c_receive_ack();
	   
	    i2c_send_byte((unsigned char)((address >> 8) & 0xff));
	    i2c_receive_ack();
	    
	    i2c_send_byte((unsigned char)(address & 0xff));
	    i2c_receive_ack();
	    
		for (i=0; i<num_bytes; i++) { 
   
			i2c_send_byte((unsigned char)((data >> (i*8)) & 0xff)); 
			i2c_receive_ack();
		}
		// i2c_send_byte((unsigned char)((data >> (i*8)) & 0xff)); 
	    i2c_stop_bit();
	}
 	

	// ioctl 操作对应的驱动接口如下:
	long gpioi2c_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
	{ 
   
		...
		case GPIO_I2C_READ_SHORT: 
			val = *(unsigned int *)arg;
			device_addr = (val&0xff000000)>>24;
			reg_addr = (val&0xffff00)>>8;
			
			reg_val = gpio_i2c2_read(device_addr, reg_addr, 2);
			*(unsigned int *)arg = reg_val;		
			break;	
		case GPIO_I2C_WRITE_SHORT:
			val = *(unsigned int *)arg;
			device_addr = (val&0xff000000)>>24;
			reg_addr = (val&0xffff00)>>8;
			
			reg_val = val&0xffff;
			gpio_i2c2_write(device_addr, reg_addr, reg_val, 2);
			break;		
	}

	//读写16位寄存器的接口;
	int xxx::writeI2c16(int devaddr, int reg, int data)
	{ 
   
	    int fd = -1;
	    int ret =0;
	    int value;

	    fd = open("/dev/gpioi2c", 0);
	    if(fd<0)
	    { 
   
	        printf("Open gpioi2c error!\n");
	        return -1;
	    }

	    value = ((devaddr&0xff)<<24) | ((reg&0xffff)<<8) | (data&0xffff);
	    ret = ioctl(fd, GPIO_I2C_WRITE_SHORT, &value);

	    close(fd);
	    return ret;
	}

(4) 触摸屏初始化

void TouchScreen::I2C_init()
{ 
   
    //system("himm 0x120F08E0 0x230"); //SDA 上拉,高速
	//system("himm 0x120F08E4 0x230"); //SCL
    SetGpio(12,7,1,1);
    SetGpio(12,6,1,1);
}

//下面的goodix_send_cfg如下:我没用到,不知道正确与否
int TouchScreen::goodix_send_cfg()
{ 
   
    u8 sum[2] = { 
   0};

    static unsigned char imps2_param [] =
    { 
   
       0x69,0x00,0x04,0x58,0x02,0x05,0x0D,0x00,0x01,0x0A,0x1E,0x0F,0x64,0x46,0x03,
       0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8C,0x2E,0x0E,
       0x3C,0x3E,0x61,0x07,0x00,0x00,0x00,0x02,0x02,0x1D,0x00,0x01,0x00,0x00,0x00,
       0x03,0x00,0x00,0x00,0x00,0x00,0x28,0x62,0x94,0xC5,0x02,0x07,0x00,0x00,0x04,
       0xA1,0x2B,0x00,0x8C,0x34,0x00,0x7D,0x3E,0x00,0x6F,0x4B,0x00,0x66,0x59,0x00,
       0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1A,0x18,0x16,0x14,0x12,0x10,0x0E,
       0x0C,0x0A,0x08,0x06,0x04,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0F,
       0x10,0x12,0x13,0x14,0x16,0x18,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x24,0x26,
       0x28,0x29,0x2A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
       0x00,0x00,0x00,0x00,0x38,0x01
    };//厂家初始化序列

    for(int i = 0; i < sizeof(imps2_param); i++)
    { 
   
       writeI2c16(GT_CMD_WR,GT_CFGS_REG+i,imps2_param[i]);//写入配置 0x8047~0x8100 共186个
        sum[0] += imps2_param[i];
        readI2c16(GT_CMD_WR,GT_CFGS_REG+i);

    }

    sum[0] = (~sum[0])+1;//校验和为补码,看手册
    sum[1]=1;

    writeI2c16(GT_CMD_WR,GT_CHECK_REG,sum[0]);//写入校验和
    writeI2c16(GT_CMD_WR,GT_FRESH_REG,sum[1]);//配置更新标记
    msleep(10);

    return 0;
}

 void TouchScreen::TouchScreenInit()
{ 
   
   SetGpio(6,3,1,0); //rst init 具体看硬件io口
   SetGpio(13,5,1,0); //INT init
   //system("himm 0x120F09B4 0x330");
   I2C_init(); //好像没用处
   goodix_init(); // IIC地址选择

   writeI2c16(GT_CMD_WR,GT_CTRL_REG,0x02);//软复位GT911
   writeI2c16(GT_CMD_WR,GT_GSTID_REG,0);
   u32 id = readI2c16(GT_CMD_WR,GT_CFGS_REG);
   if((id & 0xff) < 0x69) //0x69为配置中的首位
   { 
   
       //更新GT911寄存器配置
       goodix_send_cfg();//厂家提供,没有不要乱配,可能导致不能用;
   }
   writeI2c16(GT_CMD_WR,GT_CTRL_REG,0x00);//结束软复位
   writeI2c16(GT_CMD_WR,GT_GSTID_REG,0);//多写几次无所谓
}

(4) 主循环

void TouchScreen::PthreadProc()
{ 
      
    unsigned int t = 0 ;
    int touchStatus = 0;

    u8 buf[5];
    time_t tim, last_monitor_tim = 0;
    memset(&keyInfo,0,sizeof(keyInfo));

    while(1) //轮询方式
    { 
   
        if(0 == (t++)%50)
        { 
           
            if(touchStatus & 0x80) //&& (((touchStatus & 0xF) > 0) && ((touchStatus & 0xF) < 6)))//数据准备好可读
            { 
   
                if(touchStatus & 0x0F)//触摸点数大于1
                { 
   
                    for(int i = 0; i < 1; i++){ 
    
                        for(int j = 0; j < 5; j++){ 
   
                            buf[j] = readI2c16(GT_CMD_WR,GT911_TPX_TBL[i]+j);
                        }
                    }

                    if((touchStatus & 0xff) == 0x81) //单击
                    { 
   
                        msleep(140);//延时去抖
                        //do something
                    }
                    else if((touchStatus & 0xff) == 0x82) //双击
                    { 
   
                        msleep(100);//延时去抖
                        //do something
                    }

                    //逻辑与物理坐标转换
                    touchPos.s32XPos = (buf[0] + (buf[1] << 8)) * m_TmpWidth / m_phyWidth;
                    touchPos.s32YPos = (buf[2] + (buf[3] << 8)) * m_TmpHeight / m_phyHeight;
                    
                   //处理坐标 ... 
                }
                writeI2c16(GT_CMD_WR,GT_GSTID_REG,0x00);//将此标志清零
             }
            else
            { 
   
                msleep(150);        
            }
         }
    }
}

5.说明

(1) 本文为记录所用,代码仅供参考,错误地方欢迎指正;
(2) 主循环可以用轮询或中断方式
(3) 代码中gpio具体看硬件手册

6. 参考

https://blog.csdn.net/qlexcel/article/details/99696108
https://www.cnblogs.com/DarkBright/p/10730346.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/150685.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 计算机分子模拟聚乙烯,高分子物理实验思考题@中科大.pdf[通俗易懂]

    计算机分子模拟聚乙烯,高分子物理实验思考题@中科大.pdf[通俗易懂]高分子物理实验思考题@中科大1.为什么在计算机模拟实验1(用“分子模拟”软件构建全同立构聚丙烯分子、聚乙烯分子并计算它们末端的直线距离)中我们一再把第一个碳原子到最后一个碳原子的距离叫做末端距离,而不称通常所说的根均方末端距?2.你对计算机在高分子科学中的应用有多少了解?3.在考虑高分子链内旋转空间位阻时,高分子链的尺寸如何变化?4.在“二维高分子链形态的计算机模拟”实验中采用的是改进后…

    2022年5月25日
    30
  • PHP如何解决网站大流量与高并发的问题(四)「建议收藏」

    PHP如何解决网站大流量与高并发的问题(四)

    2022年2月9日
    38
  • 三菱fx3u步进梯形图程序实例_三菱步进梯形图

    三菱fx3u步进梯形图程序实例_三菱步进梯形图三菱FX2NPLC步进指令与步进梯形图顺序流程的SFC表示选择流程的SFC表示选择性分支选择性汇合并行流程的SFC表示并行性分支并行性汇合小结顺序流程的SFC表示选择流程的SFC表示选择性分支选择性汇合并行流程的SFC表示并行性分支并行性汇合小结实际上在这里,选择性可以看做是传统电路上的并联(满足条件),而并行性就可以看做是传统电路上的串联(必须全部满足)…

    2022年9月10日
    0
  • CentOS7下使用yum安装MariaDB

    CentOS7下使用yum安装MariaDBCentOS6或早期的版本中提供的是MySQL的服务器/客户端安装包,但CentOS7已使用了MariaDB替代了默认的MySQL。MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。全部删除MySQL/MariaDBMySQL已经…

    2022年6月3日
    30
  • javascript中function用法_年终总结反思不足之处

    javascript中function用法_年终总结反思不足之处整理了JavaScript中函数Function的各种,感觉函数就是一大对象啊,各种知识点都能牵扯进来,不单单是 Function 这个本身原生的引用类型的各种用法,还包含执行环境

    2022年8月4日
    3
  • 单射、满射、双射(一一映射)

    单射、满射、双射(一一映射)设函数f:X->Y,y=f(x)单射:任给x1和x2属于X,若x1≠x2,则f(x1)≠f(x2),称f为单射满射:任给y属于Y,都存在x属于X使得f(x)=y,称f为满射双射:若f既是单射又是满射,称f为双射,也叫一一对应。

    2022年5月1日
    333

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号