码迷,mamicode.com
首页 > 系统相关 > 详细

Linux quick write EEPROM by I2C bus

时间:2016-08-24 17:04:14      阅读:305      评论:0      收藏:0      [点我收藏+]

标签:

最近做东西遇到需要读写EEPROM的需求,利用SMBUS的方式write bye,发现效率很低,因为是利用ioctl的方式write的,所以每进行一次都需要delay 2000多us。Write 4096 bytes居然花了10秒,这不能忍啊~

SMBUS protocol 里面还有提供 i2c_smbus_write_block_data 与 i2c_smbus_write_i2c_block_data两种方法,但是貌似前面一种方法很多embeded设备中是不支持的,晕~

那就直接i2c_smbus_write_i2c_block_data吧,然后看了一下SMBUS对他的封装:

 1 static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
 2                                                __u8 length, __u8 *values)
 3 {
 4     union i2c_smbus_data data;
 5     int i;
 6     if (length > 32)
 7         length = 32;
 8     for (i = 1; i <= length; i++)
 9         data.block[i] = values[i-1];
10     data.block[0] = length;
11     return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
12                             I2C_SMBUS_I2C_BLOCK_DATA, &data);
13 }

居然直接把length写死了最大32 bytes,这应该是为了配合EEPROM 的 Page Size 的,那万一我的 Page Size 是64,128甚至256呢....

所以还是直接 override i2c_smbus_write_i2c_block_data 吧~

后来试了一下总是莫名fail...

算了,果然是不能偷懒的,索性直接自己写个 fuction 吧,也方便自己以后使用~

