Edit online

核心函数参考示例

5 Dec 2024
Read time: 6 minute(s)

写寄存器函数:用于向 gt911 发送控制命令或数据

static rt_err_t gt911_write_reg(struct rt_i2c_client *dev, rt_uint8_t *data,
                            rt_uint8_t len)
{
    struct rt_i2c_msg msgs;

    msgs.addr = dev->client_addr;       //CTP 从机地址
    msgs.flags = RT_I2C_WR;             //i2c 读写标志,这里是写标志
    msgs.buf = data;                    //要写入的数据
    msgs.len = len;                     //写入的长度

    if (rt_i2c_transfer(dev->bus, &msgs, 1) == 1) {     //i2c 标准读写接口,第一个参数是 i2c 总线句柄,第二个是 msgs,但三个 msgs 的数量
        return RT_EOK;
    } else {
        return -RT_ERROR;
    }
}

读寄存器函数:用于从 gt911 读取状态或数据

static rt_err_t gt911_read_regs(struct rt_i2c_client *dev, rt_uint8_t *reg,
                                rt_uint8_t *data, rt_uint8_t len)
{
    struct rt_i2c_msg msgs[2];

    msgs[0].addr = dev->client_addr;
    msgs[0].flags = RT_I2C_WR;
    msgs[0].buf = reg;                  //要读取的寄存器的地址,一般是 8 位的地址,但如 gt911 就有 16 位,需要每一次写入高 8 位和低 8 位两个 buf
    msgs[0].len = GT911_REGITER_LEN;    //这个与寄存器地址长度对应,8 位写 1,16 位写 2

    msgs[1].addr = dev->client_addr;
    msgs[1].flags = RT_I2C_RD;          //读标志
    msgs[1].buf = data;                 //读取到数据存放位置
    msgs[1].len = len;                  //要读取的长度

    if (rt_i2c_transfer(dev->bus, msgs, 2) == 2) {  //标准的 i2c 读流程都是先写后读,先把要读的寄存器发出去,再读数据,所以这里 msgs 的数量是 2
        return RT_EOK;
    } else {
        return -RT_ERROR;
    }
}

gt911 获得设备 ID 函数编写

static rt_err_t gt911_get_product_id(struct rt_i2c_client *dev,
                                     rt_uint8_t *data, rt_uint8_t len)
{
    rt_uint8_t reg[2];

    reg[0] = (rt_uint8_t)(GT911_PRODUCT_ID >> 8);
    reg[1] = (rt_uint8_t)(GT911_PRODUCT_ID & 0xff);

    if (gt911_read_regs(dev, reg, data, len) != RT_EOK) {
        LOG_E("read id failed");
        return -RT_ERROR;
    }
    return RT_EOK;
}

以 gt911 获得设备 ID 的函数来讲解一下 gt911 读函数的使用:

  • 第一步是定义一个 rt_uint8_t 的数组;

  • 第二步将要读取的寄存器赋值给数组
    • 16 位的 CTP 需将高 8 位赋值给 reg[0],低 8 位赋值给 reg[1]

    • 8 位的 CTP 则只需要把寄存器直接赋给 reg[0]

  • 第三步调用自己编写的 CTP 读函数把相关的参数传递过去。

注:

若某些触控芯片无设备 ID 寄存器,则此函数可直接返回成功状态。

gt911 获得设备信息参数函数

此函数旨在提取触控屏的关键信息,如分辨率、坐标范围。其编写逻辑与获取 ID 相似,利用读寄存器操作完成。

static rt_err_t gt911_get_info(struct rt_i2c_client *dev,
                               struct rt_touch_info *info)

gt911 读坐标点函数

static rt_size_t gt911_read_point(struct rt_touch_device *touch, void *buf,
                                  rt_size_t read_num)

此为核心函数,负责读取触控点坐标及事件类型(如按下、移动、抬起)。利用之前定义的读写函数,结合逻辑判断处理触控事件,由于篇幅过长在这里不一一展开,建议参考 gt911 驱动。

gt911 控制函数

此函数提供了通过命令控制触控面板的能力,涵盖获取 ID、信息查询及参数设置等功能,是驱动对外交互的接口。

static rt_err_t gt911_control(struct rt_touch_device *touch, int cmd, void *arg)

gt911 ops 注册函数

此函数将读点和控制功能注册到触摸驱动框架中,确保系统能正确调用这些操作

static struct rt_touch_ops gt911_touch_ops = {
    .touch_readpoint = gt911_read_point,
    .touch_control = gt911_control,
};

gt911 gpio 引脚定义函数

此函数提供了通过命令控制触控面板的能力,涵盖获取 ID、信息查询及参数设置等功能,是驱动对外交互的接口。

