[全志平台Android11]CST812T触摸板调试

一、前言

在产品开发中,触摸功能是非常常见的,不同厂家的触摸调试大致相同,但又有点不太一样。这款触摸板送过来时并没有触摸功能在里面,需要在安卓板通过i2c传输数据(厂家提供)到触摸板进行升级。

二、查看引脚分布

可以看到主要有中断脚、i2c、复位脚。 

三、查看规格书

 可以知道这块触摸板有两个i2c地址,未有触摸功能前是0x6A,在进行了升级后i2c地址是0x15。

四、安卓端去升级触摸板

1.编写 i2c写设备代码

//argc1:i2c句柄 argc2:i2c地址(16位)argc3:写buffer argc4:写的数据长度
int write_to_i2c_device(struct i2c_client *client, u16 reg, u8 *buf, u16 len)
{
    int ret;
    u8 *tx_buf;
    //内核中动态分配一个struct i2c_msg 结构体的内存,并将其地址存储在msgs变量中,以便后续使用。
    struct i2c_msg *msgs = kzalloc(sizeof(struct i2c_msg), GFP_KERNEL);
    if (!msgs)
    {
        return -ENOMEM;
    }
    //写buffer需要传输地址+数据
    tx_buf = kzalloc(sizeof(reg) + len, GFP_KERNEL);
    if (!tx_buf)
    {
        kfree(msgs);
        return -ENOMEM;
    }
    //将16位地址分割,将前八位赋值到tx_buf[0]、后八位赋值到tx_buf[1]
    tx_buf[0] = reg >> 8;
    tx_buf[1] = reg & 0xff;
 //因为tx_buf里面的数组是i2c地址,不能覆盖,偏移两个字节把写入的数据buf赋值到数组tx_buf中
    memcpy(tx_buf + 2, buf, len);
    msgs[0].addr = 0x6A;//升级前i2c地址
    msgs[0].flags = 0;//写标志
    msgs[0].len = len + sizeof(reg);//传输长度
    msgs[0].buf = tx_buf;//传输数据

    ret = i2c_transfer(client->adapter, msgs, 1);//发送数据
    kfree(msgs);//释放msgs
    kfree(tx_buf);//释放tx_buf数组
    return ret;
}

2.编写 i2c读设备代码

读一个字节:

//argc1 : i2c句柄 argc2:设备寄存器地址 argc3:寄存器读出数据存储数组
int read_byte_from_i2c_device(struct i2c_client *client, u16 addr, u8 *data)
{
    int ret;
    u8 buf[2];
    //写16位地址,低八位放到buf[0],高八位放到buf[1]
    buf[0] = (u8)(addr >> 8);
    buf[1] = (u8)(addr & 0xff);
    //读设备时需要写地址,读数据,所以分两个msgs发送
    struct i2c_msg msgs[] = {
        {
            .addr = 0x6A,//i2c地址
            .flags = 0,//写标志
            .len = 2,//写数据长度
            .buf = buf,//写buffer
        },
        {
            .addr = 0x6A,//i2c地址
            .flags = I2C_M_RD,//读标志
            .len = 1,//读数据长度
            .buf = data,//读buffer存放
        },
    };

    ret = i2c_transfer(client->adapter, msgs, 2);//发送数据

    if (ret < 0)
    {
        pr_debug("Failed to read from I2C device: %d\n", ret);
        return ret;
    }

    return 0;
}

读两个字节:

int read_2byte_from_i2c_device(struct i2c_client *client, u16 addr, u8 *data)
{
    int ret;
    u8 buf[2];

    buf[0] = (u8)(addr >> 8);
    buf[1] = (u8)(addr & 0xff);

    struct i2c_msg msgs[] = {
        {
            .addr = 0x6A,
            .flags = 0,
            .len = 2,
            .buf = buf,
        },
        {
            .addr = 0x6A,
            .flags = I2C_M_RD,
            .len = 2,
            .buf = data,
        },
    };

    ret = i2c_transfer(client->adapter, msgs, 2);

    if (ret < 0)
    {
        pr_debug("Failed to read from I2C device: %d\n", ret);
        return ret;
    }

    return 0;
}

 我把这个两段代码分开写的,其实是可以合并起来用len去指定,后期可以优化一下

 

