驱动版本的i2cdetect

本文介绍了一种用于检测I2C设备的驱动程序。该驱动可通过写入/proc/i2cdetectall来探测所有I2C地址,或通过写入/proc/i2cdetect来探测单条总线上的I2C地址。对于未检测到的地址,文章建议检查硬件电路或设备状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       这里写了一个驱动版本的i2cdect。其中先写/proc/i2cdetectall节点,然后读可以探测所有的i2c地址,写节点/proc/i2cdetect然后读可以探测单条总线的i2c地址。对于检测不到的i2c地址,可重新看下芯片手册或者检查硬件电路(如芯片有没有上电(摄像头地址需要需要在工作时),i2c引脚配置,dts注册了相应的i2c总线)。

原理:往i2c总线的发地址数据,如果应答了表示该地址存在。

源码如下

#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/i2c.h>
#include <linux/delay.h>

//i2cdetect all
//echo 0 > /proc/i2cdetectall
//cat  /proc/i2cdetectall

//i2cdect i2_n address
//echo n > /proc/i2cdetect
//cat /proc/i2cdetect
unsigned char tbuf=0;
unsigned int i2c_bus;
unsigned int i2c_bus_count=0;
unsigned int i2c_bus_list[20];
unsigned char i2c_addr[256];

struct i2c_msg msg={
	.flags = 0,
	.buf   = &tbuf,
	.len=1,
};

static int i2c_detect_show(struct seq_file *m, void *v)
{
	unsigned char addr;
	seq_printf(m,"found i2c_%d address:\n",i2c_bus);
	for(addr=0x1;addr<0x80;addr++)
	{	
		if(i2c_addr[addr]!=0xff)
			seq_printf(m,"0x%x ",i2c_addr[addr]);
	}
	seq_printf(m,"\n");
	return 0;
}

ssize_t i2c_detect_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
	
    	int addr;
	int ret;
	struct i2c_adapter *adapter;
	memset(i2c_addr,0xff,sizeof(i2c_addr));
	i2c_bus=simple_strtoul(buffer,NULL,10);
	printk("i2c_bus=%d\n",i2c_bus);
    	adapter = i2c_get_adapter(i2c_bus); 
    	if (!adapter) {
        	printk("get i2c_%d adapter err\n",i2c_bus);  
        	return -ENODEV;
    	} else {
        	printk("get i2c_%d adapter ok\n",i2c_bus);
    	}
	for(addr=0x1;addr<0x80;addr++){
		msg.addr=addr;
		ret=i2c_transfer(adapter, &msg, 1);
		if(ret>0)
		{
			printk("found i2c addr 0x%0x\n",addr);
			i2c_addr[addr]=addr;
		}
	};
	i2c_put_adapter(adapter); 
	return count;
}

//0xff addr1 addr2 0xff addr3 addr4 0xff
static int i2c_detect_all_show(struct seq_file *m, void *v)
{
	int i=0;
	int j=0;
	for(i=0;i<i2c_bus_count;i++)
	{
		seq_printf(m,"i2c_%d address:\n",i2c_bus_list[i]);
		j++;
		while(i2c_addr[j]!=0xff)
		{	
			seq_printf(m,"0x%x ",i2c_addr[j]);
			j++;
		}
		seq_printf(m,"\n");
	}	
	return 0;
}

ssize_t i2c_detect_all_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
	int i;
	int ret;
	int addr;
	int addr_count=0;
	struct i2c_adapter *adapter;
	memset(i2c_addr,0xff,sizeof(i2c_addr));
	for(i=0;i<i2c_bus_count;i++)
	{
    		adapter = i2c_get_adapter(i2c_bus_list[i]); 
    		if (!adapter) {
        		printk("get i2c-%d adapter err\n",i2c_bus);  
        		return -ENODEV;
    		} else {
        		printk("get i2c-%d adapter ok\n",i2c_bus);
    		}
		addr_count++;
		for(addr=0x1;addr<0x80;addr++){
			msg.addr=addr;
			ret=i2c_transfer(adapter, &msg, 1);
			if(ret>0)
			{
				printk("found i2c-%d address  0x%0x\n",i2c_bus_list[i],addr);
				i2c_addr[addr_count++]=addr;
			}
		};
		i2c_put_adapter(adapter); 
	}
	return count;
}

static int i2c_detect_open(struct inode *inode, struct file *file)
{	
	return single_open(file, i2c_detect_show, NULL);
}

