Touchscreen开发实例

本实例提供Touchscreen驱动开发示例,并简要对具体关键点进行开发说明。

加载驱动

基于HDF驱动模型,加载启动Touchscreen驱动,代码形式如下,具体原理可参考HDF驱动开发指南

  1. /* 根据实际需求,实现TouchDispatch */
  2. int32_tTouchDispatch(structHdfDeviceObject*device,int cmd,structHdfSBuf*data,structHdfSBuf*reply)
  3. {
  4. (void)device;
  5. (void)cmd;
  6. if(data == NULL || reply == NULL){
  7. HDF_LOGE("%s: param is null", __func__);
  8. return HDF_FAILURE;
  9. }
  10. return HDF_SUCCESS;
  11. }
  12. /* 根据业务实际需求,实现TouchEntryOpen */
  13. int32_tGt911TouchDriverOpen(structHdfDeviceObject*object)
  14. {
  15. if(object== NULL){
  16. HDF_LOGE("%s: param is null", __func__);
  17. return HDF_ERR_INVALID_PARAM;
  18. }
  19. staticstructIRemoteService service ={
  20. .object={0},
  21. .Dispatch=TouchDispatch,
  22. };
  23. object->service =&service;
  24. return HDF_SUCCESS;
  25. }
  26. /* Touch驱动的总入口Init函数 */
  27. intGt911TouchDriverInit(structHdfDeviceObject*object)
  28. {
  29. /* 具体实现参考下面“执行初始化”示例代码 */
  30. return HDF_SUCCESS;
  31. }
  32. /* HDF驱动入口数据结构 */
  33. structHdfDriverEntry g_gt5p5TouchDevEntry ={
  34. .moduleVersion =1,
  35. .moduleName ="HDF_TOUCHSCREEN",
  36. .Bind=Gt911TouchDriverOpen,
  37. .Init=Gt911TouchDriverInit,
  38. };
  39. HDF_INIT(g_gt5p5TouchDevEntry);

执行初始化

如下初始化流程包含常用的步骤,实际业务开发时,可根据具体需求增删及修改如下初始化中的相关步骤,具体示例如下。

  1. intTouchEntryInit(structHdfDeviceObject*object)
  2. {
  3. (void)object;
  4. /* 创建全局数据结构体,用于存储器件驱动相关信息 */
  5. g_coreData =(TouchCoreData*)OsalMemAlloc(sizeof(TouchCoreData));
  6. if(g_coreData == NULL){
  7. HDF_LOGE("%s: malloc failed", __func__);
  8. return HDF_ERR_MALLOC_FAIL;
  9. }
  10. if(memset_s(g_coreData,sizeof(TouchCoreData),0,sizeof(TouchCoreData))!= EOK){
  11. HDF_LOGE("%s: memset_s fail", __func__);
  12. return;
  13. }
  14. /* 初始化全局数据结构体,将器件驱动相关的配置信息,进行解析赋值 */
  15. TouchConfigInit(g_coreData);
  16. /* 设置GPIO相关的属性及状态 */
  17. if(TouchSetupGpio(g_coreData)){
  18. goto ERR_EXIT;
  19. }
  20. /* 设置并获取I2C BUS操作句柄 */
  21. if(TouchSetupI2c(g_coreData)){
  22. goto ERR_EXIT;
  23. }
  24. /* 创建Task用于监听处理中断业务 */
  25. if(TouchIrqTaskInit(g_coreData)){
  26. goto ERR_EXIT;
  27. }
  28. /* 进行电源初始化配置及操作 */
  29. if(TouchPowerInit(g_coreData)){
  30. goto ERR_EXIT;
  31. }
  32. /* 创建input设备文件 */
  33. (void)mkdir("/dev/input", DEFAULT_DIR_MODE);
  34. if(register_driver(TOUCH_DEVICE,&g_touchDevOps, TOUCH_DEVICE_MODE, NULL)){
  35. HDF_LOGE("%s: register touch dev failed", __func__);
  36. goto ERR_EXIT;
  37. }
  38. HDF_LOGE("%s: exit succ", __func__);
  39. return HDF_SUCCESS;
  40. ERR_EXIT:
  41. if(g_coreData->i2cClient.i2cHandle != NULL){
  42. DeviceHandleDestroy(g_coreData->i2cClient.i2cHandle);
  43. g_coreData->i2cClient.i2cHandle = NULL;
  44. }
  45. OsalMemFree(g_coreData);
  46. g_coreData = NULL;
  47. return HDF_FAILURE;
  48. }

