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

2023-09-14 16:36:02

编写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 总结

在这里插入图片描述

更多推荐

Linux 系统移植(二)--系统调试

文章目录一、编译文件系统1.1下载资源安装包1.2配置模板ARM64目标平台1.3配置交叉编译器1.4配置登录用户名和密码1.5配置Linux控制台1.6配置文件系统格式1.7编译buildroot文件系统二、编译ARM64Linux三、启动QemuLinux系统参考链接:一、编译文件系统1.1下载资源安装包我们使用b

(日积月累版)大数据基础知识点1-关系型数据库

好久不见,甚是想念。笔者最近有时间整理关于大数据的一些基础知识点,整理的目不在于能提升多少技能,关键在于巩固一些很基础的知识点,毕竟互联网就是基础略稳固的人比较有优势,在遇到或发现一些技术问题时,从底层科学的去理解这些问题,说不定会有另一片天下。那么本期带来大数据面是:关系型数据库一、什么是关系型数据库?关系型数据库是

全国职业技能大赛云计算--高职组赛题卷④(私有云)

全国职业技能大赛云计算--高职组赛题卷④(私有云)第一场次题目:OpenStack平台部署与运维任务1基础运维任务(5分)任务3OpenStack云平台运维(15分)任务4OpenStack云平台运维开发(15分,本任务只公布考试范围,不公布赛题)需要环境私信博主!!!第一场次题目:OpenStack平台部署与运维某企

2023,DaaS驶入“AI大航海时代”

2023,“制胜”已然成为所有行业、企业的共同命题,随着数字化行至中程,数据壁垒逐渐被打破,DaaS作为企业增长问题的解法,再次被看到。作者|斗斗编辑|皮爷出品|产业家2002年,在竞争激烈的美国职业棒球联盟,奥克兰运动家队无论在人员和物质配备以及资金实力上都只是“下三流”之列。然而在数据分析高材生的帮助下,经过分析数

RK3568开发笔记(十一):开发版buildroot固件移植一个ffmpeg播放rtsp的播放器Demo

若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/133022813红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…瑞芯微开

HBase基本操作及命令示例

HBase是一种分布式、可扩展、面向列的数据库,它是由Google的Bigtable项目衍生而来,并由Apache软件基金会开发及维护。对于HBase的基本操作类型,主要包括以下几种:创建表:在HBase中,可以创建一个新的表来存储数据。创建表时,需要定义表的名称以及表的列族。命令示例:create'table_nam

ASP.NET Core 8 的 Web App

WebAppWebApp与WebAPI的不同之处在于包含UI部分,所谓的UI就是HTML页面。WebApp支持几种渲染HTML的方式:服务端渲染客户端渲染混合渲染服务端渲染服务端渲染UI是在浏览器请求的时候,服务端生成HTML,然后返回给浏览器。优点是:减轻客户端的压力服务端生成HTML,适配各种浏览器极少从Clien

前端常用库之-JavaScript工具库lodash

文章目录前端常用库之-JavaScript工具库lodash一、什么是lodash二、安装三、lodash使用Lodash的pick()函数介绍和使用react实例demo:pick结合...展开运算符(spreadoperator)前端常用库之-JavaScript工具库lodash一、什么是lodash官网:htt

炒期权的资金门槛是多少 ?

期权是一种合约,买方向卖方支付一定费用后有权利在特定的时间,以特定的价格买入或卖出一定数量的特定资产,卖方需履行相应义务,期权开户支持线上和零门槛开头,下文介绍炒期权的资金门槛是多少?本文来自:期权酱一、期权一般投入多少钱?其实在期权市场上,绝大部分投资者都是中小型投资者,也就意味着期权投资不需要多少钱,几十几百几千元

【新版】系统架构设计师 - 案例分析 - 信息安全

个人总结,仅供参考,欢迎加好友一起讨论文章目录架构-案例分析-信息安全安全架构安全模型分类BLP模型Biba模型ChineseWall模型信息安全整体架构设计WPDRRC模型各模型安全防范功能网络安全体系架构设计开放系统互联安全体系结构安全服务与安全机制的对应关系认证框架访问控制框架机密性框架完整性框架抗抵赖框架什么是

PyTorch中ReduceLROnPlateau的学习率调整优化器

PyTorch中ReduceLROnPlateau的学习率调整优化器作者:安静到无声个人主页简介:在深度学习中,学习率是一个重要的超参数,影响模型的收敛速度和性能。为了自动调整学习率,PyTorch提供了ReduceLROnPlateau优化器,它可以根据验证集上的性能指标自动调整学习率。本文将详细介绍ReduceLR

热文推荐