2.2.I2C编程实践
创始人
2024-06-02 05:32:09
0

linux内核I2C驱动代码中的一些重要结构体:

一般一条I2C总线上,主设备即I2C控制器,一般由i2c_adapter对其进行描述,一般有nr描述它是第几个I2C控制器(第几条总线),而大家都知道I2C控制器提供读写能力,它内部一定会有数据传输的函数(包含在i2c_algorithm算法结构体中)。

struct i2c_adapter {struct module *owner;unsigned int class;		  /* classes to allow probing for */const struct i2c_algorithm *algo; /* the algorithm to access the bus */void *algo_data;/* data fields that are valid for all devices	*/const struct i2c_lock_operations *lock_ops;struct rt_mutex bus_lock;struct rt_mutex mux_lock;int timeout;			/* in jiffies */int retries;struct device dev;		/* the adapter device */unsigned long locked_flags;	/* owned by the I2C core */
#define I2C_ALF_IS_SUSPENDED		0
#define I2C_ALF_SUSPEND_REPORTED	1int nr;char name[48];struct completion dev_released;struct mutex userspace_clients_lock;struct list_head userspace_clients;struct i2c_bus_recovery_info *bus_recovery_info;const struct i2c_adapter_quirks *quirks;struct irq_domain *host_notify_domain;
};
struct i2c_algorithm {/** If an adapter algorithm can't do I2C-level access, set master_xfer* to NULL. If an adapter algorithm can do SMBus access, set* smbus_xfer. If set to NULL, the SMBus protocol is simulated* using common I2C messages.** master_xfer should return the number of messages successfully* processed, or a negative value on error*/int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);int (*master_xfer_atomic)(struct i2c_adapter *adap,struct i2c_msg *msgs, int num);int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr,unsigned short flags, char read_write,u8 command, int size, union i2c_smbus_data *data);int (*smbus_xfer_atomic)(struct i2c_adapter *adap, u16 addr,unsigned short flags, char read_write,u8 command, int size, union i2c_smbus_data *data);/* To determine what the adapter supports */u32 (*functionality)(struct i2c_adapter *adap);#if IS_ENABLED(CONFIG_I2C_SLAVE)int (*reg_slave)(struct i2c_client *client);int (*unreg_slave)(struct i2c_client *client);
#endif
};

而从设备也用到了一些结构体如i2c_client,它其中包括设备地址addr,以及它挂在哪条I2C总线上(在i2c_adapter *adapter中被记录)

struct i2c_client {unsigned short flags;		/* div., see below		*/
#define I2C_CLIENT_PEC		0x04	/* Use Packet Error Checking */
#define I2C_CLIENT_TEN		0x10	/* we have a ten bit chip address *//* Must equal I2C_M_TEN below */
#define I2C_CLIENT_SLAVE	0x20	/* we are the slave */
#define I2C_CLIENT_HOST_NOTIFY	0x40	/* We want to use I2C host notify */
#define I2C_CLIENT_WAKE		0x80	/* for board_info; true iff can wake */
#define I2C_CLIENT_SCCB		0x9000	/* Use Omnivision SCCB protocol *//* Must match I2C_M_STOP|IGNORE_NAK */unsigned short addr;		/* chip address - NOTE: 7bit	*//* addresses are stored in the	*//* _LOWER_ 7 bits		*/char name[I2C_NAME_SIZE];struct i2c_adapter *adapter;	/* the adapter we sit on	*/struct device dev;		/* the device structure		*/int init_irq;			/* irq set at initialization	*/int irq;			/* irq issued by device		*/struct list_head detected;
#if IS_ENABLED(CONFIG_I2C_SLAVE)i2c_slave_cb_t slave_cb;	/* callback for slave mode	*/
#endif
};

另外在i2c_algorithm并没有包含i2c_adapter结构体,那它又是如何找到设备地址信息的呢?这就得提到i2c_msg结构体了,其中包含了I2C设备的设备地址等信息。flag表示设备是读还是写。

struct i2c_msg {__u16 addr;	/* slave address			*/__u16 flags;
#define I2C_M_RD		0x0001	/* read data, from slave to master *//* I2C_M_RD is guaranteed to be 0x0001! */
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_DMA_SAFE		0x0200	/* the buffer of this message is DMA safe *//* makes only sense in kernelspace *//* userspace buffers are copied anyway */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_NOSTART */
#define I2C_M_STOP		0x8000	/* if I2C_FUNC_PROTOCOL_MANGLING */__u16 len;		/* msg length				*/__u8 *buf;		/* pointer to msg data			*/
};

总的来说就是,i2c_adapter与i2c_client间传输i2c_msg,并且i2c_adapter中有一个i2c_algorithm定义了一些传输函数。

i2c_transfer