static int i2c_detect_all_open(struct inode *inode, struct file *file)
{	
	return single_open(file, i2c_detect_all_show, NULL);
}

static const struct file_operations i2c_detect_fops = 
{
	.owner   = THIS_MODULE,
	.open    = i2c_detect_open,
	.read    = seq_read,
	.write   = i2c_detect_write,
};

static const struct file_operations i2c_detect_all_fops = 
{
	.owner   = THIS_MODULE,
	.open    = i2c_detect_all_open,
	.read    = seq_read,
	.write   = i2c_detect_all_write,
};

void i2c_bus_detect(void)
{
	int i;
	struct i2c_adapter *adapter;
	memset(i2c_bus_list,0,sizeof(i2c_bus_list));
	for(i=0;i<20;i++)
	{
		adapter=i2c_get_adapter(i);
		if(adapter)
		{
			i2c_bus_list[i2c_bus_count++]=i;
			i2c_put_adapter(adapter);
		}
	}
	printk("i2c bus %d\n",i2c_bus_count);
	for(i=0;i<i2c_bus_count;i++)
		printk("found i2c-%d\n",i2c_bus_list[i]);
					
}
static int __init i2c_detect_init(void)
{
	i2c_bus_detect();
	memset(i2c_addr,0xff,sizeof(i2c_addr));
	proc_create("i2cdetect", S_IRWXUGO, NULL, &i2c_detect_fops);
	proc_create("i2cdetectall", S_IRWXUGO, NULL, &i2c_detect_all_fops);
	return 0;
}

static void __exit i2c_detect_exit(void)
{
	remove_proc_entry("i2cdetect", NULL);	
}

module_init(i2c_detect_init);  
module_exit(i2c_detect_exit);  
MODULE_AUTHOR("www");
MODULE_LICENSE("GPL");