配置基础参数

如下示例中,主要配置了i2c的从地址及总线号、屏幕的报点范围、input设备类型、GPIO管脚号等。具体开发过程,需要根据实际使用的单板及器件进行配置,以下为示例。

  1. staticvoidTouchConfigInit(TouchCoreData*cd)
  2. {
  3. /* init waitqueue for poll */
  4. __init_waitqueue_head(&cd->pollWait);
  5. /* 配置i2c从地址、总线号、报点范围 */
  6. cd->i2cClient.i2cCfg.addr = DRIVER_CHIP_I2C_ADDR;
  7. cd->i2cClient.i2cCfg.busNum = I2C_BUS_NUM;
  8. cd->inputCfg.solutionX = TOUCH_SOLUTION_X;
  9. cd->inputCfg.solutionY = TOUCH_SOLUTION_Y;
  10. /* 配置input设备类型,本例为Touch驱动 */
  11. cd->inputDevType = INDEV_TYPE_TOUCH;
  12. /* 配置reset、irq的gpio号,以及irq的中断触发方式 */
  13. cd->rstGpioNum = RST_GPIO_OFFSET;
  14. cd->intGpioNum = INT_GPIO_OFFSET;
  15. cd->irqFlag = OSAL_IRQF_TRIGGER_FALLING;
  16. }

配置及使用IO管脚

如下为reset和irq管脚的初始化配置,统一使用PAL接口实现对GPIO的操作,具体可参考PLATFORM提供的GPIO接口使用指导

  1. staticintTouchSetupGpio(TouchCoreData*cd)
  2. {
  3. /* 配置int为输入上拉 */
  4. writel(INT_REG_CFG, IO_DEVICE_ADDR(INR_REG_ADDR));
  5. /* 设置int为输入方向 */
  6. int ret =GpioSetDir(cd->intGpioNum, GPIO_DIR_IN);
  7. if(ret != HDF_SUCCESS){
  8. HDF_LOGE("set int to input dir failed, ret %d", ret);
  9. return HDF_FAILURE;
  10. }
  11. /* 设置reset为输出方向 */
  12. ret =GpioSetDir(cd->rstGpioNum, GPIO_DIR_OUT);
  13. if(ret != HDF_SUCCESS){
  14. HDF_LOGE("set reset to output dir failed, ret %d", ret);
  15. return HDF_FAILURE;
  16. }
  17. /* 拉高reset */
  18. ret =GpioWrite(cd->rstGpioNum, GPIO_VAL_HIGH);
  19. if(ret != HDF_SUCCESS){
  20. HDF_LOGE("pull up reset gpio failed, ret %d", ret);
  21. return HDF_FAILURE;
  22. }
  23. OsalMSleep(RESET_HIGH_DELAY);
  24. /* 拉低reset */
  25. ret =GpioWrite(cd->rstGpioNum, GPIO_VAL_LOW);
  26. if(ret != HDF_SUCCESS){
  27. HDF_LOGE("pull down reset gpio failed, ret %d", ret);
  28. return HDF_FAILURE;
  29. }
  30. OsalMSleep(RESET_LOW_DELAY);
  31. /* 再次拉高reset */
  32. ret =GpioWrite(cd->rstGpioNum, GPIO_VAL_HIGH);
  33. if(ret != HDF_SUCCESS){
  34. HDF_LOGE("pull up reset gpio again failed, ret %d", ret);
  35. return HDF_FAILURE;
  36. }
  37. OsalMSleep(RESET_HIGH_DELAY);
  38. HDF_LOGI("%s: succ\n", __func__);
  39. return HDF_SUCCESS;
  40. }

