技术标签: linux 设备驱动 系统 i2c eeprom
本小节介绍两个在linux应用层访问eeprom的方法,并给出示例代码方便大家理解。第一个方法是通过sysfs文件系统对eeprom进行访问,第二个方法是通过eeprom的设备文件进行访问。这两个方法分别对应了i2c设备驱动的两个不同的实现,在后面的小结会详细的分析。
eeprom的设备驱动在/sys/bus/i2c/devices/0-0050/目录下把eeprom设备映射为一个二进制节点,文件名为eeprom。对这个eeprom文件的读写就是对eeprom进行读写。
我们可以先用cat命令来看下eeprom的内容。
[root@FORLINX210]# cat eeprom
�����������X�����������������������������������������������
发现里面都是乱码,然后用echo命令把字符串“test”输入给eeprom文件,然后再cat出来。
[root@FORLINX210]# echo "test" > eeprom
[root@FORLINX210]# cat eeprom
test
�����������X�����������������������������������������������
就会发现字符串test已经存在eeprom里面了,我们知道sysfs文件系统断电后就没了,也无法对数据进行保存,为了验证确实把“test”字符串存储在了eeprom,可以把系统断电重启,然后cat eeprom,会发现test还是存在的,证明确实对eeprom进行了写入操作。
当然,因为eeprom已经映射为一个文件了,我们还可以通过文件I/O写应用程序对其进行简单的访问测试。比如以下程序对特定地址(0x40)写入特定数据(Hi,this is an eepromtest!),然后再把写入的数据在此地址上读出来。
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main(void){
int fd, size, len, i;
char buf[50]= {
0};
char *bufw="Hi,this is an eepromtest!";//要写入的数据
len=strlen(bufw);//数据长度
fd= open("/sys/bus/i2c/devices/0-0050/eeprom",O_RDWR);//打开文件
if(fd< 0)
{
printf("####i2c test device open failed####/n");
return(-1);
}
//写操作
lseek(fd,0x40,SEEK_SET); //定位地址,地址是0x40
if((size=write(fd,bufw, len))<0)//写入数据
{
printf("write error\n");
return 1;
}
printf("writeok\n");
//读操作
lseek(fd,0x40, SEEK_SET);//准备读,首先定位地址,因为前面写入的时候更新了当前文件偏移量,所以这边需要重新定位到0x40.
if((size=read(fd,buf,len))<0)//读数据
{
printf("readerror\n");
return 1;
}
printf("readok\n");
for(i=0; i< len; i++)
printf("buff[%d]=%x\n",i, buf[i]);//打印数据
close(fd);
return 0;
}
linux的i2c驱动会针对每个i2c适配器在/dev/目录下生成一个主设备号为89的设备文件,简单的来说,对于本例的eeprom驱动,/dev/i2c/0就是它的设备文件,因此接下来的eeprom的访问就变为了对此设备文件的访问。
我们需要用到两个结构体i2c_msg和i2c_rdwr_ioctl_data。
struct i2c_msg { //i2c消息结构体,每个i2c消息对应一个结构体
__u16 addr; /* 从设备地址,此处就是eeprom地址,即0x50 */
__u16 flags; /* 一些标志,比如i2c读等*/
__u16 len; /* i2c消息的长度 */
__u8 *buf; /* 指向i2c消息中的数据 */
};
struct i2c_rdwr_ioctl_data {
struct i2c_msg __user *msgs; /* 指向一个i2c消息 */
__u32 nmsgs; /* i2c消息的数量 */
};
对一个eeprom上的特定地址(0x10)写入特定数据(0x58)并在从此地址读出写入数据的示例程序如下所示。
#include <stdio.h>
#include <linux/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
int main()
{
int fd,ret;
struct i2c_rdwr_ioctl_data e2prom_data;
fd=open("/dev/i2c/0",O_RDWR);//打开eeprom设备文件结点
if(fd<0)
{
perror("open error");
}
e2prom_data.nmsgs=2;
e2prom_data.msgs=(struct i2c_msg*)malloc(e2prom_data.nmsgs*sizeof(struct i2c_msg));//分配空间
if(!e2prom_data.msgs)
{
perror("malloc error");
exit(1);
}
ioctl(fd,I2C_TIMEOUT,1);/*超时时间*/
ioctl(fd,I2C_RETRIES,2);/*重复次数*/
/*写eeprom*/
e2prom_data.nmsgs=1;//由前面eeprom读写分析可知,写eeprom需要一条消息
(e2prom_data.msgs[0]).len=2; //此消息的长度为2个字节,第一个字节是要写入数据的地址,第二个字节是要写入的数据
(e2prom_data.msgs[0]).addr=0x50;//e2prom 设备地址
(e2prom_data.msgs[0]).flags=0; //写
(e2prom_data.msgs[0]).buf=(unsigned char*)malloc(2);
(e2prom_data.msgs[0]).buf[0]=0x10;// e2prom 写入目标的地址
(e2prom_data.msgs[0]).buf[1]=0x58;//写入的数据
ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);//通过ioctl进行实际写入操作,后面会详细分析
if(ret<0)
{
perror("ioctl error1");
}
sleep(1);
/*读eeprom*/
e2prom_data.nmsgs=2;//读eeprom需要两条消息
(e2prom_data.msgs[0]).len=1; //第一条消息实际是写eeprom,需要告诉eeprom需要读数据的地址,因此长度为1个字节
(e2prom_data.msgs[0]).addr=0x50; // e2prom 设备地址
(e2prom_data.msgs[0]).flags=0;//先是写
(e2prom_data.msgs[0]).buf[0]=0x10;//e2prom上需要读的数据的地址
(e2prom_data.msgs[1]).len=1;//第二条消息才是读eeprom,
(e2prom_data.msgs[1]).addr=0x50;// e2prom 设备地址
(e2prom_data.msgs[1]).flags=I2C_M_RD;//然后是读
(e2prom_data.msgs[1]).buf=(unsigned char*)malloc(1);//存放返回值的地址。
(e2prom_data.msgs[1]).buf[0]=0;//初始化读缓冲,读到的数据放到此缓冲区
ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);//通过ioctl进行实际的读操作
if(ret<0)
{
perror("ioctl error2");
}
printf("buff[0]=%x\n",(e2prom_data.msgs[1]).buf[0]);
/***打印读出的值,没错的话,就应该是前面写的0x58了***/
close(fd);
return 0;
}
本小节介绍了两种在linux应用层访问eeprom的方法,并且给出了示例程序,通过sysfs文件系统访问eeprom操作简单,无需了解eeprom的硬件特性以及访问时序,而通过devfs访问eeprom的方法则需要了解eeprom的读写时序。
后面分析后会发现,第一种通过sysfs文件系统的二进制结点访问eeprom的方法是由eeprom的设备驱动实现的,是一种专有的方法;而第二种通过devfs访问eeprom的方法是linux i2c提供的一种通用的方法,访问设备的能力有限。
文章浏览阅读334次,点赞5次,收藏5次。分享一套阿里大牛整理的前端资料给大家,点击前端校招面试题精编解析大全即可免费下载E 数据切图工具PSPxcook(像素大厨):https://www.fancynode.com.cn/pxcook原型设计工具自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
文章浏览阅读4k次,点赞2次,收藏2次。由于需要精准的获取投放广告的数据(投放的平台,防止数据的丢失等)。我们使用了Google Play Install Referrer API 和Facebook App Ads Referral结合采集数据,然后通过后台服务记录数据。最后服务器记录的数据与Facebook提供的数据对比,检查数据的真实性、丢包概况等。最后得出结论可以用于后续运营策略。_installreferrer
文章浏览阅读428次。使用Ffpgem ,silk-v3-decoder,wavesurfer。一:用php后台来输出波形图,可查看资源包对应的wavToImg.php(没有第二种准确)二:使用小程序web-view,通过wavesurfer来实现。因为小程序不支持绘图。以上两种方法都需要注意:如果不是真机测试,则不需要silkdecode.php,小程序录音silk文件需要base64解码。php_cmd.php用来..._php 怎么读取音频波浪
文章浏览阅读310次。力扣1342给你一个非负整数 num ,请你返回将它变成 0 所需要的步数。 如果当前数字是偶数,你需要把它除以 2 ;否则,减去 1 。示例 1:输入:num = 14输出:6解释:步骤 1) 14 是偶数,除以 2 得到 7 。步骤 2) 7 是奇数,减 1 得到 6 。步骤 3) 6 是偶数,除以 2 得到 3 。步骤 4) 3 是奇数,减 1 得到 2 。..._力扣牛客网链接
文章浏览阅读8.4k次,点赞4次,收藏6次。问题描述:查看控制台打印的日志可以看出执行了sql语句,但是也查询到了2条记录,但是返回的结果为null,说明没有设置成功数据代码:Position.javapublic class Position implements Serializable { @Id// @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "position_id") private Integer id; _mapper查询成功但是返回空对象
文章浏览阅读106次。我有以下数据框,其中pd.concat已用于对列进行分组:a bC1 C2 C3 C4 C5 C6 C7 C80 15 37 17 10 8 11 19 861 39 84 11 5 5 13 9 112 10 20 30 51 74 62 56 583 88 2 1 3 9 6..._python 并列条形图 4
文章浏览阅读154次。一键ISP是BOOT0和BOOT1通过外界硬件连接都接GND,普通ISP是配置BOOT方式,BOOT0和BOOT1 为0和X 程序下载到Flash (DSP仿真器)BOOT0和BOOT1 为1和0 程序下载到系统存储器(串口就是下载在系统存储器)BOOT0和BOOT1 为1和1 程序下载到SRAM。STM32F103VET6的USART1的TXD(PA9)和RXD(PA10)引脚,BOOT0和BOOT1引脚分别接CH340的RXD和TXD引脚,GND和GND。USB转串口驱动 要先安装。_stm32f103vet6 boot0
文章浏览阅读28次。我们可以像访问普通元组的元素一样访问命名元组的字段,并且命名元组还提供了一些有用的方法,如转换为有序字典、替换字段值和获取字段名称等。它可以用于创建具有字段名称的不可变对象,这些对象可以像元组一样高效地处理,同时又具备字典的字段命名和访问的便利性。在使用命名元组之前,我们需要导入Python的collections模块,因为命名元组是该模块的一部分。命名元组是Python中一个强大且灵活的数据结构,它为我们提供了方便地处理和访问具有字段名称的不可变对象的能力。字段的值,但由于命名元组的不可变性,会抛出。
文章浏览阅读1.1k次。本文结合之前所学的awk命令和xargs命令以及shell中小数运算的语法,给出了四种方法,算是对已学命令的回顾吧。_编写shell脚本求平均值
文章浏览阅读98次。一、数据库操作1、用完马上关闭数据库连接 访问数据库资源需要创建连接、打开连接和关闭连接几个操作。这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资源。ASP.NET中提供了连接池(Connection Pool)改善打开和关闭数据库对性能的影响。系统将用户的数据库连接放在连接池中,需要时取出,关闭时收回连接,等待下一次的连接请求。 连接池的大小是有限的,如果在连接池达到最大限..._下面代码实现了禁用整个页的视图状态,请补充空白处的代码:
文章浏览阅读15次。2019可以被分解成若干个(不是两个)两两不同的素数,请问不同的分解方案有多少种?注意:分解方案不考虑顺序,如2+2017=2019和2017+2=2019属于同一种方案思路:这道题目考察的是01背包,题目中说分成若干个两两不同的素数,也就对应着背包中的物品只能被选择一次,而且选择物品的数量是任意的,所以就可以先打出一个素数筛,然后直接套01背包即可。f[i]表示用若干个两两不同的素数组成i的方案数,那么对于当前考虑的第j个素数prime[j]就有更新方式f[i]+=f[i-prime[j]],由_质数拆分蓝桥杯
文章浏览阅读1.3w次,点赞5次,收藏59次。创作时间:2022-01-05目录:1.问题引入(UIAxes中绘图)2.各种操作的代码(举例说明)正文:1.问题引入(UIAxes中绘图) 在matlab 的appdesginer设计过程中,经常要考虑如何在绘图区操作。这和在figure中绘图,有些不同,新手很容易在此犯迷糊,不知道怎么操作。这篇文章的目的:1) 对matlab appdesginer设计中的UIAxes各种操作做梳理2)彻底让新手掌握,以后不迷糊,不迷路。 注:本文值得收藏,有问题的时候,可以翻出来看看,就像“查字典_uiaxes