LinuxI2C驅動--從兩個訪問eeprom的例子開始

本小節介紹兩個在linux應用層訪問eeprom的方法,并給出示例代碼方便大家理解。第一個方法是通過sysfs文件系統對eeprom進行訪問,第二個方法是通過eeprom的設備文件進行訪問。這兩個方法分別對應了i2c設備驅動的兩個不同的實現,在后面的小結會詳細的分析。


我們嵌入式系統中的E2PROM 是 24C02.先簡單了解一下這款芯片:AT24C02的存儲容量為2Kb,內容分成32頁,每頁8B,共256B,操作時有兩種尋址方式:芯片尋址和片內子地址尋址。 (1)芯片尋址:AT24C02的芯片地址為1010,其地址控制字格式為 1010A2A1A0R/W。其中A2,A1,A0可編程地址選擇位。A2,A1,A0引腳接高、
低電平后得到確定的三位編碼,與1010形成7位編碼, 即為該器件的地址碼。R/W為芯片讀寫控制位,該位為0,表示芯片進行寫操作。 (2)片內子地址尋址:芯片尋址可對內部256B中的任一個進行讀/寫操作,其尋址范圍為00~FF,共256個尋址單位。


1. 通過sysfs文件系統訪問I2C設備

eeprom的設備驅動在/sys/bus/i2c/devices/0-0050/目錄下把eeprom設備映射為一個二進制節點,文件名為eeprom。對這個eeprom文件的讀寫就是對eeprom進行讀寫。

我們可以先用cat命令來看下eeprom的內容。

[root@FORLINX210]# cat eeprom                                                                      
�����������X�����������������������������������������������
  • 1
  • 2
  • 1
  • 2

發現里面都是亂碼,然后用echo命令把字符串“test”輸入給eeprom文件,然后再cat出來。

[root@FORLINX210]# echo "test" > eeprom  
[root@FORLINX210]# cat eeprom                                                 
test                                                                            
�����������X�����������������������������������������������
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

就會發現字符串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); //定位地址,地址是0x40if((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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

2. 通過devfs訪問I2C設備

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消息中的數據 */};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
 struct i2c_rdwr_ioctl_data {struct i2c_msg __user *msgs;    /* 指向一個i2c消息 */__u32 nmsgs;            /* i2c消息的數量 */};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

對一個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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

3. 總結

本小節介紹了兩種在linux應用層訪問eeprom的方法,并且給出了示例程序,通過sysfs文件系統訪問eeprom操作簡單,無需了解eeprom的硬件特性以及訪問時序,而通過devfs訪問eeprom的方法則需要了解eeprom的讀寫時序。

后面分析后會發現,第一種通過sysfs文件系統的二進制結點訪問eeprom的方法是由eeprom的設備驅動實現的,是一種專有的方法;而第二種通過devfs訪問eeprom的方法是linux i2c提供的一種通用的方法,訪問設備的能力有限。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252984.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252984.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252984.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Cookie詳解整理

1.Cookie的誕生 由于HTTP協議是無狀態的&#xff0c;而服務器端的業務必須是要有狀態的。Cookie誕生的最初目的是為了存儲web中的狀態信息&#xff0c;以方便服務器端使用。比如判斷用戶是否是第一次訪問網站。目前最新的規范是RFC 6265&#xff0c;它是一個由瀏覽器服務器共同…

驍龍820和KryoCPU:異構計算與定制計算的作用 【轉】

本文轉載自&#xff1a;https://www.douban.com/group/topic/89037625/ Qualcomm驍龍820處理器專為提供創新用戶體驗的頂級移動終端而設計。為實現消費者所期望的創新&#xff0c;移動處理器必須滿足日益增長的計算需求且降低功耗&#xff0c;同時還要擁有比以往更低的溫度&…

LNMP

準備工作 建立一個軟件包目錄存放 mkdir -p /usr/local/src/ 清理已經安裝包 rpm -e httpd rpm -e mysql rpm -e php yum -y remove httpd yum -y remove mysql yum -y remove php #搜索apache包 rpm -qa http* #強制卸載apache包 rpm -e --nodeps 查詢出來的文件名 #檢查是否卸…

算法復習——計算幾何基礎(zoj1081)

題目&#xff1a; Statement of the Problem Several drawing applications allow us to draw polygons and almost all of them allow us to fill them with some color. The task of filling a polygon reduces to knowing which points are inside it, so programmers have …

亞馬遜Rekognition發布針對人臉檢測、分析和識別功能的多項更新

今天亞馬遜Rekognition針對人臉檢測、分析和識別功能推出了一系列更新。這些更新將為用戶帶來多項能力的改今&#xff0c;包括從圖像中檢測出更多人臉、執行更高精度的人臉匹配以及獲得圖像中的人臉得到更準確的年齡、性別和情感屬性。Amazon Rekognition的客戶可以從今天開始使…

(轉)CentOS分區操作詳解

CentOS分區操作詳解 原文&#xff1a;http://blog.csdn.net/yonggeit/article/details/77924393 磁盤分區 分區格式的兩種選擇&#xff1a;MBR和GPT 分區命令&#xff1a; parted的操作都是實時生效的&#xff0c;小心使用&#xff0c;主要是用于大于2T硬盤&#xff0c;支持MBR…