有如下函数i2c_transfer:该函数会从i2c_adapter中找到根本的传输函数:algo.master_xfer进行调用,然后从i2c_msg中找到设备的设备地址以及设备读写标志位信息,num则是传输多少个数据消息。

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{int ret;if (!adap->algo->master_xfer) {dev_dbg(&adap->dev, "I2C level transfers not supported\n");return -EOPNOTSUPP;}/* REVISIT the fault reporting model here is weak:**  - When we get an error after receiving N bytes from a slave,*    there is no way to report "N".**  - When we get a NAK after transmitting N bytes to a slave,*    there is no way to report "N" ... or to let the master*    continue executing the rest of this combined message, if*    that's the appropriate response.**  - When for example "num" is two and we successfully complete*    the first message but get an error part way through the*    second, it's unclear whether that should be reported as*    one (discarding status on the second message) or errno*    (discarding status on the first one).*/ret = __i2c_lock_bus_helper(adap);if (ret)return ret;ret = __i2c_transfer(adap, msgs, num);i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);return ret;
}

I2C_Tools

源代码文件自取,这里用的是4.2版本的I2C_Tools

链接:https://pan.baidu.com/s/1iHfuwMQwFppnCzdmo76DQA 
提取码:1234 
 

访问硬件的方式最普遍的思路是通过编写自己的驱动程序进而访问I2C设备,而I2C_Tools可以直接对I2C控制器上的I2C设备进行访问,我们可以通过编写APP(应用程序)来操作I2C_Tools进而来访问I2C设备,对I2C设备进行驱动。

在这里,大家可以参考这位大佬的博客:【全志T113-S3_100ask】6-编写IIC驱动GY-302(twi)_t113 i2c_第四维度4的博客-CSDN博客

 在这里不多赘述,因为他写的真的很好,这里也主要是涉及一个操作的过程。

后续可能贴出I2C_Tools的命令:

i2cdetect //i2c检测命令
//命令示例:
i2cdetect -y 0 //检测第0号总线
i2cdetect -l   //列出设备中有多少条I2C总线

使用SMBus协议:

i2cset //I2C写操作命令(SMBus)命令示例:
i2cset -f -y 0 0x1e 0 0x4 //-f强制访问I2C设备,-y不提示是否访问,0号总线,0x1e设备地址,0号寄存器地址,写入0x4
i2cset -f -y 0 0x1e 0 0x3i2cget //I2C读操作命令(SMBus)命令示例:
i2cget -f -y 0 0x1e 0xc w //-f强制访问I2C设备,-y不提示是否访问,0号总线,0x1e设备地址,0xc寄存器地址,w模式(read word data读取两个字节),b模式(read byte data读取一个字节),c模式(write byte/read byte)

 使用I2C协议:

i2ctransfer//I2C写操作命令使用示例:
i2ctransfer -f -y 0 w2@0x1e 0 0x4 //-f强制访问I2C设备,-y不提示是否访问,0号总线,w2@0x1e为描述符,w是写操作,表示写两个字节,0x1e是设备地址,0号寄存器,写入0x4i2ctransfer//I2C读操作命令使用示例:
i2ctransfer -f -y 0 w1@0x1e 0xc r2 //-f强制访问I2C设备,-y不提示是否访问,0号总线,w1@0x1e为描述符,w是写操作,表示写1个字节,0x1e是设备地址,0xc寄存器地址,r2读出两个字节,(因为读取数据需要指定寄存器地址,所以需要先写才能读)