3.触摸ic进入boot模式

static int CST812T_enter_bootmode(void)
{
    u8 retryCnt = 10;

    while (retryCnt--)
    {
        u8 cmd[3];
        u8 read_bf[2];
        gpio_direction_output(gpio_rst, 0);//复位脚操作
        gpio_set_value(gpio_rst, 0);//拉低
        mdelay(10);//延时10ms
        gpio_set_value(gpio_rst, 1);//拉高
        mdelay(5);//延时5ms
        // pr_debug("Print 3 states %d %d %d \n",b,c,d);
        cmd[0] = 0xAB;
        //将0xAB写进寄存器0xA001
        int write_flag = write_to_i2c_device(ts->client, 0xA001, cmd, 1);
        mdelay(2);//延时2ms
        //从寄存器0xA003读出数据放在read_bf里
        int read_flag = read_byte_from_i2c_device(ts->client, 0xA003, read_bf);
        pr_debug("write_flag=%d,read_flag=%d,read_bf[0]=%d \n", write_flag, read_flag, read_bf[0]);
        //进行判断
        if (read_bf[0] != 0xC1)
        {
            pr_debug("get 0xA003 value not 0xC1 \n");
            mdelay(2);
            continue;
        }
        else
        {
            pr_debug("get 0xA003 value is 0xC1 \n");
            return 0;
        }
    }
    return -1;
}

4.读取校验和

// 读取IC校验和
static u16 CST812T_read_checksum(void)
{
    union
    {
        u16 sum;
        u8 buf[2];
    } checksum;
    u8 cmd[3];
    u8 retrycnt = 100;
    u8 read_01 = 0;
    //判断触摸ic是否进入boot模式
    if (-1 == CST812T_enter_bootmode())
    {
        return 1;
    }
    cmd[0] = 0x00;
    //向寄存器地址0xA003写0x00
    write_to_i2c_device(ts->client, 0xA003, cmd, 1);
    //延时300ms
    mdelay(300);
    checksum.sum = 0;
    //循环往寄存器地址0xA000读数据放到read_01,直到读到数据0x01
    while (retrycnt--)
    {
        read_byte_from_i2c_device(ts->client, 0xA000, &read_01);
        pr_debug("read_01====%d", read_01);
        if (0x01 == read_01)
        {
            break;
        }
        mdelay(10);
    }
    //往寄存器地址0xA008读数据2个字节数据
    read_2byte_from_i2c_device(ts->client, 0xA008, checksum.buf);
    //合并两组数据
    checksum.sum = (checksum.buf[1] << 8) | checksum.buf[0];
    返回检验和
    return checksum.sum;
}

5.升级固件

// 升级固件
static int CST812T_update(u16 startAddr, u16 len, u8 *src)
{
    u16 sum_len;
    u8 cmd[10];
    u8 read_bf[2];
    u8 retrycnt = 50;
    //再次检验是否进入boot模式
    if (-1 == CST812T_enter_bootmode())
    {
        return -1;
    }
    sum_len = 0;
    do
    {
        if (sum_len >= len)
        {
            return 0;
        }
        cmd[0] = startAddr & 0xFF;
        cmd[1] = startAddr >> 8;
        //往0xA014写进数据
        write_to_i2c_device(ts->client, 0XA014, cmd, 2);
        //往0xA018连写512个字节
        write_to_i2c_device(ts->client, 0XA018, src, 512);
        mdelay(1);
        cmd[0] = 0xee;
        write_to_i2c_device(ts->client, 0XA004, cmd, 1);
        mdelay(100);
        retrycnt = 50;
        //循环读寄存器0XA005的值,直到read_bf[0] == 0x55
        while (retrycnt--)
        {
            read_2byte_from_i2c_device(ts->client, 0XA005, read_bf);
            pr_debug("read_bf=======%d and %d\n", read_bf[0], read_bf[1]);
            if (read_bf[0] == 0x55)
            {
                // success
                mdelay(1);
                break;
            }
            mdelay(5);
        }
        //往后偏移512个字节继续写
        startAddr += 512;
        src += 512;
        sum_len += 512;
    } while (len);
    cmd[0] = 0x00;
    write_to_i2c_device(ts->client, 0XA003, cmd, 1);
    return 0;
}

