正点原子IM6基于SDK2.2 > I2C触摸板驱动



#include <string.h>
#include <stdio.h>
#include "fsl_iomuxc.h"
#include "fsl_i2c.h"
#include "fsl_gpio.h"
#include "td_touch.h"
#include "td_ledkeybeep.h"
#include "td_lcd_ui_manager.h"
#include "td_usart1_down_controller.h"
/**********************************************************************************
触摸屏驱动线程,I2S2,GPIO1_9=>CT_INT,GPIO5_9=>CT_RST
**********************************************************************************/
#define ResetTouchRESET() GPIO_WritePinOutput(GPIO5, 9, 0)
#define SetTouchRESET() GPIO_WritePinOutput(GPIO5, 9, 1)
#define ResetTouchINT() GPIO_WritePinOutput(GPIO1, 9, 0)
#define SetTouchINT() GPIO_WritePinOutput(GPIO1, 9, 1)
#define GT1151QSlaveAddr        0x14//7位的设备地址,读写时后面加1为方向位
//只是struct的打包方式字节为1字节对齐
//#pragma pack(1)
//实时命令,命令的发送地址为0x8040
typedef union{
  struct {
    unsigned char Commend;
    unsigned char Data;//与命令对应的数据(不需要下发数据的命令数据区下发 0)
    unsigned char CheckSum;//命令与数据的累加和校验(sum(0x8040~0x8042)==0)
  };
  unsigned char Buffer[3];
} GTRealCommand,*pGTRealCommand;
//配置信息,地址为0x8050-0x813E
typedef union{
  struct {
    unsigned char Version;//bit7 为是否固化标记(0:普通,1:固化),bit0~bit6 为对应的版本号
    unsigned char Datas[235];//配置内容。
    unsigned short Chksum;//配置信息 16 位累加和校验(大端模式:高位存入在低地址)
    unsigned char Fresh;//
  }__attribute__((__packed__));
  unsigned char Buffer[239];
} GTConfigData,*pGTConfigData;
//扩展配置信息,地址为0xBF7B-0xBFFA
typedef union{
  struct {
    unsigned char Datas[126];//扩展配置内容。
    unsigned short Chksum;//配置信息 16 位累加和校验(大端模式:高位存入在低地址)
  };
  unsigned char Buffer[128];
} GTConfigDataEx,*pGTConfigDataEx;
//触点的版本信息,所有寄存器都是只读,0x8140-0x814B
typedef union{
  struct {
    unsigned char ProductID[4];//ASCII 码的产品id,高位在前,大端模式
    unsigned char PatchCID;//Patch 版本号之 CID。CID 为软件型号标记,为 2 位十进制数(软件存储时请用 BCD 码表示),从 00 开始,最大为 26。"0"表示公版,不需要显示出来;1~26 为定制版,转换为字母 A-Z 方式显示
    unsigned char PatchMain;//Patch 版本号之主版本号(2 位压缩 BCD 码)
    unsigned char PatchSub;//Patch 版本号之次版本号(2 位压缩 BCD 码)
    unsigned char MASKMain;//MASK 主版本号
    unsigned char MASKSub;//MASK 副版本号
    unsigned char MASKInternal;//MASK 内部版本号
    unsigned char Bonding;//按钮的相关的绑定,7-4:BondingOption,3-0:Vendor_ID,当前模组选项信息,由电路上的 sensor_opt 1 和 sensor_opt 2 引脚来共同决定标识,当两个选项脚外部连接状态不同时,分别表示 6 种不同的 sensor,如下表所示:
    unsigned char CheckSum;//触点版本信息的校验和
  };
  unsigned char Buffer[12];
} GTPointVersion,*pGTPointVersion;
//触点的多少的配置和是否有触点被按下的状态标记,0x814E地址,可读可写
typedef union{
  struct {
    /*bit7:BufferStatus,1 表示坐标(或按键)已经准备好,主控可以读取;0 表示未就绪,数据无效。当主控读取完坐标后,必须通过 I2C 将此标志(或整个字节)写为 0。
    *bit4:HaveKey,1 表示有按键,0 表示无按键(已经松键)。
    *bit3-0:Number of touch points, 屏上的坐标点个数
    */
    unsigned char Config;
  };
  unsigned char Buffer[1];
} GTTouchNumConfig,*pGTTouchNumConfig;
//额外的4个触摸按钮的状态值,0x819F地址,只读
typedef union{
  struct {
    unsigned char Value;//按键值,KeyValue 的位置并不固定,而是跟在有效坐标的后面。例如 0x8177 是屏上有 5 个坐标时的按键位置,而有 4 个坐标时按键位置则在 0x816F。
  };
  unsigned char Buffer[1];
} GTTouchKeyValue,*pGTTouchKeyValue;
//每个触点坐标及大小结构体,所有寄存器都是只读,0x814F-0x8156,最后一个字节无用,总共连续的10个触点
typedef union{
  struct {
    unsigned char Statue;//bit7:1 表示是高灵敏度触摸坐标;0 表示正常灵敏度触摸坐标。;bit3-0:track id,触摸点 ID 号。
    unsigned short PointX;//触点的X方向的位置,低字节在前
    unsigned short PointY;//触点的Y方向的位置
    unsigned char SizeW;//触点的宽度
    unsigned char SizeH;//触点的高度
  }__attribute__((__packed__));//当设置了这个时无法寻址
  unsigned char Buffer[7];
} GTPointData,*pGTPointData;
//手势信息,全部只读,地址为0x8140-0x814B
typedef union{
  struct {
    unsigned char ProductID[4];//ASCII 码GEST,高位在前
    unsigned char VersionMain;//主版本号
    unsigned char VersionSub;//副版本号
    unsigned char VersionInternal;//内部版本号
    unsigned char MASKMain;//MASK 主版本号
    unsigned char MASKSub;//MASK 副版本号
    unsigned char MASKInternal;//MASK 内部版本号
    unsigned char Bonding;//手势的绑定信息和版本?
    unsigned char CheckSum;//触点版本信息的校验和
  };
  unsigned char Buffer[12];
} GTGestureVer,*pGTGestureVer;
static GTPointData gPointDatas[10];//10个触点的数据
volatile static unsigned int GTPointColour;//当前的触点在渲染时的颜色值,可以带透明色
volatile static unsigned char GTPointCount;//当前的触点的个数
volatile static unsigned char CanOutScreen;//表示是否将触点渲染到显示屏上
volatile static unsigned char CanOutPC;//表示是否将触点信息同步输出到PC
volatile static unsigned char GTPointDataOk;//触点数据准备就绪,中断中将会设置此位
//内部函数
static void TD_Touch_Reset(void);
static void TD_Touch_WriteConfig(void);
static void TD_Touch_RequestClear(void);
static unsigned char TD_Touch_ReadRequest(void);
static unsigned char TD_Touch_ReadPointsStatue(void);
static void GT_INT_IRQHandler(uint32_t giccIar, void *param);
/**********************************************************************************
正点原子imx6ull中的iis触摸屏初始化
**********************************************************************************/
void TD_Touch_Init(void)
{
  IOMUXC_SetPinMux(IOMUXC_UART5_TX_DATA_I2C2_SCL,1U);//1表示设置将I2C2模块与UART5模块交换管脚,否则I2C2不输出信号
  IOMUXC_SetPinMux(IOMUXC_UART5_RX_DATA_I2C2_SDA,1U);
  IOMUXC_SetPinConfig(IOMUXC_UART5_TX_DATA_I2C2_SCL, 0x70B0);
  //IOMUXC_SetPinConfig(IOMUXC_UART5_RX_DATA_I2C2_SDA, 0X70B0);
  IOMUXC_SetPinConfig(IOMUXC_UART5_RX_DATA_I2C2_SDA, 
                      //IOMUXC_SW_PAD_CTL_PAD_SRE_MASK |//设置快速翻转io
                      //IOMUXC_SW_PAD_CTL_PAD_ODE_MASK |//设置开漏输出
                      IOMUXC_SW_PAD_CTL_PAD_PUE_MASK |//设置为keeper,1=pull,0=keeper
                      //IOMUXC_SW_PAD_CTL_PAD_HYS_MASK |//设置开启施密特触发器,可以过滤波形
                      IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |//输出驱动能力设置为R0/6,0=关闭,1=R0_260_Ohm___3_3V__150_Ohm_1_8V__240_Ohm_for_DDR
                      IOMUXC_SW_PAD_CTL_PAD_SPEED(2U) |//速度设置为100mhz,0=50mhz,3=200mhz
                      IOMUXC_SW_PAD_CTL_PAD_PKE_MASK |//pull或者keeper功能使能,两个功能互斥
                      IOMUXC_SW_PAD_CTL_PAD_PUS(1U));//上下拉设置,2=100k上拉,0=100k下拉,1=47k上拉
  //GPIO1_9=>CT_INT,GPIO5_9=>CT_RST
  IOMUXC_SetPinMux(IOMUXC_GPIO1_IO09_GPIO1_IO09,0);
  IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO09_GPIO1_IO09, 
                      //IOMUXC_SW_PAD_CTL_PAD_SRE_MASK |//设置快速翻转io
                      //IOMUXC_SW_PAD_CTL_PAD_ODE_MASK |//设置开漏输出
                      //IOMUXC_SW_PAD_CTL_PAD_PUE_MASK |//设置为keeper,1=pull,0=keeper
                      //IOMUXC_SW_PAD_CTL_PAD_HYS_MASK |//设置开启施密特触发器,可以过滤波形
                      IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |//输出驱动能力设置为R0/6,0=关闭,1=R0_260_Ohm___3_3V__150_Ohm_1_8V__240_Ohm_for_DDR
                      IOMUXC_SW_PAD_CTL_PAD_SPEED(2U) |//速度设置为100mhz,0=50mhz,3=200mhz
                      IOMUXC_SW_PAD_CTL_PAD_PKE_MASK);// |//pull或者keeper功能使能,两个功能互斥
                      //IOMUXC_SW_PAD_CTL_PAD_PUS(1U));//上下拉设置,2=100k上拉,0=100k下拉,1=47k上拉
  IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09,0);
  IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09, 
                      //IOMUXC_SW_PAD_CTL_PAD_SRE_MASK |//设置快速翻转io
                      //IOMUXC_SW_PAD_CTL_PAD_ODE_MASK |//设置开漏输出
                      //IOMUXC_SW_PAD_CTL_PAD_PUE_MASK |//设置为keeper,1=pull,0=keeper
                      //IOMUXC_SW_PAD_CTL_PAD_HYS_MASK |//设置开启施密特触发器,可以过滤波形
                      IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |//输出驱动能力设置为R0/6,0=关闭,1=R0_260_Ohm___3_3V__150_Ohm_1_8V__240_Ohm_for_DDR
                      IOMUXC_SW_PAD_CTL_PAD_SPEED(2U) |//速度设置为100mhz,0=50mhz,3=200mhz
                      IOMUXC_SW_PAD_CTL_PAD_PKE_MASK);// |//pull或者keeper功能使能,两个功能互斥
                      //IOMUXC_SW_PAD_CTL_PAD_PUS(1U));//上下拉设置,2=100k上拉,0=100k下拉,1=47k上拉
  gpio_pin_config_t gp;
  /* GPIO初始化 */
  gp.interruptMode = kGPIO_IntRisingEdge;
  gp.direction = kGPIO_DigitalOutput;
  gp.outputLogic = 1;
  GPIO_PinInit(GPIO1, 9, &gp);//中断pin初始化为高电平
  gp.direction = kGPIO_DigitalOutput;
  gp.outputLogic = 0;
  GPIO_PinInit(GPIO5, 9, &gp);//复位pin初始化为低电平
  //被驱动芯片GT1151Q的上电时序:
  TD_Touch_Reset();
  //复位后将gpio设置为输入
  gp.direction = kGPIO_DigitalInput;
  gp.outputLogic = 1;
  GPIO_PinInit(GPIO1, 9, &gp);
  //设置gpio1-9为中断输入
  SystemInstallIrqHandler(GPIO1_Combined_0_15_IRQn, GT_INT_IRQHandler, NULL);
  EnableIRQ(GPIO1_Combined_0_15_IRQn);
  GPIO_EnableInterrupts(GPIO1, 1U << 9);
  //初始化I2C为主设备
  i2c_master_config_t mc;
  mc.baudRate_Bps = 300000;
  mc.enableMaster = true;
  I2C_MasterInit(I2C2, &mc, CLOCK_GetFreq(kCLOCK_IpgClk) / (CLOCK_GetDiv(kCLOCK_PerclkDiv) + 1U));
  //内部使用的
  GTPointDataOk = false;
  GTPointCount = 0;
  CanOutScreen = false;
  CanOutPC = false;
  GTPointColour = 0x1f0000ff;//带透明色的默认触点颜色
  //60ms以上
  switch(TD_Touch_ReadRequest())
  {
    case 0x01://请求主机发送配置信息
      TD_Touch_WriteConfig();
      break;
    case 0x03://请求主机复位操作
      TD_Touch_Init();
      break;
    case 0xff:
    default://无需处理
      break;
  }
  TD_Touch_RequestClear();//处理完之后清0寄存器
}



