应用层操作I2C(MTK)

本文介绍了在MTK平台上,通过用户空间读写I2C设备遇到的问题及解决方案。内容涉及I2C驱动的配置、权限问题、MTK内核i2c_msg结构体差异、repeated start信号的处理,以及数据存储逻辑的分析。通过对内核代码的跟踪和理解,成功解决了I2C读取数据的不一致问题。

linux 驱动中I2C设备驱动有两种,其一为用户模式设备驱动,依赖i2c子系统中的i2c-dev驱动,在用户空间去读写i2c设备,另一种就是普通的设备驱动。本文主要讨论第一种:在用户空间读写I2C设备。

首先关于用户空间读写I2C的基本操作, 《i2c驱动之调用ioctl函数进行读写at24c08》 这篇文章看一下就好,不重复说了。然后是MTK平台,I2C驱动的分析,可以看一下 《MTK I2C驱动代码分析》

下面开始干活:
首先打开文件

	fd=open("/dev/i2c-2",O_RDWR);

发现 /dev 路径下并没有i2c-2这个节点,查看 (project)/kernel-3.18/drivers/i2c 下的Makefile

obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o

而在 (project)/kernel-3.18/arch/arm64/configs/(project)_defconfig中默认情况下,CONFIG_I2C_CHARDEV 这个宏是没有打开的。

# CONFIG_I2C_CHARDEV is not set

把这个宏打开就可以了。这时候又会引出一个权限问题,这个根据SEAndroid的规则,申请相应的权限就好,否则第三方应用无法操作 /dev/i2c-2 这个节点。

然后继续,设置i2c_rdwr_ioctl_data.msgs参数

	vcnl4200_i2c_data.nmsgs = 2;
	vcnl4200_i2c_data.msgs[0].len = 1;
	vcnl4200_i2c_data.msgs[0].flags = 0; //write
	vcnl4200_i2c_data.msgs[0].addr = 0x6B;
    data[0][0]=0x00;
    vcnl4200_i2c_data.msgs[0].buf=data[0];
    
	vcnl4200_i2c_data.msgs[1].len = 2;
	vcnl4200_i2c_data.msgs[1].flags = I2C_M_RD;  //read
	vcnl4200_i2c_data.msgs[1].addr = 0x6B;
    data[1][0]=0;
    data[1][1]=0;
    vcnl4200_i2c_data.msgs[1].buf=data[1];

结果发现无论怎样设置都没有数据输出,即I2C没有波形输出,但是抓log又没有看到报错。最后发现,MTK的内核i2c_msg结构体与linux标准的不一样:

struct i2c_msg {
   
   
	__u16 addr;	/* slave address			*/
	__u16 flags;
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_RD		0x0001	/* read data, from slave to master */
#define I2C_M_STOP		0x8000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_NOSTART */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
	__u16 len;		/* msg length				*/
	__u8 *buf;		/* pointer to msg data			*/
#ifdef CONFIG_MTK_I2C_EXTENSION
	__u32 timing;	/* parameters of timings		*/
	__u32 ext_flag;
#endif
};

mtk做的i2c_msg结构体多了 timing和ext_flag这两个成员变量。按照上面的参数设置,会出现参数校验失败,而这个参数校验失败,系统不会报错。
修改应用的i2c_msg结构体定义,与内核一致。

完整的I2C读数据函数:

unsigned char _i2c_read ( unsigned char device_addr, unsigned char sub_addr, unsigned char * buff, short int ByteNo )
{
   
   
    unsigned int fd, ret;
    struct i2c_rdwr_ioctl_data vcnl4200_i2c_data;
    const char * i2c_dev = "/dev/i2c-2";
	unsigned char data[2][10];
  
    fd = open ( i2c_dev, O_RDWR );
    if ( fd < 0 )
    {
   
   
        LOGE("error (errno=%d)", errno);
        LOGE ( "no /dev/i2c-2\r\n" );
        return FAIL;
    }
	ioctl(fd, I2C_TIMEOUT, 2);
	ioctl(fd, I2C_RETRIES, 1);
	
	vcnl4200_i2c_data.nmsgs = 2;
	vcnl4200_i2c_data.msgs 
<think> 嗯,用户这次的问题非常具体,聚焦在MTK平台触控面板I2C通信故障的排查上。从引用内容看,用户已经收集了不少技术资料,包括电源检查、波形抓取、设备冲突排查等关键点,还特别关注到地址移位和驱动注册的底层细节。用户应该是嵌入式开发工程师,正在调试触摸屏驱动。 用户引用的资料很有价值:引用[1]提到供电稳定性和I2C协议完整性检查;引用[2]显示实际调试中出现ACK错误;引用[3]给出了驱动注册的代码示例;引用[4]则说明MT8788平台的性能参数。这些信息需要整合到解决方案中。 核心问题在于I2C通信失败,可能涉及硬件层(供电/线路)、协议层(波形/地址)、驱动层(注册/配置)三个维度。需要分层梳理排查步骤: 硬件层要优先检查VDD和VDD_I2C电压是否稳定——引用[1]强调这点。还要确认SCL/SDA线路是否被意外拉低。用户提到的"坐标映射错误"可能源于此。 协议层抓波形的操作至关重要:引用[2]的ACK错误案例很典型。需要教用户确认START/STOP信号是否完整,特别注意7位地址是否需要移位运算(引用[3]代码里的0x70>>1很关键)。如果总线上有其他设备(比如传感器),必须按引用[1]建议移除测试。 驱动层要重点核对三点:一是i2c_register_board_info注册的控制器编号(IIC_PORT)是否与原理图一致;二是设备树配置的时钟频率是否匹配TP芯片规格;三是确保驱动probe函数被成功调用。引用[3]的代码框架值得参考。 用户可能遇到的陷阱包括:地址移位遗漏(7位地址需右移1位)、设备树i2c-rate值过高、供电电压纹波过大。解决方案需要给出具体命令(如i2cdetect)和调试路径(/sys/bus/i2c/devices/)。 最后生成的延伸问题都紧扣实际开发场景:性能优化涉及降功耗技巧,应用场景关联MT8788平台特性(引用[4]),驱动兼容性问题则针对Android系统升级的痛点。用户后续很可能追问这些。 </think> 针对MTK平台触控面板(TP)I2C通信故障问题,结合引用内容和调试经验,解决方案如下: --- ### **排查步骤** 1. **供电检查** - 测量TP的 **VDD**(主供电)和 **VDD_I2C**(I2C总线供电)电压是否稳定(通常3.3V/1.8V),确认电源纹波在芯片规格范围内[^1]。 - 检查电源线路是否有虚焊或短路。 2. **I2C波形抓取** - 使用示波器抓取SCL/SDA信号: - 确认 **START/STOP信号** 是否完整(起始条件:SCL高电平时SDA下降沿;停止条件:SCL高电平时SDA上升沿)。 - 检查 **ACK响应**:主机发送地址/数据后,从机(TP)是否返回低电平ACK信号。若出现NACK(高电平),说明地址错误或设备未响应[^1][^2]。 3. **地址与总线冲突** - **核对设备地址**:确认驱动代码中I2C地址是否与TP芯片手册一致。地址通常为 **7位格式**,需右移1位(如手册地址`0x50`,代码应写`0x28`)[^3]: ```c static struct i2c_board_info ft5x16_i2c_tpd = { I2C_BOARD_INFO("ft5x16", (0x50 >> 1)) // 实际地址0x28 }; ``` - **移除其他设备**:断开同一I2C总线上其他从设备(如传感器),排除总线冲突[^1]。 4. **驱动注册与设备树** - 检查I2C控制器编号(如`IIC_PORT=0`)是否与硬件连接一致[^3]。 - 在设备树(DTS)中确认: ```dts &i2c0 { status = "okay"; touchscreen@2c { compatible = "vendor,tp-chip"; reg = <0x2c>; // I2C设备地址 vdd-supply = <&vdd_3v3>; // 供电配置 }; }; ``` - 驱动加载后,检查`/sys/bus/i2c/devices/i2c-0/`下是否生成设备节点(如`0-002c`)[^2]。 5. **内核日志分析** - 查看`dmesg`日志,过滤I2C错误: ```bash dmesg | grep -i "i2c\|ack\|error" ``` - 典型错误:`i2c i2c-0: sendbytes: NAK bailout` 或 `i2c i2c-0: timeout waiting for bus ready`,指向硬件问题或时钟速率不匹配。 --- ### **常见问题与解决** | **问题现象** | **可能原因** | **解决方案** | |--------------------|--------------------------|--------------------------------| | ACK error [^2] | 地址错误/供电不足 | 核对地址、测量供电电压 | | 设备未注册 | 驱动未加载/DTS配置错误 | 检查驱动初始化、设备树status | | 总线超时 | SCL/SDA被拉死/时钟过快 | 检查上拉电阻、降低I2C速率 | | 坐标映射错误 [^1] | 固件配置异常 | 校准TP参数或更新固件 | --- ### **代码调试要点** 1. 确保驱动正确注册: ```c i2c_register_board_info(IIC_PORT, &ft5x16_i2c_tpd, 1); // 注册I2C设备 tpd_driver_add(&tpd_device_driver); // 添加TP驱动 ``` 2. 在Probe函数中增加调试打印,确认驱动是否成功绑定: ```c static int tp_probe(struct i2c_client *client) { printk("TP detected at address 0x%02x\n", client->addr); // ... } ``` --- ### **关键命令验证** ```bash # 查看I2C总线设备 ls /sys/bus/i2c/devices/i2c-0/ # 扫描I2C地址(需安装i2c-tools) i2cdetect -y 0 ``` 输出示例: ``` 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- 2c -- -- -- -- -- ``` > ✅ 若显示`2c`(或其他预期地址),表明设备已被识别。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值