嵌入式Linux驱动开发(I2C专题)(四)

news/2024/7/24 1:52:17 标签: linux, 驱动开发, 运维

编写APP直接访问EEPROM

参考资料:

  • Linux驱动程序: drivers/i2c/i2c-dev.c
  • I2C-Tools-4.2: https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/
  • AT24cxx.pdf

1. 硬件连接

  • STM32MP157的I2C模块连接方法
    在这里插入图片描述
  • IMX6ULL的I2C模块连接方法
    在这里插入图片描述

2. AT24C02访问方法

2.1 设备地址

从芯片手册上可以知道,AT24C02的设备地址跟它的A2、A1、A0引脚有关:
在这里插入图片描述

打开I2C模块的原理图(这2个文件是一样的):

  • STM32MP157\开发板配套资料\原理图\04_Extend_modules(外设模块)\eeprom.zip\i2c_eeprom_module_v1.0.pdf
  • IMX6ULL\开发板配套资料\原理图\Extend_modules\eeprom.zip\i2c_eeprom_module_v1.0.pdf
  • 如下:
    在这里插入图片描述
    从原理图可知,A2A1A0都是0,所以AT24C02的设备地址是:0b1010000,即0x50。

2.2 写数据

在这里插入图片描述

2.3 读数据

可以读1个字节,也可以连续读出多个字节。
连续读多个字节时,芯片内部的地址会自动累加。
当地址到达存储空间最后一个地址时,会从0开始。
在这里插入图片描述

3. 使用I2C-Tools的函数编程

#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <i2c/smbus.h>
#include "i2cbusses.h"
#include <time.h>