/**********************************************************************************
触摸屏GT_INT中断,每次扫描完之后会发送高电平有效的脉冲,
**********************************************************************************/
void GT_INT_IRQHandler(uint32_t giccIar, void *param)
{
  GPIO_ClearPinsInterruptFlags(GPIO1, 1U << 9);
  GTPointDataOk = true;
}
/**********************************************************************************
触摸屏执行复位时序
**********************************************************************************/
void TD_Touch_Reset(void)
{
  //10ms以上
  for(int i = 0;i < 20000;i++) gPointDatas[0].Statue++;
  SetTouchRESET();//复位低电平有效
  //200us以上
  for(int i = 0;i < 500;i++) gPointDatas[0].Statue++;
  ResetTouchINT();//拉低INT表示让芯片恢复到nomorl模式
  //200us以上
  for(int i = 0;i < 500;i++) gPointDatas[0].Statue++;
  SetTouchINT();
  //200us以上
  for(int i = 0;i < 500;i++) gPointDatas[0].Statue++;
  ResetTouchINT();
  //200us以上
  for(int i = 0;i < 500;i++) gPointDatas[0].Statue++;
  SetTouchINT();
  //上电复位时许完成,需要等60ms以上才能开始读写数据
  for(int i = 0;i < 40000;i++) gPointDatas[0].Statue++;
}
/**********************************************************************************
触摸屏写入配置
**********************************************************************************/
void TD_Touch_WriteConfig(void)
{
  static GTConfigData tConfig;
  i2c_master_transfer_t mxf;
  
  tConfig.Version |= 0x80;//固化配置
  tConfig.Version++;//版本增加,否则写入无效
  tConfig.Chksum--;//计算校验和
  
  mxf.slaveAddress = GT1151QSlaveAddr;
  mxf.direction = kI2C_Write;
  mxf.subaddress = 0x8050;
  mxf.subaddressSize = 2;
  mxf.data = tConfig.Buffer;
  mxf.dataSize = sizeof(GTConfigData);
  mxf.flags = kI2C_TransferDefaultFlag;
  
  I2C_MasterTransferBlocking(I2C2, &mxf);
}
/**********************************************************************************
触摸屏读取芯片的请求,地址0X8044
**********************************************************************************/
unsigned char TD_Touch_ReadRequest(void)
{
  static unsigned char buf[2];
  i2c_master_transfer_t mxf;
  
  mxf.slaveAddress = GT1151QSlaveAddr;
  mxf.direction = kI2C_Read;
  mxf.subaddress = 0x8044;//读取的地址
  mxf.subaddressSize = 2;
  mxf.data = buf;
  mxf.dataSize = 1;
  mxf.flags = kI2C_TransferDefaultFlag;
  
  I2C_MasterTransferBlocking(I2C2, &mxf);
  return buf[0];
}
/**********************************************************************************
触摸屏写入Request为0
**********************************************************************************/
void TD_Touch_RequestClear(void)
{
  unsigned char buf[2];
  i2c_master_transfer_t mxf;
  
  buf[0] = 0x00;//写入的数据为0
  
  mxf.slaveAddress = GT1151QSlaveAddr;
  mxf.direction = kI2C_Write;
  mxf.subaddress = 0x8044;
  mxf.subaddressSize = 2;
  mxf.data = buf;
  mxf.dataSize = 1;
  mxf.flags = kI2C_TransferDefaultFlag;
  
  I2C_MasterTransferBlocking(I2C2, &mxf);
}
/**********************************************************************************
触摸屏读取触点个数及相关信息寄存器
**********************************************************************************/
unsigned char TD_Touch_ReadPointsStatue(void)
{
  static unsigned char buf[2];
  i2c_master_transfer_t mxf;
  
  mxf.slaveAddress = GT1151QSlaveAddr;
  mxf.direction = kI2C_Read;
  mxf.subaddress = 0x814E;
  mxf.subaddressSize = 2;
  mxf.data = buf;
  mxf.dataSize = 1;
  mxf.flags = kI2C_TransferDefaultFlag;

  I2C_MasterTransferBlocking(I2C2, &mxf);
  
  return buf[0];
}
/**********************************************************************************
触摸屏读取指定的触点的信息,0-9总共10个
**********************************************************************************/
void TD_Touch_ReadPointData(int pid, pGTPointData point)
{
  i2c_master_transfer_t mxf;
  
  mxf.slaveAddress = GT1151QSlaveAddr;
  mxf.direction = kI2C_Read;
  mxf.subaddress = 0x814f + (pid << 3);
  mxf.subaddressSize = 2;
  mxf.data = point->Buffer;
  mxf.dataSize = sizeof(GTPointData);
  mxf.flags = kI2C_TransferDefaultFlag;

  I2C_MasterTransferBlocking(I2C2, &mxf);
}
/**********************************************************************************
触摸屏读取完触点数据后必须要清除寄存器
**********************************************************************************/
void TD_Touch_PointsStatueClear(void)
{
  unsigned char buf[2];
  i2c_master_transfer_t mxf;
  
  buf[0] = 0x00;//写入的数据
  
  mxf.slaveAddress = GT1151QSlaveAddr;
  mxf.direction = kI2C_Write;
  mxf.subaddress = 0x814e;
  mxf.subaddressSize = 2;
  mxf.data = buf;
  mxf.dataSize = 1;
  mxf.flags = kI2C_TransferDefaultFlag;
  
  I2C_MasterTransferBlocking(I2C2, &mxf);
}
/**********************************************************************************
触摸屏设置是否将触点输出到显示屏,0表示不输出,1表示输出
**********************************************************************************/
void TD_Touch_SetOutToScreen(unsigned char newstatue)
{
  CanOutScreen = newstatue;
}
/**********************************************************************************
触摸屏设置是否将触点输出到pc上位机,0表示不输出,1表示输出
**********************************************************************************/
void TD_Touch_SetOutToPC(unsigned char newstatue)
{
  CanOutPC = newstatue;
}
/**********************************************************************************
触摸屏设置新的触摸颜色
**********************************************************************************/
void TD_Touch_ConfigColor(unsigned int newcolor)
{
  GTPointColour = newcolor;
}
/**********************************************************************************
触摸屏服务
**********************************************************************************/
void TD_Touch_Server(void)
{
  if(GTPointDataOk){
    GTPointDataOk = false;
    unsigned char statue = TD_Touch_ReadPointsStatue();
    GTPointCount = statue & 0x0f;//获取触点的个数
    for(int i = 0;i < 10 && i < GTPointCount;i++){
      TD_Touch_ReadPointData(i, &gPointDatas[i]);
      if(CanOutScreen) TD_LcdUIManager_DrawPoint(gPointDatas[i].Buffer[1] | gPointDatas[i].Buffer[2] << 8, gPointDatas[i].Buffer[3] | gPointDatas[i].Buffer[4] << 8,gPointDatas[i].Buffer[5],GTPointColour);//表示将触点渲染到显示屏上
      if(CanOutPC) TD_Usart1DownController_Send(gPointDatas[i].Buffer, 7);
    }
    TD_Touch_PointsStatueClear();//读取完之后清空寄存器
  }
}
/**********************************************************************************
单独线程方式运行
**********************************************************************************/
void TD_Touch_Run(void)
{
  TD_Touch_Init();
  while(1) TD_Touch_Server();
}