6.正式升级

// 升级
u8 ctp_hynitron_update(void)
{
    u16 IC_checksum = 0;
    if (0 == CST812T_enter_bootmode())
    {
        if (sizeof(app_bin_debug) > 10)
        {
            u16 startAddr = app_bin_debug[1];
            u16 length = app_bin_debug[3];
            u16 checksum = app_bin_debug[5];

            startAddr <<= 8;
            startAddr |= app_bin_debug[0]; // 固件的起始地址
            length <<= 8;
            length |= app_bin_debug[2]; // 固件的大小
            checksum <<= 8;
            checksum |= app_bin_debug[4]; // 固件的校验和
            pr_debug("hex_file_checksum: 0x%02x \r\n", checksum);
            IC_checksum = CST812T_read_checksum();
            if ((IC_checksum != checksum) && ((startAddr | length) == 0x3C00)) // 读取IC里面的校验和,与固件的不一致时就进入升级流程
            {
                CST812T_update(startAddr, length, (u8 *)app_bin_debug + 6); // 开始执行升级流程
                IC_checksum = CST812T_read_checksum();                      // 读出新烧录进去的校验和
                pr_debug("after update IC_checksum: 0x%02x \r\n", IC_checksum);

                if (IC_checksum != checksum)
                {
                    pr_debug("hynitron update fail! \r\n");
                }
            }
        }
    }
    //再调整一下复位脚
    gpio_direction_output(gpio_rst, 0);
    gpio_set_value(gpio_rst, 0);
    gpio_get_value(gpio_rst);
    mdelay(10);
    gpio_set_value(gpio_rst, 1);
    return 0;
}

将ctp_hynitron_update函数放到probe函数里去执行, 这样操作后触摸板就有触摸功能了,后面就可以按照常规的方法去调试触摸板了。

五、调通触摸板和安卓板的通信

1.dts编写

&twi2 {
	clock-frequency = <100000>;//设置速率为100kHZ
	pinctrl-0 = <&twi2_pins_a>;
	pinctrl-1 = <&twi2_pins_b>;
	pinctrl-names = "default", "sleep";
	twi_drv_used = <0>;
	dmas = <&dma 45>, <&dma 45>;
	dma-names = "tx", "rx";
	status = "okay";
	ekt2101@15 {
    	compatible = "ekt2101_15";
    	reg = <0x15>;//i2c地址
    	gpio-irq = <&pio PB 1 IRQ_TYPE_EDGE_RISING>;//通过原理图可以知道中断脚在PB1	
    	gpio-reset = <&pio PB 6 GPIO_ACTIVE_HIGH>;//通过原理图可以知道复位脚在PB6	
      status = "okay";
	};
};
&pio {
//默认3.3v
...
twi2_pins_a: twi2@0 {
		pins = "PH4", "PH5";//通过原理图可以指定i2c时钟和数据脚在PH4、PH5
		function = "twi2";//i2c2
		drive-strength = <10>;
	};

	twi2_pins_b: twi2@1 {
		pins = "PH4", "PH5";
		function = "gpio_in";
	};
...
};

2.进入中断函数处理相应的数据

