自学内容网 自学内容网

Linux I2C调试分享

I2C简介

I2C(Inter-Integrated Circuit)是一种多主机、两线制、串行计算机总线,用于连接低速外围设备到处理器或微控制器。这种通信协议由Philips Semiconductor(现在的NXP Semiconductors)在1980年代初期开发。

I2C的特点

  • 两线制总线:只需要两根线,一根是数据线SDA(Serial Data Line),另一根是时钟线SCL(Serial Clock Line)。
  • 多主机能力:允许多个主设备在同一总线上通信。
  • 地址分配:每个从设备都有一个唯一的地址。
  • 简单性和灵活性:硬件实现简单,支持不同速度的数据传输。

I2C通信过程

  1. 起始信号:主设备通过将SDA从高电平拉低到低电平,同时SCL保持高电平来发出起始信号。
  2. 地址和读写位:主设备发送从设备地址和一个读/写位(0表示写,1表示读)。
  3. 应答信号:从设备接收到地址后,如果识别到自己的地址,会在时钟线的下一个高电平期间将数据线拉低,表示应答(ACK)。
  4. 数据传输:数据按字节传输,每个字节后跟一个应答位。
  5. 停止信号:通信结束时,主设备发出停止信号,即在SCL为高电平时,将SDA从低电平变为高电平。

start:开始信号,SCL置高电平 SDA拉低

bit7~bit1:I2C从设备地址

bit0:读写位 写为0,读为1,与bit7~bit1 凑成8位地址,所以有些设备分为读地址,写地址。

 ACK:响应信号,发送完地址后,主设备会置高,从设备响应后会马上拉低,主设备读取到拉低,判断设备存在

stop:结束信号,SCL置高,SDA拉高

数据传输速率

I2C协议支持多种速率模式,包括:

  • 标准模式:最高100kbps
  • 快速模式:最高400kbps
  • 快速模式+:最高1Mbps
  • 高速模式:最高3.4Mbps
  • 超快模式:最高5Mbps(仅限单向传输)

I2C地址格式

I2C设备通常使用7位或10位地址格式,这使得总线上可以有多个设备同时存在而不发生冲突。

I2C总线冲突和仲裁

当两个主设备同时尝试控制总线时,I2C协议提供了仲裁机制来处理冲突,确保只有一个主设备能够控制总线。

i2c驱动开发:

以i2c设备芯片 tda7313为例,数据手册如下

tda7313挂载在i2c5下,设备树如下:

&i2c5 {
    //时钟100k 
clock-frequency = <100000>;
    status = "okay";
    //@44设备地址
tda7313: tda7313@44 {
        status = "okay";
            compatible = "st,tda7313";
            //描述设备地址
            reg = <0x44>;
    };
}

Linux下发送I2C数据有三种方式:

 1.i2c驱动 

 2.系统应用编程

 3.命令发送

//i2c驱动
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>

int myprobe(struct i2c_client *cli, const struct i2c_device_id *id)
{
int ret;
struct i2c_msg msgs[1];
char addr[2] = { 0x11,0x22 }; //2个数据
msgs[0].addr = cli->addr;//设备地址 0x44
msgs[0].flags = 0;//读写标志位
msgs[0].len = 2;//数据长度
msgs[0].buf = addr;//数据地址
    //执行i2c_transfer = 1个开始信号 + 写地址 +  0x11 + 0x22 + 停止信号
    ret = i2c_transfer(cli->adapter, msgs, 1);
if (ret < 0){
msleep(10);
}
return 0;
}
int myremove(struct i2c_client *cli)
{
return 0;
}
struct i2c_device_id ids[] = {
{ "st,tda7313", 0 },
{},
};
MODULE_DEVICE_TABLE(i2c, ids);
//配对节点
static const struct of_device_id tda7313_of_match[] = {
{ .compatible = "st,tda7313" },
{},
};
struct i2c_driver mydrv = {
    .probe = myprobe,
    .remove = myremove,
    .driver = {
        .name = "tda7313",
        .of_match_table = tda7313_of_match,
        .owner = THIS_MODULE,
    },
    .id_table = ids,
};

module_i2c_driver(mydrv);
MODULE_LICENSE("GPL");

Linux系统编程:

 设备树打开i2c-5后会在产生/dev/i2c-5节点:

rk3568_s:/ $ ls /dev/i2c-5 -l
crw-rw-rw- 1 system system 89,   5 2017-08-04 17:00 /dev/i2c-5

可以对该节点操作i2c

 i2c_test.c

// 2.系统应用编程
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <stdint.h>
#define I2C_ADDR 0x44
int fd;
unsigned char Tuner_WriteBuffer(unsigned char *buf, uint16_t len)
{
uint16_t i;
uint8_t r;
if (fd < 0)
{
printf("fd < 0");
return -1;
}
    //i2c数据填充
struct i2c_msg msgs[1] = {
{I2C_ADDR, 0, len, buf},//第一个I2c地址,写标志位,长度,buf数据地址
};
struct i2c_rdwr_ioctl_data idata = {
.msgs = msgs,
.nmsgs = 1, //对应msgs长度
};
    //下发i2c驱动,驱动帮你写数据
if (ioctl(fd, I2C_RDWR, &idata) < 0)
{
printf("ioctl I2C_RDWR error %d", fd);
return -1;
}
usleep(1 * 1000);
return 1;
}

unsigned char Tuner_ReadBuffer(unsigned char *addr, uint16_t addrLen, unsigned char *buf, uint16_t len)
{
if (fd < 0)
{
printf("fd < 0");
return -1;
}
unsigned char reg = 0;
uint16_t i = 1;
struct i2c_msg msgs[2] = {
{I2C_ADDR, 0, addrLen, addr},
{I2C_ADDR, I2C_M_RD, len, buf},
};

struct i2c_rdwr_ioctl_data idata = {
.msgs = msgs,
.nmsgs = 2,
};

if (ioctl(fd, I2C_RDWR, &idata) < 0)
{
printf("chenjx I2C_RDWR error");
return -1;
}
return 1;
}


void Tuner_I2C_Init()
{
fd = open("/dev/i2c-5", I2C_RDWR);
if (fd < 0)
{
printf("open %s false", "/dev/i2c-5");
return;
}
printf("open %s succuss", "/dev/i2c-5");
}
void Tuner_I2C_UnInit()
{ 
   close(fd);
}

int main(){
    unsigned char data[2] = {0x11,0x22};
    Tuner_I2C_Init();
    Tuner_WriteBuffer(data,2);
    Tuner_I2C_UnInit();
}

3.Linux命令:

i2ctransfer -f -y 5 w2@0x44 0x11 0x22
-y 5:哪条总线
w2:写两个字节地址
0x11 0x22:数据

I2C调试 经验分享 :

i2cdetect -y -r 5 :扫描5总线上挂载的是有设备地址

一.查不到设备地址

1. i2cdetect -y 5如果没有扫到该地址确认供电部分 

2.有些设备需要时钟信号i2c才能正常工作(大部分图像处理芯片,xs9922)

无法写入数据:

1.无法写入数据返回-5,确认同一总线挂载上的设备影响被拉低,确认它们的电压

2.先用示波器测量数据,发现从设备应答电压无法拉低,改变上拉电阻阻值,尝试是否恢复


原文地址:https://blog.csdn.net/yinsui1839/article/details/136699551

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!