基于I2C_Tools编写I2C驱动程序

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "i2cbusses.h"
#include //应用程序的使用格式
/* ./at24c02  w "100ask.taobao.com"* ./at24c02  r*/int main(int argc, char **argv)
{unsigned char dev_addr = 0x50;//设备地址,在这里是以AT24C02为例,且A1,A2,A3都接地设备地址为1010000=0x50unsigned char mem_addr = 0;//存储空间的地址,从0开始读unsigned char buf[32];//数据缓冲区int file;char filename[20];unsigned char *str;int ret;struct timespec req;//如果用户输入的参数不正确,则打印一下用法if (argc != 3 && argc != 4){printf("Usage:\n");printf("write eeprom: %s  w string\n", argv[0]);printf("read  eeprom: %s  r\n", argv[0]);return -1;}//打开I2C设备file = open_i2c_dev(argv[1][0]-'0', filename, sizeof(filename), 0);if (file < 0){printf("can't open %s\n", filename);return -1;}if (set_slave_addr(file, dev_addr, 1)){printf("can't set_slave_addr\n");return -1;}//如果第二个参数是wif (argv[2][0] == 'w'){// write str: argv[3]str = argv[3];req.tv_sec  = 0;req.tv_nsec = 20000000; /* 20ms */while (*str){// mem_addr, *str// mem_addr++, str++ret = i2c_smbus_write_byte_data(file, mem_addr, *str);if (ret){printf("i2c_smbus_write_byte_data err\n");return -1;}// wait tWR(10ms)nanosleep(&req, NULL);mem_addr++;str++;}ret = i2c_smbus_write_byte_data(file, mem_addr, 0); // string end charif (ret){printf("i2c_smbus_write_byte_data err\n");return -1;}}else{// readret = i2c_smbus_read_i2c_block_data(file, mem_addr, sizeof(buf), buf);if (ret < 0){printf("i2c_smbus_read_i2c_block_data err\n");return -1;}buf[31] = '\0';printf("get data: %s\n", buf);}return 0;}

因为编译是用到了别的依赖库,光是上面的代码无法运行,完整代码如下:

链接:https://pan.baidu.com/s/1vGiLMWplEYwmkx2X8otLUQ 
提取码:1234 
 

相关内容

热门资讯

求宠文,男主对女主超宠,宠的没... 求宠文,男主对女主超宠,宠的没话说,宠的天理难容的那种,古代现代都可以,不求虐。我想还是4ᴨne.c...
帮我女儿起个名字,本人姓卫,妻... 帮我女儿起个名字,本人姓卫,妻姓惠,农历2007年5月初十19点40生的,在此谢谢了上面还有个姐姐:...
艾薇最终能跟拉美西斯二世一起吗... 艾薇最终能跟拉美西斯二世一起吗?当然了,他们约定:相见,亦不忘却往生结果要看作者的心情,作者不高兴就...
女主带空间穿到古代又穿回现代的... 女主带空间穿到古代又穿回现代的小说《九岁小妖后》是灵魂穿越,回了现代一次,结局又回古代了。我觉得挺好...
国足要是冲击世界杯成功 会造成... 国足要是冲击世界杯成功 会造成多大的轰动? (实话实说) 会带动多大的经济效益?估计有生之年难度较大...
零之轨迹中古战场的两个游客怎么... 零之轨迹中古战场的两个游客怎么救RPG不存在什么难度吧,路上遇一个,尽头杀完BOSS救一个
初恋的含义到底是什么呢? 初恋的含义到底是什么呢?是第一个女朋友?还是第一次爱的人??既然说是“初恋”就是初次恋爱。恋爱至少需...
你们喜欢棒棒堂还是飞轮海啊? 你们喜欢棒棒堂还是飞轮海啊?都喜欢!最喜欢棒棒堂里的王子和獒犬最喜欢飞轮海里的炎亚纶和吴尊都喜欢,更...
女生想起个笔名,要两个字,要冷... 女生想起个笔名,要两个字,要冷开头!不要那么俗的名字好不好呀~冷滢,冷清,冷冷,冷青,冷月……冷鸟,...
《魔兽世界》下个版本《熊猫人之... 《魔兽世界》下个版本《熊猫人之谜》,什么名字帅气?大家都起什么名字啊?可以考虑叫功夫熊猫里面那家伙的...
蛤蟆山怎么样 蛤蟆山怎么样-山-山在天桥附近一小山顶上,一块巨石如欲腾空飞跃的-,形象逼真,因此称之为-山。传说为...
一年级重阳节主题班会教案 一年级重阳节主题班会教案 2021年一年级重阳节主题班会教案(精选7篇)   作为一位杰出的教职工...
达芬奇画鸡蛋的故事告诉们什么道... 达芬奇画鸡蛋的故事告诉们什么道理1,孰能生巧。每个成功的背后都是要比别人花更多的努力的。2,一个物体...
为什么我点进直播间左上角却没有... 为什么我点进直播间左上角却没有邀请新用户红包?是不是新用户提交的信息有错误,这也是很有可能的,或者是...
不知道自己在写些什么的成语 不知道自己在写些什么的成语如果你想找意思是“不知道自己在写什么”的成语,可以用“不知所云”. 诸葛...
倾听自然秘语之为你“桃”醉—中... 倾听自然秘语之为你“桃”醉—中1班班本课程之十二春意浓,花开正盛,桃红梨白,各种盛放的鲜花争奇斗艳。...
道教成仙可以超出轮回吗 道教成仙可以超出轮回吗不能超越六道轮回,成仙属天道,虽寿命几万岁,但福报亨尽后,往往堕落恶道。
春眠不洗脚,处处蚊子咬,夜来巴... 春眠不洗脚,处处蚊子咬,夜来巴掌声,蚊子没有了。春眠不洗脚,处处蚊子咬,夜来巴掌声,蚊子没有了。春眠...
一个小女孩手拉一只小狗代表什么... 一个小女孩手拉一只小狗代表什么生肖小狗就是生肖狗;在十二生肖里的动物里,狗是家喻户晓的动物,狗的一生...
作文童话故事 作文童话故事暑假夏令营活动开始了,小鹿参加了一个爱心实践活动,活动回家后,它很认真地对妈妈说:“妈妈...