配置I2C的IO管脚复用,以及其操作句柄的获取,可参考PLATFORM提供的I2C接口使用指导

  1. staticintTouchSetupI2c(TouchCoreData*cd)
  2. {
  3. /* config I2C reuse I2C7 */
  4. writel(I2C_REG_CFG, IO_DEVICE_ADDR(I2C7_DATA_REG_ADDR));
  5. writel(I2C_REG_CFG, IO_DEVICE_ADDR(I2C7_CLK_REG_ADDR));
  6. /* get i2c handle */
  7. cd->i2cClient.i2cHandle = I2cOpen(cd->i2cClient.i2cCfg.busNum);
  8. if(cd->i2cClient.i2cHandle == NULL){
  9. HDF_LOGE("open i2c failed");
  10. return HDF_FAILURE;
  11. }
  12. HDF_LOGI("%s: exit succ", __func__);
  13. return HDF_SUCCESS;
  14. }

创建中断处理TASK

创建用于获取及处理报点数据的Task

  1. staticintTouchIrqTaskInit(TouchCoreData*cd)
  2. {
  3. /* 初始化消息事件 */
  4. int ret = LOS_EventInit(&g_touchEventIrq);
  5. if(ret != HDF_SUCCESS){
  6. HDF_LOGE("LOS_EventInit failed, ret = %d", ret);
  7. return HDF_FAILURE;
  8. }
  9. /* 注册中断 */
  10. ret =GpioSetIrq(cd->intGpioNum, cd->irqFlag,IrqHandle, cd);
  11. if(ret !=0){
  12. HDF_LOGE("register irq failed, ret %d", ret);
  13. return ret;
  14. }
  15. /* 使能中断 */
  16. ret =GpioEnableIrq(cd->intGpioNum);
  17. if(ret != HDF_SUCCESS){
  18. HDF_LOGE("enable irq failed, ret %d", ret);
  19. return HDF_FAILURE;
  20. }
  21. /* 创建中断处理Task,其负责input event数据的读取和解析 */
  22. TSK_INIT_PARAM_S handleEventTask ={0};
  23. UINT32 handleEventTaskID;
  24. handleEventTask.pfnTaskEntry =(TSK_ENTRY_FUNC)TouchHandleEvent;
  25. handleEventTask.uwStackSize = TASK_SIZE;
  26. handleEventTask.pcName ="HdfTouchEventHandler";
  27. handleEventTask.usTaskPrio = TASK_PRIO_LEVEL_TWO;
  28. handleEventTask.uwResved = LOS_TASK_STATUS_DETACHED;
  29. if(LOS_TaskCreate(&handleEventTaskID,&handleEventTask)!= HDF_SUCCESS){
  30. HDF_LOGE("%s: LOS_TaskCreate fail, HdfTouchEventHandler", __func__);
  31. return HDF_FAILURE;
  32. }
  33. HDF_LOGI("%s: exit succ", __func__);
  34. return HDF_SUCCESS;
  35. }

中断响应函数

  1. int32_tIrqHandle(uint16_t irqGpio,void*data)
  2. {
  3. HDF_LOGD("%s: irq is triggered, irqGpio = %d", __func__, irqGpio);
  4. (void)data;
  5. /* 关闭中断响应 */
  6. int ret =GpioDisableIrq(irqGpio);
  7. if(ret != HDF_SUCCESS){
  8. HDF_LOGE("disable irq failed, ret %d", ret);
  9. }
  10. (void)LOS_EventWrite(&g_touchEventIrq, EVENT_SYNC);
  11. return HDF_SUCCESS;
  12. }