int main(int argc, char **argv)
{
	unsigned char dev_addr = 0x50;		//设备地址
	unsigned char mem_addr = 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 <i2c_bus_number> w string\n", argv[0]);
		printf("read  eeprom: %s <i2c_bus_number> r\n", argv[0]);
		return -1;
	}

	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;
	}

	if (argv[2][0] == 'w')			//写操作
	{
		// write str: argv[3]
		str = argv[3];

		req.tv_sec  = 0;
		req.tv_nsec = 20000000; /* 20ms */
		
		while (*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 char
		if (ret)
		{
			printf("i2c_smbus_write_byte_data err\n");
			return -1;
		}
	}
	else		//读操作
	{
		// read
		ret = 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;
	
}

4. 编译

4.1 在Ubuntu设置交叉编译工具链

  • STM32MP157

    export ARCH=arm
    export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
    export PATH=$PATH:/home/book/100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin
    
  • IMX6ULL

    export ARCH=arm
    export CROSS_COMPILE=arm-linux-gnueabihf-
    export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin
    

4.2 使用I2C-Tools的源码

在这里插入图片描述

4.3 编译

为IMX6ULL编译时,有如下错误:
在这里插入图片描述
这是因为IMX6ULL的工具链自带的include目录中,没有smbus.h。

需要我们自己提供这个头文件,解决方法:

  • 提供头文件:
    在这里插入图片描述

  • 修改Makefile指定头文件目录

    all:
    	$(CROSS_COMPILE)gcc -I ./include -o at24c02_test at24c02_test.c i2cbusses.c smbus.c
    	
    

4.4 上机测试

以下命令在开发板中执行。

  • 挂载NFS

    • vmware使用NAT(假设windowsIP为192.168.1.100)

      [root@100ask:~]# mount -t nfs -o nolock,vers=3,port=2049,mountport=9999 
      192.168.1.100:/home/book/nfs_rootfs /mnt
      
    • vmware使用桥接,或者不使用vmware而是直接使用服务器:假设Ubuntu IP为192.168.1.137

      [root@100ask:~]#  mount -t nfs -o nolock,vers=3 192.168.1.137:/home/book/nfs_rootfs /mnt
      
  • 复制、执行程序

[root@100ask:~]# cp /mnt/at24c02_test   /bin
[root@100ask:~]# at24c02_test 0 w www.100ask.net
[root@100ask:~]# at24c02_test 0 r
get data: www.100ask.net

五、通用驱动i2c-dev分析

参考资料:

  • Linux驱动程序: drivers/i2c/i2c-dev.c
  • I2C-Tools-4.2: https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/
  • AT24cxx.pdf

1. 回顾字符设备驱动程序

在这里插入图片描述
怎么编写字符设备驱动程序?

  • 确定主设备号
  • 创建file_operations结构体
    • 在里面填充drv_open/drv_read/drv_ioctl等函数
  • 注册file_operations结构体
    • register_chrdev(major, &fops, name)
  • 谁调用register_chrdev?在入口函数调用
  • 有入口自然就有出口
    • 在出口函数unregister_chrdev
  • 辅助函数(帮助系统自动创建设备节点)
    • class_create
    • device_create

2. i2c-dev.c注册过程分析

2.1 register_chrdev的内部实现

在这里插入图片描述

2.2 i2c-dev驱动的注册过程

在这里插入图片描述

3. file_operations函数分析

i2c-dev.c的核心:

static const struct file_operations i2cdev_fops = {
	.owner		= THIS_MODULE,
	.llseek		= no_llseek,
	.read		= i2cdev_read,
	.write		= i2cdev_write,
	.unlocked_ioctl	= i2cdev_ioctl,
	.compat_ioctl	= compat_i2cdev_ioctl,
	.open		= i2cdev_open,
	.release	= i2cdev_release,
};

主要的系统调用:open, ioctl:
在这里插入图片描述
要理解这些接口,记住一句话:APP通过I2C Controller与I2C Device传输数据。

3.1 i2cdev_open

在这里插入图片描述

3.2 i2cdev_ioctl: I2C_SLAVE/I2C_SLAVE_FORCE

在这里插入图片描述

3.3 i2cdev_ioctl: I2C_RDWR

在这里插入图片描述

3.4 i2cdev_ioctl: I2C_SMBUS

在这里插入图片描述

3.5 总结

在这里插入图片描述


http://www.niftyadmin.cn/n/5025623.html

相关文章

STL priority_queue

文章目录 一、priority_queue 类的模拟实现 priority_queue 是优先级队列&#xff0c;又称堆&#xff0c;可以存储任意类型 模板参数 T 表示存储元素的类型&#xff0c;Container 表示底层使用的容器&#xff0c;Compare 表示存储元素的比较方法(less 建大堆&#xff0c;great…

通过ExecutorService、Callable、Future实现有返回结果的多线程来处理有轮询业务

开发中碰到类似受理业务等相关接口一般都是异步获取结果&#xff0c;要么就属于异步回调后再下一步处理业务&#xff0c;要么就定时轮询查询接口获取结果再下一步处理业务流程&#xff1b;此次碰到类似接口是没有异步回调处理&#xff0c;协同系统只提供业务受理接口及查询结果…

GTS 中testPeakPssOfAllApps fail 详解

0. 前言 GTS 在测试 case armeabi-v7a GtsMemoryHostTestCases 的时候出现下面异常&#xff0c;本文总结一下。 com.google.android.memory.gts.AllAppsMemoryHostTest#testPeakPssOfAllApps 1. error log 09-14 10:16:34 I/TestFailureListener: FailureListener.testFaile…

辊轧机液压系统泵站比例阀放大器

液压系统主要由液压泵、电机、液压缸、油箱、高压软管等组成。 液压泵将机油从油箱吸入&#xff0c;通过高压软管送至液压缸中&#xff0c;完成动力转换。液压泵的驱动由电机通过皮带或轮齿传动完成。 液压折弯机的液压油流动路线主要分为液压油箱、吸油过滤器、液压泵、主控…

关于闭包的递进理解

本文主要是介绍了闭包&#xff0c;解释什么情况下会造成内存泄露&#xff0c;还有一个关于闭包的面试题&#xff0c;闭包的所在的函数被多次调用&#xff0c;闭包中的变量会创建几次 什么是 闭包 1.定义 如果在一个内部函数里&#xff0c;在对外部作用域&#xff08;但不是在…

Template serialization - shared_ptr<class T>

下面包含的所有代码片段都在 boost::serialization 命名空间内定义。 shared_ptr < T > 在 shared_ptr.hpp 中定义。 shared_ptr 的一般类轮廓如下&#xff1a; shared_ptr 包括以下成员&#xff1a; T *px;shared_count pn;&#xff0c;其中包含指向&#xff1a; sp_c…

最新ChatGPT网站源码+支持GPT4.0+支持Midjourney绘画+支持国内全AI模型

一、智能创作系统 SparkAi创作系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&…

vue2通过.env进行多环境配置

这边 我们先创建一个本地文件夹 作为项目的存放目录 然后我们执行 vue create 项目名 创建一个vue项目 例如 我这里这样 vue create multiple_environ创建一个叫 multiple_environ 的vue项目 这里 我们选择vue2的版本 然后 在 然后 大家可以配置多个环境 但都需要用因为命…