static int rt_gt911_gpio_cfg()
{
    unsigned int g, p;
    long pin;

    // RST
    pin = drv_pin_get(GT911_RST_PIN);       //复位引脚的宏定义
    g = GPIO_GROUP(pin);
    p = GPIO_GROUP_PIN(pin);
    hal_gpio_direction_input(g, p);

    // INT
    pin = drv_pin_get(GT911_INT_PIN);       //中断引脚的宏定义
    g = GPIO_GROUP(pin);
    p = GPIO_GROUP_PIN(pin);
    hal_gpio_direction_input(g, p);
    hal_gpio_set_irq_mode(g, p, 0);

    return 0;
}

gt911 初始化函数

static int rt_hw_gt911_init(const char *name, struct rt_touch_config *cfg)
{
    struct rt_touch_device *touch_device = RT_NULL;         //初始化触摸设备句柄

    touch_device =
        (struct rt_touch_device *)rt_malloc(sizeof(struct rt_touch_device));    //动态分配内存
    if (touch_device == RT_NULL) {
        LOG_E("touch device malloc fail");
        return -RT_ERROR;
    }
    rt_memset((void *)touch_device, 0, sizeof(struct rt_touch_device));     //初始化内存空间为 0

    /* hw init*/
    // rst output 0
    rt_pin_mode(*(rt_uint8_t *)cfg->user_data, PIN_MODE_OUTPUT);        //设置复位引脚的方向
    rt_pin_write(*(rt_uint8_t *)cfg->user_data, PIN_LOW);               //设置输出低电平
    rt_thread_delay(10);                                                //一般设置完输出要延时一段时间,具体多少看规格书

    // irq output 0
    rt_pin_mode(cfg->irq_pin.pin, PIN_MODE_OUTPUT);                     //设置中断引脚的方向
    rt_pin_write(cfg->irq_pin.pin, PIN_LOW);

    rt_thread_delay(2);
    // rst output 1
    rt_pin_mode(*(rt_uint8_t *)cfg->user_data, PIN_MODE_OUTPUT);
    rt_pin_write(*(rt_uint8_t *)cfg->user_data, PIN_HIGH);              //设置输出高电平

    rt_thread_delay(5);
    // rst input
    rt_pin_mode(*(rt_uint8_t *)cfg->user_data, PIN_MODE_INPUT);

    //irq output 0
    rt_pin_mode(cfg->irq_pin.pin, PIN_MODE_OUTPUT);
    rt_pin_write(cfg->irq_pin.pin, PIN_LOW);

    rt_thread_delay(50);

    rt_pin_mode(cfg->irq_pin.pin, PIN_MODE_INPUT);

    gt911_client.bus =
        (struct rt_i2c_bus_device *)rt_device_find(cfg->dev_name);      //寻找 i2c 总线

    if (gt911_client.bus == RT_NULL) {
        LOG_E("Can't find %s device", cfg->dev_name);
        return -RT_ERROR;
    }

    if (rt_device_open((rt_device_t)gt911_client.bus, RT_DEVICE_FLAG_RDWR) !=
        RT_EOK) {                                                       //打开设备
        LOG_E("open %s device failed", cfg->dev_name);
        return -RT_ERROR;
    }

    gt911_client.client_addr = GT911_ADDRESS_HIGH;                      //将 CTP 的设备地址进行赋值

    /* register touch device */
    touch_device->info.type = RT_TOUCH_TYPE_CAPACITANCE;
    touch_device->info.vendor = RT_TOUCH_VENDOR_GT;
    rt_memcpy(&touch_device->config, cfg, sizeof(struct rt_touch_config));
    touch_device->ops = &gt911_touch_ops;

    if (RT_EOK != rt_hw_touch_register(touch_device, name, RT_DEVICE_FLAG_INT_RX, RT_NULL)) {       //注册触摸设备
        LOG_E("touch device gt911 init failed !!!");
        return -RT_ERROR;
    }

    LOG_I("touch device gt911 init success");
    return RT_EOK;
}

此函数完成硬件初始化、I²C 总线配置、设备结构体设置及注册触摸设备等关键步骤。遵循芯片规格书中关于复位和中断引脚的操作时序

gt911 驱动注册函数

static int rt_hw_gt911_port(void)
{
    struct rt_touch_config cfg;
    rt_uint8_t rst_pin;

    rt_gt911_gpio_cfg();

    rst_pin = drv_pin_get(GT911_RST_PIN);               //复位引脚宏定义
    cfg.dev_name = GT911_I2C_CHAN;
    cfg.irq_pin.pin = drv_pin_get(GT911_INT_PIN);       //中断引脚宏定义
    cfg.irq_pin.mode = PIN_MODE_INPUT;
    cfg.user_data = &rst_pin;

    rt_hw_gt911_init("gt911", &cfg);

    return 0;
}

INIT_DEVICE_EXPORT(rt_hw_gt911_port);

通过宏 INIT_DEVICE_EXPORT,驱动在系统启动时自动加载。只需调整引脚宏定义和设备名称,即可轻松适配不同型号的触控芯片,假设硬件 CTP 是 FT7411 则将示例中的 gt911 替换为 ft7411,以及修改对应的引脚宏定义