linux驅動中地址空間轉換

在linux kernel 中&#xff0c;物理地址是不能直接使用的&#xff0c;必須通過轉換才可以。轉換分為兩種&#xff0c; 靜態和動態。 靜態就是下面那種&#xff0c;不過&#xff0c;靜態的地址轉換&#xff0c;還需要在kernel 初始化的時候作映射。 動態映射是使用 ioremap 函…

getClass()和.class的區別

getClass()和.class的區別 在學習反射時想到了這個問題&#xff0c;.getClass()和.class有沒有什么區別&#xff1f; 當然&#xff0c;最明顯的區別就是.getClass()是一個對象實例的方法&#xff0c;只有對象實例才有這個方法&#xff0c;具體的類是沒有的。類的Class類實例是通…

華為敏捷 DevOps 實踐:產品經理如何開好敏捷回顧會議

開篇小故事&#xff1a;前幾年&#xff0c;一本叫《沉思錄》的書在國內突然曝光度很多&#xff0c;因為前某國家領導人“擺案頭&#xff0c;讀百遍”。《沉思錄》是古羅馬皇帝馬可奧勒寫給自己的書&#xff0c;內容大部分是在鞍馬勞頓中寫的。其實有一句“我們所聽到的不過只是…

斐波那契數列的鬼畜的性質

斐波那契數列的鬼畜的性質 斐波那契數列定理1 \(gcd(f[i],f[i1])1\) 利用輾轉相減法 證明&#xff1a;\(gcd(f[i],f[i1])\)\(gcd(f[i1]-f[i],f[i])\)\(gcd(f[i-1],f[i])\)\(....\)\(gcd(f[1],f[2])1\) 斐波那契數列定理2 \(f[mn]f[m-1]f[n]f[m]f[n1]\) 證明&#xff1a;\(f[mn]…

xml與java對象轉換 -- XStreamAlias

XStreamAlias使用 一、 特點: 簡化的API; 無映射文件; 高性能,低內存占用; 整潔的XML; 不需要修改對象;支持內部私有字段,不需要setter/getter方法 提供序列化接口; 自定義轉換類型策略; XStream的優點很多&#xff0c;但是也有一些小bug&#xff0c;比如在定義別名中的下劃線…

windows下安裝zabbix_agent

Server端在linux系統上&#xff0c;server端版本為2.2.6&#xff0c;是以前就裝好的已經跑了很久的穩定版。目前的需求是要將新業務的服務器添加到該監控隊列。而這些服務器是windows系統。 第一次下載了最新版的zabbix_agent for windows。按照正常程序安裝完成后&#xff0c;…

JS和Jquery獲取和修改label的值

獲取值&#xff1a; label標簽在JS和Jquery中使用不能像其他標簽一樣用value獲取它的值&#xff1a; var labeldocument.getElementById("id");var valuelabel.value;var value$("#id").val();可以這樣&#xff1a;JS: var labeldocument.getElementById(&…

Linux內核訪問外設I/O--動態映射(ioremap)和靜態映射(map_desc)

本篇文章主要介紹了"Linux內核訪問外設I/O--動態映射(ioremap)和靜態映射(map_desc)"&#xff0c;主要涉及到Linux內核訪問外設I/O--動態映射(ioremap)和靜態映射(map_desc)方面的內容&#xff0c;對于Linux內核訪問外設I/O--動態映射(ioremap)和靜態映射(map_desc)感…

點擊顯示隱藏盒子函數

示例&#xff1a;&#xff08;手機導航欄&#xff09; <header> <div class"logo"></div> <p class"text">微蜂傳媒</p> <div class"nav_btn" οnclick"showHide(.dropdown_menu)"></div> …

MyBatis 緩存機制

Mybatis 有兩級緩存&#xff1a; 一級緩存&#xff1a; 也稱為本地緩存&#xff0c;SqlSession級別的緩存。一級緩存是一直開啟的&#xff1b; 與數據庫同一次會話期間查詢到的數據會放在本地緩存中&#xff0c;以后如果需要獲取相同的數據&#xff0c;直接從緩存中拿&#xff…

Android虛擬化引擎VirtualApp探究

2019獨角獸企業重金招聘Python工程師標準>>> 介紹 首先需要說明的是&#xff0c;VirtualApp并不是前些陣子滴滴開源的插件化框架VirtualApk。 VirtualApp是一個更加黑科技的東西&#xff0c;他可以創建一個虛擬空間&#xff0c;你可以在虛擬空間內任意的安裝、啟動和…

揭開全景相機的創業真相

&#xff08;Bubl全景相機&#xff09; 國外一開源&#xff0c;國內就自主。這在VR&#xff08;虛擬現實&#xff09;領域體現的淋漓盡致——Google的Cardborad一開源&#xff0c;國內就有數百家廠商蜂擁做了各種插手機的VR盒子。到了全景相機&#xff0c;這一幕似乎又開始重演…

一個厲害的網站

2019獨角獸企業重金招聘Python工程師標準>>> dromara 發現一個網站&#xff0c;發現上面的開源項目真的都非常厲害誒。 轉載于:https://my.oschina.net/miaojiangmin/blog/2934221