话不多说上代码:

  1 #include <stdio.h>
  2 #include <fcntl.h>
  3 #include <unistd.h>
  4 #include <stdlib.h>
  5 #include <linux/fs.h>
  6 #include <sys/types.h>
  7 #include <sys/ioctl.h>
  8 #include <errno.h>
  9 #include <assert.h>
 10 #include <string.h>
 11 #include <linux/i2c-dev.h>
 12 
 13 
 14 #define EEPROM_TYPE_UNKNOWN      0
 15 #define EEPROM_TYPE_8BIT_ADDR    1
 16 #define EEPROM_TYPE_16BIT_ADDR   2
 17 
 18 struct eeprom
 19 {
 20     char *dev;     // device file i.e. /dev/i2c-N
 21     int addr;    // i2c address
 22     int fd;        // file descriptor
 23     int type;     // eeprom type
 24 };
 25 
 26 int eeprom_open(char *dev_fqn, int addr, int type, struct eeprom* e)
 27 {
 28     int funcs, fd, r;
 29     e->fd = e->addr = 0;
 30     e->dev = 0;
 31     
 32     fd = open(dev_fqn, O_RDWR);
 33     if (fd <= 0)
 34         return -1;
 35 
 36     // get funcs list
 37     if ((r = ioctl(fd, I2C_FUNCS, &funcs) < 0))
 38         return -1;
 39     
 40     // check for req funcs
 41     CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE );
 42     CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE );
 43     CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_BYTE_DATA );
 44     CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_BYTE_DATA );
 45     CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_READ_WORD_DATA );
 46     CHECK_I2C_FUNC( funcs, I2C_FUNC_SMBUS_WRITE_WORD_DATA );
 47 
 48     // set working device
 49     if ((r = ioctl(fd, I2C_SLAVE, addr)) < 0)
 50         return -1;
 51     e->fd = fd;
 52     e->addr = addr;
 53     e->dev = dev_fqn;
 54     e->type = type;
 55     return 0;
 56 }
 57 
 58 int eeprom_close(struct eeprom *e)
 59 {
 60     close(e->fd);
 61     e->fd = -1;
 62     e->dev = 0;
 63     e->type = EEPROM_TYPE_UNKNOWN;
 64     return 0;
 65 }
 66 
 67 int write_eeprom(char *dev_fqn, __u16 slaveAddr, __u8 eepromType, __u32 eepromPageSize, __u8 *buff, __u16 addr, int size)
 68 {
 69     struct eeprom e;
 70     __u8 buf[eepromPageSize + 2];
 71     __u32 i,j,n,m;
 72     __u16 regAddr;
 73     __u8 *readyToWrite;
 74     int lastSize = size;
 75 
 76     if (!buff || size <= 0)
 77         return -1;
 78     
 79     if (eeprom_open(dev_fqn, slaveAddr, eepromType, &e) < 0)
 80     {
 81         eeprom_close(&e);
 82         return -1;
 83     }
 84     
 85     if ((addr % eepromPageSize) != 0)
 86     {
 87         readyToWrite = buff;
 88         regAddr = addr;
 89         
 90         if ((lastSize = write_eeprom_less_pageSize_data(
 91                 e.fd, eepromPageSize, readyToWrite, regAddr, size)) < 0)
 92         {
 93             eeprom_close(&e);
 94             return -1;
 95         }
 96     }
 97 
 98     usleep(2175);
 99     
100     if (lastSize == 0)
101     {
102         eeprom_close(&e);
103         return 0;
104     }
105 
106     if (lastSize < eepromPageSize)
107     {
108         readyToWrite = buff + (size - lastSize);
109         regAddr = addr + (size - lastSize);
110         
111         if ((lastSize = write_eeprom_less_pageSize_data(
112                 e.fd, eepromPageSize, readyToWrite, regAddr, lastSize)) < 0)
113         {
114             eeprom_close(&e);
115             return -1;
116         }
117         
118         eeprom_close(&e);
119         return 0;
120     }
121     
122     usleep(2175);
123     
124     n = lastSize / eepromPageSize;
125     m = lastSize % eepromPageSize;
126     
127     for (i = 0; i < n; i ++)
128     {
129         if (i != 0)
130             lastSize -= eepromPageSize;
131         readyToWrite = buff + (size - lastSize);
132         regAddr = addr + (size - lastSize);
133 
134         buf[0] = (regAddr >> 8) & 0x00ff;  
135         buf[1] = regAddr & 0x00ff;
136 
137         for (j = 0; j < eepromPageSize; j ++)
138         {
139             buf[2 + j] = *(readyToWrite + j);
140         }
141 
142         if (write(e.fd, buf, (eepromPageSize + 2)) != (eepromPageSize + 2))
143         {
144             eeprom_close(&e);
145             return -1;
146         }
147         
148         usleep(2175);
149     }
150 
151     if (m == 0)
152     {
153         eeprom_close(&e);
154         return 0;       
155     }
156 
157     lastSize -= eepromPageSize;
158 
159     readyToWrite = buff + (size - lastSize);
160     regAddr = addr + (size - lastSize);
161     
162     if ((lastSize = write_eeprom_less_pageSize_data(
163             e.fd, eepromPageSize, readyToWrite, regAddr, lastSize)) < 0)
164     {
165         eeprom_close(&e);
166         return -1;
167     }
168     
169     eeprom_close(&e);
170     return 0;
171 }
172 
173 int write_eeprom_less_pageSize_data(int fd, __u32 eepromPageSize, __u8 *buff,  __u16 addr, int size)
175 {
176     int writeSize,pageLastSize,i;
177     __u8 buf[eepromPageSize + 1];
178     
179     if (size <= 0)
180         return -1;
181 
182     pageLastSize = eepromPageSize - (addr % eepromPageSize);
183 
184     if (size <= pageLastSize)
185         writeSize = size;
186     else
187         writeSize = pageLastSize;
188 
189     buf[0] = (addr >> 8) & 0x00ff;  
190     buf[1] = addr & 0x00ff;
191 
192     for (i = 0; i < writeSize; i ++)
193     {
194         buf[2 + i] = *(buff + i);
195     }
196 
197     if (write(fd, buf, (writeSize + 2)) != (writeSize + 2))
198         return -1;
199     
200     return (size - writeSize);
201 }

也比较简单就不注释啦~(需要注意的是usleep的时间需要根据不同设备更改)

简单的用法如下:

 1 int clean_eeprom(__u16 addr, int size)
 2 {
 3     __u8 buf[size];
 4 
 5     memset(buf, 0, sizeof(buf));
 6     
 7     if (write_eeprom("/dev/i2c-0", 0x0050, EEPROM_TYPE_16BIT_ADDR, 64, buf, addr, size) < 0)
 8         return -1;
 9 
10     return 0;
11 }

使用之后发现写4096 bytes 从10秒缩短到0.1秒哦,真是棒棒哒~

By Shirlix

Linux quick write EEPROM by I2C bus

标签:

原文地址:http://www.cnblogs.com/Shirlix/p/5803688.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!