Task处理函数

  1. staticvoidTouchHandleEvent(void)
  2. {
  3. InputEventDataevent;
  4. TouchCoreData*cd =GetCoreData();
  5. (void)memset_s(&event,sizeof(InputEventData),0,sizeof(InputEventData));
  6. while(true){
  7. /* 读取同步事件 */
  8. int ret = LOS_EventRead(&g_touchEventIrq, EVENT_SYNC, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
  9. if(ret != EVENT_SYNC){
  10. OsalMSleep(TASK_SLEEP_MS);
  11. }else{
  12. /* 报点事件的读取及解析 */
  13. if(EventHandler(cd,&event)== HDF_SUCCESS){
  14. TouchWakeupPoll();
  15. }
  16. }
  17. /* 使能中断 */
  18. ret =GpioEnableIrq(cd->intGpioNum);
  19. if(ret != HDF_SUCCESS){
  20. HDF_LOGE("enable irq failed, ret %d", ret);
  21. }
  22. if(cd->shouldStop){
  23. HDF_LOGE("%s: the event task should be stoped", __func__);
  24. break;
  25. }
  26. }
  27. }

创建及操作设备文件

设备文件的创建及其操作接口,本处仅举例Ioctl的使用

  1. /* 创建设备文件 */
  2. register_driver(TOUCH_DEVICE,&g_touchDevOps, TOUCH_DEVICE_MODE, NULL);
  3. /* 文件操作ops */
  4. staticconststruct file_operations_vfs g_touchDevOps ={
  5. .open =TouchOpen,
  6. .close =TouchClose,
  7. .read = NULL,
  8. .write = NULL,
  9. .seek = NULL,
  10. .ioctl =TouchIoctl,
  11. .mmap = NULL,
  12. #ifndef CONFIG_DISABLE_POLL
  13. .poll =TouchPoll,
  14. #endif
  15. .unlink = NULL,
  16. };
  17. /* Ioctl的操作方式 */
  18. staticintTouchIoctl(FAR struct file *filep,int cmd,unsignedlong arg)
  19. {
  20. int ret;
  21. if(filep == NULL){
  22. HDF_LOGE("%s: param is null", __func__);
  23. return HDF_ERR_INVALID_PARAM;
  24. }
  25. switch(cmd){
  26. case INPUT_IOCTL_GET_EVENT_DATA:
  27. ret =IoctlReadInputEvent(arg);
  28. break;
  29. case INPUT_IOCTL_GET_DEVICE_TYPE:
  30. ret =IoctlGetDeviceType(arg);
  31. break;
  32. case INPUT_IOCTL_GET_CHIP_INFO:
  33. ret =IoctlGetChipInfo(arg);
  34. break;
  35. default:
  36. ret =0;
  37. HDF_LOGE("%s: cmd unknown, cmd = 0x%x", __func__, cmd);
  38. break;
  39. }
  40. return ret;
  41. }

主要数据结构

  1. /* 触摸事件 */
  2. typedefenum{
  3. EVENT_DOWN,
  4. EVENT_UP,
  5. EVENT_CONTACT,
  6. }EventType;
  7. /* I2C配置信息 */
  8. typedefstruct{
  9. unsignedshort busNum;
  10. unsignedshort addr;
  11. } I2cConfig;
  12. /* I2C客户端信息 */
  13. typedefstruct{
  14. structDevHandle*i2cHandle;
  15. I2cConfig i2cCfg;
  16. }InputI2cClient;
  17. /* 输入事件数据结构体 */
  18. typedefstruct{
  19. int x;
  20. int y;
  21. int z;
  22. int definedEvent;
  23. int fingerID;
  24. int pointNum;
  25. struct timeval timeStamp;
  26. bool moreDataFlag;
  27. }InputEventData;
  28. /* 器件驱动核心数据结构体 */
  29. typedefstruct{
  30. unsignedint inputDevType;
  31. wait_queue_head_t pollWait;
  32. bool readFinishFlag;
  33. bool shouldStop;
  34. structInputConfig inputCfg;
  35. InputI2cClient i2cClient;
  36. int intGpioNum;
  37. int rstGpioNum;
  38. unsignedint irqFlag;
  39. unsignedint powerStatus;
  40. char chipInfo[CHIP_INFO_LEN];
  41. char vendorName[VENDOR_NAME_LEN];
  42. char chipName[CHIP_NAME_LEN];
  43. }TouchCoreData;