//读0x22、0x23、0x24寄存器地址,再判断上报
 CST812T_read_regs(ts->client, 0x22, &ts->cst812_reg_data[0], 1);
        CST812T_read_regs(ts->client, 0x23, &ts->cst812_reg_data[1], 1);
        CST812T_read_regs(ts->client, 0x24, &ts->cst812_reg_data[2], 1);

        if (ts->cst812_reg_data[0] == 0x01)
        { // BACK
            pr_debug("back back back back\n");
            input_report_key(input, KEY_BACK, 1);
            ts->pre_back = 1;
            gvalue_keyboard_verify = (gvalue_keyboard_verify | (0x01 << 5));//上报检验back
        }
        if (ts->cst812_reg_data[0] == 0x00 && ts->pre_back == 1)
        {
            input_report_key(input, KEY_BACK, 0);
            ts->pre_back = 0;
        }
        if (ts->cst812_reg_data[0] == 0x02)
        { // menu
            pr_debug("menu menu menu \n");
            input_report_key(input, KEY_MENU, 1);
            ts->pre_menu = 1;
            gvalue_keyboard_verify = (gvalue_keyboard_verify | (0x01 << 6));//上报检验menu
        }
        if (ts->cst812_reg_data[0] == 0x00 && ts->pre_menu == 1)
        {
            input_report_key(input, KEY_MENU, 0);
            ts->pre_menu = 0;
        }
        if (ts->cst812_reg_data[0] == 0x04)
        { // left
            pr_debug("left left left \n");
            input_report_key(input, KEY_LEFT, 1);
            ts->pre_left = 1;
            gvalue_keyboard_verify = (gvalue_keyboard_verify | (0x01 << 2));//上报检验left
        }
        if (ts->cst812_reg_data[0] == 0x00 && ts->pre_left == 1)
        {
            input_report_key(input, KEY_LEFT, 0);
            ts->pre_left = 0;
        }
        if (ts->cst812_reg_data[0] == 0x40)
        { // right
            pr_debug("right right right \n");
            input_report_key(input, KEY_RIGHT, 1);
            ts->pre_right = 1;
            gvalue_keyboard_verify = (gvalue_keyboard_verify | (0x01 << 3));//上报检验right
        }
        if (ts->cst812_reg_data[0] == 0x00 && ts->pre_right == 1)
        {
            input_report_key(input, KEY_RIGHT, 0);
            ts->pre_right = 0;
        }

        if (ts->cst812_reg_data[0] == 0x08)
        { // up
            pr_debug("up up up \n");
            input_report_key(input, KEY_UP, 1);
            ts->pre_up = 1;
            gvalue_keyboard_verify = (gvalue_keyboard_verify | (0x01 << 0));// 上报检验up
        }
        if (ts->cst812_reg_data[0] == 0x00 && ts->pre_up == 1)
        {
            input_report_key(input, KEY_UP, 0);
            ts->pre_up = 0;
        }

        if (ts->cst812_reg_data[0] == 0x10)
        { // down
            pr_debug("down down down \n");
            input_report_key(input, KEY_DOWN, 1);
            ts->pre_down = 1;
            gvalue_keyboard_verify = (gvalue_keyboard_verify | (0x01 << 1));// 上报检验down
        }
        if (ts->cst812_reg_data[0] == 0x00 && ts->pre_down == 1)
        {
            input_report_key(input, KEY_DOWN, 0);
            ts->pre_down = 0;
        }

        if (ts->cst812_reg_data[0] == 0x20)
        { // open
            pr_debug("enter enter enter \n");
            input_report_key(input, 353, 1);
            ts->pre_ok = 1;
            gvalue_keyboard_verify = (gvalue_keyboard_verify | (0x01 << 4)); // 上报检验 open
        }
        if (ts->cst812_reg_data[0] == 0x00 && ts->pre_ok == 1)
        {
            input_report_key(input, 353, 0);
            ts->pre_ok = 0;
        }
        input_sync(ts->input_dev);
    }

 六、总结

在调试触摸板的时候要关注反应时间,过多的打印会影响触摸的反应时间,这篇推文会持续优化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值