CubieBoard中文论坛

 找回密码
 立即注册
搜索
热搜: unable
查看: 11421|回复: 4

i2c访问外接AT24C256 EEPROM

[复制链接]
发表于 2013-11-18 19:23:55 | 显示全部楼层 |阅读模式
本帖最后由 soloforce 于 2013-11-18 21:17 编辑

发个i2c访问at24c256 eeprom( at24c256.pdf (362.27 KB, 下载次数: 18) )的DIY,按例先上图。
P31118-185838_1.jpg
P31118-190026.jpg
2013-11-18-192122_627x378_scrot.png
2013-11-18-191502_627x378_scrot.png

用了四个at24c256, 并联在Cubieboard的TWI-1接口上,设备文件是/dev/i2c-1。下面我画的示意图有点小错,把WP脚接VCC了,会导致写保护(无法写入),必须悬空掉。
4-at24c256.png

为了更清楚地了解at24c,给个设备编址说明,网上下载的,不过有错误,我已经修正了。
at24c.png
研究了一下午i2c on linux,终于写出了代码:

  1. /*
  2. * at24c256_i2c.c
  3. *
  4. * This script is a demo for AT24C256 EEPROM access via I2C on Cubieboard
  5. *
  6. * Author: soloforce, forum.cubietech.com
  7. * Date: 2013.11.18
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  10. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  11. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  12. * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  13. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  14. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  15. *
  16. */

  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <unistd.h>
  20. #include <fcntl.h>
  21. #include <sys/ioctl.h>
  22. #include <linux/i2c-dev.h>

  23. // Cubieboard IO port PB18 & PB19 are configured to TWI1-SCK & TWI1-SDA (I2C-1)
  24. #define DEFAULT_AT24C256_DEV  "/dev/i2c-1"

  25. // ATmega AT24C series EEPROM slave devices are addressed from 0x50~0x57
  26. // As for AT24C256, should be 0x50~0x53
  27. #define DEFAULT_AT24C256_ADDRESS 0x50

  28. // AT24C256 has 512 pages, 64 bytes each
  29. #define PAGE_BYTES  64  

  30. typedef unsigned char uint8;
  31. typedef unsigned short uint16;

  32. /*
  33. * Open the i2c bus device
  34. */
  35. int init_at24c256_i2c(const char* device)
  36. {
  37.     int fd=open(device, O_RDWR);
  38.     if(fd<0){
  39.         perror("Failed to open I2C device!");
  40.         return -1;
  41.     }

  42.     ioctl(fd, I2C_TIMEOUT, 3);        // i2c timeout, 1 for 10ms ; if too small, i2c may lose response
  43.     ioctl(fd, I2C_RETRIES, 3);        // i2c retry limit
  44.    
  45.     return fd;
  46. }

  47. /*
  48. * Page write (or partially page write), data_len should less than PAGE_BYTES
  49. *
  50. */
  51. int at24c256_write(int fd, int device_addr, uint16 offset, const char* data, int data_len)
  52. {
  53.     struct i2c_rdwr_ioctl_data at24c256;        // structure pass to i2c driver
  54.     struct i2c_msg i2cmsg;

  55.     if(data_len>PAGE_BYTES){
  56.         printf("*** Warning: Page write mode should not exceed %d bytes, otherwise the current page will be rolled over!\n",PAGE_BYTES);
  57.     }

  58.     at24c256.nmsgs = 1;        // message count in the structure
  59.     at24c256.msgs = &i2cmsg;
  60.     at24c256.msgs[0].len = 2 + data_len;        // the offset address word is 2 bytes long, plus the buf_len
  61.     at24c256.msgs[0].addr = device_addr;        // i2c slave device address
  62.     at24c256.msgs[0].flags = 0;        // 0 for write; 1 for read
  63.     at24c256.msgs[0].buf = (uint8 *)malloc( at24c256.msgs[0].len );
  64.     if(!at24c256.msgs[0].buf){
  65.         printf("at24c256_write(): Failed to allocate memory for i2c message buffer!\n");
  66.         return -1;
  67.     }
  68.    
  69.     at24c256.msgs[0].buf[0] = (uint8)(offset >> 8);        // MSB first
  70.     at24c256.msgs[0].buf[1] = (uint8)(offset);        // LSB
  71.     strncpy( at24c256.msgs[0].buf+2, data, data_len); // copy user's data to the structure buffer

  72.     if(ioctl(fd, I2C_RDWR, (unsigned long)&at24c256)<0 ){        // write ioctl data to the i2c bus
  73.         printf("at24c256_write(): Failed to write data to i2c device!\n");
  74.         free(at24c256.msgs[0].buf);
  75.         return -1;
  76.     }
  77.    
  78.     free(at24c256.msgs[0].buf);
  79.     return 0;
  80. }

  81. /*
  82. * Sequential read from AT24C256, data_len should less than PAGE_BYTES
  83. */
  84. int at24c256_read(int fd, int device_addr, uint16 offset, char* data, int data_len)
  85. {
  86.     struct i2c_rdwr_ioctl_data at24c256;        // structure pass to i2c driver
  87.     struct i2c_msg i2cmsg[2]; // message count in the structure
  88.     char dummy_write_buf[2];
  89.    
  90.     if(data_len>PAGE_BYTES){
  91.         printf("*** Warning: Sequential read should not exceed %d bytes, otherwise the read data will be rolled over!\n",PAGE_BYTES);
  92.     }

  93.     // A dummy write operation should be done according to the AT24C256 i2c protocol
  94.     at24c256.nmsgs = 2;        // message count in the structure
  95.     at24c256.msgs = i2cmsg;
  96.     at24c256.msgs[0].len = 2; // the offset address word is 2 bytes long
  97.     at24c256.msgs[0].addr = device_addr;
  98.     at24c256.msgs[0].flags = 0;        // 0 for write;
  99.     at24c256.msgs[0].buf = dummy_write_buf;
  100.     at24c256.msgs[0].buf[0] = (unsigned char)(offset >> 8);        // write address
  101.     at24c256.msgs[0].buf[1] = (unsigned char)(offset);        // write address

  102.     // read operation
  103.     at24c256.msgs[1].len = data_len;
  104.     at24c256.msgs[1].addr = device_addr;
  105.     at24c256.msgs[1].flags = 1;        // 1 for read; 0 for write
  106.     at24c256.msgs[1].buf = data;

  107.     if (ioctl(fd, I2C_RDWR, (unsigned long)&at24c256) < 0) {
  108.         printf("at24c256_read(): Failed to read data from EEPROM via i2c!\n");
  109.         return -1;
  110.     }

  111.     return 0;
  112. }

  113. /*
  114. * Show help message
  115. */
  116. void show_usage(char* argv[])
  117. {
  118.     printf("%s <-d device> <-a address> [-o offset] [-r length] [-w data] [-h]\n",argv[0]);
  119.     printf("\t-d device: i2c device file, like /dev/i2c-1 by default\n");
  120.     printf("\t-a address: i2c slave device base address, like 0x50 by default\n");
  121.     printf("\t-o offset: offset from base address, like 0x00, 0x10 ...\n");
  122.     printf("\t-r length: read length bytes from at24c256 eeprom\n");
  123.     printf("\t-w data: write to at24c256 eeprom\n");
  124.     printf("\t-h: show help message\n\n");
  125. }

  126. int main(int argc, char* argv[])
  127. {
  128.     char* device=DEFAULT_AT24C256_DEV;
  129.     int slave_address=DEFAULT_AT24C256_ADDRESS;
  130.     int offset=0x00; // default offset is 0
  131.     int length=32; // read 32 bytes by default
  132.     char* data=NULL;
  133.     int rw_mode=1; // 0 for write, 1 for read;

  134.     if(argc==1){
  135.         show_usage(argv);
  136.         return 0;
  137.     }

  138.     int i;
  139.     while ((i = getopt(argc, argv, "d:a:o:r:w:n:h")) >= 0){
  140.         switch(i){
  141.         case 'd':
  142.             device=optarg;
  143.             break;
  144.         case 'a':
  145.             if (sscanf(optarg, "0x%x", &slave_address) != 1) {
  146.             fprintf(stderr, "Cannot parse '%s' as i2c slave device address, example: '0x50'\n", optarg);
  147.                 return -1;
  148.             }
  149.             break;
  150.         case 'o':
  151.             if (sscanf(optarg, "%d", &offset) != 1) {
  152.             fprintf(stderr, "Cannot parse '%s' as address offset, example: '32'\n", optarg);
  153.                 return -1;
  154.             }
  155.             break;
  156.         case 'r':
  157.             rw_mode=1;
  158.             if (sscanf(optarg, "%d", &length) != 1) {
  159.                 fprintf(stderr, "Cannot parse '%s' as length, example: '17'\n", optarg);
  160.                 return -1;
  161.             }
  162.             break;
  163.         case 'w':
  164.             rw_mode=0;
  165.             data=optarg;
  166.             length=strlen(data);
  167.             break;
  168.         case 'h':
  169.             show_usage(argv);
  170.             return 0;
  171.             break;
  172.         }
  173.     }
  174.    
  175.     int fd=init_at24c256_i2c(device);
  176.     if(fd<0) return -1;

  177.     printf("i2c device file:%s\nslave_address:0x%X\nR/W offset:0x%X\n",device, slave_address, offset);

  178.     if(rw_mode==0){
  179.         // test at24c256 write
  180.         at24c256_write(fd, slave_address, offset, data, length);
  181.         printf("try to write: %s (%d bytes)!\n",data,length);
  182.         usleep(10000); // some delay is necessary for the write operation done
  183.     }else if(rw_mode==1){
  184.         // test at24c256 read
  185.         char *buf=(char*)malloc(length+1);
  186.         memset(buf,0,length+1);
  187.         at24c256_read(fd, slave_address, offset, buf, length);
  188.         usleep(10000); // necessary for the read operation done
  189.         
  190.         printf("read from at24c256 eeprom: %s (%d bytes)\n", buf, strlen(buf));
  191.         free(buf);
  192.     }
  193.    
  194.     close(fd);
  195. }

复制代码
回复

使用道具 举报

发表于 2013-11-19 13:20:52 | 显示全部楼层
当年用8051驱动 24C02那个心酸啊,代码一长串的。
注意一下24系列的ROM的死区时间是8ms左右。如果两次写入间隔时间太短会没有响应。
回复 支持 反对

使用道具 举报

发表于 2014-3-14 14:15:10 | 显示全部楼层
怎么报错了。at24.c:48:12: error: invalid use of undefined type ‘struct i2c_msg’
这个结构体没声明啊。差那个头文件了吗?
回复 支持 反对

使用道具 举报

发表于 2014-3-14 21:41:00 | 显示全部楼层
不错,基于应用层的驱动
回复 支持 反对

使用道具 举报

发表于 2014-3-14 21:41:38 | 显示全部楼层
内核有专门针对at eeprom的驱动
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|粤ICP备13051116号|cubie.cc---深刻的嵌入式技术讨论社区

GMT+8, 2024-4-27 10:52 , Processed in 0.031336 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2012 Comsenz Inc. | Style by Coxxs

返回顶部