将该驱动编译成模块(https://blog.youkuaiyun.com/mike8825/article/details/50495902),很方便来检测i2c设备。

应用层的i2cdetect(https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/)

<think>首先,用户的问题是:“我想查找i2cdetect命令的使用方法或教程请问i2cdetect命令使用教程或示例”。这直接要求我提供关于i2cdetect命令的使用方法和示例。根据系统级指令:-所有行内数学表达式必须使用$...$格式。-独立公式必须使用$$...$$格式并单独成段。-使用LaTeX语法正确。-使用中文回答。-生成相关问题。-回答中引用的段落末尾自然地添加引用标识,例如:[^1]。用户还提供了引用:-引用[^1]介绍了i2c工具包括i2cdetect的功能:扫描所有设备地址。-引用[^2]提到如何在yocto工程中编译rootfs时获取i2c-tools。-引用[^3]讨论了i2c-tools的使用,包括i2cdetect、i2cdump等。系统指令中说:“上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。”但这是新对话,因为没有之前的消息,所以我应该只基于当前问题回答。我的回答需要:1.**结构清晰,帮助用户逐步解决问题**:我应该一步一步地解释i2cdetect命令的用法。2.**保证回答真实可靠**:基于提供的引用和一般知识。i2cdetect是Linux下用于检测I2C总线上设备的命令。我可以从引用中提取关键点:-引用[^1]说:i2cdetect用于扫描所有设备地址。-引用[^3]提到i2c-tools包括i2cdetect用于检测I2C设备。常见用法:-`i2cdetect-l`列出所有I2Cbuses。-`i2cdetect-y[bus_number]`扫描指定bus上的设备地址。示例输出可能显示设备地址。回答结构:-开头解释i2cdetect的作用。-描述命令语法。-提供示例命令和输出。-必要时解释选项。-结尾添加引用标识。-最后生成相关问题。生成相关问题:指令要求“生成相关问题”,应该在回答末尾添加。LaTeX注意事项:用户问题是关于命令的,可能没有数学公式,但如果在描述中涉及到数学元素,如地址范围,可以用LaTeX格式表示。例如,设备地址从$0x00$到$0x7F$。完整回答计划:1.**介绍i2cdetect**:简单解释它是什么。2.**命令语法**:列出常用选项。3.**使用教程/示例**:提供一步一步的使用方法。4.**引用标识**:在相关段落末尾添加。5.**相关问题**:生成几个相关问题。从引用:-[^1]:i2cdetect用于扫描所有设备地址。-[^2]:关于编译,但不是直接相关,所以可能不引用。-[^3]:提到i2c-tools使用,包括示例。实际回答时,整合这些信息。最终输出格式:-中文回答。-生成相关问题:使用###相关问题###或类似。</think> 根据您的要求,我将清晰、逐步地解释 `i2cdetect` 命令的使用方法和提供示例教程。`i2cdetect` 是 Linux 下 `i2c-tools` 包中的核心工具,主要用于扫描 I2C 总线上的设备地址,帮助识别已连接的 I2C 设备(如传感器、EEPROM 等)。这在嵌入式系统开发、调试 I2C 设备驱动时非常实用[^1]。 以下内容基于标准 Linux 环境(如 Android/Linux on ARM)和 `i2c-tools` 包的使用说明。我将从基础知识开始,逐步指导您操作。注意:在执行命令前,确保: - 您的系统已安装 `i2c-tools`(可通过包管理器安装,如 `sudo apt install i2c-tools`)。 - 您有 root 权限(许多命令需要 `sudo`)。 - I2C 总线已启用(检查 `/etc/modules` 或内核模块)。 ### 1. **`i2cdetect` 命令概述** `i2cdetect` 扫描指定 I2C 总线上的所有可能设备地址(地址范围通常为 $0x00$ 到 $0x7F$),并显示设备是否存在。输出中: - `UU` 表示设备地址已被占用(设备存在)。 - `--` 表示空闲地址。 - 设备地址以 16 进制表示(如 `0x48`)。 常用选项: - `-l`:列出系统所有可用的 I2C 总线。 - `-y`:自动确认提示,用于脚本环境(重要!在扫描时使用以避免交互)。 - `-r`:使用 SMBus 扫描(可选,在某些设备上更可靠)。 - `[bus_number]`:指定要扫描的总线编号(e.g., `0`, `1`)。 ### 2. **使用教程:一步一步操作** 下面是一步一步的使用指南,包括实际示例。 #### **步骤 1: 识别 I2C 总线** 在扫描前,找出系统有多少个 I2C 总线。这帮助您确定要扫描的目标总线。 ```bash sudo i2cdetect -l ``` - **输出示例**: ``` i2c-0 i2c Your I2C bus name 0 I2C adapter i2c-1 i2c Your I2C bus name 1 I2C adapter ``` 假设总线编号为 `0` 和 `1`。记下总线编号用于后续扫描。如果您是第一次使用,通常从总线 `0` 开始测试[^1]。 #### **步骤 2: 扫描 I2C 总线上的设备地址** 使用 `i2cdetect -y [bus_number]` 扫描指定总线。`-y` 选项确保自动确认警告提示。 ```bash sudo i2cdetect -y 0 # 扫描总线 0 ``` - **输出示例**: ``` 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- 77 ``` - 解读: - `40` 地址表示有一个设备(e.g., 温度传感器)。 - `UU` 地址表示另一个设备(e.g., EEPROM)。 - 这个输出显示总线 `0` 上有两个设备:地址 `0x40` 和 `0x6F`。 - 如果没有设备,输出将全是 `--`。这表示总线空闲或设备未正确连接[^1]。 #### **步骤 3: 高级扫描(可选)** - **扫描所有总线**:如果您不确定总线编号,用脚本轮询(`for i in {0..3}; do sudo i2cdetect -y $i; done`)。 - **使用 `-r` 选项**:在有些设备上,SMBus 扫描可能更可靠(e.g., `sudo i2cdetect -y -r 0`)。 ### 3. **常见问题和注意事项** - **权限错误**:确保使用 `sudo`。如果失败,检查 `/dev/i2c-*` 权限(`sudo chmod 666 /dev/i2c-0`)。 - **设备未检测到**:可能原因包括: - I2C 设备未供电或接线错误。 - 内核模块未加载(运行 `sudo modprobe i2c-dev`)。 - 总线编号错误(再次用 `i2cdetect -l` 确认)。 - **如何安装工具**:如果未安装 `i2c-tools`,在 Debian/Ubuntu 系统用 `sudo apt install i2c-tools`。在 Yocto 项目编译 rootfs 时,查找 `i2c-tools_4.1.bb` 文件[^2]。 ### 4. **真实应用场景** 在调试中,`i2cdetect` 经常与其他工具结合: - 先用 `i2cdetect` 找到设备地址。 - 然后 `i2cdump` 读取寄存器的值(e.g., `sudo i2cdump -y 0 0x40`)。 - 最后用 `i2cset` 或 `i2cget` 配置设备(e.g., 设置 EEPROM 值)。这在传感器校准或驱动开发中常见[^3]。 ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值