Linux I2C调试分享
I2C简介
I2C(Inter-Integrated Circuit)是一种多主机、两线制、串行计算机总线,用于连接低速外围设备到处理器或微控制器。这种通信协议由Philips Semiconductor(现在的NXP Semiconductors)在1980年代初期开发。
I2C的特点
- 两线制总线:只需要两根线,一根是数据线SDA(Serial Data Line),另一根是时钟线SCL(Serial Clock Line)。
- 多主机能力:允许多个主设备在同一总线上通信。
- 地址分配:每个从设备都有一个唯一的地址。
- 简单性和灵活性:硬件实现简单,支持不同速度的数据传输。
I2C通信过程
- 起始信号:主设备通过将SDA从高电平拉低到低电平,同时SCL保持高电平来发出起始信号。
- 地址和读写位:主设备发送从设备地址和一个读/写位(0表示写,1表示读)。
- 应答信号:从设备接收到地址后,如果识别到自己的地址,会在时钟线的下一个高电平期间将数据线拉低,表示应答(ACK)。
- 数据传输:数据按字节传输,每个字节后跟一个应答位。
- 停止信号:通信结束时,主设备发出停止信号,即在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)!